diff options
author | Olof Johansson <olof@lixom.net> | 2013-02-05 17:03:31 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-02-05 17:03:45 -0500 |
commit | b6a03d0492dedb5c10b8a5708ee92e04b0590c07 (patch) | |
tree | 21774ee93c50847fe1ea044f2cabae0746ac39d3 /arch/arm/mach-omap2 | |
parent | 3e93093ecd0c144e86a86cc1f165221b6cd3e7fb (diff) | |
parent | 97c794a1e37b1ca128ef38f17c069186bfa5fb1b (diff) |
Merge tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers
From Tony Lindgren:
OMAP GPMC (General Purpose Memory Controller) changes to add
device tree bindings.
* tag 'omap-for-v3.9/gpmc-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
ARM: OMAP2+: gpmc: Add device tree documentation for elm handle
ARM: OMAP2+: gpmc: add DT bindings for OneNAND
ARM: OMAP2+: gpmc-onenand: drop __init annotation
mtd: omap-onenand: pass device_node in platform data
ARM: OMAP2+: Prevent potential crash if GPMC probe fails
ARM: OMAP2+: gpmc: Remove unneeded of_node_put()
ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND
ARM: OMAP: gpmc: enable hwecc for AM33xx SoCs
ARM: OMAP: gpmc-nand: drop __init annotation
mtd: omap-nand: pass device_node in platform data
ARM: OMAP: gpmc: don't create devices from initcall on DT
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/gpmc-nand.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc-onenand.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/gpmc.c | 232 |
3 files changed, 240 insertions, 9 deletions
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c index db969a5c4998..afc1e8c32d6c 100644 --- a/arch/arm/mach-omap2/gpmc-nand.c +++ b/arch/arm/mach-omap2/gpmc-nand.c | |||
@@ -89,20 +89,21 @@ static int omap2_nand_gpmc_retime( | |||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) | 92 | static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) |
93 | { | 93 | { |
94 | /* support only OMAP3 class */ | 94 | /* support only OMAP3 class */ |
95 | if (!cpu_is_omap34xx()) { | 95 | if (!cpu_is_omap34xx() && !soc_is_am33xx()) { |
96 | pr_err("BCH ecc is not supported on this CPU\n"); | 96 | pr_err("BCH ecc is not supported on this CPU\n"); |
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1. | 101 | * For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1 |
102 | * Other chips may be added if confirmed to work. | 102 | * and AM33xx derivates. Other chips may be added if confirmed to work. |
103 | */ | 103 | */ |
104 | if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) && | 104 | if ((ecc_opt == OMAP_ECC_BCH4_CODE_HW) && |
105 | (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) { | 105 | (!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0)) && |
106 | (!soc_is_am33xx())) { | ||
106 | pr_err("BCH 4-bit mode is not supported on this CPU\n"); | 107 | pr_err("BCH 4-bit mode is not supported on this CPU\n"); |
107 | return 0; | 108 | return 0; |
108 | } | 109 | } |
@@ -110,8 +111,8 @@ static bool __init gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt) | |||
110 | return 1; | 111 | return 1; |
111 | } | 112 | } |
112 | 113 | ||
113 | int __init gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, | 114 | int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data, |
114 | struct gpmc_timings *gpmc_t) | 115 | struct gpmc_timings *gpmc_t) |
115 | { | 116 | { |
116 | int err = 0; | 117 | int err = 0; |
117 | struct device *dev = &gpmc_nand_device.dev; | 118 | struct device *dev = &gpmc_nand_device.dev; |
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 94a349e4dc96..fadd87435cd0 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c | |||
@@ -356,7 +356,7 @@ static int gpmc_onenand_setup(void __iomem *onenand_base, int *freq_ptr) | |||
356 | return ret; | 356 | return ret; |
357 | } | 357 | } |
358 | 358 | ||
359 | void __init gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) | 359 | void gpmc_onenand_init(struct omap_onenand_platform_data *_onenand_data) |
360 | { | 360 | { |
361 | int err; | 361 | int err; |
362 | 362 | ||
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 8033cb747c86..1adb2d4496f6 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,9 +1125,216 @@ 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 | |||
1121 | return 0; | 1131 | return 0; |
1122 | } | 1132 | } |
1123 | 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 | { | ||
1263 | return 0; | ||
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 | ||
1337 | |||
1124 | static int gpmc_probe(struct platform_device *pdev) | 1338 | static int gpmc_probe(struct platform_device *pdev) |
1125 | { | 1339 | { |
1126 | int rc; | 1340 | int rc; |
@@ -1174,6 +1388,14 @@ static int gpmc_probe(struct platform_device *pdev) | |||
1174 | if (IS_ERR_VALUE(gpmc_setup_irq())) | 1388 | if (IS_ERR_VALUE(gpmc_setup_irq())) |
1175 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); | 1389 | dev_warn(gpmc_dev, "gpmc_setup_irq failed\n"); |
1176 | 1390 | ||
1391 | rc = gpmc_probe_dt(pdev); | ||
1392 | if (rc < 0) { | ||
1393 | clk_disable_unprepare(gpmc_l3_clk); | ||
1394 | clk_put(gpmc_l3_clk); | ||
1395 | dev_err(gpmc_dev, "failed to probe DT parameters\n"); | ||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1177 | return 0; | 1399 | return 0; |
1178 | } | 1400 | } |
1179 | 1401 | ||
@@ -1191,6 +1413,7 @@ static struct platform_driver gpmc_driver = { | |||
1191 | .driver = { | 1413 | .driver = { |
1192 | .name = DEVICE_NAME, | 1414 | .name = DEVICE_NAME, |
1193 | .owner = THIS_MODULE, | 1415 | .owner = THIS_MODULE, |
1416 | .of_match_table = of_match_ptr(gpmc_dt_ids), | ||
1194 | }, | 1417 | }, |
1195 | }; | 1418 | }; |
1196 | 1419 | ||
@@ -1214,6 +1437,13 @@ static int __init omap_gpmc_init(void) | |||
1214 | struct platform_device *pdev; | 1437 | struct platform_device *pdev; |
1215 | char *oh_name = "gpmc"; | 1438 | char *oh_name = "gpmc"; |
1216 | 1439 | ||
1440 | /* | ||
1441 | * if the board boots up with a populated DT, do not | ||
1442 | * manually add the device from this initcall | ||
1443 | */ | ||
1444 | if (of_have_populated_dt()) | ||
1445 | return -ENODEV; | ||
1446 | |||
1217 | oh = omap_hwmod_lookup(oh_name); | 1447 | oh = omap_hwmod_lookup(oh_name); |
1218 | if (!oh) { | 1448 | if (!oh) { |
1219 | pr_err("Could not look up %s\n", oh_name); | 1449 | pr_err("Could not look up %s\n", oh_name); |