Merge tag 'pm-extra-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[deliverable/linux.git] / drivers / mtd / maps / physmap_of.c
CommitLineData
a2c2fe4b 1/*
c4d5e375 2 * Flash mappings described by the OF (or flattened) device tree
a2c2fe4b
VW
3 *
4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com>
6 *
2099172d
DG
7 * Revised to handle newer style flash binding by:
8 * Copyright (C) 2007 David Gibson, IBM Corporation.
9 *
a2c2fe4b
VW
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/module.h>
17#include <linux/types.h>
a2c2fe4b
VW
18#include <linux/device.h>
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h>
143070e7 22#include <linux/mtd/concat.h>
c4d5e375 23#include <linux/of.h>
7a50d06e 24#include <linux/of_address.h>
c4d5e375 25#include <linux/of_platform.h>
5a0e3ad6 26#include <linux/slab.h>
b0afd44b 27#include "physmap_of_versatile.h"
a2c2fe4b 28
143070e7
SR
29struct of_flash_list {
30 struct mtd_info *mtd;
31 struct map_info map;
32 struct resource *res;
33};
34
c4d5e375 35struct of_flash {
143070e7 36 struct mtd_info *cmtd;
143070e7
SR
37 int list_size; /* number of elements in of_flash_list */
38 struct of_flash_list list[0];
a2c2fe4b
VW
39};
40
2dc11581 41static int of_flash_remove(struct platform_device *dev)
a2c2fe4b 42{
c4d5e375 43 struct of_flash *info;
143070e7 44 int i;
a2c2fe4b
VW
45
46 info = dev_get_drvdata(&dev->dev);
c4d5e375 47 if (!info)
a2c2fe4b
VW
48 return 0;
49 dev_set_drvdata(&dev->dev, NULL);
50
92b633a8 51 if (info->cmtd) {
984e6d8e 52 mtd_device_unregister(info->cmtd);
92b633a8
AB
53 if (info->cmtd != info->list[0].mtd)
54 mtd_concat_destroy(info->cmtd);
143070e7 55 }
143070e7 56
143070e7
SR
57 for (i = 0; i < info->list_size; i++) {
58 if (info->list[i].mtd)
59 map_destroy(info->list[i].mtd);
a2c2fe4b 60
143070e7
SR
61 if (info->list[i].map.virt)
62 iounmap(info->list[i].map.virt);
63
64 if (info->list[i].res) {
65 release_resource(info->list[i].res);
66 kfree(info->list[i].res);
67 }
a2c2fe4b 68 }
a2c2fe4b
VW
69 return 0;
70}
71
cce2a026
AB
72static const char * const rom_probe_types[] = {
73 "cfi_probe", "jedec_probe", "map_rom" };
74
2099172d
DG
75/* Helper function to handle probing of the obsolete "direct-mapped"
76 * compatible binding, which has an extra "probe-type" property
77 * describing the type of flash probe necessary. */
06f25510 78static struct mtd_info *obsolete_probe(struct platform_device *dev,
d8929942 79 struct map_info *map)
a2c2fe4b 80{
61c7a080 81 struct device_node *dp = dev->dev.of_node;
a2c2fe4b 82 const char *of_probe;
2099172d 83 struct mtd_info *mtd;
2099172d
DG
84 int i;
85
86 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
87 "flash binding\n");
88
89 of_probe = of_get_property(dp, "probe-type", NULL);
90 if (!of_probe) {
91 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
92 mtd = do_map_probe(rom_probe_types[i], map);
93 if (mtd)
94 return mtd;
95 }
96 return NULL;
97 } else if (strcmp(of_probe, "CFI") == 0) {
98 return do_map_probe("cfi_probe", map);
99 } else if (strcmp(of_probe, "JEDEC") == 0) {
100 return do_map_probe("jedec_probe", map);
101 } else {
102 if (strcmp(of_probe, "ROM") != 0)
c4d5e375
DG
103 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
104 "type '%s', mapping as rom\n", of_probe);
9b07a8d1 105 return do_map_probe("map_rom", map);
2099172d
DG
106 }
107}
108
9d5da3a9
JG
109/* When partitions are set we look for a linux,part-probe property which
110 specifies the list of partition probers to use. If none is given then the
111 default is use. These take precedence over other device tree
112 information. */
cce2a026
AB
113static const char * const part_probe_types_def[] = {
114 "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
115
116static const char * const *of_get_probes(struct device_node *dp)
9d5da3a9
JG
117{
118 const char *cp;
119 int cplen;
120 unsigned int l;
121 unsigned int count;
122 const char **res;
123
124 cp = of_get_property(dp, "linux,part-probe", &cplen);
125 if (cp == NULL)
126 return part_probe_types_def;
127
128 count = 0;
129 for (l = 0; l != cplen; l++)
130 if (cp[l] == 0)
131 count++;
132
133 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
7e0c19c9
CIK
134 if (!res)
135 return NULL;
9d5da3a9
JG
136 count = 0;
137 while (cplen > 0) {
138 res[count] = cp;
139 l = strlen(cp) + 1;
140 cp += l;
141 cplen -= l;
142 count++;
143 }
144 return res;
145}
146
cce2a026 147static void of_free_probes(const char * const *probes)
9d5da3a9
JG
148{
149 if (probes != part_probe_types_def)
150 kfree(probes);
151}
9d5da3a9 152
66610443 153static const struct of_device_id of_flash_match[];
06f25510 154static int of_flash_probe(struct platform_device *dev)
a2c2fe4b 155{
cce2a026 156 const char * const *part_probe_types;
b1608d69 157 const struct of_device_id *match;
61c7a080 158 struct device_node *dp = dev->dev.of_node;
a2c2fe4b 159 struct resource res;
c4d5e375 160 struct of_flash *info;
1c48a5c9 161 const char *probe_type;
766f271a 162 const __be32 *width;
a2c2fe4b 163 int err;
143070e7
SR
164 int i;
165 int count;
766f271a 166 const __be32 *p;
143070e7
SR
167 int reg_tuple_size;
168 struct mtd_info **mtd_list = NULL;
2763c508 169 resource_size_t res_size;
d0788ce4 170 bool map_indirect;
7dfe4be3 171 const char *mtd_name = NULL;
143070e7 172
b1608d69
GL
173 match = of_match_device(of_flash_match, &dev->dev);
174 if (!match)
1c48a5c9 175 return -EINVAL;
b1608d69 176 probe_type = match->data;
1c48a5c9 177
143070e7
SR
178 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
179
d68cbdd4
JCPV
180 of_property_read_string(dp, "linux,mtd-name", &mtd_name);
181
143070e7
SR
182 /*
183 * Get number of "reg" tuples. Scan for MTD devices on area's
184 * described by each "reg" region. This makes it possible (including
185 * the concat support) to support the Intel P30 48F4400 chips which
186 * consists internally of 2 non-identical NOR chips on one die.
187 */
188 p = of_get_property(dp, "reg", &count);
b137aab4 189 if (!p || count % reg_tuple_size != 0) {
143070e7 190 dev_err(&dev->dev, "Malformed reg property on %s\n",
61c7a080 191 dev->dev.of_node->full_name);
143070e7 192 err = -EINVAL;
ad4fbc79 193 goto err_flash_remove;
a2c2fe4b 194 }
143070e7 195 count /= reg_tuple_size;
a2c2fe4b 196
d0788ce4
SR
197 map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
198
c4d5e375 199 err = -ENOMEM;
eb82038f
EG
200 info = devm_kzalloc(&dev->dev,
201 sizeof(struct of_flash) +
202 sizeof(struct of_flash_list) * count, GFP_KERNEL);
143070e7 203 if (!info)
ad4fbc79 204 goto err_flash_remove;
a2c2fe4b
VW
205
206 dev_set_drvdata(&dev->dev, info);
207
e026255f 208 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
ad4fbc79 209 if (!mtd_list)
210 goto err_flash_remove;
211
143070e7
SR
212 for (i = 0; i < count; i++) {
213 err = -ENXIO;
214 if (of_address_to_resource(dp, i, &res)) {
940fe282
SR
215 /*
216 * Continue with next register tuple if this
217 * one is not mappable
218 */
219 continue;
143070e7 220 }
a2c2fe4b 221
f9a5279c 222 dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
143070e7
SR
223
224 err = -EBUSY;
2763c508
WS
225 res_size = resource_size(&res);
226 info->list[i].res = request_mem_region(res.start, res_size,
143070e7
SR
227 dev_name(&dev->dev));
228 if (!info->list[i].res)
229 goto err_out;
230
231 err = -ENXIO;
232 width = of_get_property(dp, "bank-width", NULL);
233 if (!width) {
234 dev_err(&dev->dev, "Can't get bank width from device"
235 " tree\n");
236 goto err_out;
237 }
a2c2fe4b 238
d68cbdd4 239 info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
143070e7 240 info->list[i].map.phys = res.start;
2763c508 241 info->list[i].map.size = res_size;
766f271a 242 info->list[i].map.bankwidth = be32_to_cpup(width);
1648eaaa 243 info->list[i].map.device_node = dp;
b0afd44b
LW
244 err = of_flash_probe_versatile(dev, dp, &info->list[i].map);
245 if (err) {
246 dev_err(&dev->dev, "Can't probe Versatile VPP\n");
247 return err;
248 }
143070e7
SR
249
250 err = -ENOMEM;
251 info->list[i].map.virt = ioremap(info->list[i].map.phys,
252 info->list[i].map.size);
253 if (!info->list[i].map.virt) {
254 dev_err(&dev->dev, "Failed to ioremap() flash"
255 " region\n");
256 goto err_out;
257 }
a2c2fe4b 258
143070e7 259 simple_map_init(&info->list[i].map);
a2c2fe4b 260
d0788ce4
SR
261 /*
262 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
263 * may cause problems with JFFS2 usage, as the local bus (LPB)
264 * doesn't support unaligned accesses as implemented in the
265 * JFFS2 code via memcpy(). By setting NO_XIP, the
266 * flash will not be exposed directly to the MTD users
267 * (e.g. JFFS2) any more.
268 */
269 if (map_indirect)
270 info->list[i].map.phys = NO_XIP;
271
143070e7
SR
272 if (probe_type) {
273 info->list[i].mtd = do_map_probe(probe_type,
274 &info->list[i].map);
275 } else {
276 info->list[i].mtd = obsolete_probe(dev,
277 &info->list[i].map);
278 }
3fc1cf5f
JS
279
280 /* Fall back to mapping region as ROM */
281 if (!info->list[i].mtd) {
282 dev_warn(&dev->dev,
283 "do_map_probe() failed for type %s\n",
284 probe_type);
285
286 info->list[i].mtd = do_map_probe("map_rom",
287 &info->list[i].map);
288 }
143070e7 289 mtd_list[i] = info->list[i].mtd;
a2c2fe4b 290
143070e7
SR
291 err = -ENXIO;
292 if (!info->list[i].mtd) {
293 dev_err(&dev->dev, "do_map_probe() failed\n");
294 goto err_out;
295 } else {
296 info->list_size++;
297 }
143070e7
SR
298 info->list[i].mtd->dev.parent = &dev->dev;
299 }
2099172d 300
143070e7 301 err = 0;
e58a66d8 302 info->cmtd = NULL;
143070e7
SR
303 if (info->list_size == 1) {
304 info->cmtd = info->list[0].mtd;
305 } else if (info->list_size > 1) {
306 /*
307 * We detected multiple devices. Concatenate them together.
308 */
143070e7
SR
309 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
310 dev_name(&dev->dev));
a2c2fe4b 311 }
e58a66d8
AP
312 if (info->cmtd == NULL)
313 err = -ENXIO;
314
143070e7
SR
315 if (err)
316 goto err_out;
a2c2fe4b 317
8361a9b8 318 info->cmtd->dev.parent = &dev->dev;
004b5e60 319 mtd_set_of_node(info->cmtd, dp);
9d5da3a9 320 part_probe_types = of_get_probes(dp);
7e0c19c9
CIK
321 if (!part_probe_types) {
322 err = -ENOMEM;
323 goto err_out;
324 }
004b5e60 325 mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
f44dcbd0 326 NULL, 0);
9d5da3a9 327 of_free_probes(part_probe_types);
9a310d21 328
143070e7 329 kfree(mtd_list);
a2c2fe4b 330
a2c2fe4b
VW
331 return 0;
332
333err_out:
143070e7 334 kfree(mtd_list);
ad4fbc79 335err_flash_remove:
c4d5e375 336 of_flash_remove(dev);
143070e7 337
a2c2fe4b 338 return err;
a2c2fe4b
VW
339}
340
66610443 341static const struct of_device_id of_flash_match[] = {
2099172d
DG
342 {
343 .compatible = "cfi-flash",
344 .data = (void *)"cfi_probe",
345 },
346 {
347 /* FIXME: JEDEC chips can't be safely and reliably
348 * probed, although the mtd code gets it right in
349 * practice most of the time. We should use the
350 * vendor and device ids specified by the binding to
351 * bypass the heuristic probe code, but the mtd layer
352 * provides, at present, no interface for doing so
353 * :(. */
354 .compatible = "jedec-flash",
355 .data = (void *)"jedec_probe",
356 },
fc28c39f
WS
357 {
358 .compatible = "mtd-ram",
359 .data = (void *)"map_ram",
360 },
e5bffb59
AS
361 {
362 .compatible = "mtd-rom",
363 .data = (void *)"map_rom",
364 },
a2c2fe4b
VW
365 {
366 .type = "rom",
367 .compatible = "direct-mapped"
368 },
369 { },
370};
c4d5e375 371MODULE_DEVICE_TABLE(of, of_flash_match);
a2c2fe4b 372
1c48a5c9 373static struct platform_driver of_flash_driver = {
4018294b
GL
374 .driver = {
375 .name = "of-flash",
4018294b
GL
376 .of_match_table = of_flash_match,
377 },
c4d5e375
DG
378 .probe = of_flash_probe,
379 .remove = of_flash_remove,
a2c2fe4b
VW
380};
381
f99640de 382module_platform_driver(of_flash_driver);
a2c2fe4b
VW
383
384MODULE_LICENSE("GPL");
385MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
c4d5e375 386MODULE_DESCRIPTION("Device tree based MTD map driver");
This page took 0.551681 seconds and 5 git commands to generate.