aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2013-12-08 20:39:02 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-20 10:45:12 -0500
commit5a04f32ce5dca8dce0061e995fc7265e58d2d5c0 (patch)
tree9ce5c8b7cf1142a83c02f6655d82b17e9475b047 /arch/arm/mach-omap2/omap_hwmod.c
parentf5749e3720c038fe92dc9ffb5e6fe7b4d8809ea1 (diff)
ARM: OMAP2+: hwmod: Fix SOFTRESET logic
commit 313a76ee11cda6700548afe68499ef174a240688 upstream. In _ocp_softreset(), after _set_softreset() + write_sysconfig(), the hwmod's sysc_cache will always contain SOFTRESET bit set so all further writes to sysconfig using this cache will initiate a repeated SOFTRESET e.g. enable_sysc(). This is true for OMAP3 like platforms that have RESET_DONE status in the SYSSTATUS register and so the the SOFTRESET bit in SYSCONFIG is not automatically cleared. It is not a problem for OMAP4 like platforms that indicate RESET completion by clearing the SOFTRESET bit in the SYSCONFIG register. This repeated SOFTRESET is undesired and was the root cause of USB host issues on OMAP3 platforms when hwmod was allowed to do the SOFTRESET for the USB Host module. To fix this we clear the SOFTRESET bit and update the sysconfig register + sysc_cache using write_sysconfig(). Signed-off-by: Roger Quadros <rogerq@ti.com> Tested-by: Tomi Valkeinen <tomi.valkeinen@ti.com> # Panda, BeagleXM [paul@pwsan.com: renamed _clr_softreset() to _clear_softreset()] Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c43
1 files changed, 42 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 7341eff63f56..44c609a1ec5d 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -399,7 +399,7 @@ static int _set_clockactivity(struct omap_hwmod *oh, u8 clockact, u32 *v)
399} 399}
400 400
401/** 401/**
402 * _set_softreset: set OCP_SYSCONFIG.CLOCKACTIVITY bits in @v 402 * _set_softreset: set OCP_SYSCONFIG.SOFTRESET bit in @v
403 * @oh: struct omap_hwmod * 403 * @oh: struct omap_hwmod *
404 * @v: pointer to register contents to modify 404 * @v: pointer to register contents to modify
405 * 405 *
@@ -427,6 +427,36 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
427} 427}
428 428
429/** 429/**
430 * _clear_softreset: clear OCP_SYSCONFIG.SOFTRESET bit in @v
431 * @oh: struct omap_hwmod *
432 * @v: pointer to register contents to modify
433 *
434 * Clear the SOFTRESET bit in @v for hwmod @oh. Returns -EINVAL upon
435 * error or 0 upon success.
436 */
437static int _clear_softreset(struct omap_hwmod *oh, u32 *v)
438{
439 u32 softrst_mask;
440
441 if (!oh->class->sysc ||
442 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
443 return -EINVAL;
444
445 if (!oh->class->sysc->sysc_fields) {
446 WARN(1,
447 "omap_hwmod: %s: sysc_fields absent for sysconfig class\n",
448 oh->name);
449 return -EINVAL;
450 }
451
452 softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
453
454 *v &= ~softrst_mask;
455
456 return 0;
457}
458
459/**
430 * _wait_softreset_complete - wait for an OCP softreset to complete 460 * _wait_softreset_complete - wait for an OCP softreset to complete
431 * @oh: struct omap_hwmod * to wait on 461 * @oh: struct omap_hwmod * to wait on
432 * 462 *
@@ -1909,6 +1939,12 @@ static int _ocp_softreset(struct omap_hwmod *oh)
1909 ret = _set_softreset(oh, &v); 1939 ret = _set_softreset(oh, &v);
1910 if (ret) 1940 if (ret)
1911 goto dis_opt_clks; 1941 goto dis_opt_clks;
1942
1943 _write_sysconfig(v, oh);
1944 ret = _clear_softreset(oh, &v);
1945 if (ret)
1946 goto dis_opt_clks;
1947
1912 _write_sysconfig(v, oh); 1948 _write_sysconfig(v, oh);
1913 1949
1914 if (oh->class->sysc->srst_udelay) 1950 if (oh->class->sysc->srst_udelay)
@@ -3148,6 +3184,11 @@ int omap_hwmod_softreset(struct omap_hwmod *oh)
3148 goto error; 3184 goto error;
3149 _write_sysconfig(v, oh); 3185 _write_sysconfig(v, oh);
3150 3186
3187 ret = _clear_softreset(oh, &v);
3188 if (ret)
3189 goto error;
3190 _write_sysconfig(v, oh);
3191
3151error: 3192error:
3152 return ret; 3193 return ret;
3153} 3194}