diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 170 | 
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 e282e35769f..1125134c9a7 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 */ @@ -904,18 +901,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); @@ -1354,14 +1349,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++) { @@ -1455,7 +1452,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)) @@ -1467,12 +1464,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); @@ -1480,9 +1475,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;  } @@ -1585,65 +1585,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.   */ -int __init omap_hwmod_init(struct omap_hwmod **ohs) +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_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; +	} -	inited = 1; +	oh = _lookup(oh_name); +	if (!oh) { +		WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); +		return -EINVAL; +	} -	if (!ohs) -		return 0; +	if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) +		omap_hwmod_setup_one(MPU_INITIATOR_NAME); -	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 = _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; +	} + +	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 @@ -1862,6 +1929,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; @@ -2162,11 +2230,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)  {  |