diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 106 |
1 files changed, 79 insertions, 27 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b7a4133267d8..cb911d7d1a3c 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 Nokia Corporation | 4 | * Copyright (C) 2009-2010 Nokia Corporation |
5 | * | 5 | * |
6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
7 | * | 7 | * |
@@ -423,7 +423,7 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
423 | } | 423 | } |
424 | 424 | ||
425 | /** | 425 | /** |
426 | * _init_interface_clk - get a struct clk * for the the hwmod's interface clks | 426 | * _init_interface_clks - get a struct clk * for the the hwmod's interface clks |
427 | * @oh: struct omap_hwmod * | 427 | * @oh: struct omap_hwmod * |
428 | * | 428 | * |
429 | * Called from _init_clocks(). Populates the @oh OCP slave interface | 429 | * Called from _init_clocks(). Populates the @oh OCP slave interface |
@@ -764,6 +764,7 @@ static struct omap_hwmod *_lookup(const char *name) | |||
764 | /** | 764 | /** |
765 | * _init_clocks - clk_get() all clocks associated with this hwmod | 765 | * _init_clocks - clk_get() all clocks associated with this hwmod |
766 | * @oh: struct omap_hwmod * | 766 | * @oh: struct omap_hwmod * |
767 | * @data: not used; pass NULL | ||
767 | * | 768 | * |
768 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). | 769 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). |
769 | * Resolves all clock names embedded in the hwmod. Must be called | 770 | * Resolves all clock names embedded in the hwmod. Must be called |
@@ -771,7 +772,7 @@ static struct omap_hwmod *_lookup(const char *name) | |||
771 | * has not yet been registered or if the clocks have already been | 772 | * has not yet been registered or if the clocks have already been |
772 | * initialized, 0 on success, or a non-zero error on failure. | 773 | * initialized, 0 on success, or a non-zero error on failure. |
773 | */ | 774 | */ |
774 | static int _init_clocks(struct omap_hwmod *oh) | 775 | static int _init_clocks(struct omap_hwmod *oh, void *data) |
775 | { | 776 | { |
776 | int ret = 0; | 777 | int ret = 0; |
777 | 778 | ||
@@ -886,7 +887,7 @@ static int _reset(struct omap_hwmod *oh) | |||
886 | } | 887 | } |
887 | 888 | ||
888 | /** | 889 | /** |
889 | * _enable - enable an omap_hwmod | 890 | * _omap_hwmod_enable - enable an omap_hwmod |
890 | * @oh: struct omap_hwmod * | 891 | * @oh: struct omap_hwmod * |
891 | * | 892 | * |
892 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's | 893 | * Enables an omap_hwmod @oh such that the MPU can access the hwmod's |
@@ -894,7 +895,7 @@ static int _reset(struct omap_hwmod *oh) | |||
894 | * Returns -EINVAL if the hwmod is in the wrong state or passes along | 895 | * Returns -EINVAL if the hwmod is in the wrong state or passes along |
895 | * the return value of _wait_target_ready(). | 896 | * the return value of _wait_target_ready(). |
896 | */ | 897 | */ |
897 | static int _enable(struct omap_hwmod *oh) | 898 | int _omap_hwmod_enable(struct omap_hwmod *oh) |
898 | { | 899 | { |
899 | int r; | 900 | int r; |
900 | 901 | ||
@@ -939,7 +940,7 @@ static int _enable(struct omap_hwmod *oh) | |||
939 | * no further work. Returns -EINVAL if the hwmod is in the wrong | 940 | * no further work. Returns -EINVAL if the hwmod is in the wrong |
940 | * state or returns 0. | 941 | * state or returns 0. |
941 | */ | 942 | */ |
942 | static int _idle(struct omap_hwmod *oh) | 943 | int _omap_hwmod_idle(struct omap_hwmod *oh) |
943 | { | 944 | { |
944 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 945 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
945 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " | 946 | WARN(1, "omap_hwmod: %s: idle state can only be entered from " |
@@ -996,19 +997,25 @@ static int _shutdown(struct omap_hwmod *oh) | |||
996 | /** | 997 | /** |
997 | * _setup - do initial configuration of omap_hwmod | 998 | * _setup - do initial configuration of omap_hwmod |
998 | * @oh: struct omap_hwmod * | 999 | * @oh: struct omap_hwmod * |
1000 | * @skip_setup_idle_p: do not idle hwmods at the end of the fn if 1 | ||
999 | * | 1001 | * |
1000 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 1002 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh |
1001 | * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex | 1003 | * OCP_SYSCONFIG register. Must be called with omap_hwmod_mutex held. |
1002 | * held. Returns -EINVAL if the hwmod is in the wrong state or returns | 1004 | * @skip_setup_idle is intended to be used on a system that will not |
1003 | * 0. | 1005 | * call omap_hwmod_enable() to enable devices (e.g., a system without |
1006 | * PM runtime). Returns -EINVAL if the hwmod is in the wrong state or | ||
1007 | * returns 0. | ||
1004 | */ | 1008 | */ |
1005 | static int _setup(struct omap_hwmod *oh) | 1009 | static int _setup(struct omap_hwmod *oh, void *data) |
1006 | { | 1010 | { |
1007 | int i, r; | 1011 | int i, r; |
1012 | u8 skip_setup_idle; | ||
1008 | 1013 | ||
1009 | if (!oh) | 1014 | if (!oh || !data) |
1010 | return -EINVAL; | 1015 | return -EINVAL; |
1011 | 1016 | ||
1017 | skip_setup_idle = *(u8 *)data; | ||
1018 | |||
1012 | /* Set iclk autoidle mode */ | 1019 | /* Set iclk autoidle mode */ |
1013 | if (oh->slaves_cnt > 0) { | 1020 | if (oh->slaves_cnt > 0) { |
1014 | for (i = 0; i < oh->slaves_cnt; i++) { | 1021 | for (i = 0; i < oh->slaves_cnt; i++) { |
@@ -1029,7 +1036,7 @@ static int _setup(struct omap_hwmod *oh) | |||
1029 | 1036 | ||
1030 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1037 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1031 | 1038 | ||
1032 | r = _enable(oh); | 1039 | r = _omap_hwmod_enable(oh); |
1033 | if (r) { | 1040 | if (r) { |
1034 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | 1041 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", |
1035 | oh->name, oh->_state); | 1042 | oh->name, oh->_state); |
@@ -1041,7 +1048,7 @@ static int _setup(struct omap_hwmod *oh) | |||
1041 | * XXX Do the OCP_SYSCONFIG bits need to be | 1048 | * XXX Do the OCP_SYSCONFIG bits need to be |
1042 | * reprogrammed after a reset? If not, then this can | 1049 | * reprogrammed after a reset? If not, then this can |
1043 | * be removed. If they do, then probably the | 1050 | * be removed. If they do, then probably the |
1044 | * _enable() function should be split to avoid the | 1051 | * _omap_hwmod_enable() function should be split to avoid the |
1045 | * rewrite of the OCP_SYSCONFIG register. | 1052 | * rewrite of the OCP_SYSCONFIG register. |
1046 | */ | 1053 | */ |
1047 | if (oh->class->sysc) { | 1054 | if (oh->class->sysc) { |
@@ -1050,8 +1057,8 @@ static int _setup(struct omap_hwmod *oh) | |||
1050 | } | 1057 | } |
1051 | } | 1058 | } |
1052 | 1059 | ||
1053 | if (!(oh->flags & HWMOD_INIT_NO_IDLE)) | 1060 | if (!(oh->flags & HWMOD_INIT_NO_IDLE) && !skip_setup_idle) |
1054 | _idle(oh); | 1061 | _omap_hwmod_idle(oh); |
1055 | 1062 | ||
1056 | return 0; | 1063 | return 0; |
1057 | } | 1064 | } |
@@ -1062,14 +1069,29 @@ static int _setup(struct omap_hwmod *oh) | |||
1062 | 1069 | ||
1063 | u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs) | 1070 | u32 omap_hwmod_readl(struct omap_hwmod *oh, u16 reg_offs) |
1064 | { | 1071 | { |
1065 | return __raw_readl(oh->_rt_va + reg_offs); | 1072 | return __raw_readl(oh->_mpu_rt_va + reg_offs); |
1066 | } | 1073 | } |
1067 | 1074 | ||
1068 | void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs) | 1075 | void omap_hwmod_writel(u32 v, struct omap_hwmod *oh, u16 reg_offs) |
1069 | { | 1076 | { |
1070 | __raw_writel(v, oh->_rt_va + reg_offs); | 1077 | __raw_writel(v, oh->_mpu_rt_va + reg_offs); |
1071 | } | 1078 | } |
1072 | 1079 | ||
1080 | /** | ||
1081 | * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode | ||
1082 | * @oh: struct omap_hwmod * | ||
1083 | * @idlemode: SIDLEMODE field bits (shifted to bit 0) | ||
1084 | * | ||
1085 | * Sets the IP block's OCP slave idlemode in hardware, and updates our | ||
1086 | * local copy. Intended to be used by drivers that have some erratum | ||
1087 | * that requires direct manipulation of the SIDLEMODE bits. Returns | ||
1088 | * -EINVAL if @oh is null, or passes along the return value from | ||
1089 | * _set_slave_idlemode(). | ||
1090 | * | ||
1091 | * XXX Does this function have any current users? If not, we should | ||
1092 | * remove it; it is better to let the rest of the hwmod code handle this. | ||
1093 | * Any users of this function should be scrutinized carefully. | ||
1094 | */ | ||
1073 | int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) | 1095 | int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) |
1074 | { | 1096 | { |
1075 | u32 v; | 1097 | u32 v; |
@@ -1124,7 +1146,7 @@ int omap_hwmod_register(struct omap_hwmod *oh) | |||
1124 | ms_id = _find_mpu_port_index(oh); | 1146 | ms_id = _find_mpu_port_index(oh); |
1125 | if (!IS_ERR_VALUE(ms_id)) { | 1147 | if (!IS_ERR_VALUE(ms_id)) { |
1126 | oh->_mpu_port_index = ms_id; | 1148 | oh->_mpu_port_index = ms_id; |
1127 | oh->_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); | 1149 | oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index); |
1128 | } else { | 1150 | } else { |
1129 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; | 1151 | oh->_int_flags |= _HWMOD_NO_MPU_PORT; |
1130 | } | 1152 | } |
@@ -1164,6 +1186,7 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name) | |||
1164 | /** | 1186 | /** |
1165 | * omap_hwmod_for_each - call function for each registered omap_hwmod | 1187 | * omap_hwmod_for_each - call function for each registered omap_hwmod |
1166 | * @fn: pointer to a callback function | 1188 | * @fn: pointer to a callback function |
1189 | * @data: void * data to pass to callback function | ||
1167 | * | 1190 | * |
1168 | * Call @fn for each registered omap_hwmod, passing @data to each | 1191 | * Call @fn for each registered omap_hwmod, passing @data to each |
1169 | * function. @fn must return 0 for success or any other value for | 1192 | * function. @fn must return 0 for success or any other value for |
@@ -1172,7 +1195,8 @@ struct omap_hwmod *omap_hwmod_lookup(const char *name) | |||
1172 | * caller of omap_hwmod_for_each(). @fn is called with | 1195 | * caller of omap_hwmod_for_each(). @fn is called with |
1173 | * omap_hwmod_for_each() held. | 1196 | * omap_hwmod_for_each() held. |
1174 | */ | 1197 | */ |
1175 | int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh)) | 1198 | int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), |
1199 | void *data) | ||
1176 | { | 1200 | { |
1177 | struct omap_hwmod *temp_oh; | 1201 | struct omap_hwmod *temp_oh; |
1178 | int ret; | 1202 | int ret; |
@@ -1182,7 +1206,7 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh)) | |||
1182 | 1206 | ||
1183 | mutex_lock(&omap_hwmod_mutex); | 1207 | mutex_lock(&omap_hwmod_mutex); |
1184 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { | 1208 | list_for_each_entry(temp_oh, &omap_hwmod_list, node) { |
1185 | ret = (*fn)(temp_oh); | 1209 | ret = (*fn)(temp_oh, data); |
1186 | if (ret) | 1210 | if (ret) |
1187 | break; | 1211 | break; |
1188 | } | 1212 | } |
@@ -1229,24 +1253,28 @@ int omap_hwmod_init(struct omap_hwmod **ohs) | |||
1229 | 1253 | ||
1230 | /** | 1254 | /** |
1231 | * omap_hwmod_late_init - do some post-clock framework initialization | 1255 | * omap_hwmod_late_init - do some post-clock framework initialization |
1256 | * @skip_setup_idle: if 1, do not idle hwmods in _setup() | ||
1232 | * | 1257 | * |
1233 | * Must be called after omap2_clk_init(). Resolves the struct clk names | 1258 | * Must be called after omap2_clk_init(). Resolves the struct clk names |
1234 | * to struct clk pointers for each registered omap_hwmod. Also calls | 1259 | * to struct clk pointers for each registered omap_hwmod. Also calls |
1235 | * _setup() on each hwmod. Returns 0. | 1260 | * _setup() on each hwmod. Returns 0. |
1236 | */ | 1261 | */ |
1237 | int omap_hwmod_late_init(void) | 1262 | int omap_hwmod_late_init(u8 skip_setup_idle) |
1238 | { | 1263 | { |
1239 | int r; | 1264 | int r; |
1240 | 1265 | ||
1241 | /* XXX check return value */ | 1266 | /* XXX check return value */ |
1242 | r = omap_hwmod_for_each(_init_clocks); | 1267 | r = omap_hwmod_for_each(_init_clocks, NULL); |
1243 | WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n"); | 1268 | WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n"); |
1244 | 1269 | ||
1245 | mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME); | 1270 | mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME); |
1246 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", | 1271 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", |
1247 | MPU_INITIATOR_NAME); | 1272 | MPU_INITIATOR_NAME); |
1248 | 1273 | ||
1249 | omap_hwmod_for_each(_setup); | 1274 | if (skip_setup_idle) |
1275 | pr_debug("omap_hwmod: will leave hwmods enabled during setup\n"); | ||
1276 | |||
1277 | omap_hwmod_for_each(_setup, &skip_setup_idle); | ||
1250 | 1278 | ||
1251 | return 0; | 1279 | return 0; |
1252 | } | 1280 | } |
@@ -1270,7 +1298,7 @@ int omap_hwmod_unregister(struct omap_hwmod *oh) | |||
1270 | pr_debug("omap_hwmod: %s: unregistering\n", oh->name); | 1298 | pr_debug("omap_hwmod: %s: unregistering\n", oh->name); |
1271 | 1299 | ||
1272 | mutex_lock(&omap_hwmod_mutex); | 1300 | mutex_lock(&omap_hwmod_mutex); |
1273 | iounmap(oh->_rt_va); | 1301 | iounmap(oh->_mpu_rt_va); |
1274 | list_del(&oh->node); | 1302 | list_del(&oh->node); |
1275 | mutex_unlock(&omap_hwmod_mutex); | 1303 | mutex_unlock(&omap_hwmod_mutex); |
1276 | 1304 | ||
@@ -1292,12 +1320,13 @@ int omap_hwmod_enable(struct omap_hwmod *oh) | |||
1292 | return -EINVAL; | 1320 | return -EINVAL; |
1293 | 1321 | ||
1294 | mutex_lock(&omap_hwmod_mutex); | 1322 | mutex_lock(&omap_hwmod_mutex); |
1295 | r = _enable(oh); | 1323 | r = _omap_hwmod_enable(oh); |
1296 | mutex_unlock(&omap_hwmod_mutex); | 1324 | mutex_unlock(&omap_hwmod_mutex); |
1297 | 1325 | ||
1298 | return r; | 1326 | return r; |
1299 | } | 1327 | } |
1300 | 1328 | ||
1329 | |||
1301 | /** | 1330 | /** |
1302 | * omap_hwmod_idle - idle an omap_hwmod | 1331 | * omap_hwmod_idle - idle an omap_hwmod |
1303 | * @oh: struct omap_hwmod * | 1332 | * @oh: struct omap_hwmod * |
@@ -1311,7 +1340,7 @@ int omap_hwmod_idle(struct omap_hwmod *oh) | |||
1311 | return -EINVAL; | 1340 | return -EINVAL; |
1312 | 1341 | ||
1313 | mutex_lock(&omap_hwmod_mutex); | 1342 | mutex_lock(&omap_hwmod_mutex); |
1314 | _idle(oh); | 1343 | _omap_hwmod_idle(oh); |
1315 | mutex_unlock(&omap_hwmod_mutex); | 1344 | mutex_unlock(&omap_hwmod_mutex); |
1316 | 1345 | ||
1317 | return 0; | 1346 | return 0; |
@@ -1413,7 +1442,7 @@ int omap_hwmod_reset(struct omap_hwmod *oh) | |||
1413 | mutex_lock(&omap_hwmod_mutex); | 1442 | mutex_lock(&omap_hwmod_mutex); |
1414 | r = _reset(oh); | 1443 | r = _reset(oh); |
1415 | if (!r) | 1444 | if (!r) |
1416 | r = _enable(oh); | 1445 | r = _omap_hwmod_enable(oh); |
1417 | mutex_unlock(&omap_hwmod_mutex); | 1446 | mutex_unlock(&omap_hwmod_mutex); |
1418 | 1447 | ||
1419 | return r; | 1448 | return r; |
@@ -1530,6 +1559,29 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) | |||
1530 | } | 1559 | } |
1531 | 1560 | ||
1532 | /** | 1561 | /** |
1562 | * omap_hwmod_get_mpu_rt_va - return the module's base address (for the MPU) | ||
1563 | * @oh: struct omap_hwmod * | ||
1564 | * | ||
1565 | * Returns the virtual address corresponding to the beginning of the | ||
1566 | * module's register target, in the address range that is intended to | ||
1567 | * be used by the MPU. Returns the virtual address upon success or NULL | ||
1568 | * upon error. | ||
1569 | */ | ||
1570 | void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh) | ||
1571 | { | ||
1572 | if (!oh) | ||
1573 | return NULL; | ||
1574 | |||
1575 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | ||
1576 | return NULL; | ||
1577 | |||
1578 | if (oh->_state == _HWMOD_STATE_UNKNOWN) | ||
1579 | return NULL; | ||
1580 | |||
1581 | return oh->_mpu_rt_va; | ||
1582 | } | ||
1583 | |||
1584 | /** | ||
1533 | * omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh | 1585 | * omap_hwmod_add_initiator_dep - add sleepdep from @init_oh to @oh |
1534 | * @oh: struct omap_hwmod * | 1586 | * @oh: struct omap_hwmod * |
1535 | * @init_oh: struct omap_hwmod * (initiator) | 1587 | * @init_oh: struct omap_hwmod * (initiator) |