diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 168 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/omap_hwmod.h | 17 |
2 files changed, 177 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3084409ad1dc..f4a569c74700 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -50,11 +50,13 @@ | |||
50 | #include <plat/powerdomain.h> | 50 | #include <plat/powerdomain.h> |
51 | #include <plat/clock.h> | 51 | #include <plat/clock.h> |
52 | #include <plat/omap_hwmod.h> | 52 | #include <plat/omap_hwmod.h> |
53 | #include <plat/prcm.h> | ||
53 | 54 | ||
54 | #include "cm.h" | 55 | #include "cm.h" |
56 | #include "prm.h" | ||
55 | 57 | ||
56 | /* Maximum microseconds to wait for OMAP module to reset */ | 58 | /* Maximum microseconds to wait for OMAP module to softreset */ |
57 | #define MAX_MODULE_RESET_WAIT 10000 | 59 | #define MAX_MODULE_SOFTRESET_WAIT 10000 |
58 | 60 | ||
59 | /* Name of the OMAP hwmod for the MPU */ | 61 | /* Name of the OMAP hwmod for the MPU */ |
60 | #define MPU_INITIATOR_NAME "mpu" | 62 | #define MPU_INITIATOR_NAME "mpu" |
@@ -834,6 +836,130 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
834 | } | 836 | } |
835 | 837 | ||
836 | /** | 838 | /** |
839 | * _lookup_hardreset - return the register bit shift for this hwmod/reset line | ||
840 | * @oh: struct omap_hwmod * | ||
841 | * @name: name of the reset line in the context of this hwmod | ||
842 | * | ||
843 | * Return the bit position of the reset line that match the | ||
844 | * input name. Return -ENOENT if not found. | ||
845 | */ | ||
846 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name) | ||
847 | { | ||
848 | int i; | ||
849 | |||
850 | for (i = 0; i < oh->rst_lines_cnt; i++) { | ||
851 | const char *rst_line = oh->rst_lines[i].name; | ||
852 | if (!strcmp(rst_line, name)) { | ||
853 | u8 shift = oh->rst_lines[i].rst_shift; | ||
854 | pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n", | ||
855 | oh->name, rst_line, shift); | ||
856 | |||
857 | return shift; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | return -ENOENT; | ||
862 | } | ||
863 | |||
864 | /** | ||
865 | * _assert_hardreset - assert the HW reset line of submodules | ||
866 | * contained in the hwmod module. | ||
867 | * @oh: struct omap_hwmod * | ||
868 | * @name: name of the reset line to lookup and assert | ||
869 | * | ||
870 | * Some IP like dsp, ipu or iva contain processor that require | ||
871 | * an HW reset line to be assert / deassert in order to enable fully | ||
872 | * the IP. | ||
873 | */ | ||
874 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | ||
875 | { | ||
876 | u8 shift; | ||
877 | |||
878 | if (!oh) | ||
879 | return -EINVAL; | ||
880 | |||
881 | shift = _lookup_hardreset(oh, name); | ||
882 | if (IS_ERR_VALUE(shift)) | ||
883 | return shift; | ||
884 | |||
885 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
886 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, | ||
887 | shift); | ||
888 | else if (cpu_is_omap44xx()) | ||
889 | return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, | ||
890 | shift); | ||
891 | else | ||
892 | return -EINVAL; | ||
893 | } | ||
894 | |||
895 | /** | ||
896 | * _deassert_hardreset - deassert the HW reset line of submodules contained | ||
897 | * in the hwmod module. | ||
898 | * @oh: struct omap_hwmod * | ||
899 | * @name: name of the reset line to look up and deassert | ||
900 | * | ||
901 | * Some IP like dsp, ipu or iva contain processor that require | ||
902 | * an HW reset line to be assert / deassert in order to enable fully | ||
903 | * the IP. | ||
904 | */ | ||
905 | static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | ||
906 | { | ||
907 | u8 shift; | ||
908 | int r; | ||
909 | |||
910 | if (!oh) | ||
911 | return -EINVAL; | ||
912 | |||
913 | shift = _lookup_hardreset(oh, name); | ||
914 | if (IS_ERR_VALUE(shift)) | ||
915 | return shift; | ||
916 | |||
917 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | ||
918 | r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, | ||
919 | shift); | ||
920 | else if (cpu_is_omap44xx()) | ||
921 | r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, | ||
922 | shift); | ||
923 | else | ||
924 | return -EINVAL; | ||
925 | |||
926 | if (r == -EBUSY) | ||
927 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); | ||
928 | |||
929 | return r; | ||
930 | } | ||
931 | |||
932 | /** | ||
933 | * _read_hardreset - read the HW reset line state of submodules | ||
934 | * contained in the hwmod module | ||
935 | * @oh: struct omap_hwmod * | ||
936 | * @name: name of the reset line to look up and read | ||
937 | * | ||
938 | * Return the state of the reset line. | ||
939 | */ | ||
940 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) | ||
941 | { | ||
942 | u8 shift; | ||
943 | |||
944 | if (!oh) | ||
945 | return -EINVAL; | ||
946 | |||
947 | shift = _lookup_hardreset(oh, name); | ||
948 | if (IS_ERR_VALUE(shift)) | ||
949 | return shift; | ||
950 | |||
951 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { | ||
952 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, | ||
953 | shift); | ||
954 | } else if (cpu_is_omap44xx()) { | ||
955 | return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, | ||
956 | shift); | ||
957 | } else { | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | /** | ||
837 | * _reset - reset an omap_hwmod | 963 | * _reset - reset an omap_hwmod |
838 | * @oh: struct omap_hwmod * | 964 | * @oh: struct omap_hwmod * |
839 | * | 965 | * |
@@ -869,20 +995,20 @@ static int _reset(struct omap_hwmod *oh) | |||
869 | 995 | ||
870 | omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & | 996 | omap_test_timeout((omap_hwmod_readl(oh, oh->class->sysc->syss_offs) & |
871 | SYSS_RESETDONE_MASK), | 997 | SYSS_RESETDONE_MASK), |
872 | MAX_MODULE_RESET_WAIT, c); | 998 | MAX_MODULE_SOFTRESET_WAIT, c); |
873 | 999 | ||
874 | if (c == MAX_MODULE_RESET_WAIT) | 1000 | if (c == MAX_MODULE_SOFTRESET_WAIT) |
875 | WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", | 1001 | WARN(1, "omap_hwmod: %s: softreset failed (waited %d usec)\n", |
876 | oh->name, MAX_MODULE_RESET_WAIT); | 1002 | oh->name, MAX_MODULE_SOFTRESET_WAIT); |
877 | else | 1003 | else |
878 | pr_debug("omap_hwmod: %s: reset in %d usec\n", oh->name, c); | 1004 | pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c); |
879 | 1005 | ||
880 | /* | 1006 | /* |
881 | * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from | 1007 | * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from |
882 | * _wait_target_ready() or _reset() | 1008 | * _wait_target_ready() or _reset() |
883 | */ | 1009 | */ |
884 | 1010 | ||
885 | return (c == MAX_MODULE_RESET_WAIT) ? -ETIMEDOUT : 0; | 1011 | return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0; |
886 | } | 1012 | } |
887 | 1013 | ||
888 | /** | 1014 | /** |
@@ -907,6 +1033,15 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
907 | 1033 | ||
908 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); | 1034 | pr_debug("omap_hwmod: %s: enabling\n", oh->name); |
909 | 1035 | ||
1036 | /* | ||
1037 | * If an IP contains only one HW reset line, then de-assert it in order | ||
1038 | * to allow to enable the clocks. Otherwise the PRCM will return | ||
1039 | * Intransition status, and the init will failed. | ||
1040 | */ | ||
1041 | if ((oh->_state == _HWMOD_STATE_INITIALIZED || | ||
1042 | oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) | ||
1043 | _deassert_hardreset(oh, oh->rst_lines[0].name); | ||
1044 | |||
910 | /* XXX mux balls */ | 1045 | /* XXX mux balls */ |
911 | 1046 | ||
912 | _add_initiator_dep(oh, mpu_oh); | 1047 | _add_initiator_dep(oh, mpu_oh); |
@@ -981,6 +1116,13 @@ static int _shutdown(struct omap_hwmod *oh) | |||
981 | if (oh->class->sysc) | 1116 | if (oh->class->sysc) |
982 | _sysc_shutdown(oh); | 1117 | _sysc_shutdown(oh); |
983 | 1118 | ||
1119 | /* | ||
1120 | * If an IP contains only one HW reset line, then assert it | ||
1121 | * before disabling the clocks and shutting down the IP. | ||
1122 | */ | ||
1123 | if (oh->rst_lines_cnt == 1) | ||
1124 | _assert_hardreset(oh, oh->rst_lines[0].name); | ||
1125 | |||
984 | /* clocks and deps are already disabled in idle */ | 1126 | /* clocks and deps are already disabled in idle */ |
985 | if (oh->_state == _HWMOD_STATE_ENABLED) { | 1127 | if (oh->_state == _HWMOD_STATE_ENABLED) { |
986 | _del_initiator_dep(oh, mpu_oh); | 1128 | _del_initiator_dep(oh, mpu_oh); |
@@ -1038,6 +1180,16 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1038 | mutex_init(&oh->_mutex); | 1180 | mutex_init(&oh->_mutex); |
1039 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1181 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1040 | 1182 | ||
1183 | /* | ||
1184 | * In the case of hwmod with hardreset that should not be | ||
1185 | * de-assert at boot time, we have to keep the module | ||
1186 | * initialized, because we cannot enable it properly with the | ||
1187 | * reset asserted. Exit without warning because that behavior is | ||
1188 | * expected. | ||
1189 | */ | ||
1190 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) | ||
1191 | return 0; | ||
1192 | |||
1041 | r = _omap_hwmod_enable(oh); | 1193 | r = _omap_hwmod_enable(oh); |
1042 | if (r) { | 1194 | if (r) { |
1043 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 1195 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", |
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 03350bac01d8..590bfae250e8 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h | |||
@@ -109,6 +109,19 @@ struct omap_hwmod_dma_info { | |||
109 | }; | 109 | }; |
110 | 110 | ||
111 | /** | 111 | /** |
112 | * struct omap_hwmod_rst_info - IPs reset lines use by hwmod | ||
113 | * @name: name of the reset line (module local name) | ||
114 | * @rst_shift: Offset of the reset bit | ||
115 | * | ||
116 | * @name should be something short, e.g., "cpu0" or "rst". It is defined | ||
117 | * locally to the hwmod. | ||
118 | */ | ||
119 | struct omap_hwmod_rst_info { | ||
120 | const char *name; | ||
121 | u8 rst_shift; | ||
122 | }; | ||
123 | |||
124 | /** | ||
112 | * struct omap_hwmod_opt_clk - optional clocks used by this hwmod | 125 | * struct omap_hwmod_opt_clk - optional clocks used by this hwmod |
113 | * @role: "sys", "32k", "tv", etc -- for use in clk_get() | 126 | * @role: "sys", "32k", "tv", etc -- for use in clk_get() |
114 | * @clk: opt clock: OMAP clock name | 127 | * @clk: opt clock: OMAP clock name |
@@ -328,10 +341,12 @@ struct omap_hwmod_omap2_prcm { | |||
328 | /** | 341 | /** |
329 | * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data | 342 | * struct omap_hwmod_omap4_prcm - OMAP4-specific PRCM data |
330 | * @clkctrl_reg: PRCM address of the clock control register | 343 | * @clkctrl_reg: PRCM address of the clock control register |
344 | * @rstctrl_reg: adress of the XXX_RSTCTRL register located in the PRM | ||
331 | * @submodule_wkdep_bit: bit shift of the WKDEP range | 345 | * @submodule_wkdep_bit: bit shift of the WKDEP range |
332 | */ | 346 | */ |
333 | struct omap_hwmod_omap4_prcm { | 347 | struct omap_hwmod_omap4_prcm { |
334 | void __iomem *clkctrl_reg; | 348 | void __iomem *clkctrl_reg; |
349 | void __iomem *rstctrl_reg; | ||
335 | u8 submodule_wkdep_bit; | 350 | u8 submodule_wkdep_bit; |
336 | }; | 351 | }; |
337 | 352 | ||
@@ -451,6 +466,7 @@ struct omap_hwmod { | |||
451 | struct omap_device *od; | 466 | struct omap_device *od; |
452 | struct omap_hwmod_irq_info *mpu_irqs; | 467 | struct omap_hwmod_irq_info *mpu_irqs; |
453 | struct omap_hwmod_dma_info *sdma_reqs; | 468 | struct omap_hwmod_dma_info *sdma_reqs; |
469 | struct omap_hwmod_rst_info *rst_lines; | ||
454 | union { | 470 | union { |
455 | struct omap_hwmod_omap2_prcm omap2; | 471 | struct omap_hwmod_omap2_prcm omap2; |
456 | struct omap_hwmod_omap4_prcm omap4; | 472 | struct omap_hwmod_omap4_prcm omap4; |
@@ -472,6 +488,7 @@ struct omap_hwmod { | |||
472 | u8 response_lat; | 488 | u8 response_lat; |
473 | u8 mpu_irqs_cnt; | 489 | u8 mpu_irqs_cnt; |
474 | u8 sdma_reqs_cnt; | 490 | u8 sdma_reqs_cnt; |
491 | u8 rst_lines_cnt; | ||
475 | u8 opt_clks_cnt; | 492 | u8 opt_clks_cnt; |
476 | u8 masters_cnt; | 493 | u8 masters_cnt; |
477 | u8 slaves_cnt; | 494 | u8 slaves_cnt; |