aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenoit Cousson <b-cousson@ti.com>2011-07-10 07:56:30 -0400
committerPaul Walmsley <paul@pwsan.com>2011-07-10 07:56:30 -0400
commit11b10341bd12c87a8409c69cdcd7ee898400842f (patch)
treeec54a29bcc1ff21bdab8f39571eeb32774fb8b18 /arch
parentd0f0631ddc61026dca71b5b679803000d70fde50 (diff)
OMAP: hwmod: Wait the idle status to be disabled
It is mandatory to wait for a module to be in disabled state before potentially disabling source clock or re-asserting a reset. omap_hwmod_idle and omap_hwmod_shutdown does not wait for the module to be fully idle. Add a cm_xxx accessor to wait the clkctrl idle status to be disabled. Fix hwmod_[idle|shutdown] to use this API. Based on Rajendra's initial patch. Please note that most interconnects hwmod will return one timeout because it is impossible for them to be in idle since the processor is accessing the registers though the interconnect. Signed-off-by: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Rajendra Nayak <rnayak@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Todd Poynor <toddpoynor@google.com> [paul@pwsan.com: move cpu_is_*() tests to the top of _wait_target_disable(); incorporate some feedback from Todd] Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c25
-rw-r--r--arch/arm/mach-omap2/cminst44xx.h1
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c40
3 files changed, 66 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 9033dd4937c1..0fe3f147f262 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -284,3 +284,28 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
284 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY; 284 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
285} 285}
286 286
287/**
288 * omap4_cminst_wait_module_idle - wait for a module to be in 'disabled'
289 * state
290 * @part: PRCM partition ID that the CM_CLKCTRL register exists in
291 * @inst: CM instance register offset (*_INST macro)
292 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
293 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
294 *
295 * Wait for the module IDLEST to be disabled. Some PRCM transition,
296 * like reset assertion or parent clock de-activation must wait the
297 * module to be fully disabled.
298 */
299int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
300{
301 int i = 0;
302
303 if (!clkctrl_offs)
304 return 0;
305
306 omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) ==
307 CLKCTRL_IDLEST_DISABLED),
308 MAX_MODULE_READY_TIME, i);
309
310 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
311}
diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h
index 8eba2ae87ad4..a98540081f97 100644
--- a/arch/arm/mach-omap2/cminst44xx.h
+++ b/arch/arm/mach-omap2/cminst44xx.h
@@ -18,6 +18,7 @@ extern void omap4_cminst_clkdm_force_sleep(u8 part, s16 inst, u16 cdoffs);
18extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs); 18extern void omap4_cminst_clkdm_force_wakeup(u8 part, s16 inst, u16 cdoffs);
19 19
20extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs); 20extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
21extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
21 22
22/* 23/*
23 * In an ideal world, we would not export these low-level functions, 24 * In an ideal world, we would not export these low-level functions,
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 00241ea5bf09..d21f49b87646 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1102,6 +1102,36 @@ static int _wait_target_ready(struct omap_hwmod *oh)
1102} 1102}
1103 1103
1104/** 1104/**
1105 * _wait_target_disable - wait for a module to be disabled
1106 * @oh: struct omap_hwmod *
1107 *
1108 * Wait for a module @oh to enter slave idle. Returns 0 if the module
1109 * does not have an IDLEST bit or if the module successfully enters
1110 * slave idle; otherwise, pass along the return value of the
1111 * appropriate *_cm*_wait_module_idle() function.
1112 */
1113static int _wait_target_disable(struct omap_hwmod *oh)
1114{
1115 /* TODO: For now just handle OMAP4+ */
1116 if (cpu_is_omap24xx() || cpu_is_omap34xx())
1117 return 0;
1118
1119 if (!oh)
1120 return -EINVAL;
1121
1122 if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
1123 return 0;
1124
1125 if (oh->flags & HWMOD_NO_IDLEST)
1126 return 0;
1127
1128 return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition,
1129 oh->clkdm->cm_inst,
1130 oh->clkdm->clkdm_offs,
1131 oh->prcm.omap4.clkctrl_offs);
1132}
1133
1134/**
1105 * _lookup_hardreset - fill register bit info for this hwmod/reset line 1135 * _lookup_hardreset - fill register bit info for this hwmod/reset line
1106 * @oh: struct omap_hwmod * 1136 * @oh: struct omap_hwmod *
1107 * @name: name of the reset line in the context of this hwmod 1137 * @name: name of the reset line in the context of this hwmod
@@ -1410,6 +1440,8 @@ static int _enable(struct omap_hwmod *oh)
1410 */ 1440 */
1411static int _idle(struct omap_hwmod *oh) 1441static int _idle(struct omap_hwmod *oh)
1412{ 1442{
1443 int ret;
1444
1413 pr_debug("omap_hwmod: %s: idling\n", oh->name); 1445 pr_debug("omap_hwmod: %s: idling\n", oh->name);
1414 1446
1415 if (oh->_state != _HWMOD_STATE_ENABLED) { 1447 if (oh->_state != _HWMOD_STATE_ENABLED) {
@@ -1422,6 +1454,10 @@ static int _idle(struct omap_hwmod *oh)
1422 _idle_sysc(oh); 1454 _idle_sysc(oh);
1423 _del_initiator_dep(oh, mpu_oh); 1455 _del_initiator_dep(oh, mpu_oh);
1424 _disable_clocks(oh); 1456 _disable_clocks(oh);
1457 ret = _wait_target_disable(oh);
1458 if (ret)
1459 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1460 oh->name);
1425 1461
1426 /* Mux pins for device idle if populated */ 1462 /* Mux pins for device idle if populated */
1427 if (oh->mux && oh->mux->pads_dynamic) 1463 if (oh->mux && oh->mux->pads_dynamic)
@@ -1514,6 +1550,10 @@ static int _shutdown(struct omap_hwmod *oh)
1514 _del_initiator_dep(oh, mpu_oh); 1550 _del_initiator_dep(oh, mpu_oh);
1515 /* XXX what about the other system initiators here? dma, dsp */ 1551 /* XXX what about the other system initiators here? dma, dsp */
1516 _disable_clocks(oh); 1552 _disable_clocks(oh);
1553 ret = _wait_target_disable(oh);
1554 if (ret)
1555 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1556 oh->name);
1517 } 1557 }
1518 /* XXX Should this code also force-disable the optional clocks? */ 1558 /* XXX Should this code also force-disable the optional clocks? */
1519 1559