diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 230 |
1 files changed, 218 insertions, 12 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 6ca8e519968d..00c006686b0d 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" |
@@ -868,6 +870,26 @@ static void _omap4_enable_module(struct omap_hwmod *oh) | |||
868 | } | 870 | } |
869 | 871 | ||
870 | /** | 872 | /** |
873 | * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX | ||
874 | * @oh: struct omap_hwmod * | ||
875 | * | ||
876 | * Enables the PRCM module mode related to the hwmod @oh. | ||
877 | * No return value. | ||
878 | */ | ||
879 | static void _am33xx_enable_module(struct omap_hwmod *oh) | ||
880 | { | ||
881 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
882 | return; | ||
883 | |||
884 | pr_debug("omap_hwmod: %s: %s: %d\n", | ||
885 | oh->name, __func__, oh->prcm.omap4.modulemode); | ||
886 | |||
887 | am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst, | ||
888 | oh->clkdm->clkdm_offs, | ||
889 | oh->prcm.omap4.clkctrl_offs); | ||
890 | } | ||
891 | |||
892 | /** | ||
871 | * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4 | 893 | * _omap4_wait_target_disable - wait for a module to be disabled on OMAP4 |
872 | * @oh: struct omap_hwmod * | 894 | * @oh: struct omap_hwmod * |
873 | * | 895 | * |
@@ -894,6 +916,31 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh) | |||
894 | } | 916 | } |
895 | 917 | ||
896 | /** | 918 | /** |
919 | * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX | ||
920 | * @oh: struct omap_hwmod * | ||
921 | * | ||
922 | * Wait for a module @oh to enter slave idle. Returns 0 if the module | ||
923 | * does not have an IDLEST bit or if the module successfully enters | ||
924 | * slave idle; otherwise, pass along the return value of the | ||
925 | * appropriate *_cm*_wait_module_idle() function. | ||
926 | */ | ||
927 | static int _am33xx_wait_target_disable(struct omap_hwmod *oh) | ||
928 | { | ||
929 | if (!oh) | ||
930 | return -EINVAL; | ||
931 | |||
932 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
933 | return 0; | ||
934 | |||
935 | if (oh->flags & HWMOD_NO_IDLEST) | ||
936 | return 0; | ||
937 | |||
938 | return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst, | ||
939 | oh->clkdm->clkdm_offs, | ||
940 | oh->prcm.omap4.clkctrl_offs); | ||
941 | } | ||
942 | |||
943 | /** | ||
897 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh | 944 | * _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh |
898 | * @oh: struct omap_hwmod *oh | 945 | * @oh: struct omap_hwmod *oh |
899 | * | 946 | * |
@@ -1438,8 +1485,8 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
1438 | * Return the bit position of the reset line that match the | 1485 | * Return the bit position of the reset line that match the |
1439 | * input name. Return -ENOENT if not found. | 1486 | * input name. Return -ENOENT if not found. |
1440 | */ | 1487 | */ |
1441 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name, | 1488 | static int _lookup_hardreset(struct omap_hwmod *oh, const char *name, |
1442 | struct omap_hwmod_rst_info *ohri) | 1489 | struct omap_hwmod_rst_info *ohri) |
1443 | { | 1490 | { |
1444 | int i; | 1491 | int i; |
1445 | 1492 | ||
@@ -1475,7 +1522,7 @@ static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name, | |||
1475 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | 1522 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) |
1476 | { | 1523 | { |
1477 | struct omap_hwmod_rst_info ohri; | 1524 | struct omap_hwmod_rst_info ohri; |
1478 | u8 ret = -EINVAL; | 1525 | int ret = -EINVAL; |
1479 | 1526 | ||
1480 | if (!oh) | 1527 | if (!oh) |
1481 | return -EINVAL; | 1528 | return -EINVAL; |
@@ -1484,7 +1531,7 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1484 | return -ENOSYS; | 1531 | return -ENOSYS; |
1485 | 1532 | ||
1486 | ret = _lookup_hardreset(oh, name, &ohri); | 1533 | ret = _lookup_hardreset(oh, name, &ohri); |
1487 | if (IS_ERR_VALUE(ret)) | 1534 | if (ret < 0) |
1488 | return ret; | 1535 | return ret; |
1489 | 1536 | ||
1490 | ret = soc_ops.assert_hardreset(oh, &ohri); | 1537 | ret = soc_ops.assert_hardreset(oh, &ohri); |
@@ -1542,7 +1589,7 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1542 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) | 1589 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) |
1543 | { | 1590 | { |
1544 | struct omap_hwmod_rst_info ohri; | 1591 | struct omap_hwmod_rst_info ohri; |
1545 | u8 ret = -EINVAL; | 1592 | int ret = -EINVAL; |
1546 | 1593 | ||
1547 | if (!oh) | 1594 | if (!oh) |
1548 | return -EINVAL; | 1595 | return -EINVAL; |
@@ -1551,7 +1598,7 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1551 | return -ENOSYS; | 1598 | return -ENOSYS; |
1552 | 1599 | ||
1553 | ret = _lookup_hardreset(oh, name, &ohri); | 1600 | ret = _lookup_hardreset(oh, name, &ohri); |
1554 | if (IS_ERR_VALUE(ret)) | 1601 | if (ret < 0) |
1555 | return ret; | 1602 | return ret; |
1556 | 1603 | ||
1557 | return soc_ops.is_hardreset_asserted(oh, &ohri); | 1604 | return soc_ops.is_hardreset_asserted(oh, &ohri); |
@@ -1614,6 +1661,36 @@ static int _omap4_disable_module(struct omap_hwmod *oh) | |||
1614 | } | 1661 | } |
1615 | 1662 | ||
1616 | /** | 1663 | /** |
1664 | * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX | ||
1665 | * @oh: struct omap_hwmod * | ||
1666 | * | ||
1667 | * Disable the PRCM module mode related to the hwmod @oh. | ||
1668 | * Return EINVAL if the modulemode is not supported and 0 in case of success. | ||
1669 | */ | ||
1670 | static int _am33xx_disable_module(struct omap_hwmod *oh) | ||
1671 | { | ||
1672 | int v; | ||
1673 | |||
1674 | if (!oh->clkdm || !oh->prcm.omap4.modulemode) | ||
1675 | return -EINVAL; | ||
1676 | |||
1677 | pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__); | ||
1678 | |||
1679 | am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs, | ||
1680 | oh->prcm.omap4.clkctrl_offs); | ||
1681 | |||
1682 | if (_are_any_hardreset_lines_asserted(oh)) | ||
1683 | return 0; | ||
1684 | |||
1685 | v = _am33xx_wait_target_disable(oh); | ||
1686 | if (v) | ||
1687 | pr_warn("omap_hwmod: %s: _wait_target_disable failed\n", | ||
1688 | oh->name); | ||
1689 | |||
1690 | return 0; | ||
1691 | } | ||
1692 | |||
1693 | /** | ||
1617 | * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit | 1694 | * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit |
1618 | * @oh: struct omap_hwmod * | 1695 | * @oh: struct omap_hwmod * |
1619 | * | 1696 | * |
@@ -1641,8 +1718,8 @@ static int _ocp_softreset(struct omap_hwmod *oh) | |||
1641 | 1718 | ||
1642 | /* clocks must be on for this operation */ | 1719 | /* clocks must be on for this operation */ |
1643 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1720 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
1644 | pr_warning("omap_hwmod: %s: reset can only be entered from " | 1721 | pr_warn("omap_hwmod: %s: reset can only be entered from enabled state\n", |
1645 | "enabled state\n", oh->name); | 1722 | oh->name); |
1646 | return -EINVAL; | 1723 | return -EINVAL; |
1647 | } | 1724 | } |
1648 | 1725 | ||
@@ -1889,6 +1966,7 @@ static int _enable(struct omap_hwmod *oh) | |||
1889 | _enable_sysc(oh); | 1966 | _enable_sysc(oh); |
1890 | } | 1967 | } |
1891 | } else { | 1968 | } else { |
1969 | _omap4_disable_module(oh); | ||
1892 | _disable_clocks(oh); | 1970 | _disable_clocks(oh); |
1893 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | 1971 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", |
1894 | oh->name, r); | 1972 | oh->name, r); |
@@ -2548,6 +2626,33 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh) | |||
2548 | } | 2626 | } |
2549 | 2627 | ||
2550 | /** | 2628 | /** |
2629 | * _am33xx_wait_target_ready - wait for a module to leave slave idle | ||
2630 | * @oh: struct omap_hwmod * | ||
2631 | * | ||
2632 | * Wait for a module @oh to leave slave idle. Returns 0 if the module | ||
2633 | * does not have an IDLEST bit or if the module successfully leaves | ||
2634 | * slave idle; otherwise, pass along the return value of the | ||
2635 | * appropriate *_cm*_wait_module_ready() function. | ||
2636 | */ | ||
2637 | static int _am33xx_wait_target_ready(struct omap_hwmod *oh) | ||
2638 | { | ||
2639 | if (!oh || !oh->clkdm) | ||
2640 | return -EINVAL; | ||
2641 | |||
2642 | if (oh->flags & HWMOD_NO_IDLEST) | ||
2643 | return 0; | ||
2644 | |||
2645 | if (!_find_mpu_rt_port(oh)) | ||
2646 | return 0; | ||
2647 | |||
2648 | /* XXX check module SIDLEMODE, hardreset status */ | ||
2649 | |||
2650 | return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst, | ||
2651 | oh->clkdm->clkdm_offs, | ||
2652 | oh->prcm.omap4.clkctrl_offs); | ||
2653 | } | ||
2654 | |||
2655 | /** | ||
2551 | * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args | 2656 | * _omap2_assert_hardreset - call OMAP2 PRM hardreset fn with hwmod args |
2552 | * @oh: struct omap_hwmod * to assert hardreset | 2657 | * @oh: struct omap_hwmod * to assert hardreset |
2553 | * @ohri: hardreset line data | 2658 | * @ohri: hardreset line data |
@@ -2678,6 +2783,72 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh, | |||
2678 | oh->prcm.omap4.rstctrl_offs); | 2783 | oh->prcm.omap4.rstctrl_offs); |
2679 | } | 2784 | } |
2680 | 2785 | ||
2786 | /** | ||
2787 | * _am33xx_assert_hardreset - call AM33XX PRM hardreset fn with hwmod args | ||
2788 | * @oh: struct omap_hwmod * to assert hardreset | ||
2789 | * @ohri: hardreset line data | ||
2790 | * | ||
2791 | * Call am33xx_prminst_assert_hardreset() with parameters extracted | ||
2792 | * from the hwmod @oh and the hardreset line data @ohri. Only | ||
2793 | * intended for use as an soc_ops function pointer. Passes along the | ||
2794 | * return value from am33xx_prminst_assert_hardreset(). XXX This | ||
2795 | * function is scheduled for removal when the PRM code is moved into | ||
2796 | * drivers/. | ||
2797 | */ | ||
2798 | static int _am33xx_assert_hardreset(struct omap_hwmod *oh, | ||
2799 | struct omap_hwmod_rst_info *ohri) | ||
2800 | |||
2801 | { | ||
2802 | return am33xx_prm_assert_hardreset(ohri->rst_shift, | ||
2803 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2804 | oh->prcm.omap4.rstctrl_offs); | ||
2805 | } | ||
2806 | |||
2807 | /** | ||
2808 | * _am33xx_deassert_hardreset - call AM33XX PRM hardreset fn with hwmod args | ||
2809 | * @oh: struct omap_hwmod * to deassert hardreset | ||
2810 | * @ohri: hardreset line data | ||
2811 | * | ||
2812 | * Call am33xx_prminst_deassert_hardreset() with parameters extracted | ||
2813 | * from the hwmod @oh and the hardreset line data @ohri. Only | ||
2814 | * intended for use as an soc_ops function pointer. Passes along the | ||
2815 | * return value from am33xx_prminst_deassert_hardreset(). XXX This | ||
2816 | * function is scheduled for removal when the PRM code is moved into | ||
2817 | * drivers/. | ||
2818 | */ | ||
2819 | static int _am33xx_deassert_hardreset(struct omap_hwmod *oh, | ||
2820 | struct omap_hwmod_rst_info *ohri) | ||
2821 | { | ||
2822 | if (ohri->st_shift) | ||
2823 | pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", | ||
2824 | oh->name, ohri->name); | ||
2825 | |||
2826 | return am33xx_prm_deassert_hardreset(ohri->rst_shift, | ||
2827 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2828 | oh->prcm.omap4.rstctrl_offs, | ||
2829 | oh->prcm.omap4.rstst_offs); | ||
2830 | } | ||
2831 | |||
2832 | /** | ||
2833 | * _am33xx_is_hardreset_asserted - call AM33XX PRM hardreset fn with hwmod args | ||
2834 | * @oh: struct omap_hwmod * to test hardreset | ||
2835 | * @ohri: hardreset line data | ||
2836 | * | ||
2837 | * Call am33xx_prminst_is_hardreset_asserted() with parameters | ||
2838 | * extracted from the hwmod @oh and the hardreset line data @ohri. | ||
2839 | * Only intended for use as an soc_ops function pointer. Passes along | ||
2840 | * the return value from am33xx_prminst_is_hardreset_asserted(). XXX | ||
2841 | * This function is scheduled for removal when the PRM code is moved | ||
2842 | * into drivers/. | ||
2843 | */ | ||
2844 | static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh, | ||
2845 | struct omap_hwmod_rst_info *ohri) | ||
2846 | { | ||
2847 | return am33xx_prm_is_hardreset_asserted(ohri->rst_shift, | ||
2848 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2849 | oh->prcm.omap4.rstctrl_offs); | ||
2850 | } | ||
2851 | |||
2681 | /* Public functions */ | 2852 | /* Public functions */ |
2682 | 2853 | ||
2683 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) | 2854 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs) |
@@ -3158,6 +3329,33 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
3158 | } | 3329 | } |
3159 | 3330 | ||
3160 | /** | 3331 | /** |
3332 | * omap_hwmod_fill_dma_resources - fill struct resource array with dma data | ||
3333 | * @oh: struct omap_hwmod * | ||
3334 | * @res: pointer to the array of struct resource to fill | ||
3335 | * | ||
3336 | * Fill the struct resource array @res with dma resource data from the | ||
3337 | * omap_hwmod @oh. Intended to be called by code that registers | ||
3338 | * omap_devices. See also omap_hwmod_count_resources(). Returns the | ||
3339 | * number of array elements filled. | ||
3340 | */ | ||
3341 | int omap_hwmod_fill_dma_resources(struct omap_hwmod *oh, struct resource *res) | ||
3342 | { | ||
3343 | int i, sdma_reqs_cnt; | ||
3344 | int r = 0; | ||
3345 | |||
3346 | sdma_reqs_cnt = _count_sdma_reqs(oh); | ||
3347 | for (i = 0; i < sdma_reqs_cnt; i++) { | ||
3348 | (res + r)->name = (oh->sdma_reqs + i)->name; | ||
3349 | (res + r)->start = (oh->sdma_reqs + i)->dma_req; | ||
3350 | (res + r)->end = (oh->sdma_reqs + i)->dma_req; | ||
3351 | (res + r)->flags = IORESOURCE_DMA; | ||
3352 | r++; | ||
3353 | } | ||
3354 | |||
3355 | return r; | ||
3356 | } | ||
3357 | |||
3358 | /** | ||
3161 | * omap_hwmod_get_resource_byname - fetch IP block integration data by name | 3359 | * omap_hwmod_get_resource_byname - fetch IP block integration data by name |
3162 | * @oh: struct omap_hwmod * to operate on | 3360 | * @oh: struct omap_hwmod * to operate on |
3163 | * @type: one of the IORESOURCE_* constants from include/linux/ioport.h | 3361 | * @type: one of the IORESOURCE_* constants from include/linux/ioport.h |
@@ -3677,6 +3875,14 @@ void __init omap_hwmod_init(void) | |||
3677 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; | 3875 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; |
3678 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; | 3876 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; |
3679 | soc_ops.init_clkdm = _init_clkdm; | 3877 | soc_ops.init_clkdm = _init_clkdm; |
3878 | } else if (soc_is_am33xx()) { | ||
3879 | soc_ops.enable_module = _am33xx_enable_module; | ||
3880 | soc_ops.disable_module = _am33xx_disable_module; | ||
3881 | soc_ops.wait_target_ready = _am33xx_wait_target_ready; | ||
3882 | soc_ops.assert_hardreset = _am33xx_assert_hardreset; | ||
3883 | soc_ops.deassert_hardreset = _am33xx_deassert_hardreset; | ||
3884 | soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted; | ||
3885 | soc_ops.init_clkdm = _init_clkdm; | ||
3680 | } else { | 3886 | } else { |
3681 | WARN(1, "omap_hwmod: unknown SoC type\n"); | 3887 | WARN(1, "omap_hwmod: unknown SoC type\n"); |
3682 | } | 3888 | } |