diff options
author | Tony Lindgren <tony@atomide.com> | 2012-09-23 22:31:35 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2012-09-23 22:31:35 -0400 |
commit | 9cd68fa707cf6372f33eb51a5719dd7626efe5f6 (patch) | |
tree | 66cde27bd288e011a6e4cff87d342666399a1266 /arch/arm/mach-omap2/omap_hwmod.c | |
parent | 5698bd757d55b1bb87edd1a9744ab09c142abfc2 (diff) | |
parent | 76a5d9bfc42d60e9a672e0cae776157a60970f4e (diff) |
Merge tag 'omap-devel-b-c-2-for-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into devel-late
OMAP patches intended for the 3.7 merge window:
- Runtime PM conversions for the GPMC and RNG IP blocks
- Preparation patches for the OMAP common clock framework conversion
- clkdev alias additions required by other drivers
- Performance Monitoring Unit (PMU) support for OMAP2, 3, and non-4430 OMAP4
- OMAP hwmod code and data improvements
- Preparation patches for the IOMMU runtime PM conversion
- Preparation patches for OMAP4 full-chip retention support
Based on a merge of v3.6-rc6, the omap-cleanup-b-for-3.7 tag
(7852ec0536ca39cefffc6301dc77f8ae55592926),the cleanup-fixes-for-v3.7
tag (de6ca33a96a6bf61fcb91d3d399703e19ead9d1e), and the
omap-devel-am33xx-for-v3.7 tag
(11964f53eb4d9ce59a058be9999d9cfcb1ced878), due to dependencies.
These patches have been tested for meaningful warnings from
checkpatch, sparse, smatch, and cppcheck. Basic build, boot[1], and
PM test logs are available here:
http://www.pwsan.com/omap/testlogs/hwmod_prcm_clock_a_3.7/20120923173830/
...
1. Note that the N800 boot fails due to a known issue present in the
base commit:
http://www.spinics.net/lists/arm-kernel/msg196034.html
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 336 |
1 files changed, 294 insertions, 42 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 37afbd173c2c..6af64bbd9e1d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -139,18 +139,20 @@ | |||
139 | #include <linux/slab.h> | 139 | #include <linux/slab.h> |
140 | #include <linux/bootmem.h> | 140 | #include <linux/bootmem.h> |
141 | 141 | ||
142 | #include "common.h" | ||
143 | #include <plat/cpu.h> | ||
144 | #include "clockdomain.h" | ||
145 | #include "powerdomain.h" | ||
146 | #include <plat/clock.h> | 142 | #include <plat/clock.h> |
147 | #include <plat/omap_hwmod.h> | 143 | #include <plat/omap_hwmod.h> |
148 | #include <plat/prcm.h> | 144 | #include <plat/prcm.h> |
149 | 145 | ||
146 | #include "soc.h" | ||
147 | #include "common.h" | ||
148 | #include "clockdomain.h" | ||
149 | #include "powerdomain.h" | ||
150 | #include "cm2xxx_3xxx.h" | 150 | #include "cm2xxx_3xxx.h" |
151 | #include "cminst44xx.h" | 151 | #include "cminst44xx.h" |
152 | #include "cm33xx.h" | ||
152 | #include "prm2xxx_3xxx.h" | 153 | #include "prm2xxx_3xxx.h" |
153 | #include "prm44xx.h" | 154 | #include "prm44xx.h" |
155 | #include "prm33xx.h" | ||
154 | #include "prminst44xx.h" | 156 | #include "prminst44xx.h" |
155 | #include "mux.h" | 157 | #include "mux.h" |
156 | #include "pm.h" | 158 | #include "pm.h" |
@@ -677,16 +679,25 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
677 | if (!oh->main_clk) | 679 | if (!oh->main_clk) |
678 | return 0; | 680 | return 0; |
679 | 681 | ||
680 | oh->_clk = omap_clk_get_by_name(oh->main_clk); | 682 | oh->_clk = clk_get(NULL, oh->main_clk); |
681 | if (!oh->_clk) { | 683 | if (IS_ERR(oh->_clk)) { |
682 | pr_warning("omap_hwmod: %s: cannot clk_get main_clk %s\n", | 684 | pr_warning("omap_hwmod: %s: cannot clk_get main_clk %s\n", |
683 | oh->name, oh->main_clk); | 685 | oh->name, oh->main_clk); |
684 | return -EINVAL; | 686 | return -EINVAL; |
685 | } | 687 | } |
688 | /* | ||
689 | * HACK: This needs a re-visit once clk_prepare() is implemented | ||
690 | * to do something meaningful. Today its just a no-op. | ||
691 | * If clk_prepare() is used at some point to do things like | ||
692 | * voltage scaling etc, then this would have to be moved to | ||
693 | * some point where subsystems like i2c and pmic become | ||
694 | * available. | ||
695 | */ | ||
696 | clk_prepare(oh->_clk); | ||
686 | 697 | ||
687 | if (!oh->_clk->clkdm) | 698 | if (!oh->_clk->clkdm) |
688 | pr_warning("omap_hwmod: %s: missing clockdomain for %s.\n", | 699 | pr_debug("omap_hwmod: %s: missing clockdomain for %s.\n", |
689 | oh->main_clk, oh->_clk->name); | 700 | oh->name, oh->main_clk); |
690 | 701 | ||
691 | return ret; | 702 | return ret; |
692 | } | 703 | } |
@@ -713,13 +724,22 @@ static int _init_interface_clks(struct omap_hwmod *oh) | |||
713 | if (!os->clk) | 724 | if (!os->clk) |
714 | continue; | 725 | continue; |
715 | 726 | ||
716 | c = omap_clk_get_by_name(os->clk); | 727 | c = clk_get(NULL, os->clk); |
717 | if (!c) { | 728 | if (IS_ERR(c)) { |
718 | pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", | 729 | pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", |
719 | oh->name, os->clk); | 730 | oh->name, os->clk); |
720 | ret = -EINVAL; | 731 | ret = -EINVAL; |
721 | } | 732 | } |
722 | os->_clk = c; | 733 | os->_clk = c; |
734 | /* | ||
735 | * HACK: This needs a re-visit once clk_prepare() is implemented | ||
736 | * to do something meaningful. Today its just a no-op. | ||
737 | * If clk_prepare() is used at some point to do things like | ||
738 | * voltage scaling etc, then this would have to be moved to | ||
739 | * some point where subsystems like i2c and pmic become | ||
740 | * available. | ||
741 | */ | ||
742 | clk_prepare(os->_clk); | ||
723 | } | 743 | } |
724 | 744 | ||
725 | return ret; | 745 | return ret; |
@@ -740,13 +760,22 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
740 | int ret = 0; | 760 | int ret = 0; |
741 | 761 | ||
742 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { | 762 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { |
743 | c = omap_clk_get_by_name(oc->clk); | 763 | c = clk_get(NULL, oc->clk); |
744 | if (!c) { | 764 | if (IS_ERR(c)) { |
745 | pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", | 765 | pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", |
746 | oh->name, oc->clk); | 766 | oh->name, oc->clk); |
747 | ret = -EINVAL; | 767 | ret = -EINVAL; |
748 | } | 768 | } |
749 | oc->_clk = c; | 769 | oc->_clk = c; |
770 | /* | ||
771 | * HACK: This needs a re-visit once clk_prepare() is implemented | ||
772 | * to do something meaningful. Today its just a no-op. | ||
773 | * If clk_prepare() is used at some point to do things like | ||
774 | * voltage scaling etc, then this would have to be moved to | ||
775 | * some point where subsystems like i2c and pmic become | ||
776 | * available. | ||
777 | */ | ||
778 | clk_prepare(oc->_clk); | ||
750 | } | 779 | } |
751 | 780 | ||
752 | return ret; | 781 | return ret; |
@@ -825,7 +854,7 @@ static void _enable_optional_clocks(struct omap_hwmod *oh) | |||
825 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) | 854 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) |
826 | if (oc->_clk) { | 855 | if (oc->_clk) { |
827 | pr_debug("omap_hwmod: enable %s:%s\n", oc->role, | 856 | pr_debug("omap_hwmod: enable %s:%s\n", oc->role, |
828 | oc->_clk->name); | 857 | __clk_get_name(oc->_clk)); |
829 | clk_enable(oc->_clk); | 858 | clk_enable(oc->_clk); |
830 | } | 859 | } |
831 | } | 860 | } |
@@ -840,7 +869,7 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) | |||
840 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) | 869 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) |
841 | if (oc->_clk) { | 870 | if (oc->_clk) { |
842 | pr_debug("omap_hwmod: disable %s:%s\n", oc->role, | 871 | pr_debug("omap_hwmod: disable %s:%s\n", oc->role, |
843 | oc->_clk->name); | 872 | __clk_get_name(oc->_clk)); |
844 | clk_disable(oc->_clk); | 873 | clk_disable(oc->_clk); |
845 | } | 874 | } |
846 | } | 875 | } |
@@ -868,6 +897,26 @@ static void _omap4_enable_module(struct omap_hwmod *oh) | |||
868 | } | 897 | } |
869 | 898 | ||
870 | /** | 899 | /** |
900 | * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX | ||
901 | * @oh: struct omap_hwmod * | ||
902 | * | ||
903 | * Enables the PRCM module mode related to the hwmod @oh. | ||
904 | * No return value. | ||
905 | */ | ||
906 | static void _am33xx_enable_module(struct omap_hwmod *oh) | ||
907 | { | ||
908 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
909 | return; | ||
910 | |||
911 | pr_debug("omap_hwmod: %s: %s: %d\n", | ||
912 | oh->name, __func__, oh->prcm.omap4.modulemode); | ||
913 | |||
914 | am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, | ||
915 | oh->clkdm->clkdm_offs, | ||
916 | oh->prcm.omap4.clkctrl_offs); | ||
917 | } | ||
918 | |||
919 | /** | ||
871 | * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4 | 920 | * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4 |
872 | * @oh: struct omap_hwmod * | 921 | * @oh: struct omap_hwmod * |
873 | * | 922 | * |
@@ -878,10 +927,10 @@ static void _omap4_enable_module(struct omap_hwmod *oh) | |||
878 | */ | 927 | */ |
879 | static int _omap4_wait_target_disable(struct omap_hwmod *oh) | 928 | static int _omap4_wait_target_disable(struct omap_hwmod *oh) |
880 | { | 929 | { |
881 | if (!oh || !oh->clkdm) | 930 | if (!oh) |
882 | return -EINVAL; | 931 | return -EINVAL; |
883 | 932 | ||
884 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 933 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT || !oh->clkdm) |
885 | return 0; | 934 | return 0; |
886 | 935 | ||
887 | if (oh->flags & HWMOD_NO_IDLEST) | 936 | if (oh->flags & HWMOD_NO_IDLEST) |
@@ -894,6 +943,31 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) | |||
894 | } | 943 | } |
895 | 944 | ||
896 | /** | 945 | /** |
946 | * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX | ||
947 | * @oh: struct omap_hwmod * | ||
948 | * | ||
949 | * Wait for a module @oh to enter slave idle. Returns 0 if the module | ||
950 | * does not have an IDLEST bit or if the module successfully enters | ||
951 | * slave idle; otherwise, pass along the return value of the | ||
952 | * appropriate *_cm*_wait_module_idle() function. | ||
953 | */ | ||
954 | static int _am33xx_wait_target_disable(struct omap_hwmod *oh) | ||
955 | { | ||
956 | if (!oh) | ||
957 | return -EINVAL; | ||
958 | |||
959 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
960 | return 0; | ||
961 | |||
962 | if (oh->flags & HWMOD_NO_IDLEST) | ||
963 | return 0; | ||
964 | |||
965 | return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, | ||
966 | oh->clkdm->clkdm_offs, | ||
967 | oh->prcm.omap4.clkctrl_offs); | ||
968 | } | ||
969 | |||
970 | /** | ||
897 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh | 971 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh |
898 | * @oh: struct omap_hwmod *oh | 972 | * @oh: struct omap_hwmod *oh |
899 | * | 973 | * |
@@ -1380,8 +1454,10 @@ static struct omap_hwmod *_lookup(const char *name) | |||
1380 | */ | 1454 | */ |
1381 | static int _init_clkdm(struct omap_hwmod *oh) | 1455 | static int _init_clkdm(struct omap_hwmod *oh) |
1382 | { | 1456 | { |
1383 | if (!oh->clkdm_name) | 1457 | if (!oh->clkdm_name) { |
1458 | pr_debug("omap_hwmod: %s: missing clockdomain\n", oh->name); | ||
1384 | return 0; | 1459 | return 0; |
1460 | } | ||
1385 | 1461 | ||
1386 | oh->clkdm = clkdm_lookup(oh->clkdm_name); | 1462 | oh->clkdm = clkdm_lookup(oh->clkdm_name); |
1387 | if (!oh->clkdm) { | 1463 | if (!oh->clkdm) { |
@@ -1438,8 +1514,8 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
1438 | * Return the bit position of the reset line that match the | 1514 | * Return the bit position of the reset line that match the |
1439 | * input name. Return -ENOENT if not found. | 1515 | * input name. Return -ENOENT if not found. |
1440 | */ | 1516 | */ |
1441 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name, | 1517 | static int _lookup_hardreset(struct omap_hwmod *oh, const char *name, |
1442 | struct omap_hwmod_rst_info *ohri) | 1518 | struct omap_hwmod_rst_info *ohri) |
1443 | { | 1519 | { |
1444 | int i; | 1520 | int i; |
1445 | 1521 | ||
@@ -1475,7 +1551,7 @@ static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name, | |||
1475 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | 1551 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) |
1476 | { | 1552 | { |
1477 | struct omap_hwmod_rst_info ohri; | 1553 | struct omap_hwmod_rst_info ohri; |
1478 | u8 ret = -EINVAL; | 1554 | int ret = -EINVAL; |
1479 | 1555 | ||
1480 | if (!oh) | 1556 | if (!oh) |
1481 | return -EINVAL; | 1557 | return -EINVAL; |
@@ -1484,7 +1560,7 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1484 | return -ENOSYS; | 1560 | return -ENOSYS; |
1485 | 1561 | ||
1486 | ret = _lookup_hardreset(oh, name, &ohri); | 1562 | ret = _lookup_hardreset(oh, name, &ohri); |
1487 | if (IS_ERR_VALUE(ret)) | 1563 | if (ret < 0) |
1488 | return ret; | 1564 | return ret; |
1489 | 1565 | ||
1490 | ret = soc_ops.assert_hardreset(oh, &ohri); | 1566 | ret = soc_ops.assert_hardreset(oh, &ohri); |
@@ -1509,6 +1585,7 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1509 | { | 1585 | { |
1510 | struct omap_hwmod_rst_info ohri; | 1586 | struct omap_hwmod_rst_info ohri; |
1511 | int ret = -EINVAL; | 1587 | int ret = -EINVAL; |
1588 | int hwsup = 0; | ||
1512 | 1589 | ||
1513 | if (!oh) | 1590 | if (!oh) |
1514 | return -EINVAL; | 1591 | return -EINVAL; |
@@ -1520,10 +1597,46 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1520 | if (IS_ERR_VALUE(ret)) | 1597 | if (IS_ERR_VALUE(ret)) |
1521 | return ret; | 1598 | return ret; |
1522 | 1599 | ||
1600 | if (oh->clkdm) { | ||
1601 | /* | ||
1602 | * A clockdomain must be in SW_SUP otherwise reset | ||
1603 | * might not be completed. The clockdomain can be set | ||
1604 | * in HW_AUTO only when the module become ready. | ||
1605 | */ | ||
1606 | hwsup = clkdm_in_hwsup(oh->clkdm); | ||
1607 | ret = clkdm_hwmod_enable(oh->clkdm, oh); | ||
1608 | if (ret) { | ||
1609 | WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n", | ||
1610 | oh->name, oh->clkdm->name, ret); | ||
1611 | return ret; | ||
1612 | } | ||
1613 | } | ||
1614 | |||
1615 | _enable_clocks(oh); | ||
1616 | if (soc_ops.enable_module) | ||
1617 | soc_ops.enable_module(oh); | ||
1618 | |||
1523 | ret = soc_ops.deassert_hardreset(oh, &ohri); | 1619 | ret = soc_ops.deassert_hardreset(oh, &ohri); |
1620 | |||
1621 | if (soc_ops.disable_module) | ||
1622 | soc_ops.disable_module(oh); | ||
1623 | _disable_clocks(oh); | ||
1624 | |||
1524 | if (ret == -EBUSY) | 1625 | if (ret == -EBUSY) |
1525 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); | 1626 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); |
1526 | 1627 | ||
1628 | if (!ret) { | ||
1629 | /* | ||
1630 | * Set the clockdomain to HW_AUTO, assuming that the | ||
1631 | * previous state was HW_AUTO. | ||
1632 | */ | ||
1633 | if (oh->clkdm && hwsup) | ||
1634 | clkdm_allow_idle(oh->clkdm); | ||
1635 | } else { | ||
1636 | if (oh->clkdm) | ||
1637 | clkdm_hwmod_disable(oh->clkdm, oh); | ||
1638 | } | ||
1639 | |||
1527 | return ret; | 1640 | return ret; |
1528 | } | 1641 | } |
1529 | 1642 | ||
@@ -1542,7 +1655,7 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1542 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) | 1655 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) |
1543 | { | 1656 | { |
1544 | struct omap_hwmod_rst_info ohri; | 1657 | struct omap_hwmod_rst_info ohri; |
1545 | u8 ret = -EINVAL; | 1658 | int ret = -EINVAL; |
1546 | 1659 | ||
1547 | if (!oh) | 1660 | if (!oh) |
1548 | return -EINVAL; | 1661 | return -EINVAL; |
@@ -1551,32 +1664,35 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1551 | return -ENOSYS; | 1664 | return -ENOSYS; |
1552 | 1665 | ||
1553 | ret = _lookup_hardreset(oh, name, &ohri); | 1666 | ret = _lookup_hardreset(oh, name, &ohri); |
1554 | if (IS_ERR_VALUE(ret)) | 1667 | if (ret < 0) |
1555 | return ret; | 1668 | return ret; |
1556 | 1669 | ||
1557 | return soc_ops.is_hardreset_asserted(oh, &ohri); | 1670 | return soc_ops.is_hardreset_asserted(oh, &ohri); |
1558 | } | 1671 | } |
1559 | 1672 | ||
1560 | /** | 1673 | /** |
1561 | * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset | 1674 | * _are_all_hardreset_lines_asserted - return true if the @oh is hard-reset |
1562 | * @oh: struct omap_hwmod * | 1675 | * @oh: struct omap_hwmod * |
1563 | * | 1676 | * |
1564 | * If any hardreset line associated with @oh is asserted, then return true. | 1677 | * If all hardreset lines associated with @oh are asserted, then return true. |
1565 | * Otherwise, if @oh has no hardreset lines associated with it, or if | 1678 | * Otherwise, if part of @oh is out hardreset or if no hardreset lines |
1566 | * no hardreset lines associated with @oh are asserted, then return false. | 1679 | * associated with @oh are asserted, then return false. |
1567 | * This function is used to avoid executing some parts of the IP block | 1680 | * This function is used to avoid executing some parts of the IP block |
1568 | * enable/disable sequence if a hardreset line is set. | 1681 | * enable/disable sequence if its hardreset line is set. |
1569 | */ | 1682 | */ |
1570 | static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh) | 1683 | static bool _are_all_hardreset_lines_asserted(struct omap_hwmod *oh) |
1571 | { | 1684 | { |
1572 | int i; | 1685 | int i, rst_cnt = 0; |
1573 | 1686 | ||
1574 | if (oh->rst_lines_cnt == 0) | 1687 | if (oh->rst_lines_cnt == 0) |
1575 | return false; | 1688 | return false; |
1576 | 1689 | ||
1577 | for (i = 0; i < oh->rst_lines_cnt; i++) | 1690 | for (i = 0; i < oh->rst_lines_cnt; i++) |
1578 | if (_read_hardreset(oh, oh->rst_lines[i].name) > 0) | 1691 | if (_read_hardreset(oh, oh->rst_lines[i].name) > 0) |
1579 | return true; | 1692 | rst_cnt++; |
1693 | |||
1694 | if (oh->rst_lines_cnt == rst_cnt) | ||
1695 | return true; | ||
1580 | 1696 | ||
1581 | return false; | 1697 | return false; |
1582 | } | 1698 | } |
@@ -1595,6 +1711,13 @@ static int _omap4_disable_module(struct omap_hwmod *oh) | |||
1595 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | 1711 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) |
1596 | return -EINVAL; | 1712 | return -EINVAL; |
1597 | 1713 | ||
1714 | /* | ||
1715 | * Since integration code might still be doing something, only | ||
1716 | * disable if all lines are under hardreset. | ||
1717 | */ | ||
1718 | if (!_are_all_hardreset_lines_asserted(oh)) | ||
1719 | return 0; | ||
1720 | |||
1598 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); | 1721 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); |
1599 | 1722 | ||
1600 | omap4_cminst_module_disable(oh->clkdm->prcm_partition, | 1723 | omap4_cminst_module_disable(oh->clkdm->prcm_partition, |
@@ -1602,10 +1725,37 @@ static int _omap4_disable_module(struct omap_hwmod *oh) | |||
1602 | oh->clkdm->clkdm_offs, | 1725 | oh->clkdm->clkdm_offs, |
1603 | oh->prcm.omap4.clkctrl_offs); | 1726 | oh->prcm.omap4.clkctrl_offs); |
1604 | 1727 | ||
1605 | if (_are_any_hardreset_lines_asserted(oh)) | 1728 | v = _omap4_wait_target_disable(oh); |
1729 | if (v) | ||
1730 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1731 | oh->name); | ||
1732 | |||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | /** | ||
1737 | * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX | ||
1738 | * @oh: struct omap_hwmod * | ||
1739 | * | ||
1740 | * Disable the PRCM module mode related to the hwmod @oh. | ||
1741 | * Return EINVAL if the modulemode is not supported and 0 in case of success. | ||
1742 | */ | ||
1743 | static int _am33xx_disable_module(struct omap_hwmod *oh) | ||
1744 | { | ||
1745 | int v; | ||
1746 | |||
1747 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
1748 | return -EINVAL; | ||
1749 | |||
1750 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); | ||
1751 | |||
1752 | am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, | ||
1753 | oh->prcm.omap4.clkctrl_offs); | ||
1754 | |||
1755 | if (_are_all_hardreset_lines_asserted(oh)) | ||
1606 | return 0; | 1756 | return 0; |
1607 | 1757 | ||
1608 | v = _omap4_wait_target_disable(oh); | 1758 | v = _am33xx_wait_target_disable(oh); |
1609 | if (v) | 1759 | if (v) |
1610 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | 1760 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", |
1611 | oh->name); | 1761 | oh->name); |
@@ -1641,8 +1791,8 @@ static int _ocp_softreset(struct omap_hwmod *oh) | |||
1641 | 1791 | ||
1642 | /* clocks must be on for this operation */ | 1792 | /* clocks must be on for this operation */ |
1643 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1793 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
1644 | pr_warning("omap_hwmod: %s: reset can only be entered from " | 1794 | pr_warn("omap_hwmod: %s: reset can only be entered from enabled state\n", |
1645 | "enabled state\n", oh->name); | 1795 | oh->name); |
1646 | return -EINVAL; | 1796 | return -EINVAL; |
1647 | } | 1797 | } |
1648 | 1798 | ||
@@ -1830,7 +1980,7 @@ static int _enable(struct omap_hwmod *oh) | |||
1830 | } | 1980 | } |
1831 | 1981 | ||
1832 | /* | 1982 | /* |
1833 | * If an IP block contains HW reset lines and any of them are | 1983 | * If an IP block contains HW reset lines and all of them are |
1834 | * asserted, we let integration code associated with that | 1984 | * asserted, we let integration code associated with that |
1835 | * block handle the enable. We've received very little | 1985 | * block handle the enable. We've received very little |
1836 | * information on what those driver authors need, and until | 1986 | * information on what those driver authors need, and until |
@@ -1838,7 +1988,7 @@ static int _enable(struct omap_hwmod *oh) | |||
1838 | * posted to the public lists, this is probably the best we | 1988 | * posted to the public lists, this is probably the best we |
1839 | * can do. | 1989 | * can do. |
1840 | */ | 1990 | */ |
1841 | if (_are_any_hardreset_lines_asserted(oh)) | 1991 | if (_are_all_hardreset_lines_asserted(oh)) |
1842 | return 0; | 1992 | return 0; |
1843 | 1993 | ||
1844 | /* Mux pins for device runtime if populated */ | 1994 | /* Mux pins for device runtime if populated */ |
@@ -1857,7 +2007,8 @@ static int _enable(struct omap_hwmod *oh) | |||
1857 | * completely the module. The clockdomain can be set | 2007 | * completely the module. The clockdomain can be set |
1858 | * in HW_AUTO only when the module become ready. | 2008 | * in HW_AUTO only when the module become ready. |
1859 | */ | 2009 | */ |
1860 | hwsup = clkdm_in_hwsup(oh->clkdm); | 2010 | hwsup = clkdm_in_hwsup(oh->clkdm) && |
2011 | !clkdm_missing_idle_reporting(oh->clkdm); | ||
1861 | r = clkdm_hwmod_enable(oh->clkdm, oh); | 2012 | r = clkdm_hwmod_enable(oh->clkdm, oh); |
1862 | if (r) { | 2013 | if (r) { |
1863 | WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n", | 2014 | WARN(1, "omap_hwmod: %s: could not enable clockdomain %s: %d\n", |
@@ -1919,7 +2070,7 @@ static int _idle(struct omap_hwmod *oh) | |||
1919 | return -EINVAL; | 2070 | return -EINVAL; |
1920 | } | 2071 | } |
1921 | 2072 | ||
1922 | if (_are_any_hardreset_lines_asserted(oh)) | 2073 | if (_are_all_hardreset_lines_asserted(oh)) |
1923 | return 0; | 2074 | return 0; |
1924 | 2075 | ||
1925 | if (oh->class->sysc) | 2076 | if (oh->class->sysc) |
@@ -2007,7 +2158,7 @@ static int _shutdown(struct omap_hwmod *oh) | |||
2007 | return -EINVAL; | 2158 | return -EINVAL; |
2008 | } | 2159 | } |
2009 | 2160 | ||
2010 | if (_are_any_hardreset_lines_asserted(oh)) | 2161 | if (_are_all_hardreset_lines_asserted(oh)) |
2011 | return 0; | 2162 | return 0; |
2012 | 2163 | ||
2013 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); | 2164 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); |
@@ -2531,10 +2682,10 @@ static int _omap2_wait_target_ready(struct omap_hwmod *oh) | |||
2531 | */ | 2682 | */ |
2532 | static int _omap4_wait_target_ready(struct omap_hwmod *oh) | 2683 | static int _omap4_wait_target_ready(struct omap_hwmod *oh) |
2533 | { | 2684 | { |
2534 | if (!oh || !oh->clkdm) | 2685 | if (!oh) |
2535 | return -EINVAL; | 2686 | return -EINVAL; |
2536 | 2687 | ||
2537 | if (oh->flags & HWMOD_NO_IDLEST) | 2688 | if (oh->flags & HWMOD_NO_IDLEST || !oh->clkdm) |
2538 | return 0; | 2689 | return 0; |
2539 | 2690 | ||
2540 | if (!_find_mpu_rt_port(oh)) | 2691 | if (!_find_mpu_rt_port(oh)) |
@@ -2549,6 +2700,33 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) | |||
2549 | } | 2700 | } |
2550 | 2701 | ||
2551 | /** | 2702 | /** |
2703 | * _am33xx_wait_target_ready - wait for a module to leave slave idle | ||
2704 | * @oh: struct omap_hwmod * | ||
2705 | * | ||
2706 | * Wait for a module @oh to leave slave idle. Returns 0 if the module | ||
2707 | * does not have an IDLEST bit or if the module successfully leaves | ||
2708 | * slave idle; otherwise, pass along the return value of the | ||
2709 | * appropriate *_cm*_wait_module_ready() function. | ||
2710 | */ | ||
2711 | static int _am33xx_wait_target_ready(struct omap_hwmod *oh) | ||
2712 | { | ||
2713 | if (!oh || !oh->clkdm) | ||
2714 | return -EINVAL; | ||
2715 | |||
2716 | if (oh->flags & HWMOD_NO_IDLEST) | ||
2717 | return 0; | ||
2718 | |||
2719 | if (!_find_mpu_rt_port(oh)) | ||
2720 | return 0; | ||
2721 | |||
2722 | /* XXX check module SIDLEMODE, hardreset status */ | ||
2723 | |||
2724 | return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, | ||
2725 | oh->clkdm->clkdm_offs, | ||
2726 | oh->prcm.omap4.clkctrl_offs); | ||
2727 | } | ||
2728 | |||
2729 | /** | ||
2552 | * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args | 2730 | * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args |
2553 | * @oh: struct omap_hwmod * to assert hardreset | 2731 | * @oh: struct omap_hwmod * to assert hardreset |
2554 | * @ohri: hardreset line data | 2732 | * @ohri: hardreset line data |
@@ -2679,6 +2857,72 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, | |||
2679 | oh->prcm.omap4.rstctrl_offs); | 2857 | oh->prcm.omap4.rstctrl_offs); |
2680 | } | 2858 | } |
2681 | 2859 | ||
2860 | /** | ||
2861 | * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args | ||
2862 | * @oh: struct omap_hwmod * to assert hardreset | ||
2863 | * @ohri: hardreset line data | ||
2864 | * | ||
2865 | * Call am33xx_prminst_assert_hardreset() with parameters extracted | ||
2866 | * from the hwmod @oh and the hardreset line data @ohri. Only | ||
2867 | * intended for use as an soc_ops function pointer. Passes along the | ||
2868 | * return value from am33xx_prminst_assert_hardreset(). XXX This | ||
2869 | * function is scheduled for removal when the PRM code is moved into | ||
2870 | * drivers/. | ||
2871 | */ | ||
2872 | static int _am33xx_assert_hardreset(struct omap_hwmod *oh, | ||
2873 | struct omap_hwmod_rst_info *ohri) | ||
2874 | |||
2875 | { | ||
2876 | return am33xx_prm_assert_hardreset(ohri->rst_shift, | ||
2877 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2878 | oh->prcm.omap4.rstctrl_offs); | ||
2879 | } | ||
2880 | |||
2881 | /** | ||
2882 | * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args | ||
2883 | * @oh: struct omap_hwmod * to deassert hardreset | ||
2884 | * @ohri: hardreset line data | ||
2885 | * | ||
2886 | * Call am33xx_prminst_deassert_hardreset() with parameters extracted | ||
2887 | * from the hwmod @oh and the hardreset line data @ohri. Only | ||
2888 | * intended for use as an soc_ops function pointer. Passes along the | ||
2889 | * return value from am33xx_prminst_deassert_hardreset(). XXX This | ||
2890 | * function is scheduled for removal when the PRM code is moved into | ||
2891 | * drivers/. | ||
2892 | */ | ||
2893 | static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, | ||
2894 | struct omap_hwmod_rst_info *ohri) | ||
2895 | { | ||
2896 | if (ohri->st_shift) | ||
2897 | pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", | ||
2898 | oh->name, ohri->name); | ||
2899 | |||
2900 | return am33xx_prm_deassert_hardreset(ohri->rst_shift, | ||
2901 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2902 | oh->prcm.omap4.rstctrl_offs, | ||
2903 | oh->prcm.omap4.rstst_offs); | ||
2904 | } | ||
2905 | |||
2906 | /** | ||
2907 | * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args | ||
2908 | * @oh: struct omap_hwmod * to test hardreset | ||
2909 | * @ohri: hardreset line data | ||
2910 | * | ||
2911 | * Call am33xx_prminst_is_hardreset_asserted() with parameters | ||
2912 | * extracted from the hwmod @oh and the hardreset line data @ohri. | ||
2913 | * Only intended for use as an soc_ops function pointer. Passes along | ||
2914 | * the return value from am33xx_prminst_is_hardreset_asserted(). XXX | ||
2915 | * This function is scheduled for removal when the PRM code is moved | ||
2916 | * into drivers/. | ||
2917 | */ | ||
2918 | static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, | ||
2919 | struct omap_hwmod_rst_info *ohri) | ||
2920 | { | ||
2921 | return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, | ||
2922 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2923 | oh->prcm.omap4.rstctrl_offs); | ||
2924 | } | ||
2925 | |||
2682 | /* Public functions */ | 2926 | /* Public functions */ |
2683 | 2927 | ||
2684 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) | 2928 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) |
@@ -3678,6 +3922,14 @@ void __init omap_hwmod_init(void) | |||
3678 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; | 3922 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; |
3679 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; | 3923 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; |
3680 | soc_ops.init_clkdm = _init_clkdm; | 3924 | soc_ops.init_clkdm = _init_clkdm; |
3925 | } else if (soc_is_am33xx()) { | ||
3926 | soc_ops.enable_module = _am33xx_enable_module; | ||
3927 | soc_ops.disable_module = _am33xx_disable_module; | ||
3928 | soc_ops.wait_target_ready = _am33xx_wait_target_ready; | ||
3929 | soc_ops.assert_hardreset = _am33xx_assert_hardreset; | ||
3930 | soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; | ||
3931 | soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; | ||
3932 | soc_ops.init_clkdm = _init_clkdm; | ||
3681 | } else { | 3933 | } else { |
3682 | WARN(1, "omap_hwmod: unknown SoC type\n"); | 3934 | WARN(1, "omap_hwmod: unknown SoC type\n"); |
3683 | } | 3935 | } |