diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 63 | 
1 files changed, 49 insertions, 14 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b969ab1d258..87cc6d058de 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -422,6 +422,38 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)  }  /** + * _wait_softreset_complete - wait for an OCP softreset to complete + * @oh: struct omap_hwmod * to wait on + * + * Wait until the IP block represented by @oh reports that its OCP + * softreset is complete.  This can be triggered by software (see + * _ocp_softreset()) or by hardware upon returning from off-mode (one + * example is HSMMC).  Waits for up to MAX_MODULE_SOFTRESET_WAIT + * microseconds.  Returns the number of microseconds waited. + */ +static int _wait_softreset_complete(struct omap_hwmod *oh) +{ +	struct omap_hwmod_class_sysconfig *sysc; +	u32 softrst_mask; +	int c = 0; + +	sysc = oh->class->sysc; + +	if (sysc->sysc_flags & SYSS_HAS_RESET_STATUS) +		omap_test_timeout((omap_hwmod_read(oh, sysc->syss_offs) +				   & SYSS_RESETDONE_MASK), +				  MAX_MODULE_SOFTRESET_WAIT, c); +	else if (sysc->sysc_flags & SYSC_HAS_RESET_STATUS) { +		softrst_mask = (0x1 << sysc->sysc_fields->srst_shift); +		omap_test_timeout(!(omap_hwmod_read(oh, sysc->sysc_offs) +				    & softrst_mask), +				  MAX_MODULE_SOFTRESET_WAIT, c); +	} + +	return c; +} + +/**   * _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v   * @oh: struct omap_hwmod *   * @@ -1282,6 +1314,18 @@ static void _enable_sysc(struct omap_hwmod *oh)  	if (!oh->class->sysc)  		return; +	/* +	 * Wait until reset has completed, this is needed as the IP +	 * block is reset automatically by hardware in some cases +	 * (off-mode for example), and the drivers require the +	 * IP to be ready when they access it +	 */ +	if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) +		_enable_optional_clocks(oh); +	_wait_softreset_complete(oh); +	if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) +		_disable_optional_clocks(oh); +  	v = oh->_sysc_cache;  	sf = oh->class->sysc->sysc_flags; @@ -1804,7 +1848,7 @@ static int _am33xx_disable_module(struct omap_hwmod *oh)   */  static int _ocp_softreset(struct omap_hwmod *oh)  { -	u32 v, softrst_mask; +	u32 v;  	int c = 0;  	int ret = 0; @@ -1834,19 +1878,7 @@ static int _ocp_softreset(struct omap_hwmod *oh)  	if (oh->class->sysc->srst_udelay)  		udelay(oh->class->sysc->srst_udelay); -	if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) -		omap_test_timeout((omap_hwmod_read(oh, -						    oh->class->sysc->syss_offs) -				   & SYSS_RESETDONE_MASK), -				  MAX_MODULE_SOFTRESET_WAIT, c); -	else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS) { -		softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift); -		omap_test_timeout(!(omap_hwmod_read(oh, -						     oh->class->sysc->sysc_offs) -				   & softrst_mask), -				  MAX_MODULE_SOFTRESET_WAIT, c); -	} - +	c = _wait_softreset_complete(oh);  	if (c == MAX_MODULE_SOFTRESET_WAIT)  		pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",  			   oh->name, MAX_MODULE_SOFTRESET_WAIT); @@ -2352,6 +2384,9 @@ static int __init _setup_reset(struct omap_hwmod *oh)  	if (oh->_state != _HWMOD_STATE_INITIALIZED)  		return -EINVAL; +	if (oh->flags & HWMOD_EXT_OPT_MAIN_CLK) +		return -EPERM; +  	if (oh->rst_lines_cnt == 0) {  		r = _enable(oh);  		if (r) {  |