aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c170
1 files changed, 119 insertions, 51 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 2dd1ea9859b..e39772beaed 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1,7 +1,7 @@
/*
* omap_hwmod implementation for OMAP2/3/4
*
- * Copyright (C) 2009-2010 Nokia Corporation
+ * Copyright (C) 2009-2011 Nokia Corporation
*
* Paul Walmsley, BenoƮt Cousson, Kevin Hilman
*
@@ -162,9 +162,6 @@ static LIST_HEAD(omap_hwmod_list);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;
-/* inited: 0 if omap_hwmod_init() has not yet been called; 1 otherwise */
-static u8 inited;
-
/* Private functions */
@@ -912,18 +909,16 @@ static struct omap_hwmod *_lookup(const char *name)
* @oh: struct omap_hwmod *
* @data: not used; pass NULL
*
- * Called by omap_hwmod_late_init() (after omap2_clk_init()).
- * Resolves all clock names embedded in the hwmod. Returns -EINVAL if
- * the omap_hwmod has not yet been registered or if the clocks have
- * already been initialized, 0 on success, or a non-zero error on
- * failure.
+ * Called by omap_hwmod_setup_*() (after omap2_clk_init()).
+ * Resolves all clock names embedded in the hwmod. Returns 0 on
+ * success, or a negative error code on failure.
*/
static int _init_clocks(struct omap_hwmod *oh, void *data)
{
int ret = 0;
- if (!oh || (oh->_state != _HWMOD_STATE_REGISTERED))
- return -EINVAL;
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
+ return 0;
pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name);
@@ -1398,14 +1393,16 @@ static int _shutdown(struct omap_hwmod *oh)
* @oh: struct omap_hwmod *
*
* Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the
- * wrong state or returns 0.
+ * OCP_SYSCONFIG register. Returns 0.
*/
static int _setup(struct omap_hwmod *oh, void *data)
{
int i, r;
u8 postsetup_state;
+ if (oh->_state != _HWMOD_STATE_CLKS_INITED)
+ return 0;
+
/* Set iclk autoidle mode */
if (oh->slaves_cnt > 0) {
for (i = 0; i < oh->slaves_cnt; i++) {
@@ -1499,7 +1496,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
*/
static int __init _register(struct omap_hwmod *oh)
{
- int ret, ms_id;
+ int ms_id;
if (!oh || !oh->name || !oh->class || !oh->class->name ||
(oh->_state != _HWMOD_STATE_UNKNOWN))
@@ -1511,12 +1508,10 @@ static int __init _register(struct omap_hwmod *oh)
return -EEXIST;
ms_id = _find_mpu_port_index(oh);
- if (!IS_ERR_VALUE(ms_id)) {
+ if (!IS_ERR_VALUE(ms_id))
oh->_mpu_port_index = ms_id;
- oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
- } else {
+ else
oh->_int_flags |= _HWMOD_NO_MPU_PORT;
- }
list_add_tail(&oh->node, &omap_hwmod_list);
@@ -1524,9 +1519,14 @@ static int __init _register(struct omap_hwmod *oh)
oh->_state = _HWMOD_STATE_REGISTERED;
- ret = 0;
+ /*
+ * XXX Rather than doing a strcmp(), this should test a flag
+ * set in the hwmod data, inserted by the autogenerator code.
+ */
+ if (!strcmp(oh->name, MPU_INITIATOR_NAME))
+ mpu_oh = oh;
- return ret;
+ return 0;
}
@@ -1629,65 +1629,132 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
return ret;
}
-
/**
- * omap_hwmod_init - init omap_hwmod code and register hwmods
+ * omap_hwmod_register - register an array of hwmods
* @ohs: pointer to an array of omap_hwmods to register
*
* Intended to be called early in boot before the clock framework is
* initialized. If @ohs is not null, will register all omap_hwmods
- * listed in @ohs that are valid for this chip. Returns -EINVAL if
- * omap_hwmod_init() has already been called or 0 otherwise.
+ * listed in @ohs that are valid for this chip. Returns 0.
+ */
+int __init omap_hwmod_register(struct omap_hwmod **ohs)
+{
+ int r, i;
+
+ if (!ohs)
+ return 0;
+
+ i = 0;
+ do {
+ if (!omap_chip_is(ohs[i]->omap_chip))
+ continue;
+
+ r = _register(ohs[i]);
+ WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name,
+ r);
+ } while (ohs[++i]);
+
+ return 0;
+}
+
+/*
+ * _populate_mpu_rt_base - populate the virtual address for a hwmod
+ *
+ * Must be called only from omap_hwmod_setup_*() so ioremap works properly.
+ * Assumes the caller takes care of locking if needed.
+ */
+static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data)
+{
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
+ return 0;
+
+ if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+ return 0;
+
+ oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
+ if (!oh->_mpu_rt_va)
+ pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n",
+ __func__, oh->name);
+
+ return 0;
+}
+
+/**
+ * omap_hwmod_setup_one - set up a single hwmod
+ * @oh_name: const char * name of the already-registered hwmod to set up
+ *
+ * Must be called after omap2_clk_init(). Resolves the struct clk
+ * names to struct clk pointers for each registered omap_hwmod. Also
+ * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon
+ * success.
*/
-int __init omap_hwmod_init(struct omap_hwmod **ohs)
+int __init omap_hwmod_setup_one(const char *oh_name)
{
struct omap_hwmod *oh;
int r;
- if (inited)
+ pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
+
+ if (!mpu_oh) {
+ pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n",
+ oh_name, MPU_INITIATOR_NAME);
+ return -EINVAL;
+ }
+
+ oh = _lookup(oh_name);
+ if (!oh) {
+ WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
return -EINVAL;
+ }
- inited = 1;
+ if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
+ omap_hwmod_setup_one(MPU_INITIATOR_NAME);
- if (!ohs)
- return 0;
+ r = _populate_mpu_rt_base(oh, NULL);
+ if (IS_ERR_VALUE(r)) {
+ WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name);
+ return -EINVAL;
+ }
- oh = *ohs;
- while (oh) {
- if (omap_chip_is(oh->omap_chip)) {
- r = _register(oh);
- WARN(r, "omap_hwmod: %s: _register returned "
- "%d\n", oh->name, r);
- }
- oh = *++ohs;
+ r = _init_clocks(oh, NULL);
+ if (IS_ERR_VALUE(r)) {
+ WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name);
+ return -EINVAL;
}
+ _setup(oh, NULL);
+
return 0;
}
/**
- * omap_hwmod_late_init - do some post-clock framework initialization
+ * omap_hwmod_setup - do some post-clock framework initialization
*
* Must be called after omap2_clk_init(). Resolves the struct clk names
* to struct clk pointers for each registered omap_hwmod. Also calls
- * _setup() on each hwmod. Returns 0.
+ * _setup() on each hwmod. Returns 0 upon success.
*/
-int omap_hwmod_late_init(void)
+static int __init omap_hwmod_setup_all(void)
{
int r;
- /* XXX check return value */
- r = omap_hwmod_for_each(_init_clocks, NULL);
- WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n");
+ if (!mpu_oh) {
+ pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
+ __func__, MPU_INITIATOR_NAME);
+ return -EINVAL;
+ }
+
+ r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL);
- mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME);
- WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n",
- MPU_INITIATOR_NAME);
+ r = omap_hwmod_for_each(_init_clocks, NULL);
+ WARN(IS_ERR_VALUE(r),
+ "omap_hwmod: %s: _init_clocks failed\n", __func__);
omap_hwmod_for_each(_setup, NULL);
return 0;
}
+core_initcall(omap_hwmod_setup_all);
/**
* omap_hwmod_enable - enable an omap_hwmod
@@ -1906,6 +1973,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
os = oh->slaves[i];
for (j = 0; j < os->addr_cnt; j++) {
+ (res + r)->name = (os->addr + j)->name;
(res + r)->start = (os->addr + j)->pa_start;
(res + r)->end = (os->addr + j)->pa_end;
(res + r)->flags = IORESOURCE_MEM;
@@ -2206,11 +2274,11 @@ int omap_hwmod_for_each_by_class(const char *classname,
* @oh: struct omap_hwmod *
* @state: state that _setup() should leave the hwmod in
*
- * Sets the hwmod state that @oh will enter at the end of _setup() (called by
- * omap_hwmod_late_init()). Only valid to call between calls to
- * omap_hwmod_init() and omap_hwmod_late_init(). Returns 0 upon success or
- * -EINVAL if there is a problem with the arguments or if the hwmod is
- * in the wrong state.
+ * Sets the hwmod state that @oh will enter at the end of _setup()
+ * (called by omap_hwmod_setup_*()). Only valid to call between
+ * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns
+ * 0 upon success or -EINVAL if there is a problem with the arguments
+ * or if the hwmod is in the wrong state.
*/
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
{