diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 483 |
1 files changed, 292 insertions, 191 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 5a30658444d0..e282e35769fd 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -116,7 +116,6 @@ | |||
116 | * - Open Core Protocol Specification 2.2 | 116 | * - Open Core Protocol Specification 2.2 |
117 | * | 117 | * |
118 | * To do: | 118 | * To do: |
119 | * - pin mux handling | ||
120 | * - handle IO mapping | 119 | * - handle IO mapping |
121 | * - bus throughput & module latency measurement code | 120 | * - bus throughput & module latency measurement code |
122 | * | 121 | * |
@@ -135,17 +134,21 @@ | |||
135 | #include <linux/err.h> | 134 | #include <linux/err.h> |
136 | #include <linux/list.h> | 135 | #include <linux/list.h> |
137 | #include <linux/mutex.h> | 136 | #include <linux/mutex.h> |
137 | #include <linux/spinlock.h> | ||
138 | 138 | ||
139 | #include <plat/common.h> | 139 | #include <plat/common.h> |
140 | #include <plat/cpu.h> | 140 | #include <plat/cpu.h> |
141 | #include <plat/clockdomain.h> | 141 | #include "clockdomain.h" |
142 | #include <plat/powerdomain.h> | 142 | #include "powerdomain.h" |
143 | #include <plat/clock.h> | 143 | #include <plat/clock.h> |
144 | #include <plat/omap_hwmod.h> | 144 | #include <plat/omap_hwmod.h> |
145 | #include <plat/prcm.h> | 145 | #include <plat/prcm.h> |
146 | 146 | ||
147 | #include "cm.h" | 147 | #include "cm2xxx_3xxx.h" |
148 | #include "prm.h" | 148 | #include "cm44xx.h" |
149 | #include "prm2xxx_3xxx.h" | ||
150 | #include "prm44xx.h" | ||
151 | #include "mux.h" | ||
149 | 152 | ||
150 | /* Maximum microseconds to wait for OMAP module to softreset */ | 153 | /* Maximum microseconds to wait for OMAP module to softreset */ |
151 | #define MAX_MODULE_SOFTRESET_WAIT 10000 | 154 | #define MAX_MODULE_SOFTRESET_WAIT 10000 |
@@ -156,8 +159,6 @@ | |||
156 | /* omap_hwmod_list contains all registered struct omap_hwmods */ | 159 | /* omap_hwmod_list contains all registered struct omap_hwmods */ |
157 | static LIST_HEAD(omap_hwmod_list); | 160 | static LIST_HEAD(omap_hwmod_list); |
158 | 161 | ||
159 | static DEFINE_MUTEX(omap_hwmod_mutex); | ||
160 | |||
161 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ | 162 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ |
162 | static struct omap_hwmod *mpu_oh; | 163 | static struct omap_hwmod *mpu_oh; |
163 | 164 | ||
@@ -209,10 +210,9 @@ static void _write_sysconfig(u32 v, struct omap_hwmod *oh) | |||
209 | 210 | ||
210 | /* XXX ensure module interface clock is up */ | 211 | /* XXX ensure module interface clock is up */ |
211 | 212 | ||
212 | if (oh->_sysc_cache != v) { | 213 | /* Module might have lost context, always update cache and register */ |
213 | oh->_sysc_cache = v; | 214 | oh->_sysc_cache = v; |
214 | omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs); | 215 | omap_hwmod_write(v, oh, oh->class->sysc->sysc_offs); |
215 | } | ||
216 | } | 216 | } |
217 | 217 | ||
218 | /** | 218 | /** |
@@ -388,12 +388,13 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, | |||
388 | * Allow the hardware module @oh to send wakeups. Returns -EINVAL | 388 | * Allow the hardware module @oh to send wakeups. Returns -EINVAL |
389 | * upon error or 0 upon success. | 389 | * upon error or 0 upon success. |
390 | */ | 390 | */ |
391 | static int _enable_wakeup(struct omap_hwmod *oh) | 391 | static int _enable_wakeup(struct omap_hwmod *oh, u32 *v) |
392 | { | 392 | { |
393 | u32 v, wakeup_mask; | 393 | u32 wakeup_mask; |
394 | 394 | ||
395 | if (!oh->class->sysc || | 395 | if (!oh->class->sysc || |
396 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 396 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || |
397 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) | ||
397 | return -EINVAL; | 398 | return -EINVAL; |
398 | 399 | ||
399 | if (!oh->class->sysc->sysc_fields) { | 400 | if (!oh->class->sysc->sysc_fields) { |
@@ -403,9 +404,10 @@ static int _enable_wakeup(struct omap_hwmod *oh) | |||
403 | 404 | ||
404 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); | 405 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); |
405 | 406 | ||
406 | v = oh->_sysc_cache; | 407 | *v |= wakeup_mask; |
407 | v |= wakeup_mask; | 408 | |
408 | _write_sysconfig(v, oh); | 409 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) |
410 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v); | ||
409 | 411 | ||
410 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ | 412 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ |
411 | 413 | ||
@@ -421,12 +423,13 @@ static int _enable_wakeup(struct omap_hwmod *oh) | |||
421 | * Prevent the hardware module @oh to send wakeups. Returns -EINVAL | 423 | * Prevent the hardware module @oh to send wakeups. Returns -EINVAL |
422 | * upon error or 0 upon success. | 424 | * upon error or 0 upon success. |
423 | */ | 425 | */ |
424 | static int _disable_wakeup(struct omap_hwmod *oh) | 426 | static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) |
425 | { | 427 | { |
426 | u32 v, wakeup_mask; | 428 | u32 wakeup_mask; |
427 | 429 | ||
428 | if (!oh->class->sysc || | 430 | if (!oh->class->sysc || |
429 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 431 | !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) || |
432 | (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP))) | ||
430 | return -EINVAL; | 433 | return -EINVAL; |
431 | 434 | ||
432 | if (!oh->class->sysc->sysc_fields) { | 435 | if (!oh->class->sysc->sysc_fields) { |
@@ -436,9 +439,10 @@ static int _disable_wakeup(struct omap_hwmod *oh) | |||
436 | 439 | ||
437 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); | 440 | wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); |
438 | 441 | ||
439 | v = oh->_sysc_cache; | 442 | *v &= ~wakeup_mask; |
440 | v &= ~wakeup_mask; | 443 | |
441 | _write_sysconfig(v, oh); | 444 | if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP) |
445 | _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v); | ||
442 | 446 | ||
443 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ | 447 | /* XXX test pwrdm_get_wken for this hwmod's subsystem */ |
444 | 448 | ||
@@ -675,7 +679,7 @@ static void _disable_optional_clocks(struct omap_hwmod *oh) | |||
675 | * Returns the array index of the OCP slave port that the MPU | 679 | * Returns the array index of the OCP slave port that the MPU |
676 | * addresses the device on, or -EINVAL upon error or not found. | 680 | * addresses the device on, or -EINVAL upon error or not found. |
677 | */ | 681 | */ |
678 | static int _find_mpu_port_index(struct omap_hwmod *oh) | 682 | static int __init _find_mpu_port_index(struct omap_hwmod *oh) |
679 | { | 683 | { |
680 | int i; | 684 | int i; |
681 | int found = 0; | 685 | int found = 0; |
@@ -709,7 +713,7 @@ static int _find_mpu_port_index(struct omap_hwmod *oh) | |||
709 | * Return the virtual address of the base of the register target of | 713 | * Return the virtual address of the base of the register target of |
710 | * device @oh, or NULL on error. | 714 | * device @oh, or NULL on error. |
711 | */ | 715 | */ |
712 | static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | 716 | static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index) |
713 | { | 717 | { |
714 | struct omap_hwmod_ocp_if *os; | 718 | struct omap_hwmod_ocp_if *os; |
715 | struct omap_hwmod_addr_space *mem; | 719 | struct omap_hwmod_addr_space *mem; |
@@ -786,11 +790,11 @@ static void _enable_sysc(struct omap_hwmod *oh) | |||
786 | (sf & SYSC_HAS_CLOCKACTIVITY)) | 790 | (sf & SYSC_HAS_CLOCKACTIVITY)) |
787 | _set_clockactivity(oh, oh->class->sysc->clockact, &v); | 791 | _set_clockactivity(oh, oh->class->sysc->clockact, &v); |
788 | 792 | ||
789 | _write_sysconfig(v, oh); | ||
790 | |||
791 | /* If slave is in SMARTIDLE, also enable wakeup */ | 793 | /* If slave is in SMARTIDLE, also enable wakeup */ |
792 | if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) | 794 | if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) |
793 | _enable_wakeup(oh); | 795 | _enable_wakeup(oh, &v); |
796 | |||
797 | _write_sysconfig(v, oh); | ||
794 | 798 | ||
795 | /* | 799 | /* |
796 | * Set the autoidle bit only after setting the smartidle bit | 800 | * Set the autoidle bit only after setting the smartidle bit |
@@ -836,6 +840,10 @@ static void _idle_sysc(struct omap_hwmod *oh) | |||
836 | _set_master_standbymode(oh, idlemode, &v); | 840 | _set_master_standbymode(oh, idlemode, &v); |
837 | } | 841 | } |
838 | 842 | ||
843 | /* If slave is in SMARTIDLE, also enable wakeup */ | ||
844 | if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) | ||
845 | _enable_wakeup(oh, &v); | ||
846 | |||
839 | _write_sysconfig(v, oh); | 847 | _write_sysconfig(v, oh); |
840 | } | 848 | } |
841 | 849 | ||
@@ -874,7 +882,6 @@ static void _shutdown_sysc(struct omap_hwmod *oh) | |||
874 | * @name: find an omap_hwmod by name | 882 | * @name: find an omap_hwmod by name |
875 | * | 883 | * |
876 | * Return a pointer to an omap_hwmod by name, or NULL if not found. | 884 | * Return a pointer to an omap_hwmod by name, or NULL if not found. |
877 | * Caller must hold omap_hwmod_mutex. | ||
878 | */ | 885 | */ |
879 | static struct omap_hwmod *_lookup(const char *name) | 886 | static struct omap_hwmod *_lookup(const char *name) |
880 | { | 887 | { |
@@ -1089,7 +1096,7 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1089 | } | 1096 | } |
1090 | 1097 | ||
1091 | /** | 1098 | /** |
1092 | * _reset - reset an omap_hwmod | 1099 | * _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit |
1093 | * @oh: struct omap_hwmod * | 1100 | * @oh: struct omap_hwmod * |
1094 | * | 1101 | * |
1095 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be | 1102 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be |
@@ -1098,12 +1105,13 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1098 | * the module did not reset in time, or 0 upon success. | 1105 | * the module did not reset in time, or 0 upon success. |
1099 | * | 1106 | * |
1100 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. | 1107 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. |
1101 | * Starting in OMAP4, some IPs does not have SYSSTATUS register and instead | 1108 | * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead |
1102 | * use the SYSCONFIG softreset bit to provide the status. | 1109 | * use the SYSCONFIG softreset bit to provide the status. |
1103 | * | 1110 | * |
1104 | * Note that some IP like McBSP does have a reset control but no reset status. | 1111 | * Note that some IP like McBSP do have reset control but don't have |
1112 | * reset status. | ||
1105 | */ | 1113 | */ |
1106 | static int _reset(struct omap_hwmod *oh) | 1114 | static int _ocp_softreset(struct omap_hwmod *oh) |
1107 | { | 1115 | { |
1108 | u32 v; | 1116 | u32 v; |
1109 | int c = 0; | 1117 | int c = 0; |
@@ -1124,7 +1132,7 @@ static int _reset(struct omap_hwmod *oh) | |||
1124 | if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) | 1132 | if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET) |
1125 | _enable_optional_clocks(oh); | 1133 | _enable_optional_clocks(oh); |
1126 | 1134 | ||
1127 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); | 1135 | pr_debug("omap_hwmod: %s: resetting via OCP SOFTRESET\n", oh->name); |
1128 | 1136 | ||
1129 | v = oh->_sysc_cache; | 1137 | v = oh->_sysc_cache; |
1130 | ret = _set_softreset(oh, &v); | 1138 | ret = _set_softreset(oh, &v); |
@@ -1164,17 +1172,41 @@ dis_opt_clks: | |||
1164 | } | 1172 | } |
1165 | 1173 | ||
1166 | /** | 1174 | /** |
1167 | * _omap_hwmod_enable - enable an omap_hwmod | 1175 | * _reset - reset an omap_hwmod |
1176 | * @oh: struct omap_hwmod * | ||
1177 | * | ||
1178 | * Resets an omap_hwmod @oh. The default software reset mechanism for | ||
1179 | * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET | ||
1180 | * bit. However, some hwmods cannot be reset via this method: some | ||
1181 | * are not targets and therefore have no OCP header registers to | ||
1182 | * access; others (like the IVA) have idiosyncratic reset sequences. | ||
1183 | * So for these relatively rare cases, custom reset code can be | ||
1184 | * supplied in the struct omap_hwmod_class .reset function pointer. | ||
1185 | * Passes along the return value from either _reset() or the custom | ||
1186 | * reset function - these must return -EINVAL if the hwmod cannot be | ||
1187 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if | ||
1188 | * the module did not reset in time, or 0 upon success. | ||
1189 | */ | ||
1190 | static int _reset(struct omap_hwmod *oh) | ||
1191 | { | ||
1192 | int ret; | ||
1193 | |||
1194 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); | ||
1195 | |||
1196 | ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh); | ||
1197 | |||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
1201 | /** | ||
1202 | * _enable - enable an omap_hwmod | ||
1168 | * @oh: struct omap_hwmod * | 1203 | * @oh: struct omap_hwmod * |
1169 | * | 1204 | * |
1170 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's | 1205 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's |
1171 | * register target. (This function has a full name -- | 1206 | * register target. Returns -EINVAL if the hwmod is in the wrong |
1172 | * _omap_hwmod_enable() rather than simply _enable() -- because it is | 1207 | * state or passes along the return value of _wait_target_ready(). |
1173 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if | ||
1174 | * the hwmod is in the wrong state or passes along the return value of | ||
1175 | * _wait_target_ready(). | ||
1176 | */ | 1208 | */ |
1177 | int _omap_hwmod_enable(struct omap_hwmod *oh) | 1209 | static int _enable(struct omap_hwmod *oh) |
1178 | { | 1210 | { |
1179 | int r; | 1211 | int r; |
1180 | 1212 | ||
@@ -1197,7 +1229,9 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
1197 | oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) | 1229 | oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1) |
1198 | _deassert_hardreset(oh, oh->rst_lines[0].name); | 1230 | _deassert_hardreset(oh, oh->rst_lines[0].name); |
1199 | 1231 | ||
1200 | /* XXX mux balls */ | 1232 | /* Mux pins for device runtime if populated */ |
1233 | if (oh->mux) | ||
1234 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); | ||
1201 | 1235 | ||
1202 | _add_initiator_dep(oh, mpu_oh); | 1236 | _add_initiator_dep(oh, mpu_oh); |
1203 | _enable_clocks(oh); | 1237 | _enable_clocks(oh); |
@@ -1213,6 +1247,7 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
1213 | _enable_sysc(oh); | 1247 | _enable_sysc(oh); |
1214 | } | 1248 | } |
1215 | } else { | 1249 | } else { |
1250 | _disable_clocks(oh); | ||
1216 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | 1251 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", |
1217 | oh->name, r); | 1252 | oh->name, r); |
1218 | } | 1253 | } |
@@ -1221,16 +1256,14 @@ int _omap_hwmod_enable(struct omap_hwmod *oh) | |||
1221 | } | 1256 | } |
1222 | 1257 | ||
1223 | /** | 1258 | /** |
1224 | * _omap_hwmod_idle - idle an omap_hwmod | 1259 | * _idle - idle an omap_hwmod |
1225 | * @oh: struct omap_hwmod * | 1260 | * @oh: struct omap_hwmod * |
1226 | * | 1261 | * |
1227 | * Idles an omap_hwmod @oh. This should be called once the hwmod has | 1262 | * Idles an omap_hwmod @oh. This should be called once the hwmod has |
1228 | * no further work. (This function has a full name -- | 1263 | * no further work. Returns -EINVAL if the hwmod is in the wrong |
1229 | * _omap_hwmod_idle() rather than simply _idle() -- because it is | 1264 | * state or returns 0. |
1230 | * currently required by the pm34xx.c idle loop.) Returns -EINVAL if | ||
1231 | * the hwmod is in the wrong state or returns 0. | ||
1232 | */ | 1265 | */ |
1233 | int _omap_hwmod_idle(struct omap_hwmod *oh) | 1266 | static int _idle(struct omap_hwmod *oh) |
1234 | { | 1267 | { |
1235 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1268 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
1236 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " | 1269 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " |
@@ -1245,6 +1278,10 @@ int _omap_hwmod_idle(struct omap_hwmod *oh) | |||
1245 | _del_initiator_dep(oh, mpu_oh); | 1278 | _del_initiator_dep(oh, mpu_oh); |
1246 | _disable_clocks(oh); | 1279 | _disable_clocks(oh); |
1247 | 1280 | ||
1281 | /* Mux pins for device idle if populated */ | ||
1282 | if (oh->mux) | ||
1283 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); | ||
1284 | |||
1248 | oh->_state = _HWMOD_STATE_IDLE; | 1285 | oh->_state = _HWMOD_STATE_IDLE; |
1249 | 1286 | ||
1250 | return 0; | 1287 | return 0; |
@@ -1261,6 +1298,9 @@ int _omap_hwmod_idle(struct omap_hwmod *oh) | |||
1261 | */ | 1298 | */ |
1262 | static int _shutdown(struct omap_hwmod *oh) | 1299 | static int _shutdown(struct omap_hwmod *oh) |
1263 | { | 1300 | { |
1301 | int ret; | ||
1302 | u8 prev_state; | ||
1303 | |||
1264 | if (oh->_state != _HWMOD_STATE_IDLE && | 1304 | if (oh->_state != _HWMOD_STATE_IDLE && |
1265 | oh->_state != _HWMOD_STATE_ENABLED) { | 1305 | oh->_state != _HWMOD_STATE_ENABLED) { |
1266 | WARN(1, "omap_hwmod: %s: disabled state can only be entered " | 1306 | WARN(1, "omap_hwmod: %s: disabled state can only be entered " |
@@ -1270,6 +1310,18 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1270 | 1310 | ||
1271 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); | 1311 | pr_debug("omap_hwmod: %s: disabling\n", oh->name); |
1272 | 1312 | ||
1313 | if (oh->class->pre_shutdown) { | ||
1314 | prev_state = oh->_state; | ||
1315 | if (oh->_state == _HWMOD_STATE_IDLE) | ||
1316 | _enable(oh); | ||
1317 | ret = oh->class->pre_shutdown(oh); | ||
1318 | if (ret) { | ||
1319 | if (prev_state == _HWMOD_STATE_IDLE) | ||
1320 | _idle(oh); | ||
1321 | return ret; | ||
1322 | } | ||
1323 | } | ||
1324 | |||
1273 | if (oh->class->sysc) | 1325 | if (oh->class->sysc) |
1274 | _shutdown_sysc(oh); | 1326 | _shutdown_sysc(oh); |
1275 | 1327 | ||
@@ -1288,7 +1340,9 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1288 | } | 1340 | } |
1289 | /* XXX Should this code also force-disable the optional clocks? */ | 1341 | /* XXX Should this code also force-disable the optional clocks? */ |
1290 | 1342 | ||
1291 | /* XXX mux any associated balls to safe mode */ | 1343 | /* Mux pins to safe mode or use populated off mode values */ |
1344 | if (oh->mux) | ||
1345 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED); | ||
1292 | 1346 | ||
1293 | oh->_state = _HWMOD_STATE_DISABLED; | 1347 | oh->_state = _HWMOD_STATE_DISABLED; |
1294 | 1348 | ||
@@ -1298,23 +1352,15 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1298 | /** | 1352 | /** |
1299 | * _setup - do initial configuration of omap_hwmod | 1353 | * _setup - do initial configuration of omap_hwmod |
1300 | * @oh: struct omap_hwmod * | 1354 | * @oh: struct omap_hwmod * |
1301 | * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 | ||
1302 | * | 1355 | * |
1303 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 1356 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh |
1304 | * OCP_SYSCONFIG register. @skip_setup_idle is intended to be used on | 1357 | * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the |
1305 | * a system that will not call omap_hwmod_enable() to enable devices | 1358 | * wrong state or returns 0. |
1306 | * (e.g., a system without PM runtime). Returns -EINVAL if the hwmod | ||
1307 | * is in the wrong state or returns 0. | ||
1308 | */ | 1359 | */ |
1309 | static int _setup(struct omap_hwmod *oh, void *data) | 1360 | static int _setup(struct omap_hwmod *oh, void *data) |
1310 | { | 1361 | { |
1311 | int i, r; | 1362 | int i, r; |
1312 | u8 skip_setup_idle; | 1363 | u8 postsetup_state; |
1313 | |||
1314 | if (!oh || !data) | ||
1315 | return -EINVAL; | ||
1316 | |||
1317 | skip_setup_idle = *(u8 *)data; | ||
1318 | 1364 | ||
1319 | /* Set iclk autoidle mode */ | 1365 | /* Set iclk autoidle mode */ |
1320 | if (oh->slaves_cnt > 0) { | 1366 | if (oh->slaves_cnt > 0) { |
@@ -1334,7 +1380,6 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1334 | } | 1380 | } |
1335 | } | 1381 | } |
1336 | 1382 | ||
1337 | mutex_init(&oh->_mutex); | ||
1338 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1383 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1339 | 1384 | ||
1340 | /* | 1385 | /* |
@@ -1347,7 +1392,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1347 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) | 1392 | if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1) |
1348 | return 0; | 1393 | return 0; |
1349 | 1394 | ||
1350 | r = _omap_hwmod_enable(oh); | 1395 | r = _enable(oh); |
1351 | if (r) { | 1396 | if (r) { |
1352 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 1397 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", |
1353 | oh->name, oh->_state); | 1398 | oh->name, oh->_state); |
@@ -1359,7 +1404,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1359 | 1404 | ||
1360 | /* | 1405 | /* |
1361 | * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. | 1406 | * OCP_SYSCONFIG bits need to be reprogrammed after a softreset. |
1362 | * The _omap_hwmod_enable() function should be split to | 1407 | * The _enable() function should be split to |
1363 | * avoid the rewrite of the OCP_SYSCONFIG register. | 1408 | * avoid the rewrite of the OCP_SYSCONFIG register. |
1364 | */ | 1409 | */ |
1365 | if (oh->class->sysc) { | 1410 | if (oh->class->sysc) { |
@@ -1368,12 +1413,77 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1368 | } | 1413 | } |
1369 | } | 1414 | } |
1370 | 1415 | ||
1371 | if (!(oh->flags & HWMOD_INIT_NO_IDLE) && !skip_setup_idle) | 1416 | postsetup_state = oh->_postsetup_state; |
1372 | _omap_hwmod_idle(oh); | 1417 | if (postsetup_state == _HWMOD_STATE_UNKNOWN) |
1418 | postsetup_state = _HWMOD_STATE_ENABLED; | ||
1419 | |||
1420 | /* | ||
1421 | * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data - | ||
1422 | * it should be set by the core code as a runtime flag during startup | ||
1423 | */ | ||
1424 | if ((oh->flags & HWMOD_INIT_NO_IDLE) && | ||
1425 | (postsetup_state == _HWMOD_STATE_IDLE)) | ||
1426 | postsetup_state = _HWMOD_STATE_ENABLED; | ||
1427 | |||
1428 | if (postsetup_state == _HWMOD_STATE_IDLE) | ||
1429 | _idle(oh); | ||
1430 | else if (postsetup_state == _HWMOD_STATE_DISABLED) | ||
1431 | _shutdown(oh); | ||
1432 | else if (postsetup_state != _HWMOD_STATE_ENABLED) | ||
1433 | WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n", | ||
1434 | oh->name, postsetup_state); | ||
1373 | 1435 | ||
1374 | return 0; | 1436 | return 0; |
1375 | } | 1437 | } |
1376 | 1438 | ||
1439 | /** | ||
1440 | * _register - register a struct omap_hwmod | ||
1441 | * @oh: struct omap_hwmod * | ||
1442 | * | ||
1443 | * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod | ||
1444 | * already has been registered by the same name; -EINVAL if the | ||
1445 | * omap_hwmod is in the wrong state, if @oh is NULL, if the | ||
1446 | * omap_hwmod's class field is NULL; if the omap_hwmod is missing a | ||
1447 | * name, or if the omap_hwmod's class is missing a name; or 0 upon | ||
1448 | * success. | ||
1449 | * | ||
1450 | * XXX The data should be copied into bootmem, so the original data | ||
1451 | * should be marked __initdata and freed after init. This would allow | ||
1452 | * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note | ||
1453 | * that the copy process would be relatively complex due to the large number | ||
1454 | * of substructures. | ||
1455 | */ | ||
1456 | static int __init _register(struct omap_hwmod *oh) | ||
1457 | { | ||
1458 | int ret, ms_id; | ||
1459 | |||
1460 | if (!oh || !oh->name || !oh->class || !oh->class->name || | ||
1461 | (oh->_state != _HWMOD_STATE_UNKNOWN)) | ||
1462 | return -EINVAL; | ||
1463 | |||
1464 | pr_debug("omap_hwmod: %s: registering\n", oh->name); | ||
1465 | |||
1466 | if (_lookup(oh->name)) | ||
1467 | return -EEXIST; | ||
1468 | |||
1469 | ms_id = _find_mpu_port_index(oh); | ||
1470 | if (!IS_ERR_VALUE(ms_id)) { | ||
1471 | oh->_mpu_port_index = ms_id; | ||
1472 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | ||
1473 | } else { | ||
1474 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; | ||
1475 | } | ||
1476 | |||
1477 | list_add_tail(&oh->node, &omap_hwmod_list); | ||
1478 | |||
1479 | spin_lock_init(&oh->_lock); | ||
1480 | |||
1481 | oh->_state = _HWMOD_STATE_REGISTERED; | ||
1482 | |||
1483 | ret = 0; | ||
1484 | |||
1485 | return ret; | ||
1486 | } | ||
1377 | 1487 | ||
1378 | 1488 | ||
1379 | /* Public functions */ | 1489 | /* Public functions */ |
@@ -1427,59 +1537,6 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) | |||
1427 | } | 1537 | } |
1428 | 1538 | ||
1429 | /** | 1539 | /** |
1430 | * omap_hwmod_register - register a struct omap_hwmod | ||
1431 | * @oh: struct omap_hwmod * | ||
1432 | * | ||
1433 | * Registers the omap_hwmod @oh. Returns -EEXIST if an omap_hwmod | ||
1434 | * already has been registered by the same name; -EINVAL if the | ||
1435 | * omap_hwmod is in the wrong state, if @oh is NULL, if the | ||
1436 | * omap_hwmod's class field is NULL; if the omap_hwmod is missing a | ||
1437 | * name, or if the omap_hwmod's class is missing a name; or 0 upon | ||
1438 | * success. | ||
1439 | * | ||
1440 | * XXX The data should be copied into bootmem, so the original data | ||
1441 | * should be marked __initdata and freed after init. This would allow | ||
1442 | * unneeded omap_hwmods to be freed on multi-OMAP configurations. Note | ||
1443 | * that the copy process would be relatively complex due to the large number | ||
1444 | * of substructures. | ||
1445 | */ | ||
1446 | int omap_hwmod_register(struct omap_hwmod *oh) | ||
1447 | { | ||
1448 | int ret, ms_id; | ||
1449 | |||
1450 | if (!oh || !oh->name || !oh->class || !oh->class->name || | ||
1451 | (oh->_state != _HWMOD_STATE_UNKNOWN)) | ||
1452 | return -EINVAL; | ||
1453 | |||
1454 | mutex_lock(&omap_hwmod_mutex); | ||
1455 | |||
1456 | pr_debug("omap_hwmod: %s: registering\n", oh->name); | ||
1457 | |||
1458 | if (_lookup(oh->name)) { | ||
1459 | ret = -EEXIST; | ||
1460 | goto ohr_unlock; | ||
1461 | } | ||
1462 | |||
1463 | ms_id = _find_mpu_port_index(oh); | ||
1464 | if (!IS_ERR_VALUE(ms_id)) { | ||
1465 | oh->_mpu_port_index = ms_id; | ||
1466 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | ||
1467 | } else { | ||
1468 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; | ||
1469 | } | ||
1470 | |||
1471 | list_add_tail(&oh->node, &omap_hwmod_list); | ||
1472 | |||
1473 | oh->_state = _HWMOD_STATE_REGISTERED; | ||
1474 | |||
1475 | ret = 0; | ||
1476 | |||
1477 | ohr_unlock: | ||
1478 | mutex_unlock(&omap_hwmod_mutex); | ||
1479 | return ret; | ||
1480 | } | ||
1481 | |||
1482 | /** | ||
1483 | * omap_hwmod_lookup - look up a registered omap_hwmod by name | 1540 | * omap_hwmod_lookup - look up a registered omap_hwmod by name |
1484 | * @name: name of the omap_hwmod to look up | 1541 | * @name: name of the omap_hwmod to look up |
1485 | * | 1542 | * |
@@ -1493,9 +1550,7 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name) | |||
1493 | if (!name) | 1550 | if (!name) |
1494 | return NULL; | 1551 | return NULL; |
1495 | 1552 | ||
1496 | mutex_lock(&omap_hwmod_mutex); | ||
1497 | oh = _lookup(name); | 1553 | oh = _lookup(name); |
1498 | mutex_unlock(&omap_hwmod_mutex); | ||
1499 | 1554 | ||
1500 | return oh; | 1555 | return oh; |
1501 | } | 1556 | } |
@@ -1521,13 +1576,11 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), | |||
1521 | if (!fn) | 1576 | if (!fn) |
1522 | return -EINVAL; | 1577 | return -EINVAL; |
1523 | 1578 | ||
1524 | mutex_lock(&omap_hwmod_mutex); | ||
1525 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { | 1579 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { |
1526 | ret = (*fn)(temp_oh, data); | 1580 | ret = (*fn)(temp_oh, data); |
1527 | if (ret) | 1581 | if (ret) |
1528 | break; | 1582 | break; |
1529 | } | 1583 | } |
1530 | mutex_unlock(&omap_hwmod_mutex); | ||
1531 | 1584 | ||
1532 | return ret; | 1585 | return ret; |
1533 | } | 1586 | } |
@@ -1542,7 +1595,7 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), | |||
1542 | * listed in @ohs that are valid for this chip. Returns -EINVAL if | 1595 | * listed in @ohs that are valid for this chip. Returns -EINVAL if |
1543 | * omap_hwmod_init() has already been called or 0 otherwise. | 1596 | * omap_hwmod_init() has already been called or 0 otherwise. |
1544 | */ | 1597 | */ |
1545 | int omap_hwmod_init(struct omap_hwmod **ohs) | 1598 | int __init omap_hwmod_init(struct omap_hwmod **ohs) |
1546 | { | 1599 | { |
1547 | struct omap_hwmod *oh; | 1600 | struct omap_hwmod *oh; |
1548 | int r; | 1601 | int r; |
@@ -1558,8 +1611,8 @@ int omap_hwmod_init(struct omap_hwmod **ohs) | |||
1558 | oh = *ohs; | 1611 | oh = *ohs; |
1559 | while (oh) { | 1612 | while (oh) { |
1560 | if (omap_chip_is(oh->omap_chip)) { | 1613 | if (omap_chip_is(oh->omap_chip)) { |
1561 | r = omap_hwmod_register(oh); | 1614 | r = _register(oh); |
1562 | WARN(r, "omap_hwmod: %s: omap_hwmod_register returned " | 1615 | WARN(r, "omap_hwmod: %s: _register returned " |
1563 | "%d\n", oh->name, r); | 1616 | "%d\n", oh->name, r); |
1564 | } | 1617 | } |
1565 | oh = *++ohs; | 1618 | oh = *++ohs; |
@@ -1570,13 +1623,12 @@ int omap_hwmod_init(struct omap_hwmod **ohs) | |||
1570 | 1623 | ||
1571 | /** | 1624 | /** |
1572 | * omap_hwmod_late_init - do some post-clock framework initialization | 1625 | * omap_hwmod_late_init - do some post-clock framework initialization |
1573 | * @skip_setup_idle: if 1, do not idle hwmods in _setup() | ||
1574 | * | 1626 | * |
1575 | * Must be called after omap2_clk_init(). Resolves the struct clk names | 1627 | * Must be called after omap2_clk_init(). Resolves the struct clk names |
1576 | * to struct clk pointers for each registered omap_hwmod. Also calls | 1628 | * to struct clk pointers for each registered omap_hwmod. Also calls |
1577 | * _setup() on each hwmod. Returns 0. | 1629 | * _setup() on each hwmod. Returns 0. |
1578 | */ | 1630 | */ |
1579 | int omap_hwmod_late_init(u8 skip_setup_idle) | 1631 | int omap_hwmod_late_init(void) |
1580 | { | 1632 | { |
1581 | int r; | 1633 | int r; |
1582 | 1634 | ||
@@ -1588,36 +1640,7 @@ int omap_hwmod_late_init(u8 skip_setup_idle) | |||
1588 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", | 1640 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", |
1589 | MPU_INITIATOR_NAME); | 1641 | MPU_INITIATOR_NAME); |
1590 | 1642 | ||
1591 | if (skip_setup_idle) | 1643 | omap_hwmod_for_each(_setup, NULL); |
1592 | pr_debug("omap_hwmod: will leave hwmods enabled during setup\n"); | ||
1593 | |||
1594 | omap_hwmod_for_each(_setup, &skip_setup_idle); | ||
1595 | |||
1596 | return 0; | ||
1597 | } | ||
1598 | |||
1599 | /** | ||
1600 | * omap_hwmod_unregister - unregister an omap_hwmod | ||
1601 | * @oh: struct omap_hwmod * | ||
1602 | * | ||
1603 | * Unregisters a previously-registered omap_hwmod @oh. There's probably | ||
1604 | * no use case for this, so it is likely to be removed in a later version. | ||
1605 | * | ||
1606 | * XXX Free all of the bootmem-allocated structures here when that is | ||
1607 | * implemented. Make it clear that core code is the only code that is | ||
1608 | * expected to unregister modules. | ||
1609 | */ | ||
1610 | int omap_hwmod_unregister(struct omap_hwmod *oh) | ||
1611 | { | ||
1612 | if (!oh) | ||
1613 | return -EINVAL; | ||
1614 | |||
1615 | pr_debug("omap_hwmod: %s: unregistering\n", oh->name); | ||
1616 | |||
1617 | mutex_lock(&omap_hwmod_mutex); | ||
1618 | iounmap(oh->_mpu_rt_va); | ||
1619 | list_del(&oh->node); | ||
1620 | mutex_unlock(&omap_hwmod_mutex); | ||
1621 | 1644 | ||
1622 | return 0; | 1645 | return 0; |
1623 | } | 1646 | } |
@@ -1632,18 +1655,18 @@ int omap_hwmod_unregister(struct omap_hwmod *oh) | |||
1632 | int omap_hwmod_enable(struct omap_hwmod *oh) | 1655 | int omap_hwmod_enable(struct omap_hwmod *oh) |
1633 | { | 1656 | { |
1634 | int r; | 1657 | int r; |
1658 | unsigned long flags; | ||
1635 | 1659 | ||
1636 | if (!oh) | 1660 | if (!oh) |
1637 | return -EINVAL; | 1661 | return -EINVAL; |
1638 | 1662 | ||
1639 | mutex_lock(&oh->_mutex); | 1663 | spin_lock_irqsave(&oh->_lock, flags); |
1640 | r = _omap_hwmod_enable(oh); | 1664 | r = _enable(oh); |
1641 | mutex_unlock(&oh->_mutex); | 1665 | spin_unlock_irqrestore(&oh->_lock, flags); |
1642 | 1666 | ||
1643 | return r; | 1667 | return r; |
1644 | } | 1668 | } |
1645 | 1669 | ||
1646 | |||
1647 | /** | 1670 | /** |
1648 | * omap_hwmod_idle - idle an omap_hwmod | 1671 | * omap_hwmod_idle - idle an omap_hwmod |
1649 | * @oh: struct omap_hwmod * | 1672 | * @oh: struct omap_hwmod * |
@@ -1653,12 +1676,14 @@ int omap_hwmod_enable(struct omap_hwmod *oh) | |||
1653 | */ | 1676 | */ |
1654 | int omap_hwmod_idle(struct omap_hwmod *oh) | 1677 | int omap_hwmod_idle(struct omap_hwmod *oh) |
1655 | { | 1678 | { |
1679 | unsigned long flags; | ||
1680 | |||
1656 | if (!oh) | 1681 | if (!oh) |
1657 | return -EINVAL; | 1682 | return -EINVAL; |
1658 | 1683 | ||
1659 | mutex_lock(&oh->_mutex); | 1684 | spin_lock_irqsave(&oh->_lock, flags); |
1660 | _omap_hwmod_idle(oh); | 1685 | _idle(oh); |
1661 | mutex_unlock(&oh->_mutex); | 1686 | spin_unlock_irqrestore(&oh->_lock, flags); |
1662 | 1687 | ||
1663 | return 0; | 1688 | return 0; |
1664 | } | 1689 | } |
@@ -1673,12 +1698,14 @@ int omap_hwmod_idle(struct omap_hwmod *oh) | |||
1673 | */ | 1698 | */ |
1674 | int omap_hwmod_shutdown(struct omap_hwmod *oh) | 1699 | int omap_hwmod_shutdown(struct omap_hwmod *oh) |
1675 | { | 1700 | { |
1701 | unsigned long flags; | ||
1702 | |||
1676 | if (!oh) | 1703 | if (!oh) |
1677 | return -EINVAL; | 1704 | return -EINVAL; |
1678 | 1705 | ||
1679 | mutex_lock(&oh->_mutex); | 1706 | spin_lock_irqsave(&oh->_lock, flags); |
1680 | _shutdown(oh); | 1707 | _shutdown(oh); |
1681 | mutex_unlock(&oh->_mutex); | 1708 | spin_unlock_irqrestore(&oh->_lock, flags); |
1682 | 1709 | ||
1683 | return 0; | 1710 | return 0; |
1684 | } | 1711 | } |
@@ -1691,9 +1718,11 @@ int omap_hwmod_shutdown(struct omap_hwmod *oh) | |||
1691 | */ | 1718 | */ |
1692 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | 1719 | int omap_hwmod_enable_clocks(struct omap_hwmod *oh) |
1693 | { | 1720 | { |
1694 | mutex_lock(&oh->_mutex); | 1721 | unsigned long flags; |
1722 | |||
1723 | spin_lock_irqsave(&oh->_lock, flags); | ||
1695 | _enable_clocks(oh); | 1724 | _enable_clocks(oh); |
1696 | mutex_unlock(&oh->_mutex); | 1725 | spin_unlock_irqrestore(&oh->_lock, flags); |
1697 | 1726 | ||
1698 | return 0; | 1727 | return 0; |
1699 | } | 1728 | } |
@@ -1706,9 +1735,11 @@ int omap_hwmod_enable_clocks(struct omap_hwmod *oh) | |||
1706 | */ | 1735 | */ |
1707 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) | 1736 | int omap_hwmod_disable_clocks(struct omap_hwmod *oh) |
1708 | { | 1737 | { |
1709 | mutex_lock(&oh->_mutex); | 1738 | unsigned long flags; |
1739 | |||
1740 | spin_lock_irqsave(&oh->_lock, flags); | ||
1710 | _disable_clocks(oh); | 1741 | _disable_clocks(oh); |
1711 | mutex_unlock(&oh->_mutex); | 1742 | spin_unlock_irqrestore(&oh->_lock, flags); |
1712 | 1743 | ||
1713 | return 0; | 1744 | return 0; |
1714 | } | 1745 | } |
@@ -1752,13 +1783,14 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh) | |||
1752 | int omap_hwmod_reset(struct omap_hwmod *oh) | 1783 | int omap_hwmod_reset(struct omap_hwmod *oh) |
1753 | { | 1784 | { |
1754 | int r; | 1785 | int r; |
1786 | unsigned long flags; | ||
1755 | 1787 | ||
1756 | if (!oh) | 1788 | if (!oh) |
1757 | return -EINVAL; | 1789 | return -EINVAL; |
1758 | 1790 | ||
1759 | mutex_lock(&oh->_mutex); | 1791 | spin_lock_irqsave(&oh->_lock, flags); |
1760 | r = _reset(oh); | 1792 | r = _reset(oh); |
1761 | mutex_unlock(&oh->_mutex); | 1793 | spin_unlock_irqrestore(&oh->_lock, flags); |
1762 | 1794 | ||
1763 | return r; | 1795 | return r; |
1764 | } | 1796 | } |
@@ -1955,13 +1987,18 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, | |||
1955 | */ | 1987 | */ |
1956 | int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | 1988 | int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) |
1957 | { | 1989 | { |
1990 | unsigned long flags; | ||
1991 | u32 v; | ||
1992 | |||
1958 | if (!oh->class->sysc || | 1993 | if (!oh->class->sysc || |
1959 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 1994 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
1960 | return -EINVAL; | 1995 | return -EINVAL; |
1961 | 1996 | ||
1962 | mutex_lock(&oh->_mutex); | 1997 | spin_lock_irqsave(&oh->_lock, flags); |
1963 | _enable_wakeup(oh); | 1998 | v = oh->_sysc_cache; |
1964 | mutex_unlock(&oh->_mutex); | 1999 | _enable_wakeup(oh, &v); |
2000 | _write_sysconfig(v, oh); | ||
2001 | spin_unlock_irqrestore(&oh->_lock, flags); | ||
1965 | 2002 | ||
1966 | return 0; | 2003 | return 0; |
1967 | } | 2004 | } |
@@ -1980,13 +2017,18 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) | |||
1980 | */ | 2017 | */ |
1981 | int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | 2018 | int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) |
1982 | { | 2019 | { |
2020 | unsigned long flags; | ||
2021 | u32 v; | ||
2022 | |||
1983 | if (!oh->class->sysc || | 2023 | if (!oh->class->sysc || |
1984 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) | 2024 | !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) |
1985 | return -EINVAL; | 2025 | return -EINVAL; |
1986 | 2026 | ||
1987 | mutex_lock(&oh->_mutex); | 2027 | spin_lock_irqsave(&oh->_lock, flags); |
1988 | _disable_wakeup(oh); | 2028 | v = oh->_sysc_cache; |
1989 | mutex_unlock(&oh->_mutex); | 2029 | _disable_wakeup(oh, &v); |
2030 | _write_sysconfig(v, oh); | ||
2031 | spin_unlock_irqrestore(&oh->_lock, flags); | ||
1990 | 2032 | ||
1991 | return 0; | 2033 | return 0; |
1992 | } | 2034 | } |
@@ -2006,13 +2048,14 @@ int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) | |||
2006 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) | 2048 | int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) |
2007 | { | 2049 | { |
2008 | int ret; | 2050 | int ret; |
2051 | unsigned long flags; | ||
2009 | 2052 | ||
2010 | if (!oh) | 2053 | if (!oh) |
2011 | return -EINVAL; | 2054 | return -EINVAL; |
2012 | 2055 | ||
2013 | mutex_lock(&oh->_mutex); | 2056 | spin_lock_irqsave(&oh->_lock, flags); |
2014 | ret = _assert_hardreset(oh, name); | 2057 | ret = _assert_hardreset(oh, name); |
2015 | mutex_unlock(&oh->_mutex); | 2058 | spin_unlock_irqrestore(&oh->_lock, flags); |
2016 | 2059 | ||
2017 | return ret; | 2060 | return ret; |
2018 | } | 2061 | } |
@@ -2032,13 +2075,14 @@ int omap_hwmod_assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
2032 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) | 2075 | int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) |
2033 | { | 2076 | { |
2034 | int ret; | 2077 | int ret; |
2078 | unsigned long flags; | ||
2035 | 2079 | ||
2036 | if (!oh) | 2080 | if (!oh) |
2037 | return -EINVAL; | 2081 | return -EINVAL; |
2038 | 2082 | ||
2039 | mutex_lock(&oh->_mutex); | 2083 | spin_lock_irqsave(&oh->_lock, flags); |
2040 | ret = _deassert_hardreset(oh, name); | 2084 | ret = _deassert_hardreset(oh, name); |
2041 | mutex_unlock(&oh->_mutex); | 2085 | spin_unlock_irqrestore(&oh->_lock, flags); |
2042 | 2086 | ||
2043 | return ret; | 2087 | return ret; |
2044 | } | 2088 | } |
@@ -2057,13 +2101,14 @@ int omap_hwmod_deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
2057 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) | 2101 | int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) |
2058 | { | 2102 | { |
2059 | int ret; | 2103 | int ret; |
2104 | unsigned long flags; | ||
2060 | 2105 | ||
2061 | if (!oh) | 2106 | if (!oh) |
2062 | return -EINVAL; | 2107 | return -EINVAL; |
2063 | 2108 | ||
2064 | mutex_lock(&oh->_mutex); | 2109 | spin_lock_irqsave(&oh->_lock, flags); |
2065 | ret = _read_hardreset(oh, name); | 2110 | ret = _read_hardreset(oh, name); |
2066 | mutex_unlock(&oh->_mutex); | 2111 | spin_unlock_irqrestore(&oh->_lock, flags); |
2067 | 2112 | ||
2068 | return ret; | 2113 | return ret; |
2069 | } | 2114 | } |
@@ -2075,9 +2120,8 @@ int omap_hwmod_read_hardreset(struct omap_hwmod *oh, const char *name) | |||
2075 | * @fn: callback function pointer to call for each hwmod in class @classname | 2120 | * @fn: callback function pointer to call for each hwmod in class @classname |
2076 | * @user: arbitrary context data to pass to the callback function | 2121 | * @user: arbitrary context data to pass to the callback function |
2077 | * | 2122 | * |
2078 | * For each omap_hwmod of class @classname, call @fn. Takes | 2123 | * For each omap_hwmod of class @classname, call @fn. |
2079 | * omap_hwmod_mutex to prevent the hwmod list from changing during the | 2124 | * If the callback function returns something other than |
2080 | * iteration. If the callback function returns something other than | ||
2081 | * zero, the iterator is terminated, and the callback function's return | 2125 | * zero, the iterator is terminated, and the callback function's return |
2082 | * value is passed back to the caller. Returns 0 upon success, -EINVAL | 2126 | * value is passed back to the caller. Returns 0 upon success, -EINVAL |
2083 | * if @classname or @fn are NULL, or passes back the error code from @fn. | 2127 | * if @classname or @fn are NULL, or passes back the error code from @fn. |
@@ -2096,8 +2140,6 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2096 | pr_debug("omap_hwmod: %s: looking for modules of class %s\n", | 2140 | pr_debug("omap_hwmod: %s: looking for modules of class %s\n", |
2097 | __func__, classname); | 2141 | __func__, classname); |
2098 | 2142 | ||
2099 | mutex_lock(&omap_hwmod_mutex); | ||
2100 | |||
2101 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { | 2143 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { |
2102 | if (!strcmp(temp_oh->class->name, classname)) { | 2144 | if (!strcmp(temp_oh->class->name, classname)) { |
2103 | pr_debug("omap_hwmod: %s: %s: calling callback fn\n", | 2145 | pr_debug("omap_hwmod: %s: %s: calling callback fn\n", |
@@ -2108,8 +2150,6 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2108 | } | 2150 | } |
2109 | } | 2151 | } |
2110 | 2152 | ||
2111 | mutex_unlock(&omap_hwmod_mutex); | ||
2112 | |||
2113 | if (ret) | 2153 | if (ret) |
2114 | pr_debug("omap_hwmod: %s: iterator terminated early: %d\n", | 2154 | pr_debug("omap_hwmod: %s: iterator terminated early: %d\n", |
2115 | __func__, ret); | 2155 | __func__, ret); |
@@ -2117,3 +2157,64 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2117 | return ret; | 2157 | return ret; |
2118 | } | 2158 | } |
2119 | 2159 | ||
2160 | /** | ||
2161 | * omap_hwmod_set_postsetup_state - set the post-_setup() state for this hwmod | ||
2162 | * @oh: struct omap_hwmod * | ||
2163 | * @state: state that _setup() should leave the hwmod in | ||
2164 | * | ||
2165 | * Sets the hwmod state that @oh will enter at the end of _setup() (called by | ||
2166 | * omap_hwmod_late_init()). Only valid to call between calls to | ||
2167 | * omap_hwmod_init() and omap_hwmod_late_init(). Returns 0 upon success or | ||
2168 | * -EINVAL if there is a problem with the arguments or if the hwmod is | ||
2169 | * in the wrong state. | ||
2170 | */ | ||
2171 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | ||
2172 | { | ||
2173 | int ret; | ||
2174 | unsigned long flags; | ||
2175 | |||
2176 | if (!oh) | ||
2177 | return -EINVAL; | ||
2178 | |||
2179 | if (state != _HWMOD_STATE_DISABLED && | ||
2180 | state != _HWMOD_STATE_ENABLED && | ||
2181 | state != _HWMOD_STATE_IDLE) | ||
2182 | return -EINVAL; | ||
2183 | |||
2184 | spin_lock_irqsave(&oh->_lock, flags); | ||
2185 | |||
2186 | if (oh->_state != _HWMOD_STATE_REGISTERED) { | ||
2187 | ret = -EINVAL; | ||
2188 | goto ohsps_unlock; | ||
2189 | } | ||
2190 | |||
2191 | oh->_postsetup_state = state; | ||
2192 | ret = 0; | ||
2193 | |||
2194 | ohsps_unlock: | ||
2195 | spin_unlock_irqrestore(&oh->_lock, flags); | ||
2196 | |||
2197 | return ret; | ||
2198 | } | ||
2199 | |||
2200 | /** | ||
2201 | * omap_hwmod_get_context_loss_count - get lost context count | ||
2202 | * @oh: struct omap_hwmod * | ||
2203 | * | ||
2204 | * Query the powerdomain of of @oh to get the context loss | ||
2205 | * count for this device. | ||
2206 | * | ||
2207 | * Returns the context loss count of the powerdomain assocated with @oh | ||
2208 | * upon success, or zero if no powerdomain exists for @oh. | ||
2209 | */ | ||
2210 | u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) | ||
2211 | { | ||
2212 | struct powerdomain *pwrdm; | ||
2213 | int ret = 0; | ||
2214 | |||
2215 | pwrdm = omap_hwmod_get_pwrdm(oh); | ||
2216 | if (pwrdm) | ||
2217 | ret = pwrdm_get_context_loss_count(pwrdm); | ||
2218 | |||
2219 | return ret; | ||
2220 | } | ||