diff options
Diffstat (limited to 'arch/arm/mach-omap2/gpmc.c')
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 244 |
1 files changed, 236 insertions, 8 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index bc0783364ad3..8d70bd03c5d8 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c | |||
@@ -25,6 +25,10 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/of.h> | ||
29 | #include <linux/of_mtd.h> | ||
30 | #include <linux/of_device.h> | ||
31 | #include <linux/mtd/nand.h> | ||
28 | 32 | ||
29 | #include <linux/platform_data/mtd-nand-omap2.h> | 33 | #include <linux/platform_data/mtd-nand-omap2.h> |
30 | 34 | ||
@@ -34,6 +38,8 @@ | |||
34 | #include "common.h" | 38 | #include "common.h" |
35 | #include "omap_device.h" | 39 | #include "omap_device.h" |
36 | #include "gpmc.h" | 40 | #include "gpmc.h" |
41 | #include "gpmc-nand.h" | ||
42 | #include "gpmc-onenand.h" | ||
37 | 43 | ||
38 | #define DEVICE_NAME "omap-gpmc" | 44 | #define DEVICE_NAME "omap-gpmc" |
39 | 45 | ||
@@ -145,7 +151,8 @@ static unsigned gpmc_irq_start; | |||
145 | static struct resource gpmc_mem_root; | 151 | static struct resource gpmc_mem_root; |
146 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; | 152 | static struct resource gpmc_cs_mem[GPMC_CS_NUM]; |
147 | static DEFINE_SPINLOCK(gpmc_mem_lock); | 153 | static DEFINE_SPINLOCK(gpmc_mem_lock); |
148 | static unsigned int gpmc_cs_map; /* flag for cs which are initialized */ | 154 | /* Define chip-selects as reserved by default until probe completes */ |
155 | static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1); | ||
149 | static struct device *gpmc_dev; | 156 | static struct device *gpmc_dev; |
150 | static int gpmc_irq; | 157 | static int gpmc_irq; |
151 | static resource_size_t phys_base, mem_size; | 158 | static resource_size_t phys_base, mem_size; |
@@ -1118,8 +1125,215 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t, | |||
1118 | /* TODO: remove, see function definition */ | 1125 | /* TODO: remove, see function definition */ |
1119 | gpmc_convert_ps_to_ns(gpmc_t); | 1126 | gpmc_convert_ps_to_ns(gpmc_t); |
1120 | 1127 | ||
1128 | /* Now the GPMC is initialised, unreserve the chip-selects */ | ||
1129 | gpmc_cs_map = 0; | ||
1130 | |||
1131 | return 0; | ||
1132 | } | ||
1133 | |||
1134 | #ifdef CONFIG_OF | ||
1135 | static struct of_device_id gpmc_dt_ids[] = { | ||
1136 | { .compatible = "ti,omap2420-gpmc" }, | ||
1137 | { .compatible = "ti,omap2430-gpmc" }, | ||
1138 | { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */ | ||
1139 | { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */ | ||
1140 | { .compatible = "ti,am3352-gpmc" }, /* am335x devices */ | ||
1141 | { } | ||
1142 | }; | ||
1143 | MODULE_DEVICE_TABLE(of, gpmc_dt_ids); | ||
1144 | |||
1145 | static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, | ||
1146 | struct gpmc_timings *gpmc_t) | ||
1147 | { | ||
1148 | u32 val; | ||
1149 | |||
1150 | memset(gpmc_t, 0, sizeof(*gpmc_t)); | ||
1151 | |||
1152 | /* minimum clock period for syncronous mode */ | ||
1153 | if (!of_property_read_u32(np, "gpmc,sync-clk", &val)) | ||
1154 | gpmc_t->sync_clk = val; | ||
1155 | |||
1156 | /* chip select timtings */ | ||
1157 | if (!of_property_read_u32(np, "gpmc,cs-on", &val)) | ||
1158 | gpmc_t->cs_on = val; | ||
1159 | |||
1160 | if (!of_property_read_u32(np, "gpmc,cs-rd-off", &val)) | ||
1161 | gpmc_t->cs_rd_off = val; | ||
1162 | |||
1163 | if (!of_property_read_u32(np, "gpmc,cs-wr-off", &val)) | ||
1164 | gpmc_t->cs_wr_off = val; | ||
1165 | |||
1166 | /* ADV signal timings */ | ||
1167 | if (!of_property_read_u32(np, "gpmc,adv-on", &val)) | ||
1168 | gpmc_t->adv_on = val; | ||
1169 | |||
1170 | if (!of_property_read_u32(np, "gpmc,adv-rd-off", &val)) | ||
1171 | gpmc_t->adv_rd_off = val; | ||
1172 | |||
1173 | if (!of_property_read_u32(np, "gpmc,adv-wr-off", &val)) | ||
1174 | gpmc_t->adv_wr_off = val; | ||
1175 | |||
1176 | /* WE signal timings */ | ||
1177 | if (!of_property_read_u32(np, "gpmc,we-on", &val)) | ||
1178 | gpmc_t->we_on = val; | ||
1179 | |||
1180 | if (!of_property_read_u32(np, "gpmc,we-off", &val)) | ||
1181 | gpmc_t->we_off = val; | ||
1182 | |||
1183 | /* OE signal timings */ | ||
1184 | if (!of_property_read_u32(np, "gpmc,oe-on", &val)) | ||
1185 | gpmc_t->oe_on = val; | ||
1186 | |||
1187 | if (!of_property_read_u32(np, "gpmc,oe-off", &val)) | ||
1188 | gpmc_t->oe_off = val; | ||
1189 | |||
1190 | /* access and cycle timings */ | ||
1191 | if (!of_property_read_u32(np, "gpmc,page-burst-access", &val)) | ||
1192 | gpmc_t->page_burst_access = val; | ||
1193 | |||
1194 | if (!of_property_read_u32(np, "gpmc,access", &val)) | ||
1195 | gpmc_t->access = val; | ||
1196 | |||
1197 | if (!of_property_read_u32(np, "gpmc,rd-cycle", &val)) | ||
1198 | gpmc_t->rd_cycle = val; | ||
1199 | |||
1200 | if (!of_property_read_u32(np, "gpmc,wr-cycle", &val)) | ||
1201 | gpmc_t->wr_cycle = val; | ||
1202 | |||
1203 | /* only for OMAP3430 */ | ||
1204 | if (!of_property_read_u32(np, "gpmc,wr-access", &val)) | ||
1205 | gpmc_t->wr_access = val; | ||
1206 | |||
1207 | if (!of_property_read_u32(np, "gpmc,wr-data-mux-bus", &val)) | ||
1208 | gpmc_t->wr_data_mux_bus = val; | ||
1209 | } | ||
1210 | |||
1211 | #ifdef CONFIG_MTD_NAND | ||
1212 | |||
1213 | static const char * const nand_ecc_opts[] = { | ||
1214 | [OMAP_ECC_HAMMING_CODE_DEFAULT] = "sw", | ||
1215 | [OMAP_ECC_HAMMING_CODE_HW] = "hw", | ||
1216 | [OMAP_ECC_HAMMING_CODE_HW_ROMCODE] = "hw-romcode", | ||
1217 | [OMAP_ECC_BCH4_CODE_HW] = "bch4", | ||
1218 | [OMAP_ECC_BCH8_CODE_HW] = "bch8", | ||
1219 | }; | ||
1220 | |||
1221 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1222 | struct device_node *child) | ||
1223 | { | ||
1224 | u32 val; | ||
1225 | const char *s; | ||
1226 | struct gpmc_timings gpmc_t; | ||
1227 | struct omap_nand_platform_data *gpmc_nand_data; | ||
1228 | |||
1229 | if (of_property_read_u32(child, "reg", &val) < 0) { | ||
1230 | dev_err(&pdev->dev, "%s has no 'reg' property\n", | ||
1231 | child->full_name); | ||
1232 | return -ENODEV; | ||
1233 | } | ||
1234 | |||
1235 | gpmc_nand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_nand_data), | ||
1236 | GFP_KERNEL); | ||
1237 | if (!gpmc_nand_data) | ||
1238 | return -ENOMEM; | ||
1239 | |||
1240 | gpmc_nand_data->cs = val; | ||
1241 | gpmc_nand_data->of_node = child; | ||
1242 | |||
1243 | if (!of_property_read_string(child, "ti,nand-ecc-opt", &s)) | ||
1244 | for (val = 0; val < ARRAY_SIZE(nand_ecc_opts); val++) | ||
1245 | if (!strcasecmp(s, nand_ecc_opts[val])) { | ||
1246 | gpmc_nand_data->ecc_opt = val; | ||
1247 | break; | ||
1248 | } | ||
1249 | |||
1250 | val = of_get_nand_bus_width(child); | ||
1251 | if (val == 16) | ||
1252 | gpmc_nand_data->devsize = NAND_BUSWIDTH_16; | ||
1253 | |||
1254 | gpmc_read_timings_dt(child, &gpmc_t); | ||
1255 | gpmc_nand_init(gpmc_nand_data, &gpmc_t); | ||
1256 | |||
1257 | return 0; | ||
1258 | } | ||
1259 | #else | ||
1260 | static int gpmc_probe_nand_child(struct platform_device *pdev, | ||
1261 | struct device_node *child) | ||
1262 | { | ||
1121 | return 0; | 1263 | return 0; |
1122 | } | 1264 | } |
1265 | #endif | ||
1266 | |||
1267 | #ifdef CONFIG_MTD_ONENAND | ||
1268 | static int gpmc_probe_onenand_child(struct platform_device *pdev, | ||
1269 | struct device_node *child) | ||
1270 | { | ||
1271 | u32 val; | ||
1272 | struct omap_onenand_platform_data *gpmc_onenand_data; | ||
1273 | |||
1274 | if (of_property_read_u32(child, "reg", &val) < 0) { | ||
1275 | dev_err(&pdev->dev, "%s has no 'reg' property\n", | ||
1276 | child->full_name); | ||
1277 | return -ENODEV; | ||
1278 | } | ||
1279 | |||
1280 | gpmc_onenand_data = devm_kzalloc(&pdev->dev, sizeof(*gpmc_onenand_data), | ||
1281 | GFP_KERNEL); | ||
1282 | if (!gpmc_onenand_data) | ||
1283 | return -ENOMEM; | ||
1284 | |||
1285 | gpmc_onenand_data->cs = val; | ||
1286 | gpmc_onenand_data->of_node = child; | ||
1287 | gpmc_onenand_data->dma_channel = -1; | ||
1288 | |||
1289 | if (!of_property_read_u32(child, "dma-channel", &val)) | ||
1290 | gpmc_onenand_data->dma_channel = val; | ||
1291 | |||
1292 | gpmc_onenand_init(gpmc_onenand_data); | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | #else | ||
1297 | static int gpmc_probe_onenand_child(struct platform_device *pdev, | ||
1298 | struct device_node *child) | ||
1299 | { | ||
1300 | return 0; | ||
1301 | } | ||
1302 | #endif | ||
1303 | |||
1304 | static int gpmc_probe_dt(struct platform_device *pdev) | ||
1305 | { | ||
1306 | int ret; | ||
1307 | struct device_node *child; | ||
1308 | const struct of_device_id *of_id = | ||
1309 | of_match_device(gpmc_dt_ids, &pdev->dev); | ||
1310 | |||
1311 | if (!of_id) | ||
1312 | return 0; | ||
1313 | |||
1314 | for_each_node_by_name(child, "nand") { | ||
1315 | ret = gpmc_probe_nand_child(pdev, child); | ||
1316 | if (ret < 0) { | ||
1317 | of_node_put(child); | ||
1318 | return ret; | ||
1319 | } | ||
1320 | } | ||
1321 | |||
1322 | for_each_node_by_name(child, "onenand") { | ||
1323 | ret = gpmc_probe_onenand_child(pdev, child); | ||
1324 | if (ret < 0) { | ||
1325 | of_node_put(child); | ||
1326 | return ret; | ||
1327 | } | ||
1328 | } | ||
1329 | return 0; | ||
1330 | } | ||
1331 | #else | ||
1332 | static int gpmc_probe_dt(struct platform_device *pdev) | ||
1333 | { | ||
1334 | return 0; | ||
1335 | } | ||
1336 | #endif | ||
1123 | 1337 | ||
1124 | static int gpmc_probe(struct platform_device *pdev) | 1338 | static int gpmc_probe(struct platform_device *pdev) |
1125 | { | 1339 | { |
@@ -1134,11 +1348,9 @@ static int gpmc_probe(struct platform_device *pdev) | |||
1134 | phys_base = res->start; | 1348 | phys_base = res->start; |
1135 | mem_size = resource_size(res); | 1349 | mem_size = resource_size(res); |
1136 | 1350 | ||
1137 | gpmc_base = devm_request_and_ioremap(&pdev->dev, res); | 1351 | gpmc_base = devm_ioremap_resource(&pdev->dev, res); |
1138 | if (!gpmc_base) { | 1352 | if (IS_ERR(gpmc_base)) |
1139 | dev_err(&pdev->dev, "error: request memory / ioremap\n"); | 1353 | return PTR_ERR(gpmc_base); |
1140 | return -EADDRNOTAVAIL; | ||
1141 | } | ||
1142 | 1354 | ||
1143 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1355 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1144 | if (res == NULL) | 1356 | if (res == NULL) |
@@ -1174,6 +1386,14 @@ static int gpmc_probe(struct platform_device *pdev) | |||
1174 | if (IS_ERR_VALUE(gpmc_setup_irq())) | 1386 | if (IS_ERR_VALUE(gpmc_setup_irq())) |
1175 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); | 1387 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); |
1176 | 1388 | ||
1389 | rc = gpmc_probe_dt(pdev); | ||
1390 | if (rc < 0) { | ||
1391 | clk_disable_unprepare(gpmc_l3_clk); | ||
1392 | clk_put(gpmc_l3_clk); | ||
1393 | dev_err(gpmc_dev, "failed to probe DT parameters\n"); | ||
1394 | return rc; | ||
1395 | } | ||
1396 | |||
1177 | return 0; | 1397 | return 0; |
1178 | } | 1398 | } |
1179 | 1399 | ||
@@ -1191,6 +1411,7 @@ static struct platform_driver gpmc_driver = { | |||
1191 | .driver = { | 1411 | .driver = { |
1192 | .name = DEVICE_NAME, | 1412 | .name = DEVICE_NAME, |
1193 | .owner = THIS_MODULE, | 1413 | .owner = THIS_MODULE, |
1414 | .of_match_table = of_match_ptr(gpmc_dt_ids), | ||
1194 | }, | 1415 | }, |
1195 | }; | 1416 | }; |
1196 | 1417 | ||
@@ -1205,7 +1426,7 @@ static __exit void gpmc_exit(void) | |||
1205 | 1426 | ||
1206 | } | 1427 | } |
1207 | 1428 | ||
1208 | postcore_initcall(gpmc_init); | 1429 | omap_postcore_initcall(gpmc_init); |
1209 | module_exit(gpmc_exit); | 1430 | module_exit(gpmc_exit); |
1210 | 1431 | ||
1211 | static int __init omap_gpmc_init(void) | 1432 | static int __init omap_gpmc_init(void) |
@@ -1214,6 +1435,13 @@ static int __init omap_gpmc_init(void) | |||
1214 | struct platform_device *pdev; | 1435 | struct platform_device *pdev; |
1215 | char *oh_name = "gpmc"; | 1436 | char *oh_name = "gpmc"; |
1216 | 1437 | ||
1438 | /* | ||
1439 | * if the board boots up with a populated DT, do not | ||
1440 | * manually add the device from this initcall | ||
1441 | */ | ||
1442 | if (of_have_populated_dt()) | ||
1443 | return -ENODEV; | ||
1444 | |||
1217 | oh = omap_hwmod_lookup(oh_name); | 1445 | oh = omap_hwmod_lookup(oh_name); |
1218 | if (!oh) { | 1446 | if (!oh) { |
1219 | pr_err("Could not look up %s\n", oh_name); | 1447 | pr_err("Could not look up %s\n", oh_name); |
@@ -1225,7 +1453,7 @@ static int __init omap_gpmc_init(void) | |||
1225 | 1453 | ||
1226 | return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; | 1454 | return IS_ERR(pdev) ? PTR_ERR(pdev) : 0; |
1227 | } | 1455 | } |
1228 | postcore_initcall(omap_gpmc_init); | 1456 | omap_postcore_initcall(omap_gpmc_init); |
1229 | 1457 | ||
1230 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) | 1458 | static irqreturn_t gpmc_handle_irq(int irq, void *dev) |
1231 | { | 1459 | { |