diff options
author | Tony Lindgren <tony@atomide.com> | 2010-09-23 14:05:25 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-09-23 14:05:25 -0400 |
commit | 9af2ebbd09e01bd2711617dcafce5f608cace6ec (patch) | |
tree | 637af612e07c98a0fd998e558a56382a52eeab36 | |
parent | 493c32a0de2bfbcc33d52f32a39f3c301c6ffd62 (diff) | |
parent | 74ff3a68ed11f1e9eede4fe301f42cc3cdf7396a (diff) |
Merge branch 'hwmod_2.6.37' of git://git.pwsan.com/linux-2.6 into omap-for-linus
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 562 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prcm.c | 29 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm2xxx_3xxx.c | 110 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm44xx.c | 116 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/omap_hwmod.h | 55 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/prcm.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/omap_device.c | 43 |
9 files changed, 829 insertions, 110 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 88d3a1e920f5..eb2504a300c2 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | # Common support | 5 | # Common support |
6 | obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o | 6 | obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer-gp.o pm.o |
7 | 7 | ||
8 | omap-2-3-common = irq.o sdrc.o | 8 | omap-2-3-common = irq.o sdrc.o prm2xxx_3xxx.o |
9 | hwmod-common = omap_hwmod.o \ | 9 | hwmod-common = omap_hwmod.o \ |
10 | omap_hwmod_common_data.o | 10 | omap_hwmod_common_data.o |
11 | prcm-common = prcm.o powerdomain.o | 11 | prcm-common = prcm.o powerdomain.o |
@@ -15,7 +15,7 @@ clock-common = clock.o clock_common_data.o \ | |||
15 | 15 | ||
16 | obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) | 16 | obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) |
17 | obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) | 17 | obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(prcm-common) $(hwmod-common) |
18 | obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) $(hwmod-common) | 18 | obj-$(CONFIG_ARCH_OMAP4) += $(prcm-common) prm44xx.o $(hwmod-common) |
19 | 19 | ||
20 | obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o | 20 | obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o |
21 | 21 | ||
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index cb911d7d1a3c..c3a5889d8add 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -13,10 +13,102 @@ | |||
13 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
15 | * | 15 | * |
16 | * This code manages "OMAP modules" (on-chip devices) and their | 16 | * Introduction |
17 | * integration with Linux device driver and bus code. | 17 | * ------------ |
18 | * | 18 | * One way to view an OMAP SoC is as a collection of largely unrelated |
19 | * References: | 19 | * IP blocks connected by interconnects. The IP blocks include |
20 | * devices such as ARM processors, audio serial interfaces, UARTs, | ||
21 | * etc. Some of these devices, like the DSP, are created by TI; | ||
22 | * others, like the SGX, largely originate from external vendors. In | ||
23 | * TI's documentation, on-chip devices are referred to as "OMAP | ||
24 | * modules." Some of these IP blocks are identical across several | ||
25 | * OMAP versions. Others are revised frequently. | ||
26 | * | ||
27 | * These OMAP modules are tied together by various interconnects. | ||
28 | * Most of the address and data flow between modules is via OCP-based | ||
29 | * interconnects such as the L3 and L4 buses; but there are other | ||
30 | * interconnects that distribute the hardware clock tree, handle idle | ||
31 | * and reset signaling, supply power, and connect the modules to | ||
32 | * various pads or balls on the OMAP package. | ||
33 | * | ||
34 | * OMAP hwmod provides a consistent way to describe the on-chip | ||
35 | * hardware blocks and their integration into the rest of the chip. | ||
36 | * This description can be automatically generated from the TI | ||
37 | * hardware database. OMAP hwmod provides a standard, consistent API | ||
38 | * to reset, enable, idle, and disable these hardware blocks. And | ||
39 | * hwmod provides a way for other core code, such as the Linux device | ||
40 | * code or the OMAP power management and address space mapping code, | ||
41 | * to query the hardware database. | ||
42 | * | ||
43 | * Using hwmod | ||
44 | * ----------- | ||
45 | * Drivers won't call hwmod functions directly. That is done by the | ||
46 | * omap_device code, and in rare occasions, by custom integration code | ||
47 | * in arch/arm/ *omap*. The omap_device code includes functions to | ||
48 | * build a struct platform_device using omap_hwmod data, and that is | ||
49 | * currently how hwmod data is communicated to drivers and to the | ||
50 | * Linux driver model. Most drivers will call omap_hwmod functions only | ||
51 | * indirectly, via pm_runtime*() functions. | ||
52 | * | ||
53 | * From a layering perspective, here is where the OMAP hwmod code | ||
54 | * fits into the kernel software stack: | ||
55 | * | ||
56 | * +-------------------------------+ | ||
57 | * | Device driver code | | ||
58 | * | (e.g., drivers/) | | ||
59 | * +-------------------------------+ | ||
60 | * | Linux driver model | | ||
61 | * | (platform_device / | | ||
62 | * | platform_driver data/code) | | ||
63 | * +-------------------------------+ | ||
64 | * | OMAP core-driver integration | | ||
65 | * |(arch/arm/mach-omap2/devices.c)| | ||
66 | * +-------------------------------+ | ||
67 | * | omap_device code | | ||
68 | * | (../plat-omap/omap_device.c) | | ||
69 | * +-------------------------------+ | ||
70 | * ----> | omap_hwmod code/data | <----- | ||
71 | * | (../mach-omap2/omap_hwmod*) | | ||
72 | * +-------------------------------+ | ||
73 | * | OMAP clock/PRCM/register fns | | ||
74 | * | (__raw_{read,write}l, clk*) | | ||
75 | * +-------------------------------+ | ||
76 | * | ||
77 | * Device drivers should not contain any OMAP-specific code or data in | ||
78 | * them. They should only contain code to operate the IP block that | ||
79 | * the driver is responsible for. This is because these IP blocks can | ||
80 | * also appear in other SoCs, either from TI (such as DaVinci) or from | ||
81 | * other manufacturers; and drivers should be reusable across other | ||
82 | * platforms. | ||
83 | * | ||
84 | * The OMAP hwmod code also will attempt to reset and idle all on-chip | ||
85 | * devices upon boot. The goal here is for the kernel to be | ||
86 | * completely self-reliant and independent from bootloaders. This is | ||
87 | * to ensure a repeatable configuration, both to ensure consistent | ||
88 | * runtime behavior, and to make it easier for others to reproduce | ||
89 | * bugs. | ||
90 | * | ||
91 | * OMAP module activity states | ||
92 | * --------------------------- | ||
93 | * The hwmod code considers modules to be in one of several activity | ||
94 | * states. IP blocks start out in an UNKNOWN state, then once they | ||
95 | * are registered via the hwmod code, proceed to the REGISTERED state. | ||
96 | * Once their clock names are resolved to clock pointers, the module | ||
97 | * enters the CLKS_INITED state; and finally, once the module has been | ||
98 | * reset and the integration registers programmed, the INITIALIZED state | ||
99 | * is entered. The hwmod code will then place the module into either | ||
100 | * the IDLE state to save power, or in the case of a critical system | ||
101 | * module, the ENABLED state. | ||
102 | * | ||
103 | * OMAP core integration code can then call omap_hwmod*() functions | ||
104 | * directly to move the module between the IDLE, ENABLED, and DISABLED | ||
105 | * states, as needed. This is done during both the PM idle loop, and | ||
106 | * in the OMAP core integration code's implementation of the PM runtime | ||
107 | * functions. | ||
108 | * | ||
109 | * References | ||
110 | * ---------- | ||
111 | * This is a partial list. | ||
20 | * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064) | 112 | * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064) |
21 | * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090) | 113 | * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090) |
22 | * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108) | 114 | * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108) |
@@ -50,11 +142,13 @@ | |||
50 | #include <plat/powerdomain.h> | 142 | #include <plat/powerdomain.h> |
51 | #include <plat/clock.h> | 143 | #include <plat/clock.h> |
52 | #include <plat/omap_hwmod.h> | 144 | #include <plat/omap_hwmod.h> |
145 | #include <plat/prcm.h> | ||
53 | 146 | ||
54 | #include "cm.h" | 147 | #include "cm.h" |
148 | #include "prm.h" | ||
55 | 149 | ||
56 | /* Maximum microseconds to wait for OMAP module to reset */ | 150 | /* Maximum microseconds to wait for OMAP module to softreset */ |
57 | #define MAX_MODULE_RESET_WAIT 10000 | 151 | #define MAX_MODULE_SOFTRESET_WAIT 10000 |
58 | 152 | ||
59 | /* Name of the OMAP hwmod for the MPU */ | 153 | /* Name of the OMAP hwmod for the MPU */ |
60 | #define MPU_INITIATOR_NAME "mpu" | 154 | #define MPU_INITIATOR_NAME "mpu" |
@@ -544,6 +638,36 @@ static int _disable_clocks(struct omap_hwmod *oh) | |||
544 | return 0; | 638 | return 0; |
545 | } | 639 | } |
546 | 640 | ||
641 | static void _enable_optional_clocks(struct omap_hwmod *oh) | ||
642 | { | ||
643 | struct omap_hwmod_opt_clk *oc; | ||
644 | int i; | ||
645 | |||
646 | pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name); | ||
647 | |||
648 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) | ||
649 | if (oc->_clk) { | ||
650 | pr_debug("omap_hwmod: enable %s:%s\n", oc->role, | ||
651 | oc->_clk->name); | ||
652 | clk_enable(oc->_clk); | ||
653 | } | ||
654 | } | ||
655 | |||
656 | static void _disable_optional_clocks(struct omap_hwmod *oh) | ||
657 | { | ||
658 | struct omap_hwmod_opt_clk *oc; | ||
659 | int i; | ||
660 | |||
661 | pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name); | ||
662 | |||
663 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) | ||
664 | if (oc->_clk) { | ||
665 | pr_debug("omap_hwmod: disable %s:%s\n", oc->role, | ||
666 | oc->_clk->name); | ||
667 | clk_disable(oc->_clk); | ||
668 | } | ||
669 | } | ||
670 | |||
547 | /** | 671 | /** |
548 | * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use | 672 | * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use |
549 | * @oh: struct omap_hwmod * | 673 | * @oh: struct omap_hwmod * |
@@ -622,7 +746,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
622 | } | 746 | } |
623 | 747 | ||
624 | /** | 748 | /** |
625 | * _sysc_enable - try to bring a module out of idle via OCP_SYSCONFIG | 749 | * _enable_sysc - try to bring a module out of idle via OCP_SYSCONFIG |
626 | * @oh: struct omap_hwmod * | 750 | * @oh: struct omap_hwmod * |
627 | * | 751 | * |
628 | * If module is marked as SWSUP_SIDLE, force the module out of slave | 752 | * If module is marked as SWSUP_SIDLE, force the module out of slave |
@@ -630,7 +754,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
630 | * as SWSUP_MSUSPEND, force the module out of master standby; | 754 | * as SWSUP_MSUSPEND, force the module out of master standby; |
631 | * otherwise, configure it for smart-standby. No return value. | 755 | * otherwise, configure it for smart-standby. No return value. |
632 | */ | 756 | */ |
633 | static void _sysc_enable(struct omap_hwmod *oh) | 757 | static void _enable_sysc(struct omap_hwmod *oh) |
634 | { | 758 | { |
635 | u8 idlemode, sf; | 759 | u8 idlemode, sf; |
636 | u32 v; | 760 | u32 v; |
@@ -659,8 +783,6 @@ static void _sysc_enable(struct omap_hwmod *oh) | |||
659 | _set_module_autoidle(oh, idlemode, &v); | 783 | _set_module_autoidle(oh, idlemode, &v); |
660 | } | 784 | } |
661 | 785 | ||
662 | /* XXX OCP ENAWAKEUP bit? */ | ||
663 | |||
664 | /* | 786 | /* |
665 | * XXX The clock framework should handle this, by | 787 | * XXX The clock framework should handle this, by |
666 | * calling into this code. But this must wait until the | 788 | * calling into this code. But this must wait until the |
@@ -671,10 +793,14 @@ static void _sysc_enable(struct omap_hwmod *oh) | |||
671 | _set_clockactivity(oh, oh->class->sysc->clockact, &v); | 793 | _set_clockactivity(oh, oh->class->sysc->clockact, &v); |
672 | 794 | ||
673 | _write_sysconfig(v, oh); | 795 | _write_sysconfig(v, oh); |
796 | |||
797 | /* If slave is in SMARTIDLE, also enable wakeup */ | ||
798 | if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) | ||
799 | _enable_wakeup(oh); | ||
674 | } | 800 | } |
675 | 801 | ||
676 | /** | 802 | /** |
677 | * _sysc_idle - try to put a module into idle via OCP_SYSCONFIG | 803 | * _idle_sysc - try to put a module into idle via OCP_SYSCONFIG |
678 | * @oh: struct omap_hwmod * | 804 | * @oh: struct omap_hwmod * |
679 | * | 805 | * |
680 | * If module is marked as SWSUP_SIDLE, force the module into slave | 806 | * If module is marked as SWSUP_SIDLE, force the module into slave |
@@ -682,7 +808,7 @@ static void _sysc_enable(struct omap_hwmod *oh) | |||
682 | * as SWSUP_MSUSPEND, force the module into master standby; otherwise, | 808 | * as SWSUP_MSUSPEND, force the module into master standby; otherwise, |
683 | * configure it for smart-standby. No return value. | 809 | * configure it for smart-standby. No return value. |
684 | */ | 810 | */ |
685 | static void _sysc_idle(struct omap_hwmod *oh) | 811 | static void _idle_sysc(struct omap_hwmod *oh) |
686 | { | 812 | { |
687 | u8 idlemode, sf; | 813 | u8 idlemode, sf; |
688 | u32 v; | 814 | u32 v; |
@@ -709,13 +835,13 @@ static void _sysc_idle(struct omap_hwmod *oh) | |||
709 | } | 835 | } |
710 | 836 | ||
711 | /** | 837 | /** |
712 | * _sysc_shutdown - force a module into idle via OCP_SYSCONFIG | 838 | * _shutdown_sysc - force a module into idle via OCP_SYSCONFIG |
713 | * @oh: struct omap_hwmod * | 839 | * @oh: struct omap_hwmod * |
714 | * | 840 | * |
715 | * Force the module into slave idle and master suspend. No return | 841 | * Force the module into slave idle and master suspend. No return |
716 | * value. | 842 | * value. |
717 | */ | 843 | */ |
718 | static void _sysc_shutdown(struct omap_hwmod *oh) | 844 | static void _shutdown_sysc(struct omap_hwmod *oh) |
719 | { | 845 | { |
720 | u32 v; | 846 | u32 v; |
721 | u8 sf; | 847 | u8 sf; |
@@ -767,10 +893,10 @@ static struct omap_hwmod *_lookup(const char *name) | |||
767 | * @data: not used; pass NULL | 893 | * @data: not used; pass NULL |
768 | * | 894 | * |
769 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). | 895 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). |
770 | * Resolves all clock names embedded in the hwmod. Must be called | 896 | * Resolves all clock names embedded in the hwmod. Returns -EINVAL if |
771 | * with omap_hwmod_mutex held. Returns -EINVAL if the omap_hwmod | 897 | * the omap_hwmod has not yet been registered or if the clocks have |
772 | * has not yet been registered or if the clocks have already been | 898 | * already been initialized, 0 on success, or a non-zero error on |
773 | * initialized, 0 on success, or a non-zero error on failure. | 899 | * failure. |
774 | */ | 900 | */ |
775 | static int _init_clocks(struct omap_hwmod *oh, void *data) | 901 | static int _init_clocks(struct omap_hwmod *oh, void *data) |
776 | { | 902 | { |
@@ -834,56 +960,202 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
834 | } | 960 | } |
835 | 961 | ||
836 | /** | 962 | /** |
963 | * _lookup_hardreset - return the register bit shift for this hwmod/reset line | ||
964 | * @oh: struct omap_hwmod * | ||
965 | * @name: name of the reset line in the context of this hwmod | ||
966 | * | ||
967 | * Return the bit position of the reset line that match the | ||
968 | * input name. Return -ENOENT if not found. | ||
969 | */ | ||
970 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name) | ||
971 | { | ||
972 | int i; | ||
973 | |||
974 | for (i = 0; i < oh->rst_lines_cnt; i++) { | ||
975 | const char *rst_line = oh->rst_lines[i].name; | ||
976 | if (!strcmp(rst_line, name)) { | ||
977 | u8 shift = oh->rst_lines[i].rst_shift; | ||
978 | pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n", | ||
979 | oh->name, rst_line, shift); | ||
980 | |||
981 | return shift; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | return -ENOENT; | ||
986 | } | ||
987 | |||
988 | /** | ||
989 | * _assert_hardreset - assert the HW reset line of submodules | ||
990 | * contained in the hwmod module. | ||
991 | * @oh: struct omap_hwmod * | ||
992 | * @name: name of the reset line to lookup and assert | ||
993 | * | ||
994 | * Some IP like dsp, ipu or iva contain processor that require | ||
995 | * an HW reset line to be assert / deassert in order to enable fully | ||
996 | * the IP. | ||
997 | */ | ||
998 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | ||
999 | { | ||
1000 | u8 shift; | ||
1001 | |||
1002 | if (!oh) | ||
1003 | return -EINVAL; | ||
1004 | |||
1005 | shift = _lookup_hardreset(oh, name); | ||
1006 | if (IS_ERR_VALUE(shift)) | ||
1007 | return shift; | ||
1008 | |||
1009 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1010 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, | ||
1011 | shift); | ||
1012 | else if (cpu_is_omap44xx()) | ||
1013 | return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, | ||
1014 | shift); | ||
1015 | else | ||
1016 | return -EINVAL; | ||
1017 | } | ||
1018 | |||
1019 | /** | ||
1020 | * _deassert_hardreset - deassert the HW reset line of submodules contained | ||
1021 | * in the hwmod module. | ||
1022 | * @oh: struct omap_hwmod * | ||
1023 | * @name: name of the reset line to look up and deassert | ||
1024 | * | ||
1025 | * Some IP like dsp, ipu or iva contain processor that require | ||
1026 | * an HW reset line to be assert / deassert in order to enable fully | ||
1027 | * the IP. | ||
1028 | */ | ||
1029 | static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | ||
1030 | { | ||
1031 | u8 shift; | ||
1032 | int r; | ||
1033 | |||
1034 | if (!oh) | ||
1035 | return -EINVAL; | ||
1036 | |||
1037 | shift = _lookup_hardreset(oh, name); | ||
1038 | if (IS_ERR_VALUE(shift)) | ||
1039 | return shift; | ||
1040 | |||
1041 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
1042 | r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, | ||
1043 | shift); | ||
1044 | else if (cpu_is_omap44xx()) | ||
1045 | r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, | ||
1046 | shift); | ||
1047 | else | ||
1048 | return -EINVAL; | ||
1049 | |||
1050 | if (r == -EBUSY) | ||
1051 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); | ||
1052 | |||
1053 | return r; | ||
1054 | } | ||
1055 | |||
1056 | /** | ||
1057 | * _read_hardreset - read the HW reset line state of submodules | ||
1058 | * contained in the hwmod module | ||
1059 | * @oh: struct omap_hwmod * | ||
1060 | * @name: name of the reset line to look up and read | ||
1061 | * | ||
1062 | * Return the state of the reset line. | ||
1063 | */ | ||
1064 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) | ||
1065 | { | ||
1066 | u8 shift; | ||
1067 | |||
1068 | if (!oh) | ||
1069 | return -EINVAL; | ||
1070 | |||
1071 | shift = _lookup_hardreset(oh, name); | ||
1072 | if (IS_ERR_VALUE(shift)) | ||
1073 | return shift; | ||
1074 | |||
1075 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { | ||
1076 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, | ||
1077 | shift); | ||
1078 | } else if (cpu_is_omap44xx()) { | ||
1079 | return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, | ||
1080 | shift); | ||
1081 | } else { | ||
1082 | return -EINVAL; | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | /** | ||
837 | * _reset - reset an omap_hwmod | 1087 | * _reset - reset an omap_hwmod |
838 | * @oh: struct omap_hwmod * | 1088 | * @oh: struct omap_hwmod * |
839 | * | 1089 | * |
840 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be | 1090 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be |
841 | * enabled for this to work. Must be called with omap_hwmod_mutex | 1091 | * enabled for this to work. Returns -EINVAL if the hwmod cannot be |
842 | * held. Returns -EINVAL if the hwmod cannot be reset this way or if | 1092 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if |
843 | * the hwmod is in the wrong state, -ETIMEDOUT if the module did not | 1093 | * the module did not reset in time, or 0 upon success. |
844 | * reset in time, or 0 upon success. | 1094 | * |
1095 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. | ||
1096 | * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead | ||
1097 | * use the SYSCONFIG softreset bit to provide the status. | ||
1098 | * | ||
1099 | * Note that some IP like McBSP does have a reset control but no reset status. | ||
845 | */ | 1100 | */ |
846 | static int _reset(struct omap_hwmod *oh) | 1101 | static int _reset(struct omap_hwmod *oh) |
847 | { | 1102 | { |
848 | u32 r, v; | 1103 | u32 v; |
849 | int c = 0; | 1104 | int c = 0; |
1105 | int ret = 0; | ||
850 | 1106 | ||
851 | if (!oh->class->sysc || | 1107 | if (!oh->class->sysc || |
852 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET) || | 1108 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) |
853 | (oh->class->sysc->sysc_flags & SYSS_MISSING)) | ||
854 | return -EINVAL; | 1109 | return -EINVAL; |
855 | 1110 | ||
856 | /* clocks must be on for this operation */ | 1111 | /* clocks must be on for this operation */ |
857 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1112 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
858 | WARN(1, "omap_hwmod: %s: reset can only be entered from " | 1113 | pr_warning("omap_hwmod: %s: reset can only be entered from " |
859 | "enabled state\n", oh->name); | 1114 | "enabled state\n", oh->name); |
860 | return -EINVAL; | 1115 | return -EINVAL; |
861 | } | 1116 | } |
862 | 1117 | ||
1118 | /* For some modules, all optionnal clocks need to be enabled as well */ | ||
1119 | if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) | ||
1120 | _enable_optional_clocks(oh); | ||
1121 | |||
863 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); | 1122 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); |
864 | 1123 | ||
865 | v = oh->_sysc_cache; | 1124 | v = oh->_sysc_cache; |
866 | r = _set_softreset(oh, &v); | 1125 | ret = _set_softreset(oh, &v); |
867 | if (r) | 1126 | if (ret) |
868 | return r; | 1127 | goto dis_opt_clks; |
869 | _write_sysconfig(v, oh); | 1128 | _write_sysconfig(v, oh); |
870 | 1129 | ||
871 | omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & | 1130 | if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS) |
872 | SYSS_RESETDONE_MASK), | 1131 | omap_test_timeout((omap_hwmod_readl(oh, |
873 | MAX_MODULE_RESET_WAIT, c); | 1132 | oh->class->sysc->syss_offs) |
874 | 1133 | & SYSS_RESETDONE_MASK), | |
875 | if (c == MAX_MODULE_RESET_WAIT) | 1134 | MAX_MODULE_SOFTRESET_WAIT, c); |
876 | WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", | 1135 | else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS) |
877 | oh->name, MAX_MODULE_RESET_WAIT); | 1136 | omap_test_timeout(!(omap_hwmod_readl(oh, |
1137 | oh->class->sysc->sysc_offs) | ||
1138 | & SYSC_TYPE2_SOFTRESET_MASK), | ||
1139 | MAX_MODULE_SOFTRESET_WAIT, c); | ||
1140 | |||
1141 | if (c == MAX_MODULE_SOFTRESET_WAIT) | ||
1142 | pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n", | ||
1143 | oh->name, MAX_MODULE_SOFTRESET_WAIT); | ||
878 | else | 1144 | else |
879 | pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c); | 1145 | pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c); |
880 | 1146 | ||
881 | /* | 1147 | /* |
882 | * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from | 1148 | * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from |
883 | * _wait_target_ready() or _reset() | 1149 | * _wait_target_ready() or _reset() |
884 | */ | 1150 | */ |
885 | 1151 | ||
886 | return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0; | 1152 | ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; |
1153 | |||
1154 | dis_opt_clks: | ||
1155 | if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) | ||
1156 | _disable_optional_clocks(oh); | ||
1157 | |||
1158 | return ret; | ||
887 | } | 1159 | } |
888 | 1160 | ||
889 | /** | 1161 | /** |
@@ -891,9 +1163,11 @@ static int _reset(struct omap_hwmod *oh) | |||
891 | * @oh: struct omap_hwmod * | 1163 | * @oh: struct omap_hwmod * |
892 | * | 1164 | * |
893 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's | 1165 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's |
894 | * register target. Must be called with omap_hwmod_mutex held. | 1166 | * register target. (This function has a full name -- |
895 | * Returns -EINVAL if the hwmod is in the wrong state or passes along | 1167 | * _omap_hwmod_enable() rather than simply _enable() -- because it is |
896 | * the return value of _wait_target_ready(). | 1168 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if |
1169 | * the hwmod is in the wrong state or passes along the return value of | ||
1170 | * _wait_target_ready(). | ||
897 | */ | 1171 | */ |
898 | int _omap_hwmod_enable(struct omap_hwmod *oh) | 1172 | int _omap_hwmod_enable(struct omap_hwmod *oh) |
899 | { | 1173 | { |
@@ -909,6 +1183,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
909 | 1183 | ||
910 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | 1184 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); |
911 | 1185 | ||
1186 | /* | ||
1187 | * If an IP contains only one HW reset line, then de-assert it in order | ||
1188 | * to allow to enable the clocks. Otherwise the PRCM will return | ||
1189 | * Intransition status, and the init will failed. | ||
1190 | */ | ||
1191 | if ((oh->_state == _HWMOD_STATE_INITIALIZED || | ||
1192 | oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) | ||
1193 | _deassert_hardreset(oh, oh->rst_lines[0].name); | ||
1194 | |||
912 | /* XXX mux balls */ | 1195 | /* XXX mux balls */ |
913 | 1196 | ||
914 | _add_initiator_dep(oh, mpu_oh); | 1197 | _add_initiator_dep(oh, mpu_oh); |
@@ -922,7 +1205,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
922 | if (oh->class->sysc) { | 1205 | if (oh->class->sysc) { |
923 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) | 1206 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) |
924 | _update_sysc_cache(oh); | 1207 | _update_sysc_cache(oh); |
925 | _sysc_enable(oh); | 1208 | _enable_sysc(oh); |
926 | } | 1209 | } |
927 | } else { | 1210 | } else { |
928 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | 1211 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", |
@@ -933,12 +1216,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
933 | } | 1216 | } |
934 | 1217 | ||
935 | /** | 1218 | /** |
936 | * _idle - idle an omap_hwmod | 1219 | * _omap_hwmod_idle - idle an omap_hwmod |
937 | * @oh: struct omap_hwmod * | 1220 | * @oh: struct omap_hwmod * |
938 | * | 1221 | * |
939 | * Idles an omap_hwmod @oh. This should be called once the hwmod has | 1222 | * Idles an omap_hwmod @oh. This should be called once the hwmod has |
940 | * no further work. Returns -EINVAL if the hwmod is in the wrong | 1223 | * no further work. (This function has a full name -- |
941 | * state or returns 0. | 1224 | * _omap_hwmod_idle() rather than simply _idle() -- because it is |
1225 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if | ||
1226 | * the hwmod is in the wrong state or returns 0. | ||
942 | */ | 1227 | */ |
943 | int _omap_hwmod_idle(struct omap_hwmod *oh) | 1228 | int _omap_hwmod_idle(struct omap_hwmod *oh) |
944 | { | 1229 | { |
@@ -951,7 +1236,7 @@ int _omap_hwmod_idle(struct omap_hwmod *oh) | |||
951 | pr_debug("omap_hwmod: %s: idling\n", oh->name); | 1236 | pr_debug("omap_hwmod: %s: idling\n", oh->name); |
952 | 1237 | ||
953 | if (oh->class->sysc) | 1238 | if (oh->class->sysc) |
954 | _sysc_idle(oh); | 1239 | _idle_sysc(oh); |
955 | _del_initiator_dep(oh, mpu_oh); | 1240 | _del_initiator_dep(oh, mpu_oh); |
956 | _disable_clocks(oh); | 1241 | _disable_clocks(oh); |
957 | 1242 | ||
@@ -981,10 +1266,21 @@ static int _shutdown(struct omap_hwmod *oh) | |||
981 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); | 1266 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); |
982 | 1267 | ||
983 | if (oh->class->sysc) | 1268 | if (oh->class->sysc) |
984 | _sysc_shutdown(oh); | 1269 | _shutdown_sysc(oh); |
985 | _del_initiator_dep(oh, mpu_oh); | 1270 | |
986 | /* XXX what about the other system initiators here? DMA, tesla, d2d */ | 1271 | /* |
987 | _disable_clocks(oh); | 1272 | * If an IP contains only one HW reset line, then assert it |
1273 | * before disabling the clocks and shutting down the IP. | ||
1274 | */ | ||
1275 | if (oh->rst_lines_cnt == 1) | ||
1276 | _assert_hardreset(oh, oh->rst_lines[0].name); | ||
1277 | |||
1278 | /* clocks and deps are already disabled in idle */ | ||
1279 | if (oh->_state == _HWMOD_STATE_ENABLED) { | ||
1280 | _del_initiator_dep(oh, mpu_oh); | ||
1281 | /* XXX what about the other system initiators here? dma, dsp */ | ||
1282 | _disable_clocks(oh); | ||
1283 | } | ||
988 | /* XXX Should this code also force-disable the optional clocks? */ | 1284 | /* XXX Should this code also force-disable the optional clocks? */ |
989 | 1285 | ||
990 | /* XXX mux any associated balls to safe mode */ | 1286 | /* XXX mux any associated balls to safe mode */ |
@@ -1000,11 +1296,10 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1000 | * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 | 1296 | * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 |
1001 | * | 1297 | * |
1002 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 1298 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh |
1003 | * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex held. | 1299 | * OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on |
1004 | * @skip_setup_idle is intended to be used on a system that will not | 1300 | * a system that will not call omap_hwmod_enable() to enable devices |
1005 | * call omap_hwmod_enable() to enable devices (e.g., a system without | 1301 | * (e.g., a system without PM runtime). Returns -EINVAL if the hwmod |
1006 | * PM runtime). Returns -EINVAL if the hwmod is in the wrong state or | 1302 | * is in the wrong state or returns 0. |
1007 | * returns 0. | ||
1008 | */ | 1303 | */ |
1009 | static int _setup(struct omap_hwmod *oh, void *data) | 1304 | static int _setup(struct omap_hwmod *oh, void *data) |
1010 | { | 1305 | { |
@@ -1034,8 +1329,19 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1034 | } | 1329 | } |
1035 | } | 1330 | } |
1036 | 1331 | ||
1332 | mutex_init(&oh->_mutex); | ||
1037 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1333 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1038 | 1334 | ||
1335 | /* | ||
1336 | * In the case of hwmod with hardreset that should not be | ||
1337 | * de-assert at boot time, we have to keep the module | ||
1338 | * initialized, because we cannot enable it properly with the | ||
1339 | * reset asserted. Exit without warning because that behavior is | ||
1340 | * expected. | ||
1341 | */ | ||
1342 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) | ||
1343 | return 0; | ||
1344 | |||
1039 | r = _omap_hwmod_enable(oh); | 1345 | r = _omap_hwmod_enable(oh); |
1040 | if (r) { | 1346 | if (r) { |
1041 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 1347 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", |
@@ -1044,16 +1350,16 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1044 | } | 1350 | } |
1045 | 1351 | ||
1046 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { | 1352 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { |
1353 | _reset(oh); | ||
1354 | |||
1047 | /* | 1355 | /* |
1048 | * XXX Do the OCP_SYSCONFIG bits need to be | 1356 | * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. |
1049 | * reprogrammed after a reset? If not, then this can | 1357 | * The _omap_hwmod_enable() function should be split to |
1050 | * be removed. If they do, then probably the | 1358 | * avoid the rewrite of the OCP_SYSCONFIG register. |
1051 | * _omap_hwmod_enable() function should be split to avoid the | ||
1052 | * rewrite of the OCP_SYSCONFIG register. | ||
1053 | */ | 1359 | */ |
1054 | if (oh->class->sysc) { | 1360 | if (oh->class->sysc) { |
1055 | _update_sysc_cache(oh); | 1361 | _update_sysc_cache(oh); |
1056 | _sysc_enable(oh); | 1362 | _enable_sysc(oh); |
1057 | } | 1363 | } |
1058 | } | 1364 | } |
1059 | 1365 | ||
@@ -1309,7 +1615,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh) | |||
1309 | * omap_hwmod_enable - enable an omap_hwmod | 1615 | * omap_hwmod_enable - enable an omap_hwmod |
1310 | * @oh: struct omap_hwmod * | 1616 | * @oh: struct omap_hwmod * |
1311 | * | 1617 | * |
1312 | * Enable an omap_hwomd @oh. Intended to be called by omap_device_enable(). | 1618 | * Enable an omap_hwmod @oh. Intended to be called by omap_device_enable(). |
1313 | * Returns -EINVAL on error or passes along the return value from _enable(). | 1619 | * Returns -EINVAL on error or passes along the return value from _enable(). |
1314 | */ | 1620 | */ |
1315 | int omap_hwmod_enable(struct omap_hwmod *oh) | 1621 | int omap_hwmod_enable(struct omap_hwmod *oh) |
@@ -1319,9 +1625,9 @@ int omap_hwmod_enable(struct omap_hwmod *oh) | |||
1319 | if (!oh) | 1625 | if (!oh) |
1320 | return -EINVAL; | 1626 | return -EINVAL; |
1321 | 1627 | ||
1322 | mutex_lock(&omap_hwmod_mutex); | 1628 | mutex_lock(&oh->_mutex); |
1323 | r = _omap_hwmod_enable(oh); | 1629 | r = _omap_hwmod_enable(oh); |
1324 | mutex_unlock(&omap_hwmod_mutex); | 1630 | mutex_unlock(&oh->_mutex); |
1325 | 1631 | ||
1326 | return r; | 1632 | return r; |
1327 | } | 1633 | } |
@@ -1331,7 +1637,7 @@ int omap_hwmod_enable(struct omap_hwmod *oh) | |||
1331 | * omap_hwmod_idle - idle an omap_hwmod | 1637 | * omap_hwmod_idle - idle an omap_hwmod |
1332 | * @oh: struct omap_hwmod * | 1638 | * @oh: struct omap_hwmod * |
1333 | * | 1639 | * |
1334 | * Idle an omap_hwomd @oh. Intended to be called by omap_device_idle(). | 1640 | * Idle an omap_hwmod @oh. Intended to be called by omap_device_idle(). |
1335 | * Returns -EINVAL on error or passes along the return value from _idle(). | 1641 | * Returns -EINVAL on error or passes along the return value from _idle(). |
1336 | */ | 1642 | */ |
1337 | int omap_hwmod_idle(struct omap_hwmod *oh) | 1643 | int omap_hwmod_idle(struct omap_hwmod *oh) |
@@ -1339,9 +1645,9 @@ int omap_hwmod_idle(struct omap_hwmod *oh) | |||
1339 | if (!oh) | 1645 | if (!oh) |
1340 | return -EINVAL; | 1646 | return -EINVAL; |
1341 | 1647 | ||
1342 | mutex_lock(&omap_hwmod_mutex); | 1648 | mutex_lock(&oh->_mutex); |
1343 | _omap_hwmod_idle(oh); | 1649 | _omap_hwmod_idle(oh); |
1344 | mutex_unlock(&omap_hwmod_mutex); | 1650 | mutex_unlock(&oh->_mutex); |
1345 | 1651 | ||
1346 | return 0; | 1652 | return 0; |
1347 | } | 1653 | } |
@@ -1350,7 +1656,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh) | |||
1350 | * omap_hwmod_shutdown - shutdown an omap_hwmod | 1656 | * omap_hwmod_shutdown - shutdown an omap_hwmod |
1351 | * @oh: struct omap_hwmod * | 1657 | * @oh: struct omap_hwmod * |
1352 | * | 1658 | * |
1353 | * Shutdown an omap_hwomd @oh. Intended to be called by | 1659 | * Shutdown an omap_hwmod @oh. Intended to be called by |
1354 | * omap_device_shutdown(). Returns -EINVAL on error or passes along | 1660 | * omap_device_shutdown(). Returns -EINVAL on error or passes along |
1355 | * the return value from _shutdown(). | 1661 | * the return value from _shutdown(). |
1356 | */ | 1662 | */ |
@@ -1359,9 +1665,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) | |||
1359 | if (!oh) | 1665 | if (!oh) |
1360 | return -EINVAL; | 1666 | return -EINVAL; |
1361 | 1667 | ||
1362 | mutex_lock(&omap_hwmod_mutex); | 1668 | mutex_lock(&oh->_mutex); |
1363 | _shutdown(oh); | 1669 | _shutdown(oh); |
1364 | mutex_unlock(&omap_hwmod_mutex); | 1670 | mutex_unlock(&oh->_mutex); |
1365 | 1671 | ||
1366 | return 0; | 1672 | return 0; |
1367 | } | 1673 | } |
@@ -1374,9 +1680,9 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) | |||
1374 | */ | 1680 | */ |
1375 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | 1681 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) |
1376 | { | 1682 | { |
1377 | mutex_lock(&omap_hwmod_mutex); | 1683 | mutex_lock(&oh->_mutex); |
1378 | _enable_clocks(oh); | 1684 | _enable_clocks(oh); |
1379 | mutex_unlock(&omap_hwmod_mutex); | 1685 | mutex_unlock(&oh->_mutex); |
1380 | 1686 | ||
1381 | return 0; | 1687 | return 0; |
1382 | } | 1688 | } |
@@ -1389,9 +1695,9 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | |||
1389 | */ | 1695 | */ |
1390 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) | 1696 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) |
1391 | { | 1697 | { |
1392 | mutex_lock(&omap_hwmod_mutex); | 1698 | mutex_lock(&oh->_mutex); |
1393 | _disable_clocks(oh); | 1699 | _disable_clocks(oh); |
1394 | mutex_unlock(&omap_hwmod_mutex); | 1700 | mutex_unlock(&oh->_mutex); |
1395 | 1701 | ||
1396 | return 0; | 1702 | return 0; |
1397 | } | 1703 | } |
@@ -1430,20 +1736,18 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) | |||
1430 | * | 1736 | * |
1431 | * Under some conditions, a driver may wish to reset the entire device. | 1737 | * Under some conditions, a driver may wish to reset the entire device. |
1432 | * Called from omap_device code. Returns -EINVAL on error or passes along | 1738 | * Called from omap_device code. Returns -EINVAL on error or passes along |
1433 | * the return value from _reset()/_enable(). | 1739 | * the return value from _reset(). |
1434 | */ | 1740 | */ |
1435 | int omap_hwmod_reset(struct omap_hwmod *oh) | 1741 | int omap_hwmod_reset(struct omap_hwmod *oh) |
1436 | { | 1742 | { |
1437 | int r; | 1743 | int r; |
1438 | 1744 | ||
1439 | if (!oh || !(oh->_state & _HWMOD_STATE_ENABLED)) | 1745 | if (!oh) |
1440 | return -EINVAL; | 1746 | return -EINVAL; |
1441 | 1747 | ||
1442 | mutex_lock(&omap_hwmod_mutex); | 1748 | mutex_lock(&oh->_mutex); |
1443 | r = _reset(oh); | 1749 | r = _reset(oh); |
1444 | if (!r) | 1750 | mutex_unlock(&oh->_mutex); |
1445 | r = _omap_hwmod_enable(oh); | ||
1446 | mutex_unlock(&omap_hwmod_mutex); | ||
1447 | 1751 | ||
1448 | return r; | 1752 | return r; |
1449 | } | 1753 | } |
@@ -1468,7 +1772,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
1468 | { | 1772 | { |
1469 | int ret, i; | 1773 | int ret, i; |
1470 | 1774 | ||
1471 | ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; | 1775 | ret = oh->mpu_irqs_cnt + oh->sdma_reqs_cnt; |
1472 | 1776 | ||
1473 | for (i = 0; i < oh->slaves_cnt; i++) | 1777 | for (i = 0; i < oh->slaves_cnt; i++) |
1474 | ret += oh->slaves[i]->addr_cnt; | 1778 | ret += oh->slaves[i]->addr_cnt; |
@@ -1501,10 +1805,10 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1501 | r++; | 1805 | r++; |
1502 | } | 1806 | } |
1503 | 1807 | ||
1504 | for (i = 0; i < oh->sdma_chs_cnt; i++) { | 1808 | for (i = 0; i < oh->sdma_reqs_cnt; i++) { |
1505 | (res + r)->name = (oh->sdma_chs + i)->name; | 1809 | (res + r)->name = (oh->sdma_reqs + i)->name; |
1506 | (res + r)->start = (oh->sdma_chs + i)->dma_ch; | 1810 | (res + r)->start = (oh->sdma_reqs + i)->dma_req; |
1507 | (res + r)->end = (oh->sdma_chs + i)->dma_ch; | 1811 | (res + r)->end = (oh->sdma_reqs + i)->dma_req; |
1508 | (res + r)->flags = IORESOURCE_DMA; | 1812 | (res + r)->flags = IORESOURCE_DMA; |
1509 | r++; | 1813 | r++; |
1510 | } | 1814 | } |
@@ -1644,9 +1948,9 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | |||
1644 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 1948 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
1645 | return -EINVAL; | 1949 | return -EINVAL; |
1646 | 1950 | ||
1647 | mutex_lock(&omap_hwmod_mutex); | 1951 | mutex_lock(&oh->_mutex); |
1648 | _enable_wakeup(oh); | 1952 | _enable_wakeup(oh); |
1649 | mutex_unlock(&omap_hwmod_mutex); | 1953 | mutex_unlock(&oh->_mutex); |
1650 | 1954 | ||
1651 | return 0; | 1955 | return 0; |
1652 | } | 1956 | } |
@@ -1669,14 +1973,92 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | |||
1669 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 1973 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
1670 | return -EINVAL; | 1974 | return -EINVAL; |
1671 | 1975 | ||
1672 | mutex_lock(&omap_hwmod_mutex); | 1976 | mutex_lock(&oh->_mutex); |
1673 | _disable_wakeup(oh); | 1977 | _disable_wakeup(oh); |
1674 | mutex_unlock(&omap_hwmod_mutex); | 1978 | mutex_unlock(&oh->_mutex); |
1675 | 1979 | ||
1676 | return 0; | 1980 | return 0; |
1677 | } | 1981 | } |
1678 | 1982 | ||
1679 | /** | 1983 | /** |
1984 | * omap_hwmod_assert_hardreset - assert the HW reset line of submodules | ||
1985 | * contained in the hwmod module. | ||
1986 | * @oh: struct omap_hwmod * | ||
1987 | * @name: name of the reset line to lookup and assert | ||
1988 | * | ||
1989 | * Some IP like dsp, ipu or iva contain processor that require | ||
1990 | * an HW reset line to be assert / deassert in order to enable fully | ||
1991 | * the IP. Returns -EINVAL if @oh is null or if the operation is not | ||
1992 | * yet supported on this OMAP; otherwise, passes along the return value | ||
1993 | * from _assert_hardreset(). | ||
1994 | */ | ||
1995 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) | ||
1996 | { | ||
1997 | int ret; | ||
1998 | |||
1999 | if (!oh) | ||
2000 | return -EINVAL; | ||
2001 | |||
2002 | mutex_lock(&oh->_mutex); | ||
2003 | ret = _assert_hardreset(oh, name); | ||
2004 | mutex_unlock(&oh->_mutex); | ||
2005 | |||
2006 | return ret; | ||
2007 | } | ||
2008 | |||
2009 | /** | ||
2010 | * omap_hwmod_deassert_hardreset - deassert the HW reset line of submodules | ||
2011 | * contained in the hwmod module. | ||
2012 | * @oh: struct omap_hwmod * | ||
2013 | * @name: name of the reset line to look up and deassert | ||
2014 | * | ||
2015 | * Some IP like dsp, ipu or iva contain processor that require | ||
2016 | * an HW reset line to be assert / deassert in order to enable fully | ||
2017 | * the IP. Returns -EINVAL if @oh is null or if the operation is not | ||
2018 | * yet supported on this OMAP; otherwise, passes along the return value | ||
2019 | * from _deassert_hardreset(). | ||
2020 | */ | ||
2021 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) | ||
2022 | { | ||
2023 | int ret; | ||
2024 | |||
2025 | if (!oh) | ||
2026 | return -EINVAL; | ||
2027 | |||
2028 | mutex_lock(&oh->_mutex); | ||
2029 | ret = _deassert_hardreset(oh, name); | ||
2030 | mutex_unlock(&oh->_mutex); | ||
2031 | |||
2032 | return ret; | ||
2033 | } | ||
2034 | |||
2035 | /** | ||
2036 | * omap_hwmod_read_hardreset - read the HW reset line state of submodules | ||
2037 | * contained in the hwmod module | ||
2038 | * @oh: struct omap_hwmod * | ||
2039 | * @name: name of the reset line to look up and read | ||
2040 | * | ||
2041 | * Return the current state of the hwmod @oh's reset line named @name: | ||
2042 | * returns -EINVAL upon parameter error or if this operation | ||
2043 | * is unsupported on the current OMAP; otherwise, passes along the return | ||
2044 | * value from _read_hardreset(). | ||
2045 | */ | ||
2046 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) | ||
2047 | { | ||
2048 | int ret; | ||
2049 | |||
2050 | if (!oh) | ||
2051 | return -EINVAL; | ||
2052 | |||
2053 | mutex_lock(&oh->_mutex); | ||
2054 | ret = _read_hardreset(oh, name); | ||
2055 | mutex_unlock(&oh->_mutex); | ||
2056 | |||
2057 | return ret; | ||
2058 | } | ||
2059 | |||
2060 | |||
2061 | /** | ||
1680 | * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname | 2062 | * omap_hwmod_for_each_by_class - call @fn for each hwmod of class @classname |
1681 | * @classname: struct omap_hwmod_class name to search for | 2063 | * @classname: struct omap_hwmod_class name to search for |
1682 | * @fn: callback function pointer to call for each hwmod in class @classname | 2064 | * @fn: callback function pointer to call for each hwmod in class @classname |
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c index c20137497c92..d4388d34c26a 100644 --- a/arch/arm/mach-omap2/prcm.c +++ b/arch/arm/mach-omap2/prcm.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "cm.h" | 33 | #include "cm.h" |
34 | #include "prm.h" | 34 | #include "prm.h" |
35 | #include "prm-regbits-24xx.h" | 35 | #include "prm-regbits-24xx.h" |
36 | #include "prm-regbits-44xx.h" | ||
36 | 37 | ||
37 | static void __iomem *prm_base; | 38 | static void __iomem *prm_base; |
38 | static void __iomem *cm_base; | 39 | static void __iomem *cm_base; |
@@ -161,8 +162,8 @@ void omap_prcm_arch_reset(char mode, const char *cmd) | |||
161 | prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs, | 162 | prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs, |
162 | OMAP2_RM_RSTCTRL); | 163 | OMAP2_RM_RSTCTRL); |
163 | if (cpu_is_omap44xx()) | 164 | if (cpu_is_omap44xx()) |
164 | prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, prcm_offs, | 165 | prm_set_mod_reg_bits(OMAP4430_RST_GLOBAL_WARM_SW_MASK, |
165 | OMAP4_RM_RSTCTRL); | 166 | prcm_offs, OMAP4_RM_RSTCTRL); |
166 | } | 167 | } |
167 | 168 | ||
168 | static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg) | 169 | static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg) |
@@ -215,6 +216,30 @@ u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask) | |||
215 | return v; | 216 | return v; |
216 | } | 217 | } |
217 | 218 | ||
219 | /* Read a PRM register, AND it, and shift the result down to bit 0 */ | ||
220 | u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask) | ||
221 | { | ||
222 | u32 v; | ||
223 | |||
224 | v = __raw_readl(reg); | ||
225 | v &= mask; | ||
226 | v >>= __ffs(mask); | ||
227 | |||
228 | return v; | ||
229 | } | ||
230 | |||
231 | /* Read-modify-write a register in a PRM module. Caller must lock */ | ||
232 | u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg) | ||
233 | { | ||
234 | u32 v; | ||
235 | |||
236 | v = __raw_readl(reg); | ||
237 | v &= ~mask; | ||
238 | v |= bits; | ||
239 | __raw_writel(v, reg); | ||
240 | |||
241 | return v; | ||
242 | } | ||
218 | /* Read a register in a CM module */ | 243 | /* Read a register in a CM module */ |
219 | u32 cm_read_mod_reg(s16 module, u16 idx) | 244 | u32 cm_read_mod_reg(s16 module, u16 idx) |
220 | { | 245 | { |
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h index 588873b9303a..7be040b2fdab 100644 --- a/arch/arm/mach-omap2/prm.h +++ b/arch/arm/mach-omap2/prm.h | |||
@@ -5,7 +5,7 @@ | |||
5 | * OMAP2/3 Power/Reset Management (PRM) register definitions | 5 | * OMAP2/3 Power/Reset Management (PRM) register definitions |
6 | * | 6 | * |
7 | * Copyright (C) 2007-2009 Texas Instruments, Inc. | 7 | * Copyright (C) 2007-2009 Texas Instruments, Inc. |
8 | * Copyright (C) 2009 Nokia Corporation | 8 | * Copyright (C) 2010 Nokia Corporation |
9 | * | 9 | * |
10 | * Written by Paul Walmsley | 10 | * Written by Paul Walmsley |
11 | * | 11 | * |
@@ -246,6 +246,15 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) | |||
246 | return prm_rmw_mod_reg_bits(bits, 0x0, module, idx); | 246 | return prm_rmw_mod_reg_bits(bits, 0x0, module, idx); |
247 | } | 247 | } |
248 | 248 | ||
249 | /* These omap2_ PRM functions apply to both OMAP2 and 3 */ | ||
250 | int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); | ||
251 | int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); | ||
252 | int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift); | ||
253 | |||
254 | int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift); | ||
255 | int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift); | ||
256 | int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift); | ||
257 | |||
249 | #endif | 258 | #endif |
250 | 259 | ||
251 | /* | 260 | /* |
@@ -398,4 +407,11 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx) | |||
398 | #define OMAP_POWERSTATE_MASK (0x3 << 0) | 407 | #define OMAP_POWERSTATE_MASK (0x3 << 0) |
399 | 408 | ||
400 | 409 | ||
410 | /* | ||
411 | * MAX_MODULE_HARDRESET_WAIT: Maximum microseconds to wait for an OMAP | ||
412 | * submodule to exit hardreset | ||
413 | */ | ||
414 | #define MAX_MODULE_HARDRESET_WAIT 10000 | ||
415 | |||
416 | |||
401 | #endif | 417 | #endif |
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c new file mode 100644 index 000000000000..421771eee450 --- /dev/null +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * OMAP2/3 PRM module functions | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2010 Nokia Corporation | ||
6 | * Benoît Cousson | ||
7 | * Paul Walmsley | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <plat/common.h> | ||
20 | #include <plat/cpu.h> | ||
21 | #include <plat/prcm.h> | ||
22 | |||
23 | #include "prm.h" | ||
24 | #include "prm-regbits-24xx.h" | ||
25 | #include "prm-regbits-34xx.h" | ||
26 | |||
27 | /** | ||
28 | * omap2_prm_is_hardreset_asserted - read the HW reset line state of | ||
29 | * submodules contained in the hwmod module | ||
30 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | ||
31 | * @shift: register bit shift corresponding to the reset line to check | ||
32 | * | ||
33 | * Returns 1 if the (sub)module hardreset line is currently asserted, | ||
34 | * 0 if the (sub)module hardreset line is not currently asserted, or | ||
35 | * -EINVAL if called while running on a non-OMAP2/3 chip. | ||
36 | */ | ||
37 | int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift) | ||
38 | { | ||
39 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | ||
40 | return -EINVAL; | ||
41 | |||
42 | return prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, | ||
43 | (1 << shift)); | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * omap2_prm_assert_hardreset - assert the HW reset line of a submodule | ||
48 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | ||
49 | * @shift: register bit shift corresponding to the reset line to assert | ||
50 | * | ||
51 | * Some IPs like dsp or iva contain processors that require an HW | ||
52 | * reset line to be asserted / deasserted in order to fully enable the | ||
53 | * IP. These modules may have multiple hard-reset lines that reset | ||
54 | * different 'submodules' inside the IP block. This function will | ||
55 | * place the submodule into reset. Returns 0 upon success or -EINVAL | ||
56 | * upon an argument error. | ||
57 | */ | ||
58 | int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift) | ||
59 | { | ||
60 | u32 mask; | ||
61 | |||
62 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | ||
63 | return -EINVAL; | ||
64 | |||
65 | mask = 1 << shift; | ||
66 | prm_rmw_mod_reg_bits(mask, mask, prm_mod, OMAP2_RM_RSTCTRL); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * omap2_prm_deassert_hardreset - deassert a submodule hardreset line and wait | ||
73 | * @prm_mod: PRM submodule base (e.g. CORE_MOD) | ||
74 | * @shift: register bit shift corresponding to the reset line to deassert | ||
75 | * | ||
76 | * Some IPs like dsp or iva contain processors that require an HW | ||
77 | * reset line to be asserted / deasserted in order to fully enable the | ||
78 | * IP. These modules may have multiple hard-reset lines that reset | ||
79 | * different 'submodules' inside the IP block. This function will | ||
80 | * take the submodule out of reset and wait until the PRCM indicates | ||
81 | * that the reset has completed before returning. Returns 0 upon success or | ||
82 | * -EINVAL upon an argument error, -EEXIST if the submodule was already out | ||
83 | * of reset, or -EBUSY if the submodule did not exit reset promptly. | ||
84 | */ | ||
85 | int omap2_prm_deassert_hardreset(s16 prm_mod, u8 shift) | ||
86 | { | ||
87 | u32 mask; | ||
88 | int c; | ||
89 | |||
90 | if (!(cpu_is_omap24xx() || cpu_is_omap34xx())) | ||
91 | return -EINVAL; | ||
92 | |||
93 | mask = 1 << shift; | ||
94 | |||
95 | /* Check the current status to avoid de-asserting the line twice */ | ||
96 | if (prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL, mask) == 0) | ||
97 | return -EEXIST; | ||
98 | |||
99 | /* Clear the reset status by writing 1 to the status bit */ | ||
100 | prm_rmw_mod_reg_bits(0xffffffff, mask, prm_mod, OMAP2_RM_RSTST); | ||
101 | /* de-assert the reset control line */ | ||
102 | prm_rmw_mod_reg_bits(mask, 0, prm_mod, OMAP2_RM_RSTCTRL); | ||
103 | /* wait the status to be set */ | ||
104 | omap_test_timeout(prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTST, | ||
105 | mask), | ||
106 | MAX_MODULE_HARDRESET_WAIT, c); | ||
107 | |||
108 | return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; | ||
109 | } | ||
110 | |||
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c new file mode 100644 index 000000000000..a1ff918d9bed --- /dev/null +++ b/arch/arm/mach-omap2/prm44xx.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * OMAP4 PRM module functions | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2010 Nokia Corporation | ||
6 | * Benoît Cousson | ||
7 | * Paul Walmsley | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/err.h> | ||
18 | |||
19 | #include <plat/common.h> | ||
20 | #include <plat/cpu.h> | ||
21 | #include <plat/prcm.h> | ||
22 | |||
23 | #include "prm.h" | ||
24 | #include "prm-regbits-44xx.h" | ||
25 | |||
26 | /* | ||
27 | * Address offset (in bytes) between the reset control and the reset | ||
28 | * status registers: 4 bytes on OMAP4 | ||
29 | */ | ||
30 | #define OMAP4_RST_CTRL_ST_OFFSET 4 | ||
31 | |||
32 | /** | ||
33 | * omap4_prm_is_hardreset_asserted - read the HW reset line state of | ||
34 | * submodules contained in the hwmod module | ||
35 | * @rstctrl_reg: RM_RSTCTRL register address for this module | ||
36 | * @shift: register bit shift corresponding to the reset line to check | ||
37 | * | ||
38 | * Returns 1 if the (sub)module hardreset line is currently asserted, | ||
39 | * 0 if the (sub)module hardreset line is not currently asserted, or | ||
40 | * -EINVAL upon parameter error. | ||
41 | */ | ||
42 | int omap4_prm_is_hardreset_asserted(void __iomem *rstctrl_reg, u8 shift) | ||
43 | { | ||
44 | if (!cpu_is_omap44xx() || !rstctrl_reg) | ||
45 | return -EINVAL; | ||
46 | |||
47 | return omap4_prm_read_bits_shift(rstctrl_reg, (1 << shift)); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * omap4_prm_assert_hardreset - assert the HW reset line of a submodule | ||
52 | * @rstctrl_reg: RM_RSTCTRL register address for this module | ||
53 | * @shift: register bit shift corresponding to the reset line to assert | ||
54 | * | ||
55 | * Some IPs like dsp, ipu or iva contain processors that require an HW | ||
56 | * reset line to be asserted / deasserted in order to fully enable the | ||
57 | * IP. These modules may have multiple hard-reset lines that reset | ||
58 | * different 'submodules' inside the IP block. This function will | ||
59 | * place the submodule into reset. Returns 0 upon success or -EINVAL | ||
60 | * upon an argument error. | ||
61 | */ | ||
62 | int omap4_prm_assert_hardreset(void __iomem *rstctrl_reg, u8 shift) | ||
63 | { | ||
64 | u32 mask; | ||
65 | |||
66 | if (!cpu_is_omap44xx() || !rstctrl_reg) | ||
67 | return -EINVAL; | ||
68 | |||
69 | mask = 1 << shift; | ||
70 | omap4_prm_rmw_reg_bits(mask, mask, rstctrl_reg); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * omap4_prm_deassert_hardreset - deassert a submodule hardreset line and wait | ||
77 | * @rstctrl_reg: RM_RSTCTRL register address for this module | ||
78 | * @shift: register bit shift corresponding to the reset line to deassert | ||
79 | * | ||
80 | * Some IPs like dsp, ipu or iva contain processors that require an HW | ||
81 | * reset line to be asserted / deasserted in order to fully enable the | ||
82 | * IP. These modules may have multiple hard-reset lines that reset | ||
83 | * different 'submodules' inside the IP block. This function will | ||
84 | * take the submodule out of reset and wait until the PRCM indicates | ||
85 | * that the reset has completed before returning. Returns 0 upon success or | ||
86 | * -EINVAL upon an argument error, -EEXIST if the submodule was already out | ||
87 | * of reset, or -EBUSY if the submodule did not exit reset promptly. | ||
88 | */ | ||
89 | int omap4_prm_deassert_hardreset(void __iomem *rstctrl_reg, u8 shift) | ||
90 | { | ||
91 | u32 mask; | ||
92 | void __iomem *rstst_reg; | ||
93 | int c; | ||
94 | |||
95 | if (!cpu_is_omap44xx() || !rstctrl_reg) | ||
96 | return -EINVAL; | ||
97 | |||
98 | rstst_reg = rstctrl_reg + OMAP4_RST_CTRL_ST_OFFSET; | ||
99 | |||
100 | mask = 1 << shift; | ||
101 | |||
102 | /* Check the current status to avoid de-asserting the line twice */ | ||
103 | if (omap4_prm_read_bits_shift(rstctrl_reg, mask) == 0) | ||
104 | return -EEXIST; | ||
105 | |||
106 | /* Clear the reset status by writing 1 to the status bit */ | ||
107 | omap4_prm_rmw_reg_bits(0xffffffff, mask, rstst_reg); | ||
108 | /* de-assert the reset control line */ | ||
109 | omap4_prm_rmw_reg_bits(mask, 0, rstctrl_reg); | ||
110 | /* wait the status to be set */ | ||
111 | omap_test_timeout(omap4_prm_read_bits_shift(rstst_reg, mask), | ||
112 | MAX_MODULE_HARDRESET_WAIT, c); | ||
113 | |||
114 | return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0; | ||
115 | } | ||
116 | |||
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index a4e508dfaba2..72902814c3ca 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h | |||
@@ -14,19 +14,16 @@ | |||
14 | * | 14 | * |
15 | * These headers and macros are used to define OMAP on-chip module | 15 | * These headers and macros are used to define OMAP on-chip module |
16 | * data and their integration with other OMAP modules and Linux. | 16 | * data and their integration with other OMAP modules and Linux. |
17 | * | 17 | * Copious documentation and references can also be found in the |
18 | * References: | 18 | * omap_hwmod code, in arch/arm/mach-omap2/omap_hwmod.c (as of this |
19 | * - OMAP2420 Multimedia Processor Silicon Revision 2.1.1, 2.2 (SWPU064) | 19 | * writing). |
20 | * - OMAP2430 Multimedia Device POP Silicon Revision 2.1 (SWPU090) | ||
21 | * - OMAP34xx Multimedia Device Silicon Revision 3.1 (SWPU108) | ||
22 | * - OMAP4430 Multimedia Device Silicon Revision 1.0 (SWPU140) | ||
23 | * - Open Core Protocol Specification 2.2 | ||
24 | * | 20 | * |
25 | * To do: | 21 | * To do: |
26 | * - add interconnect error log structures | 22 | * - add interconnect error log structures |
27 | * - add pinmuxing | 23 | * - add pinmuxing |
28 | * - init_conn_id_bit (CONNID_BIT_VECTOR) | 24 | * - init_conn_id_bit (CONNID_BIT_VECTOR) |
29 | * - implement default hwmod SMS/SDRC flags? | 25 | * - implement default hwmod SMS/SDRC flags? |
26 | * - remove unused fields | ||
30 | * | 27 | * |
31 | */ | 28 | */ |
32 | #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H | 29 | #ifndef __ARCH_ARM_PLAT_OMAP_INCLUDE_MACH_OMAP_HWMOD_H |
@@ -35,6 +32,7 @@ | |||
35 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
36 | #include <linux/list.h> | 33 | #include <linux/list.h> |
37 | #include <linux/ioport.h> | 34 | #include <linux/ioport.h> |
35 | #include <linux/mutex.h> | ||
38 | #include <plat/cpu.h> | 36 | #include <plat/cpu.h> |
39 | 37 | ||
40 | struct omap_device; | 38 | struct omap_device; |
@@ -96,7 +94,7 @@ struct omap_hwmod_irq_info { | |||
96 | /** | 94 | /** |
97 | * struct omap_hwmod_dma_info - DMA channels used by the hwmod | 95 | * struct omap_hwmod_dma_info - DMA channels used by the hwmod |
98 | * @name: name of the DMA channel (module local name) | 96 | * @name: name of the DMA channel (module local name) |
99 | * @dma_ch: DMA channel ID | 97 | * @dma_req: DMA request ID |
100 | * | 98 | * |
101 | * @name should be something short, e.g., "tx" or "rx". It is for use | 99 | * @name should be something short, e.g., "tx" or "rx". It is for use |
102 | * by platform_get_resource_byname(). It is defined locally to the | 100 | * by platform_get_resource_byname(). It is defined locally to the |
@@ -104,7 +102,20 @@ struct omap_hwmod_irq_info { | |||
104 | */ | 102 | */ |
105 | struct omap_hwmod_dma_info { | 103 | struct omap_hwmod_dma_info { |
106 | const char *name; | 104 | const char *name; |
107 | u16 dma_ch; | 105 | u16 dma_req; |
106 | }; | ||
107 | |||
108 | /** | ||
109 | * struct omap_hwmod_rst_info - IPs reset lines use by hwmod | ||
110 | * @name: name of the reset line (module local name) | ||
111 | * @rst_shift: Offset of the reset bit | ||
112 | * | ||
113 | * @name should be something short, e.g., "cpu0" or "rst". It is defined | ||
114 | * locally to the hwmod. | ||
115 | */ | ||
116 | struct omap_hwmod_rst_info { | ||
117 | const char *name; | ||
118 | u8 rst_shift; | ||
108 | }; | 119 | }; |
109 | 120 | ||
110 | /** | 121 | /** |
@@ -237,8 +248,9 @@ struct omap_hwmod_ocp_if { | |||
237 | #define SYSC_HAS_CLOCKACTIVITY (1 << 4) | 248 | #define SYSC_HAS_CLOCKACTIVITY (1 << 4) |
238 | #define SYSC_HAS_SIDLEMODE (1 << 5) | 249 | #define SYSC_HAS_SIDLEMODE (1 << 5) |
239 | #define SYSC_HAS_MIDLEMODE (1 << 6) | 250 | #define SYSC_HAS_MIDLEMODE (1 << 6) |
240 | #define SYSS_MISSING (1 << 7) | 251 | #define SYSS_HAS_RESET_STATUS (1 << 7) |
241 | #define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */ | 252 | #define SYSC_NO_CACHE (1 << 8) /* XXX SW flag, belongs elsewhere */ |
253 | #define SYSC_HAS_RESET_STATUS (1 << 9) | ||
242 | 254 | ||
243 | /* omap_hwmod_sysconfig.clockact flags */ | 255 | /* omap_hwmod_sysconfig.clockact flags */ |
244 | #define CLOCKACT_TEST_BOTH 0x0 | 256 | #define CLOCKACT_TEST_BOTH 0x0 |
@@ -327,10 +339,12 @@ struct omap_hwmod_omap2_prcm { | |||
327 | /** | 339 | /** |
328 | * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data | 340 | * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data |
329 | * @clkctrl_reg: PRCM address of the clock control register | 341 | * @clkctrl_reg: PRCM address of the clock control register |
342 | * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM | ||
330 | * @submodule_wkdep_bit: bit shift of the WKDEP range | 343 | * @submodule_wkdep_bit: bit shift of the WKDEP range |
331 | */ | 344 | */ |
332 | struct omap_hwmod_omap4_prcm { | 345 | struct omap_hwmod_omap4_prcm { |
333 | void __iomem *clkctrl_reg; | 346 | void __iomem *clkctrl_reg; |
347 | void __iomem *rstctrl_reg; | ||
334 | u8 submodule_wkdep_bit; | 348 | u8 submodule_wkdep_bit; |
335 | }; | 349 | }; |
336 | 350 | ||
@@ -352,6 +366,10 @@ struct omap_hwmod_omap4_prcm { | |||
352 | * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup | 366 | * HWMOD_SET_DEFAULT_CLOCKACT: program CLOCKACTIVITY bits at startup |
353 | * HWMOD_NO_IDLEST : this module does not have idle status - this is the case | 367 | * HWMOD_NO_IDLEST : this module does not have idle status - this is the case |
354 | * only for few initiator modules on OMAP2 & 3. | 368 | * only for few initiator modules on OMAP2 & 3. |
369 | * HWMOD_CONTROL_OPT_CLKS_IN_RESET: Enable all optional clocks during reset. | ||
370 | * This is needed for devices like DSS that require optional clocks enabled | ||
371 | * in order to complete the reset. Optional clocks will be disabled | ||
372 | * again after the reset. | ||
355 | */ | 373 | */ |
356 | #define HWMOD_SWSUP_SIDLE (1 << 0) | 374 | #define HWMOD_SWSUP_SIDLE (1 << 0) |
357 | #define HWMOD_SWSUP_MSTANDBY (1 << 1) | 375 | #define HWMOD_SWSUP_MSTANDBY (1 << 1) |
@@ -360,6 +378,7 @@ struct omap_hwmod_omap4_prcm { | |||
360 | #define HWMOD_NO_OCP_AUTOIDLE (1 << 4) | 378 | #define HWMOD_NO_OCP_AUTOIDLE (1 << 4) |
361 | #define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5) | 379 | #define HWMOD_SET_DEFAULT_CLOCKACT (1 << 5) |
362 | #define HWMOD_NO_IDLEST (1 << 6) | 380 | #define HWMOD_NO_IDLEST (1 << 6) |
381 | #define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7) | ||
363 | 382 | ||
364 | /* | 383 | /* |
365 | * omap_hwmod._int_flags definitions | 384 | * omap_hwmod._int_flags definitions |
@@ -410,7 +429,7 @@ struct omap_hwmod_class { | |||
410 | * @class: struct omap_hwmod_class * to the class of this hwmod | 429 | * @class: struct omap_hwmod_class * to the class of this hwmod |
411 | * @od: struct omap_device currently associated with this hwmod (internal use) | 430 | * @od: struct omap_device currently associated with this hwmod (internal use) |
412 | * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt) | 431 | * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt) |
413 | * @sdma_chs: ptr to an array of SDMA channel IDs (see also sdma_chs_cnt) | 432 | * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt) |
414 | * @prcm: PRCM data pertaining to this hwmod | 433 | * @prcm: PRCM data pertaining to this hwmod |
415 | * @main_clk: main clock: OMAP clock name | 434 | * @main_clk: main clock: OMAP clock name |
416 | * @_clk: pointer to the main struct clk (filled in at runtime) | 435 | * @_clk: pointer to the main struct clk (filled in at runtime) |
@@ -424,7 +443,7 @@ struct omap_hwmod_class { | |||
424 | * @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6) | 443 | * @msuspendmux_reg_id: CONTROL_MSUSPENDMUX register ID (1-6) |
425 | * @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift | 444 | * @msuspendmux_shift: CONTROL_MSUSPENDMUX register bit shift |
426 | * @mpu_irqs_cnt: number of @mpu_irqs | 445 | * @mpu_irqs_cnt: number of @mpu_irqs |
427 | * @sdma_chs_cnt: number of @sdma_chs | 446 | * @sdma_reqs_cnt: number of @sdma_reqs |
428 | * @opt_clks_cnt: number of @opt_clks | 447 | * @opt_clks_cnt: number of @opt_clks |
429 | * @master_cnt: number of @master entries | 448 | * @master_cnt: number of @master entries |
430 | * @slaves_cnt: number of @slave entries | 449 | * @slaves_cnt: number of @slave entries |
@@ -433,6 +452,7 @@ struct omap_hwmod_class { | |||
433 | * @_state: internal-use hwmod state | 452 | * @_state: internal-use hwmod state |
434 | * @flags: hwmod flags (documented below) | 453 | * @flags: hwmod flags (documented below) |
435 | * @omap_chip: OMAP chips this hwmod is present on | 454 | * @omap_chip: OMAP chips this hwmod is present on |
455 | * @_mutex: mutex serializing operations on this hwmod | ||
436 | * @node: list node for hwmod list (internal use) | 456 | * @node: list node for hwmod list (internal use) |
437 | * | 457 | * |
438 | * @main_clk refers to this module's "main clock," which for our | 458 | * @main_clk refers to this module's "main clock," which for our |
@@ -448,7 +468,8 @@ struct omap_hwmod { | |||
448 | struct omap_hwmod_class *class; | 468 | struct omap_hwmod_class *class; |
449 | struct omap_device *od; | 469 | struct omap_device *od; |
450 | struct omap_hwmod_irq_info *mpu_irqs; | 470 | struct omap_hwmod_irq_info *mpu_irqs; |
451 | struct omap_hwmod_dma_info *sdma_chs; | 471 | struct omap_hwmod_dma_info *sdma_reqs; |
472 | struct omap_hwmod_rst_info *rst_lines; | ||
452 | union { | 473 | union { |
453 | struct omap_hwmod_omap2_prcm omap2; | 474 | struct omap_hwmod_omap2_prcm omap2; |
454 | struct omap_hwmod_omap4_prcm omap4; | 475 | struct omap_hwmod_omap4_prcm omap4; |
@@ -461,6 +482,7 @@ struct omap_hwmod { | |||
461 | void *dev_attr; | 482 | void *dev_attr; |
462 | u32 _sysc_cache; | 483 | u32 _sysc_cache; |
463 | void __iomem *_mpu_rt_va; | 484 | void __iomem *_mpu_rt_va; |
485 | struct mutex _mutex; | ||
464 | struct list_head node; | 486 | struct list_head node; |
465 | u16 flags; | 487 | u16 flags; |
466 | u8 _mpu_port_index; | 488 | u8 _mpu_port_index; |
@@ -468,7 +490,8 @@ struct omap_hwmod { | |||
468 | u8 msuspendmux_shift; | 490 | u8 msuspendmux_shift; |
469 | u8 response_lat; | 491 | u8 response_lat; |
470 | u8 mpu_irqs_cnt; | 492 | u8 mpu_irqs_cnt; |
471 | u8 sdma_chs_cnt; | 493 | u8 sdma_reqs_cnt; |
494 | u8 rst_lines_cnt; | ||
472 | u8 opt_clks_cnt; | 495 | u8 opt_clks_cnt; |
473 | u8 masters_cnt; | 496 | u8 masters_cnt; |
474 | u8 slaves_cnt; | 497 | u8 slaves_cnt; |
@@ -492,6 +515,10 @@ int omap_hwmod_idle(struct omap_hwmod *oh); | |||
492 | int _omap_hwmod_idle(struct omap_hwmod *oh); | 515 | int _omap_hwmod_idle(struct omap_hwmod *oh); |
493 | int omap_hwmod_shutdown(struct omap_hwmod *oh); | 516 | int omap_hwmod_shutdown(struct omap_hwmod *oh); |
494 | 517 | ||
518 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name); | ||
519 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name); | ||
520 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name); | ||
521 | |||
495 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh); | 522 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh); |
496 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh); | 523 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh); |
497 | 524 | ||
diff --git a/arch/arm/plat-omap/include/plat/prcm.h b/arch/arm/plat-omap/include/plat/prcm.h index 9fbd91419cd1..ab77442e42ab 100644 --- a/arch/arm/plat-omap/include/plat/prcm.h +++ b/arch/arm/plat-omap/include/plat/prcm.h | |||
@@ -38,6 +38,8 @@ u32 prm_read_mod_reg(s16 module, u16 idx); | |||
38 | void prm_write_mod_reg(u32 val, s16 module, u16 idx); | 38 | void prm_write_mod_reg(u32 val, s16 module, u16 idx); |
39 | u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); | 39 | u32 prm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); |
40 | u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask); | 40 | u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask); |
41 | u32 omap4_prm_read_bits_shift(void __iomem *reg, u32 mask); | ||
42 | u32 omap4_prm_rmw_reg_bits(u32 mask, u32 bits, void __iomem *reg); | ||
41 | u32 cm_read_mod_reg(s16 module, u16 idx); | 43 | u32 cm_read_mod_reg(s16 module, u16 idx); |
42 | void cm_write_mod_reg(u32 val, s16 module, u16 idx); | 44 | void cm_write_mod_reg(u32 val, s16 module, u16 idx); |
43 | u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); | 45 | u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx); |
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index d2b160942ccc..ceba58a47595 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c | |||
@@ -82,6 +82,7 @@ | |||
82 | #include <linux/slab.h> | 82 | #include <linux/slab.h> |
83 | #include <linux/err.h> | 83 | #include <linux/err.h> |
84 | #include <linux/io.h> | 84 | #include <linux/io.h> |
85 | #include <linux/clk.h> | ||
85 | 86 | ||
86 | #include <plat/omap_device.h> | 87 | #include <plat/omap_device.h> |
87 | #include <plat/omap_hwmod.h> | 88 | #include <plat/omap_hwmod.h> |
@@ -243,6 +244,44 @@ static inline struct omap_device *_find_by_pdev(struct platform_device *pdev) | |||
243 | return container_of(pdev, struct omap_device, pdev); | 244 | return container_of(pdev, struct omap_device, pdev); |
244 | } | 245 | } |
245 | 246 | ||
247 | /** | ||
248 | * _add_optional_clock_alias - Add clock alias for hwmod optional clocks | ||
249 | * @od: struct omap_device *od | ||
250 | * | ||
251 | * For every optional clock present per hwmod per omap_device, this function | ||
252 | * adds an entry in the clocks list of the form <dev-id=dev_name, con-id=role> | ||
253 | * if an entry is already present in it with the form <dev-id=NULL, con-id=role> | ||
254 | * | ||
255 | * The function is called from inside omap_device_build_ss(), after | ||
256 | * omap_device_register. | ||
257 | * | ||
258 | * This allows drivers to get a pointer to its optional clocks based on its role | ||
259 | * by calling clk_get(<dev*>, <role>). | ||
260 | * | ||
261 | * No return value. | ||
262 | */ | ||
263 | static void _add_optional_clock_alias(struct omap_device *od, | ||
264 | struct omap_hwmod *oh) | ||
265 | { | ||
266 | int i; | ||
267 | |||
268 | for (i = 0; i < oh->opt_clks_cnt; i++) { | ||
269 | struct omap_hwmod_opt_clk *oc; | ||
270 | int r; | ||
271 | |||
272 | oc = &oh->opt_clks[i]; | ||
273 | |||
274 | if (!oc->_clk) | ||
275 | continue; | ||
276 | |||
277 | r = clk_add_alias(oc->role, dev_name(&od->pdev.dev), | ||
278 | (char *)oc->clk, &od->pdev.dev); | ||
279 | if (r) | ||
280 | pr_err("omap_device: %s: clk_add_alias for %s failed\n", | ||
281 | dev_name(&od->pdev.dev), oc->role); | ||
282 | } | ||
283 | } | ||
284 | |||
246 | 285 | ||
247 | /* Public functions for use by core code */ | 286 | /* Public functions for use by core code */ |
248 | 287 | ||
@@ -421,8 +460,10 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id, | |||
421 | else | 460 | else |
422 | ret = omap_device_register(od); | 461 | ret = omap_device_register(od); |
423 | 462 | ||
424 | for (i = 0; i < oh_cnt; i++) | 463 | for (i = 0; i < oh_cnt; i++) { |
425 | hwmods[i]->od = od; | 464 | hwmods[i]->od = od; |
465 | _add_optional_clock_alias(od, hwmods[i]); | ||
466 | } | ||
426 | 467 | ||
427 | if (ret) | 468 | if (ret) |
428 | goto odbs_exit4; | 469 | goto odbs_exit4; |