aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorBenoit Cousson <b-cousson@ti.com>2011-07-10 07:56:33 -0400
committerPaul Walmsley <paul@pwsan.com>2011-07-10 07:56:33 -0400
commit45c38252d76a96e6e0e05f982ca44096191a8eea (patch)
tree0153ffca190c3bc431af7efda25f54f6f3fc58fe /arch/arm
parent288d6a161819ee99b3a6e2972c5b0d9ede22c553 (diff)
OMAP4: hwmod: Introduce the module control in hwmod control
Take advantage of the explicit modulemode control to fix the way parents clocks are managed. A module must be disabled before any parents are disabled. That programming model was not possible with the previous implementation that was considering a modulemode as a leaf clock node managed by the clock fmwk. This was leading to bad crash upon disable when the parent clock was gated before the module completed its transition to idle. Signed-off-by: Benoit Cousson <b-cousson@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c63
1 files changed, 61 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index a0f7d313e69f..4424fee5cd5a 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -680,6 +680,56 @@ static void _disable_optional_clocks(struct omap_hwmod *oh)
680} 680}
681 681
682/** 682/**
683 * _enable_module - enable CLKCTRL modulemode on OMAP4
684 * @oh: struct omap_hwmod *
685 *
686 * Enables the PRCM module mode related to the hwmod @oh.
687 * No return value.
688 */
689static void _enable_module(struct omap_hwmod *oh)
690{
691 /* The module mode does not exist prior OMAP4 */
692 if (cpu_is_omap24xx() || cpu_is_omap34xx())
693 return;
694
695 if (!oh->clkdm || !oh->prcm.omap4.modulemode)
696 return;
697
698 pr_debug("omap_hwmod: %s: _enable_module: %d\n",
699 oh->name, oh->prcm.omap4.modulemode);
700
701 omap4_cminst_module_enable(oh->prcm.omap4.modulemode,
702 oh->clkdm->prcm_partition,
703 oh->clkdm->cm_inst,
704 oh->clkdm->clkdm_offs,
705 oh->prcm.omap4.clkctrl_offs);
706}
707
708/**
709 * _disable_module - enable CLKCTRL modulemode on OMAP4
710 * @oh: struct omap_hwmod *
711 *
712 * Disable the PRCM module mode related to the hwmod @oh.
713 * No return value.
714 */
715static void _disable_module(struct omap_hwmod *oh)
716{
717 /* The module mode does not exist prior OMAP4 */
718 if (cpu_is_omap24xx() || cpu_is_omap34xx())
719 return;
720
721 if (!oh->clkdm || !oh->prcm.omap4.modulemode)
722 return;
723
724 pr_debug("omap_hwmod: %s: _disable_module\n", oh->name);
725
726 omap4_cminst_module_disable(oh->clkdm->prcm_partition,
727 oh->clkdm->cm_inst,
728 oh->clkdm->clkdm_offs,
729 oh->prcm.omap4.clkctrl_offs);
730}
731
732/**
683 * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh 733 * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
684 * @oh: struct omap_hwmod *oh 734 * @oh: struct omap_hwmod *oh
685 * 735 *
@@ -1424,6 +1474,7 @@ static int _enable(struct omap_hwmod *oh)
1424 1474
1425 return r; 1475 return r;
1426 } 1476 }
1477 _enable_module(oh);
1427 1478
1428 oh->_state = _HWMOD_STATE_ENABLED; 1479 oh->_state = _HWMOD_STATE_ENABLED;
1429 1480
@@ -1460,11 +1511,18 @@ static int _idle(struct omap_hwmod *oh)
1460 if (oh->class->sysc) 1511 if (oh->class->sysc)
1461 _idle_sysc(oh); 1512 _idle_sysc(oh);
1462 _del_initiator_dep(oh, mpu_oh); 1513 _del_initiator_dep(oh, mpu_oh);
1463 _disable_clocks(oh); 1514 _disable_module(oh);
1464 ret = _wait_target_disable(oh); 1515 ret = _wait_target_disable(oh);
1465 if (ret) 1516 if (ret)
1466 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", 1517 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1467 oh->name); 1518 oh->name);
1519 /*
1520 * The module must be in idle mode before disabling any parents
1521 * clocks. Otherwise, the parent clock might be disabled before
1522 * the module transition is done, and thus will prevent the
1523 * transition to complete properly.
1524 */
1525 _disable_clocks(oh);
1468 1526
1469 /* Mux pins for device idle if populated */ 1527 /* Mux pins for device idle if populated */
1470 if (oh->mux && oh->mux->pads_dynamic) 1528 if (oh->mux && oh->mux->pads_dynamic)
@@ -1556,11 +1614,12 @@ static int _shutdown(struct omap_hwmod *oh)
1556 if (oh->_state == _HWMOD_STATE_ENABLED) { 1614 if (oh->_state == _HWMOD_STATE_ENABLED) {
1557 _del_initiator_dep(oh, mpu_oh); 1615 _del_initiator_dep(oh, mpu_oh);
1558 /* XXX what about the other system initiators here? dma, dsp */ 1616 /* XXX what about the other system initiators here? dma, dsp */
1559 _disable_clocks(oh); 1617 _disable_module(oh);
1560 ret = _wait_target_disable(oh); 1618 ret = _wait_target_disable(oh);
1561 if (ret) 1619 if (ret)
1562 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", 1620 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1563 oh->name); 1621 oh->name);
1622 _disable_clocks(oh);
1564 } 1623 }
1565 /* XXX Should this code also force-disable the optional clocks? */ 1624 /* XXX Should this code also force-disable the optional clocks? */
1566 1625