aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorRajendra Nayak <rnayak@ti.com>2011-07-10 07:57:07 -0400
committerPaul Walmsley <paul@pwsan.com>2011-07-10 07:57:07 -0400
commit665d001338b494d6d62810aa99b4c0fa1a0884b9 (patch)
treecd86d6a86edce56931c261b79d1d5706b2f0c667 /arch/arm/mach-omap2/omap_hwmod.c
parent12706c542574ea0127a13815efe59ca9ba6d88d7 (diff)
OMAP2+: hwmod: Follow the recommended PRCM module enable sequence
On OMAP4, the PRCM recommended sequence for enabling a module after power-on-reset is: -1- Force clkdm to SW_WKUP -2- Enabling the clocks -3- Configure desired module mode to "enable" or "auto" -4- Wait for the desired module idle status to be FUNC -5- Program clkdm in HW_AUTO(if supported) This sequence applies to all older OMAPs' as well, however since they use autodeps, it makes sure that no clkdm is in IDLE, and hence not requiring a force SW_WKUP when a module is being enabled. OMAP4 does not need to support autodeps, because of the dyanamic dependency feature, wherein the HW takes care of waking up a clockdomain from idle and hence the module, whenever an interconnect access happens to the given module. Implementing the sequence for OMAP4 requires the clockdomain handling that is currently done in clock framework to be done as part of hwmod framework since the step -4- above to "Wait for the desired module idle status to be FUNC" is done as part of hwmod framework. Signed-off-by: Rajendra Nayak <rnayak@ti.com> [b-cousson@ti.com: Adapt it to the new clkdm hwmod attribute and API] Signed-off-by: Benoit Cousson <b-cousson@ti.com> Cc: Paul Walmsley <paul@pwsan.com> [paul@pwsan.com: dropped mach-omap2/clock.c changes; modified to only call the clockdomain code if oh->clkdm is set; disable clock->clockdomain interaction on OMAP4] Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c70
1 files changed, 50 insertions, 20 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 4424fee5cd5a..84cc0bdda3ae 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1437,6 +1437,7 @@ static int _reset(struct omap_hwmod *oh)
1437static int _enable(struct omap_hwmod *oh) 1437static int _enable(struct omap_hwmod *oh)
1438{ 1438{
1439 int r; 1439 int r;
1440 int hwsup = 0;
1440 1441
1441 pr_debug("omap_hwmod: %s: enabling\n", oh->name); 1442 pr_debug("omap_hwmod: %s: enabling\n", oh->name);
1442 1443
@@ -1448,14 +1449,6 @@ static int _enable(struct omap_hwmod *oh)
1448 return -EINVAL; 1449 return -EINVAL;
1449 } 1450 }
1450 1451
1451 /* Mux pins for device runtime if populated */
1452 if (oh->mux && (!oh->mux->enabled ||
1453 ((oh->_state == _HWMOD_STATE_IDLE) &&
1454 oh->mux->pads_dynamic)))
1455 omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
1456
1457 _add_initiator_dep(oh, mpu_oh);
1458 _enable_clocks(oh);
1459 1452
1460 /* 1453 /*
1461 * If an IP contains only one HW reset line, then de-assert it in order 1454 * If an IP contains only one HW reset line, then de-assert it in order
@@ -1466,23 +1459,56 @@ static int _enable(struct omap_hwmod *oh)
1466 oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) 1459 oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
1467 _deassert_hardreset(oh, oh->rst_lines[0].name); 1460 _deassert_hardreset(oh, oh->rst_lines[0].name);
1468 1461
1469 r = _wait_target_ready(oh); 1462 /* Mux pins for device runtime if populated */
1470 if (r) { 1463 if (oh->mux && (!oh->mux->enabled ||
1471 pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", 1464 ((oh->_state == _HWMOD_STATE_IDLE) &&
1472 oh->name, r); 1465 oh->mux->pads_dynamic)))
1473 _disable_clocks(oh); 1466 omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
1467
1468 _add_initiator_dep(oh, mpu_oh);
1474 1469
1475 return r; 1470 if (oh->clkdm) {
1471 /*
1472 * A clockdomain must be in SW_SUP before enabling
1473 * completely the module. The clockdomain can be set
1474 * in HW_AUTO only when the module become ready.
1475 */
1476 hwsup = clkdm_in_hwsup(oh->clkdm);
1477 r = clkdm_hwmod_enable(oh->clkdm, oh);
1478 if (r) {
1479 WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n",
1480 oh->name, oh->clkdm->name, r);
1481 return r;
1482 }
1476 } 1483 }
1484
1485 _enable_clocks(oh);
1477 _enable_module(oh); 1486 _enable_module(oh);
1478 1487
1479 oh->_state = _HWMOD_STATE_ENABLED; 1488 r = _wait_target_ready(oh);
1489 if (!r) {
1490 /*
1491 * Set the clockdomain to HW_AUTO only if the target is ready,
1492 * assuming that the previous state was HW_AUTO
1493 */
1494 if (oh->clkdm && hwsup)
1495 clkdm_allow_idle(oh->clkdm);
1480 1496
1481 /* Access the sysconfig only if the target is ready */ 1497 oh->_state = _HWMOD_STATE_ENABLED;
1482 if (oh->class->sysc) { 1498
1483 if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) 1499 /* Access the sysconfig only if the target is ready */
1484 _update_sysc_cache(oh); 1500 if (oh->class->sysc) {
1485 _enable_sysc(oh); 1501 if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED))
1502 _update_sysc_cache(oh);
1503 _enable_sysc(oh);
1504 }
1505 } else {
1506 _disable_clocks(oh);
1507 pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
1508 oh->name, r);
1509
1510 if (oh->clkdm)
1511 clkdm_hwmod_disable(oh->clkdm, oh);
1486 } 1512 }
1487 1513
1488 return r; 1514 return r;
@@ -1523,6 +1549,8 @@ static int _idle(struct omap_hwmod *oh)
1523 * transition to complete properly. 1549 * transition to complete properly.
1524 */ 1550 */
1525 _disable_clocks(oh); 1551 _disable_clocks(oh);
1552 if (oh->clkdm)
1553 clkdm_hwmod_disable(oh->clkdm, oh);
1526 1554
1527 /* Mux pins for device idle if populated */ 1555 /* Mux pins for device idle if populated */
1528 if (oh->mux && oh->mux->pads_dynamic) 1556 if (oh->mux && oh->mux->pads_dynamic)
@@ -1620,6 +1648,8 @@ static int _shutdown(struct omap_hwmod *oh)
1620 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", 1648 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1621 oh->name); 1649 oh->name);
1622 _disable_clocks(oh); 1650 _disable_clocks(oh);
1651 if (oh->clkdm)
1652 clkdm_hwmod_disable(oh->clkdm, oh);
1623 } 1653 }
1624 /* XXX Should this code also force-disable the optional clocks? */ 1654 /* XXX Should this code also force-disable the optional clocks? */
1625 1655