diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 333 |
1 files changed, 242 insertions, 91 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index e282e35769fd..e03429453ce7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * omap_hwmod implementation for OMAP2/3/4 | 2 | * omap_hwmod implementation for OMAP2/3/4 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Nokia Corporation | 4 | * Copyright (C) 2009-2011 Nokia Corporation |
5 | * | 5 | * |
6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
7 | * | 7 | * |
@@ -162,9 +162,6 @@ static LIST_HEAD(omap_hwmod_list); | |||
162 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ | 162 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ |
163 | static struct omap_hwmod *mpu_oh; | 163 | static struct omap_hwmod *mpu_oh; |
164 | 164 | ||
165 | /* inited: 0 if omap_hwmod_init() has not yet been called; 1 otherwise */ | ||
166 | static u8 inited; | ||
167 | |||
168 | 165 | ||
169 | /* Private functions */ | 166 | /* Private functions */ |
170 | 167 | ||
@@ -373,7 +370,7 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, | |||
373 | } | 370 | } |
374 | 371 | ||
375 | autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift; | 372 | autoidle_shift = oh->class->sysc->sysc_fields->autoidle_shift; |
376 | autoidle_mask = (0x3 << autoidle_shift); | 373 | autoidle_mask = (0x1 << autoidle_shift); |
377 | 374 | ||
378 | *v &= ~autoidle_mask; | 375 | *v &= ~autoidle_mask; |
379 | *v |= autoidle << autoidle_shift; | 376 | *v |= autoidle << autoidle_shift; |
@@ -460,14 +457,18 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
460 | * will be accessed by a particular initiator (e.g., if a module will | 457 | * will be accessed by a particular initiator (e.g., if a module will |
461 | * be accessed by the IVA, there should be a sleepdep between the IVA | 458 | * be accessed by the IVA, there should be a sleepdep between the IVA |
462 | * initiator and the module). Only applies to modules in smart-idle | 459 | * initiator and the module). Only applies to modules in smart-idle |
463 | * mode. Returns -EINVAL upon error or passes along | 460 | * mode. If the clockdomain is marked as not needing autodeps, return |
464 | * clkdm_add_sleepdep() value upon success. | 461 | * 0 without doing anything. Otherwise, returns -EINVAL upon error or |
462 | * passes along clkdm_add_sleepdep() value upon success. | ||
465 | */ | 463 | */ |
466 | static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | 464 | static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) |
467 | { | 465 | { |
468 | if (!oh->_clk) | 466 | if (!oh->_clk) |
469 | return -EINVAL; | 467 | return -EINVAL; |
470 | 468 | ||
469 | if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS) | ||
470 | return 0; | ||
471 | |||
471 | return clkdm_add_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); | 472 | return clkdm_add_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); |
472 | } | 473 | } |
473 | 474 | ||
@@ -480,14 +481,18 @@ static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | |||
480 | * be accessed by a particular initiator (e.g., if a module will not | 481 | * be accessed by a particular initiator (e.g., if a module will not |
481 | * be accessed by the IVA, there should be no sleepdep between the IVA | 482 | * be accessed by the IVA, there should be no sleepdep between the IVA |
482 | * initiator and the module). Only applies to modules in smart-idle | 483 | * initiator and the module). Only applies to modules in smart-idle |
483 | * mode. Returns -EINVAL upon error or passes along | 484 | * mode. If the clockdomain is marked as not needing autodeps, return |
484 | * clkdm_del_sleepdep() value upon success. | 485 | * 0 without doing anything. Returns -EINVAL upon error or passes |
486 | * along clkdm_del_sleepdep() value upon success. | ||
485 | */ | 487 | */ |
486 | static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | 488 | static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) |
487 | { | 489 | { |
488 | if (!oh->_clk) | 490 | if (!oh->_clk) |
489 | return -EINVAL; | 491 | return -EINVAL; |
490 | 492 | ||
493 | if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS) | ||
494 | return 0; | ||
495 | |||
491 | return clkdm_del_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); | 496 | return clkdm_del_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); |
492 | } | 497 | } |
493 | 498 | ||
@@ -904,18 +909,16 @@ static struct omap_hwmod *_lookup(const char *name) | |||
904 | * @oh: struct omap_hwmod * | 909 | * @oh: struct omap_hwmod * |
905 | * @data: not used; pass NULL | 910 | * @data: not used; pass NULL |
906 | * | 911 | * |
907 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). | 912 | * Called by omap_hwmod_setup_*() (after omap2_clk_init()). |
908 | * Resolves all clock names embedded in the hwmod. Returns -EINVAL if | 913 | * Resolves all clock names embedded in the hwmod. Returns 0 on |
909 | * the omap_hwmod has not yet been registered or if the clocks have | 914 | * success, or a negative error code on failure. |
910 | * already been initialized, 0 on success, or a non-zero error on | ||
911 | * failure. | ||
912 | */ | 915 | */ |
913 | static int _init_clocks(struct omap_hwmod *oh, void *data) | 916 | static int _init_clocks(struct omap_hwmod *oh, void *data) |
914 | { | 917 | { |
915 | int ret = 0; | 918 | int ret = 0; |
916 | 919 | ||
917 | if (!oh || (oh->_state != _HWMOD_STATE_REGISTERED)) | 920 | if (oh->_state != _HWMOD_STATE_REGISTERED) |
918 | return -EINVAL; | 921 | return 0; |
919 | 922 | ||
920 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); | 923 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); |
921 | 924 | ||
@@ -926,7 +929,7 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
926 | if (!ret) | 929 | if (!ret) |
927 | oh->_state = _HWMOD_STATE_CLKS_INITED; | 930 | oh->_state = _HWMOD_STATE_CLKS_INITED; |
928 | 931 | ||
929 | return 0; | 932 | return ret; |
930 | } | 933 | } |
931 | 934 | ||
932 | /** | 935 | /** |
@@ -972,25 +975,29 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
972 | } | 975 | } |
973 | 976 | ||
974 | /** | 977 | /** |
975 | * _lookup_hardreset - return the register bit shift for this hwmod/reset line | 978 | * _lookup_hardreset - fill register bit info for this hwmod/reset line |
976 | * @oh: struct omap_hwmod * | 979 | * @oh: struct omap_hwmod * |
977 | * @name: name of the reset line in the context of this hwmod | 980 | * @name: name of the reset line in the context of this hwmod |
981 | * @ohri: struct omap_hwmod_rst_info * that this function will fill in | ||
978 | * | 982 | * |
979 | * Return the bit position of the reset line that match the | 983 | * Return the bit position of the reset line that match the |
980 | * input name. Return -ENOENT if not found. | 984 | * input name. Return -ENOENT if not found. |
981 | */ | 985 | */ |
982 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name) | 986 | static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name, |
987 | struct omap_hwmod_rst_info *ohri) | ||
983 | { | 988 | { |
984 | int i; | 989 | int i; |
985 | 990 | ||
986 | for (i = 0; i < oh->rst_lines_cnt; i++) { | 991 | for (i = 0; i < oh->rst_lines_cnt; i++) { |
987 | const char *rst_line = oh->rst_lines[i].name; | 992 | const char *rst_line = oh->rst_lines[i].name; |
988 | if (!strcmp(rst_line, name)) { | 993 | if (!strcmp(rst_line, name)) { |
989 | u8 shift = oh->rst_lines[i].rst_shift; | 994 | ohri->rst_shift = oh->rst_lines[i].rst_shift; |
990 | pr_debug("omap_hwmod: %s: _lookup_hardreset: %s: %d\n", | 995 | ohri->st_shift = oh->rst_lines[i].st_shift; |
991 | oh->name, rst_line, shift); | 996 | pr_debug("omap_hwmod: %s: %s: %s: rst %d st %d\n", |
997 | oh->name, __func__, rst_line, ohri->rst_shift, | ||
998 | ohri->st_shift); | ||
992 | 999 | ||
993 | return shift; | 1000 | return 0; |
994 | } | 1001 | } |
995 | } | 1002 | } |
996 | 1003 | ||
@@ -1009,21 +1016,22 @@ static u8 _lookup_hardreset(struct omap_hwmod *oh, const char *name) | |||
1009 | */ | 1016 | */ |
1010 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | 1017 | static int _assert_hardreset(struct omap_hwmod *oh, const char *name) |
1011 | { | 1018 | { |
1012 | u8 shift; | 1019 | struct omap_hwmod_rst_info ohri; |
1020 | u8 ret; | ||
1013 | 1021 | ||
1014 | if (!oh) | 1022 | if (!oh) |
1015 | return -EINVAL; | 1023 | return -EINVAL; |
1016 | 1024 | ||
1017 | shift = _lookup_hardreset(oh, name); | 1025 | ret = _lookup_hardreset(oh, name, &ohri); |
1018 | if (IS_ERR_VALUE(shift)) | 1026 | if (IS_ERR_VALUE(ret)) |
1019 | return shift; | 1027 | return ret; |
1020 | 1028 | ||
1021 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 1029 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) |
1022 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, | 1030 | return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs, |
1023 | shift); | 1031 | ohri.rst_shift); |
1024 | else if (cpu_is_omap44xx()) | 1032 | else if (cpu_is_omap44xx()) |
1025 | return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, | 1033 | return omap4_prm_assert_hardreset(oh->prcm.omap4.rstctrl_reg, |
1026 | shift); | 1034 | ohri.rst_shift); |
1027 | else | 1035 | else |
1028 | return -EINVAL; | 1036 | return -EINVAL; |
1029 | } | 1037 | } |
@@ -1040,29 +1048,34 @@ static int _assert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1040 | */ | 1048 | */ |
1041 | static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | 1049 | static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) |
1042 | { | 1050 | { |
1043 | u8 shift; | 1051 | struct omap_hwmod_rst_info ohri; |
1044 | int r; | 1052 | int ret; |
1045 | 1053 | ||
1046 | if (!oh) | 1054 | if (!oh) |
1047 | return -EINVAL; | 1055 | return -EINVAL; |
1048 | 1056 | ||
1049 | shift = _lookup_hardreset(oh, name); | 1057 | ret = _lookup_hardreset(oh, name, &ohri); |
1050 | if (IS_ERR_VALUE(shift)) | 1058 | if (IS_ERR_VALUE(ret)) |
1051 | return shift; | 1059 | return ret; |
1052 | 1060 | ||
1053 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 1061 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { |
1054 | r = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, | 1062 | ret = omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs, |
1055 | shift); | 1063 | ohri.rst_shift, |
1056 | else if (cpu_is_omap44xx()) | 1064 | ohri.st_shift); |
1057 | r = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, | 1065 | } else if (cpu_is_omap44xx()) { |
1058 | shift); | 1066 | if (ohri.st_shift) |
1059 | else | 1067 | pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n", |
1068 | oh->name, name); | ||
1069 | ret = omap4_prm_deassert_hardreset(oh->prcm.omap4.rstctrl_reg, | ||
1070 | ohri.rst_shift); | ||
1071 | } else { | ||
1060 | return -EINVAL; | 1072 | return -EINVAL; |
1073 | } | ||
1061 | 1074 | ||
1062 | if (r == -EBUSY) | 1075 | if (ret == -EBUSY) |
1063 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); | 1076 | pr_warning("omap_hwmod: %s: failed to hardreset\n", oh->name); |
1064 | 1077 | ||
1065 | return r; | 1078 | return ret; |
1066 | } | 1079 | } |
1067 | 1080 | ||
1068 | /** | 1081 | /** |
@@ -1075,21 +1088,22 @@ static int _deassert_hardreset(struct omap_hwmod *oh, const char *name) | |||
1075 | */ | 1088 | */ |
1076 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) | 1089 | static int _read_hardreset(struct omap_hwmod *oh, const char *name) |
1077 | { | 1090 | { |
1078 | u8 shift; | 1091 | struct omap_hwmod_rst_info ohri; |
1092 | u8 ret; | ||
1079 | 1093 | ||
1080 | if (!oh) | 1094 | if (!oh) |
1081 | return -EINVAL; | 1095 | return -EINVAL; |
1082 | 1096 | ||
1083 | shift = _lookup_hardreset(oh, name); | 1097 | ret = _lookup_hardreset(oh, name, &ohri); |
1084 | if (IS_ERR_VALUE(shift)) | 1098 | if (IS_ERR_VALUE(ret)) |
1085 | return shift; | 1099 | return ret; |
1086 | 1100 | ||
1087 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { | 1101 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) { |
1088 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, | 1102 | return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs, |
1089 | shift); | 1103 | ohri.st_shift); |
1090 | } else if (cpu_is_omap44xx()) { | 1104 | } else if (cpu_is_omap44xx()) { |
1091 | return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, | 1105 | return omap4_prm_is_hardreset_asserted(oh->prcm.omap4.rstctrl_reg, |
1092 | shift); | 1106 | ohri.rst_shift); |
1093 | } else { | 1107 | } else { |
1094 | return -EINVAL; | 1108 | return -EINVAL; |
1095 | } | 1109 | } |
@@ -1230,7 +1244,9 @@ static int _enable(struct omap_hwmod *oh) | |||
1230 | _deassert_hardreset(oh, oh->rst_lines[0].name); | 1244 | _deassert_hardreset(oh, oh->rst_lines[0].name); |
1231 | 1245 | ||
1232 | /* Mux pins for device runtime if populated */ | 1246 | /* Mux pins for device runtime if populated */ |
1233 | if (oh->mux) | 1247 | if (oh->mux && (!oh->mux->enabled || |
1248 | ((oh->_state == _HWMOD_STATE_IDLE) && | ||
1249 | oh->mux->pads_dynamic))) | ||
1234 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); | 1250 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); |
1235 | 1251 | ||
1236 | _add_initiator_dep(oh, mpu_oh); | 1252 | _add_initiator_dep(oh, mpu_oh); |
@@ -1279,7 +1295,7 @@ static int _idle(struct omap_hwmod *oh) | |||
1279 | _disable_clocks(oh); | 1295 | _disable_clocks(oh); |
1280 | 1296 | ||
1281 | /* Mux pins for device idle if populated */ | 1297 | /* Mux pins for device idle if populated */ |
1282 | if (oh->mux) | 1298 | if (oh->mux && oh->mux->pads_dynamic) |
1283 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); | 1299 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); |
1284 | 1300 | ||
1285 | oh->_state = _HWMOD_STATE_IDLE; | 1301 | oh->_state = _HWMOD_STATE_IDLE; |
@@ -1288,6 +1304,42 @@ static int _idle(struct omap_hwmod *oh) | |||
1288 | } | 1304 | } |
1289 | 1305 | ||
1290 | /** | 1306 | /** |
1307 | * omap_hwmod_set_ocp_autoidle - set the hwmod's OCP autoidle bit | ||
1308 | * @oh: struct omap_hwmod * | ||
1309 | * @autoidle: desired AUTOIDLE bitfield value (0 or 1) | ||
1310 | * | ||
1311 | * Sets the IP block's OCP autoidle bit in hardware, and updates our | ||
1312 | * local copy. Intended to be used by drivers that require | ||
1313 | * direct manipulation of the AUTOIDLE bits. | ||
1314 | * Returns -EINVAL if @oh is null or is not in the ENABLED state, or passes | ||
1315 | * along the return value from _set_module_autoidle(). | ||
1316 | * | ||
1317 | * Any users of this function should be scrutinized carefully. | ||
1318 | */ | ||
1319 | int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle) | ||
1320 | { | ||
1321 | u32 v; | ||
1322 | int retval = 0; | ||
1323 | unsigned long flags; | ||
1324 | |||
1325 | if (!oh || oh->_state != _HWMOD_STATE_ENABLED) | ||
1326 | return -EINVAL; | ||
1327 | |||
1328 | spin_lock_irqsave(&oh->_lock, flags); | ||
1329 | |||
1330 | v = oh->_sysc_cache; | ||
1331 | |||
1332 | retval = _set_module_autoidle(oh, autoidle, &v); | ||
1333 | |||
1334 | if (!retval) | ||
1335 | _write_sysconfig(v, oh); | ||
1336 | |||
1337 | spin_unlock_irqrestore(&oh->_lock, flags); | ||
1338 | |||
1339 | return retval; | ||
1340 | } | ||
1341 | |||
1342 | /** | ||
1291 | * _shutdown - shutdown an omap_hwmod | 1343 | * _shutdown - shutdown an omap_hwmod |
1292 | * @oh: struct omap_hwmod * | 1344 | * @oh: struct omap_hwmod * |
1293 | * | 1345 | * |
@@ -1354,14 +1406,16 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1354 | * @oh: struct omap_hwmod * | 1406 | * @oh: struct omap_hwmod * |
1355 | * | 1407 | * |
1356 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 1408 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh |
1357 | * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the | 1409 | * OCP_SYSCONFIG register. Returns 0. |
1358 | * wrong state or returns 0. | ||
1359 | */ | 1410 | */ |
1360 | static int _setup(struct omap_hwmod *oh, void *data) | 1411 | static int _setup(struct omap_hwmod *oh, void *data) |
1361 | { | 1412 | { |
1362 | int i, r; | 1413 | int i, r; |
1363 | u8 postsetup_state; | 1414 | u8 postsetup_state; |
1364 | 1415 | ||
1416 | if (oh->_state != _HWMOD_STATE_CLKS_INITED) | ||
1417 | return 0; | ||
1418 | |||
1365 | /* Set iclk autoidle mode */ | 1419 | /* Set iclk autoidle mode */ |
1366 | if (oh->slaves_cnt > 0) { | 1420 | if (oh->slaves_cnt > 0) { |
1367 | for (i = 0; i < oh->slaves_cnt; i++) { | 1421 | for (i = 0; i < oh->slaves_cnt; i++) { |
@@ -1455,7 +1509,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1455 | */ | 1509 | */ |
1456 | static int __init _register(struct omap_hwmod *oh) | 1510 | static int __init _register(struct omap_hwmod *oh) |
1457 | { | 1511 | { |
1458 | int ret, ms_id; | 1512 | int ms_id; |
1459 | 1513 | ||
1460 | if (!oh || !oh->name || !oh->class || !oh->class->name || | 1514 | if (!oh || !oh->name || !oh->class || !oh->class->name || |
1461 | (oh->_state != _HWMOD_STATE_UNKNOWN)) | 1515 | (oh->_state != _HWMOD_STATE_UNKNOWN)) |
@@ -1467,12 +1521,10 @@ static int __init _register(struct omap_hwmod *oh) | |||
1467 | return -EEXIST; | 1521 | return -EEXIST; |
1468 | 1522 | ||
1469 | ms_id = _find_mpu_port_index(oh); | 1523 | ms_id = _find_mpu_port_index(oh); |
1470 | if (!IS_ERR_VALUE(ms_id)) { | 1524 | if (!IS_ERR_VALUE(ms_id)) |
1471 | oh->_mpu_port_index = ms_id; | 1525 | oh->_mpu_port_index = ms_id; |
1472 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | 1526 | else |
1473 | } else { | ||
1474 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; | 1527 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; |
1475 | } | ||
1476 | 1528 | ||
1477 | list_add_tail(&oh->node, &omap_hwmod_list); | 1529 | list_add_tail(&oh->node, &omap_hwmod_list); |
1478 | 1530 | ||
@@ -1480,9 +1532,14 @@ static int __init _register(struct omap_hwmod *oh) | |||
1480 | 1532 | ||
1481 | oh->_state = _HWMOD_STATE_REGISTERED; | 1533 | oh->_state = _HWMOD_STATE_REGISTERED; |
1482 | 1534 | ||
1483 | ret = 0; | 1535 | /* |
1536 | * XXX Rather than doing a strcmp(), this should test a flag | ||
1537 | * set in the hwmod data, inserted by the autogenerator code. | ||
1538 | */ | ||
1539 | if (!strcmp(oh->name, MPU_INITIATOR_NAME)) | ||
1540 | mpu_oh = oh; | ||
1484 | 1541 | ||
1485 | return ret; | 1542 | return 0; |
1486 | } | 1543 | } |
1487 | 1544 | ||
1488 | 1545 | ||
@@ -1585,65 +1642,132 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), | |||
1585 | return ret; | 1642 | return ret; |
1586 | } | 1643 | } |
1587 | 1644 | ||
1588 | |||
1589 | /** | 1645 | /** |
1590 | * omap_hwmod_init - init omap_hwmod code and register hwmods | 1646 | * omap_hwmod_register - register an array of hwmods |
1591 | * @ohs: pointer to an array of omap_hwmods to register | 1647 | * @ohs: pointer to an array of omap_hwmods to register |
1592 | * | 1648 | * |
1593 | * Intended to be called early in boot before the clock framework is | 1649 | * Intended to be called early in boot before the clock framework is |
1594 | * initialized. If @ohs is not null, will register all omap_hwmods | 1650 | * initialized. If @ohs is not null, will register all omap_hwmods |
1595 | * listed in @ohs that are valid for this chip. Returns -EINVAL if | 1651 | * listed in @ohs that are valid for this chip. Returns 0. |
1596 | * omap_hwmod_init() has already been called or 0 otherwise. | ||
1597 | */ | 1652 | */ |
1598 | int __init omap_hwmod_init(struct omap_hwmod **ohs) | 1653 | int __init omap_hwmod_register(struct omap_hwmod **ohs) |
1654 | { | ||
1655 | int r, i; | ||
1656 | |||
1657 | if (!ohs) | ||
1658 | return 0; | ||
1659 | |||
1660 | i = 0; | ||
1661 | do { | ||
1662 | if (!omap_chip_is(ohs[i]->omap_chip)) | ||
1663 | continue; | ||
1664 | |||
1665 | r = _register(ohs[i]); | ||
1666 | WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, | ||
1667 | r); | ||
1668 | } while (ohs[++i]); | ||
1669 | |||
1670 | return 0; | ||
1671 | } | ||
1672 | |||
1673 | /* | ||
1674 | * _populate_mpu_rt_base - populate the virtual address for a hwmod | ||
1675 | * | ||
1676 | * Must be called only from omap_hwmod_setup_*() so ioremap works properly. | ||
1677 | * Assumes the caller takes care of locking if needed. | ||
1678 | */ | ||
1679 | static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) | ||
1680 | { | ||
1681 | if (oh->_state != _HWMOD_STATE_REGISTERED) | ||
1682 | return 0; | ||
1683 | |||
1684 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
1685 | return 0; | ||
1686 | |||
1687 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | ||
1688 | if (!oh->_mpu_rt_va) | ||
1689 | pr_warning("omap_hwmod: %s found no _mpu_rt_va for %s\n", | ||
1690 | __func__, oh->name); | ||
1691 | |||
1692 | return 0; | ||
1693 | } | ||
1694 | |||
1695 | /** | ||
1696 | * omap_hwmod_setup_one - set up a single hwmod | ||
1697 | * @oh_name: const char * name of the already-registered hwmod to set up | ||
1698 | * | ||
1699 | * Must be called after omap2_clk_init(). Resolves the struct clk | ||
1700 | * names to struct clk pointers for each registered omap_hwmod. Also | ||
1701 | * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon | ||
1702 | * success. | ||
1703 | */ | ||
1704 | int __init omap_hwmod_setup_one(const char *oh_name) | ||
1599 | { | 1705 | { |
1600 | struct omap_hwmod *oh; | 1706 | struct omap_hwmod *oh; |
1601 | int r; | 1707 | int r; |
1602 | 1708 | ||
1603 | if (inited) | 1709 | pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__); |
1710 | |||
1711 | if (!mpu_oh) { | ||
1712 | pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n", | ||
1713 | oh_name, MPU_INITIATOR_NAME); | ||
1604 | return -EINVAL; | 1714 | return -EINVAL; |
1715 | } | ||
1605 | 1716 | ||
1606 | inited = 1; | 1717 | oh = _lookup(oh_name); |
1718 | if (!oh) { | ||
1719 | WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); | ||
1720 | return -EINVAL; | ||
1721 | } | ||
1607 | 1722 | ||
1608 | if (!ohs) | 1723 | if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) |
1609 | return 0; | 1724 | omap_hwmod_setup_one(MPU_INITIATOR_NAME); |
1610 | 1725 | ||
1611 | oh = *ohs; | 1726 | r = _populate_mpu_rt_base(oh, NULL); |
1612 | while (oh) { | 1727 | if (IS_ERR_VALUE(r)) { |
1613 | if (omap_chip_is(oh->omap_chip)) { | 1728 | WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name); |
1614 | r = _register(oh); | 1729 | return -EINVAL; |
1615 | WARN(r, "omap_hwmod: %s: _register returned " | ||
1616 | "%d\n", oh->name, r); | ||
1617 | } | ||
1618 | oh = *++ohs; | ||
1619 | } | 1730 | } |
1620 | 1731 | ||
1732 | r = _init_clocks(oh, NULL); | ||
1733 | if (IS_ERR_VALUE(r)) { | ||
1734 | WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name); | ||
1735 | return -EINVAL; | ||
1736 | } | ||
1737 | |||
1738 | _setup(oh, NULL); | ||
1739 | |||
1621 | return 0; | 1740 | return 0; |
1622 | } | 1741 | } |
1623 | 1742 | ||
1624 | /** | 1743 | /** |
1625 | * omap_hwmod_late_init - do some post-clock framework initialization | 1744 | * omap_hwmod_setup - do some post-clock framework initialization |
1626 | * | 1745 | * |
1627 | * Must be called after omap2_clk_init(). Resolves the struct clk names | 1746 | * Must be called after omap2_clk_init(). Resolves the struct clk names |
1628 | * to struct clk pointers for each registered omap_hwmod. Also calls | 1747 | * to struct clk pointers for each registered omap_hwmod. Also calls |
1629 | * _setup() on each hwmod. Returns 0. | 1748 | * _setup() on each hwmod. Returns 0 upon success. |
1630 | */ | 1749 | */ |
1631 | int omap_hwmod_late_init(void) | 1750 | static int __init omap_hwmod_setup_all(void) |
1632 | { | 1751 | { |
1633 | int r; | 1752 | int r; |
1634 | 1753 | ||
1635 | /* XXX check return value */ | 1754 | if (!mpu_oh) { |
1636 | r = omap_hwmod_for_each(_init_clocks, NULL); | 1755 | pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", |
1637 | WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n"); | 1756 | __func__, MPU_INITIATOR_NAME); |
1757 | return -EINVAL; | ||
1758 | } | ||
1638 | 1759 | ||
1639 | mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME); | 1760 | r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL); |
1640 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", | 1761 | |
1641 | MPU_INITIATOR_NAME); | 1762 | r = omap_hwmod_for_each(_init_clocks, NULL); |
1763 | WARN(IS_ERR_VALUE(r), | ||
1764 | "omap_hwmod: %s: _init_clocks failed\n", __func__); | ||
1642 | 1765 | ||
1643 | omap_hwmod_for_each(_setup, NULL); | 1766 | omap_hwmod_for_each(_setup, NULL); |
1644 | 1767 | ||
1645 | return 0; | 1768 | return 0; |
1646 | } | 1769 | } |
1770 | core_initcall(omap_hwmod_setup_all); | ||
1647 | 1771 | ||
1648 | /** | 1772 | /** |
1649 | * omap_hwmod_enable - enable an omap_hwmod | 1773 | * omap_hwmod_enable - enable an omap_hwmod |
@@ -1862,6 +1986,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1862 | os = oh->slaves[i]; | 1986 | os = oh->slaves[i]; |
1863 | 1987 | ||
1864 | for (j = 0; j < os->addr_cnt; j++) { | 1988 | for (j = 0; j < os->addr_cnt; j++) { |
1989 | (res + r)->name = (os->addr + j)->name; | ||
1865 | (res + r)->start = (os->addr + j)->pa_start; | 1990 | (res + r)->start = (os->addr + j)->pa_start; |
1866 | (res + r)->end = (os->addr + j)->pa_end; | 1991 | (res + r)->end = (os->addr + j)->pa_end; |
1867 | (res + r)->flags = IORESOURCE_MEM; | 1992 | (res + r)->flags = IORESOURCE_MEM; |
@@ -2162,11 +2287,11 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2162 | * @oh: struct omap_hwmod * | 2287 | * @oh: struct omap_hwmod * |
2163 | * @state: state that _setup() should leave the hwmod in | 2288 | * @state: state that _setup() should leave the hwmod in |
2164 | * | 2289 | * |
2165 | * Sets the hwmod state that @oh will enter at the end of _setup() (called by | 2290 | * Sets the hwmod state that @oh will enter at the end of _setup() |
2166 | * omap_hwmod_late_init()). Only valid to call between calls to | 2291 | * (called by omap_hwmod_setup_*()). Only valid to call between |
2167 | * omap_hwmod_init() and omap_hwmod_late_init(). Returns 0 upon success or | 2292 | * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns |
2168 | * -EINVAL if there is a problem with the arguments or if the hwmod is | 2293 | * 0 upon success or -EINVAL if there is a problem with the arguments |
2169 | * in the wrong state. | 2294 | * or if the hwmod is in the wrong state. |
2170 | */ | 2295 | */ |
2171 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | 2296 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) |
2172 | { | 2297 | { |
@@ -2218,3 +2343,29 @@ u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) | |||
2218 | 2343 | ||
2219 | return ret; | 2344 | return ret; |
2220 | } | 2345 | } |
2346 | |||
2347 | /** | ||
2348 | * omap_hwmod_no_setup_reset - prevent a hwmod from being reset upon setup | ||
2349 | * @oh: struct omap_hwmod * | ||
2350 | * | ||
2351 | * Prevent the hwmod @oh from being reset during the setup process. | ||
2352 | * Intended for use by board-*.c files on boards with devices that | ||
2353 | * cannot tolerate being reset. Must be called before the hwmod has | ||
2354 | * been set up. Returns 0 upon success or negative error code upon | ||
2355 | * failure. | ||
2356 | */ | ||
2357 | int omap_hwmod_no_setup_reset(struct omap_hwmod *oh) | ||
2358 | { | ||
2359 | if (!oh) | ||
2360 | return -EINVAL; | ||
2361 | |||
2362 | if (oh->_state != _HWMOD_STATE_REGISTERED) { | ||
2363 | pr_err("omap_hwmod: %s: cannot prevent setup reset; in wrong state\n", | ||
2364 | oh->name); | ||
2365 | return -EINVAL; | ||
2366 | } | ||
2367 | |||
2368 | oh->flags |= HWMOD_INIT_NO_RESET; | ||
2369 | |||
2370 | return 0; | ||
2371 | } | ||