aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenoit Cousson <b-cousson@ti.com>2010-09-21 12:57:58 -0400
committerPaul Walmsley <paul@pwsan.com>2010-09-21 17:28:30 -0400
commit96835af970e5d6aeedf868e53590a947be5e4a7a (patch)
tree5251098665c477c9ce6f7a0215ca04493140fa47
parent2cb068149c365f1c2b10f2ece6786139527dcc16 (diff)
OMAP: hwmod: Fix softreset for modules with optional clocks
Some modules (like GPIO, DSS...) require optionals clock to be enabled in order to complete the sofreset properly. Add a HWMOD_CONTROL_OPT_CLKS_IN_RESET flag to force all optional clocks to be enabled before reset. Disabled them once the reset is done. TODO: For the moment it is very hard to understand from the HW spec, which optional clock is needed and which one is not. So the current approach will enable all the optional clocks. Paul proposed a much finer approach that will allow to tag only the needed clock in the optional clock table. This might be doable as soon as we have a clear understanding of these dependencies. Reported-by: Partha Basak <p-basak2@ti.com> Signed-off-by: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Kevin Hilman <khilman@deeprootsystems.com>
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c51
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h5
2 files changed, 51 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 5027879b062f..f320cfb911d5 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -546,6 +546,36 @@ static int _disable_clocks(struct omap_hwmod *oh)
546 return 0; 546 return 0;
547} 547}
548 548
549static void _enable_optional_clocks(struct omap_hwmod *oh)
550{
551 struct omap_hwmod_opt_clk *oc;
552 int i;
553
554 pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
555
556 for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
557 if (oc->_clk) {
558 pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
559 oc->_clk->name);
560 clk_enable(oc->_clk);
561 }
562}
563
564static void _disable_optional_clocks(struct omap_hwmod *oh)
565{
566 struct omap_hwmod_opt_clk *oc;
567 int i;
568
569 pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
570
571 for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
572 if (oc->_clk) {
573 pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
574 oc->_clk->name);
575 clk_disable(oc->_clk);
576 }
577}
578
549/** 579/**
550 * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use 580 * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
551 * @oh: struct omap_hwmod * 581 * @oh: struct omap_hwmod *
@@ -976,8 +1006,9 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
976 */ 1006 */
977static int _reset(struct omap_hwmod *oh) 1007static int _reset(struct omap_hwmod *oh)
978{ 1008{
979 u32 r, v; 1009 u32 v;
980 int c = 0; 1010 int c = 0;
1011 int ret = 0;
981 1012
982 if (!oh->class->sysc || 1013 if (!oh->class->sysc ||
983 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) 1014 !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
@@ -990,12 +1021,16 @@ static int _reset(struct omap_hwmod *oh)
990 return -EINVAL; 1021 return -EINVAL;
991 } 1022 }
992 1023
1024 /* For some modules, all optionnal clocks need to be enabled as well */
1025 if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1026 _enable_optional_clocks(oh);
1027
993 pr_debug("omap_hwmod: %s: resetting\n", oh->name); 1028 pr_debug("omap_hwmod: %s: resetting\n", oh->name);
994 1029
995 v = oh->_sysc_cache; 1030 v = oh->_sysc_cache;
996 r = _set_softreset(oh, &v); 1031 ret = _set_softreset(oh, &v);
997 if (r) 1032 if (ret)
998 return r; 1033 goto dis_opt_clks;
999 _write_sysconfig(v, oh); 1034 _write_sysconfig(v, oh);
1000 1035
1001 if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) 1036 if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
@@ -1020,7 +1055,13 @@ static int _reset(struct omap_hwmod *oh)
1020 * _wait_target_ready() or _reset() 1055 * _wait_target_ready() or _reset()
1021 */ 1056 */
1022 1057
1023 return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; 1058 ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
1059
1060dis_opt_clks:
1061 if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
1062 _disable_optional_clocks(oh);
1063
1064 return ret;
1024} 1065}
1025 1066
1026/** 1067/**
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index faa08273b1e4..ee53758e1f49 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -369,6 +369,10 @@ struct omap_hwmod_omap4_prcm {
369 * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup 369 * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup
370 * HWMOD_NO_IDLEST : this module does not have idle status - this is the case 370 * HWMOD_NO_IDLEST : this module does not have idle status - this is the case
371 * only for few initiator modules on OMAP2 & 3. 371 * only for few initiator modules on OMAP2 & 3.
372 * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset.
373 * This is needed for devices like DSS that require optional clocks enabled
374 * in order to complete the reset. Optional clocks will be disabled
375 * again after the reset.
372 */ 376 */
373#define HWMOD_SWSUP_SIDLE (1 << 0) 377#define HWMOD_SWSUP_SIDLE (1 << 0)
374#define HWMOD_SWSUP_MSTANDBY (1 << 1) 378#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -377,6 +381,7 @@ struct omap_hwmod_omap4_prcm {
377#define HWMOD_NO_OCP_AUTOIDLE (1 << 4) 381#define HWMOD_NO_OCP_AUTOIDLE (1 << 4)
378#define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5) 382#define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5)
379#define HWMOD_NO_IDLEST (1 << 6) 383#define HWMOD_NO_IDLEST (1 << 6)
384#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)
380 385
381/* 386/*
382 * omap_hwmod._int_flags definitions 387 * omap_hwmod._int_flags definitions