aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2012-04-18 21:10:04 -0400
committerPaul Walmsley <paul@pwsan.com>2012-04-19 06:03:10 -0400
commit747834ab83475f47878c68954d913e27124e4391 (patch)
tree0c7176d00834eb893ab241a30be5e7ff1b9f7817 /arch/arm/mach-omap2/omap_hwmod.c
parent64813c3fa68fc3e93e99187d313126710d7c4b0d (diff)
ARM: OMAP2+: hwmod: revise hardreset behavior
Change the way that hardreset lines are handled by the hwmod code. Hardreset lines are generally associated with initiator IP blocks. Prior to this change, the hwmod code expected to control hardreset lines itself, asserting them on shutdown and deasserting them upon enable. But driver authors inside TI have commented to us that their drivers require direct control over these lines. Unfortunately, these drivers haven't been posted publicly yet, so it's hard to determine exactly what is needed, a priori. This change attempts to set forth some reasonable semantics that should be an improvement over the current code. The semantics implemented by this patch are as follows: - If the hwmod is not marked with HWMOD_INIT_NO_RESET, then assert all associated hardreset lines during IP block setup. This is intended to place the IP blocks into a known state that will not interfere with other devices during kernel boot. - IP blocks with hardreset lines will not be automatically enabled or idled during setup. Instead, they will be left in the INITIALIZED state. - When the hwmod code is asked to enable, idle, or shutdown an IP block with asserted hardreset lines, the hwmod code will do nothing. The driver integration code must do the remaining work needed to control these IP blocks. Once this driver integration code is posted to the lists, hopefully we can consolidate it and move it inside the hwmod code. Custom reset functions for IP blocks with hardreset lines still should be supported and are strongly endorsed. It is intended that every subsystem with hardreset lines should have a custom reset function that can place their subsystem into quiescent idle with the hardreset lines deasserted. This reverts most of commit 5365efbe29250a227502256cc912351fe2157b42 ("OMAP: hwmod: Add hardreset management support"). Later code reorganizations caused the sequencing of the code from this patch to be changed, anyway. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: BenoƮt Cousson <b-cousson@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c139
1 files changed, 83 insertions, 56 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 6c6d31b432d2..bd9fc10ea737 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -781,39 +781,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
781} 781}
782 782
783/** 783/**
784 * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
785 * @oh: struct omap_hwmod *
786 *
787 * Disable the PRCM module mode related to the hwmod @oh.
788 * Return EINVAL if the modulemode is not supported and 0 in case of success.
789 */
790static int _omap4_disable_module(struct omap_hwmod *oh)
791{
792 int v;
793
794 /* The module mode does not exist prior OMAP4 */
795 if (!cpu_is_omap44xx())
796 return -EINVAL;
797
798 if (!oh->clkdm || !oh->prcm.omap4.modulemode)
799 return -EINVAL;
800
801 pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
802
803 omap4_cminst_module_disable(oh->clkdm->prcm_partition,
804 oh->clkdm->cm_inst,
805 oh->clkdm->clkdm_offs,
806 oh->prcm.omap4.clkctrl_offs);
807
808 v = _omap4_wait_target_disable(oh);
809 if (v)
810 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
811 oh->name);
812
813 return 0;
814}
815
816/**
817 * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh 784 * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
818 * @oh: struct omap_hwmod *oh 785 * @oh: struct omap_hwmod *oh
819 * 786 *
@@ -1378,6 +1345,66 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
1378} 1345}
1379 1346
1380/** 1347/**
1348 * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset
1349 * @oh: struct omap_hwmod *
1350 *
1351 * If any hardreset line associated with @oh is asserted, then return true.
1352 * Otherwise, if @oh has no hardreset lines associated with it, or if
1353 * no hardreset lines associated with @oh are asserted, then return false.
1354 * This function is used to avoid executing some parts of the IP block
1355 * enable/disable sequence if a hardreset line is set.
1356 */
1357static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
1358{
1359 int i;
1360
1361 if (oh->rst_lines_cnt == 0)
1362 return false;
1363
1364 for (i = 0; i < oh->rst_lines_cnt; i++)
1365 if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
1366 return true;
1367
1368 return false;
1369}
1370
1371/**
1372 * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
1373 * @oh: struct omap_hwmod *
1374 *
1375 * Disable the PRCM module mode related to the hwmod @oh.
1376 * Return EINVAL if the modulemode is not supported and 0 in case of success.
1377 */
1378static int _omap4_disable_module(struct omap_hwmod *oh)
1379{
1380 int v;
1381
1382 /* The module mode does not exist prior OMAP4 */
1383 if (!cpu_is_omap44xx())
1384 return -EINVAL;
1385
1386 if (!oh->clkdm || !oh->prcm.omap4.modulemode)
1387 return -EINVAL;
1388
1389 pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
1390
1391 omap4_cminst_module_disable(oh->clkdm->prcm_partition,
1392 oh->clkdm->cm_inst,
1393 oh->clkdm->clkdm_offs,
1394 oh->prcm.omap4.clkctrl_offs);
1395
1396 if (_are_any_hardreset_lines_asserted(oh))
1397 return 0;
1398
1399 v = _omap4_wait_target_disable(oh);
1400 if (v)
1401 pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
1402 oh->name);
1403
1404 return 0;
1405}
1406
1407/**
1381 * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit 1408 * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
1382 * @oh: struct omap_hwmod * 1409 * @oh: struct omap_hwmod *
1383 * 1410 *
@@ -1528,7 +1555,7 @@ static int _reset(struct omap_hwmod *oh)
1528 */ 1555 */
1529static int _enable(struct omap_hwmod *oh) 1556static int _enable(struct omap_hwmod *oh)
1530{ 1557{
1531 int r, i; 1558 int r;
1532 int hwsup = 0; 1559 int hwsup = 0;
1533 1560
1534 pr_debug("omap_hwmod: %s: enabling\n", oh->name); 1561 pr_debug("omap_hwmod: %s: enabling\n", oh->name);
@@ -1560,14 +1587,16 @@ static int _enable(struct omap_hwmod *oh)
1560 } 1587 }
1561 1588
1562 /* 1589 /*
1563 * If an IP contains HW reset lines, then de-assert them in order 1590 * If an IP block contains HW reset lines and any of them are
1564 * to allow the module state transition. Otherwise the PRCM will return 1591 * asserted, we let integration code associated with that
1565 * Intransition status, and the init will failed. 1592 * block handle the enable. We've received very little
1593 * information on what those driver authors need, and until
1594 * detailed information is provided and the driver code is
1595 * posted to the public lists, this is probably the best we
1596 * can do.
1566 */ 1597 */
1567 if (oh->_state == _HWMOD_STATE_INITIALIZED || 1598 if (_are_any_hardreset_lines_asserted(oh))
1568 oh->_state == _HWMOD_STATE_DISABLED) 1599 return 0;
1569 for (i = 0; i < oh->rst_lines_cnt; i++)
1570 _deassert_hardreset(oh, oh->rst_lines[i].name);
1571 1600
1572 /* Mux pins for device runtime if populated */ 1601 /* Mux pins for device runtime if populated */
1573 if (oh->mux && (!oh->mux->enabled || 1602 if (oh->mux && (!oh->mux->enabled ||
@@ -1642,6 +1671,9 @@ static int _idle(struct omap_hwmod *oh)
1642 return -EINVAL; 1671 return -EINVAL;
1643 } 1672 }
1644 1673
1674 if (_are_any_hardreset_lines_asserted(oh))
1675 return 0;
1676
1645 if (oh->class->sysc) 1677 if (oh->class->sysc)
1646 _idle_sysc(oh); 1678 _idle_sysc(oh);
1647 _del_initiator_dep(oh, mpu_oh); 1679 _del_initiator_dep(oh, mpu_oh);
@@ -1724,6 +1756,9 @@ static int _shutdown(struct omap_hwmod *oh)
1724 return -EINVAL; 1756 return -EINVAL;
1725 } 1757 }
1726 1758
1759 if (_are_any_hardreset_lines_asserted(oh))
1760 return 0;
1761
1727 pr_debug("omap_hwmod: %s: disabling\n", oh->name); 1762 pr_debug("omap_hwmod: %s: disabling\n", oh->name);
1728 1763
1729 if (oh->class->pre_shutdown) { 1764 if (oh->class->pre_shutdown) {
@@ -1866,21 +1901,13 @@ static int __init _setup_reset(struct omap_hwmod *oh)
1866 if (oh->_state != _HWMOD_STATE_INITIALIZED) 1901 if (oh->_state != _HWMOD_STATE_INITIALIZED)
1867 return -EINVAL; 1902 return -EINVAL;
1868 1903
1869 /* 1904 if (oh->rst_lines_cnt == 0) {
1870 * In the case of hwmod with hardreset that should not be 1905 r = _enable(oh);
1871 * de-assert at boot time, we have to keep the module 1906 if (r) {
1872 * initialized, because we cannot enable it properly with the 1907 pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n",
1873 * reset asserted. Exit without warning because that behavior 1908 oh->name, oh->_state);
1874 * is expected. 1909 return -EINVAL;
1875 */ 1910 }
1876 if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt > 0)
1877 return 0;
1878
1879 r = _enable(oh);
1880 if (r) {
1881 pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
1882 oh->name, oh->_state);
1883 return 0;
1884 } 1911 }
1885 1912
1886 if (!(oh->flags & HWMOD_INIT_NO_RESET)) 1913 if (!(oh->flags & HWMOD_INIT_NO_RESET))