• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Flash mappings described by the OF (or flattened) device tree
3  *
4  * Copyright (C) 2006 MontaVista Software Inc.
5  * Author: Vitaly Wool <vwool@ru.mvista.com>
6  *
7  * Revised to handle newer style flash binding by:
8  *   Copyright (C) 2007 David Gibson, IBM Corporation.
9  *
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>
18 #include <linux/device.h>
19 #include <linux/mtd/mtd.h>
20 #include <linux/mtd/map.h>
21 #include <linux/mtd/partitions.h>
22 #include <linux/mtd/concat.h>
23 #include <linux/of.h>
24 #include <linux/of_address.h>
25 #include <linux/of_platform.h>
26 #include <linux/slab.h>
27 
28 struct of_flash_list {
29 	struct mtd_info *mtd;
30 	struct map_info map;
31 	struct resource *res;
32 };
33 
34 struct of_flash {
35 	struct mtd_info		*cmtd;
36 	int list_size; /* number of elements in of_flash_list */
37 	struct of_flash_list	list[0];
38 };
39 
of_flash_remove(struct platform_device * dev)40 static int of_flash_remove(struct platform_device *dev)
41 {
42 	struct of_flash *info;
43 	int i;
44 
45 	info = dev_get_drvdata(&dev->dev);
46 	if (!info)
47 		return 0;
48 	dev_set_drvdata(&dev->dev, NULL);
49 
50 	if (info->cmtd != info->list[0].mtd) {
51 		mtd_device_unregister(info->cmtd);
52 		mtd_concat_destroy(info->cmtd);
53 	}
54 
55 	if (info->cmtd)
56 		mtd_device_unregister(info->cmtd);
57 
58 	for (i = 0; i < info->list_size; i++) {
59 		if (info->list[i].mtd)
60 			map_destroy(info->list[i].mtd);
61 
62 		if (info->list[i].map.virt)
63 			iounmap(info->list[i].map.virt);
64 
65 		if (info->list[i].res) {
66 			release_resource(info->list[i].res);
67 			kfree(info->list[i].res);
68 		}
69 	}
70 	return 0;
71 }
72 
73 static const char * const rom_probe_types[] = {
74 	"cfi_probe", "jedec_probe", "map_rom" };
75 
76 /* Helper function to handle probing of the obsolete "direct-mapped"
77  * compatible binding, which has an extra "probe-type" property
78  * describing the type of flash probe necessary. */
obsolete_probe(struct platform_device * dev,struct map_info * map)79 static struct mtd_info *obsolete_probe(struct platform_device *dev,
80 				       struct map_info *map)
81 {
82 	struct device_node *dp = dev->dev.of_node;
83 	const char *of_probe;
84 	struct mtd_info *mtd;
85 	int i;
86 
87 	dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
88 		 "flash binding\n");
89 
90 	of_probe = of_get_property(dp, "probe-type", NULL);
91 	if (!of_probe) {
92 		for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
93 			mtd = do_map_probe(rom_probe_types[i], map);
94 			if (mtd)
95 				return mtd;
96 		}
97 		return NULL;
98 	} else if (strcmp(of_probe, "CFI") == 0) {
99 		return do_map_probe("cfi_probe", map);
100 	} else if (strcmp(of_probe, "JEDEC") == 0) {
101 		return do_map_probe("jedec_probe", map);
102 	} else {
103 		if (strcmp(of_probe, "ROM") != 0)
104 			dev_warn(&dev->dev, "obsolete_probe: don't know probe "
105 				 "type '%s', mapping as rom\n", of_probe);
106 		return do_map_probe("map_rom", map);
107 	}
108 }
109 
110 /* When partitions are set we look for a linux,part-probe property which
111    specifies the list of partition probers to use. If none is given then the
112    default is use. These take precedence over other device tree
113    information. */
114 static const char * const part_probe_types_def[] = {
115 	"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
116 
of_get_probes(struct device_node * dp)117 static const char * const *of_get_probes(struct device_node *dp)
118 {
119 	const char *cp;
120 	int cplen;
121 	unsigned int l;
122 	unsigned int count;
123 	const char **res;
124 
125 	cp = of_get_property(dp, "linux,part-probe", &cplen);
126 	if (cp == NULL)
127 		return part_probe_types_def;
128 
129 	count = 0;
130 	for (l = 0; l != cplen; l++)
131 		if (cp[l] == 0)
132 			count++;
133 
134 	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
135 	count = 0;
136 	while (cplen > 0) {
137 		res[count] = cp;
138 		l = strlen(cp) + 1;
139 		cp += l;
140 		cplen -= l;
141 		count++;
142 	}
143 	return res;
144 }
145 
of_free_probes(const char * const * probes)146 static void of_free_probes(const char * const *probes)
147 {
148 	if (probes != part_probe_types_def)
149 		kfree(probes);
150 }
151 
152 static struct of_device_id of_flash_match[];
of_flash_probe(struct platform_device * dev)153 static int of_flash_probe(struct platform_device *dev)
154 {
155 	const char * const *part_probe_types;
156 	const struct of_device_id *match;
157 	struct device_node *dp = dev->dev.of_node;
158 	struct resource res;
159 	struct of_flash *info;
160 	const char *probe_type;
161 	const __be32 *width;
162 	int err;
163 	int i;
164 	int count;
165 	const __be32 *p;
166 	int reg_tuple_size;
167 	struct mtd_info **mtd_list = NULL;
168 	resource_size_t res_size;
169 	struct mtd_part_parser_data ppdata;
170 	bool map_indirect;
171 	const char *mtd_name = NULL;
172 
173 	match = of_match_device(of_flash_match, &dev->dev);
174 	if (!match)
175 		return -EINVAL;
176 	probe_type = match->data;
177 
178 	reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
179 
180 	of_property_read_string(dp, "linux,mtd-name", &mtd_name);
181 
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);
189 	if (count % reg_tuple_size != 0) {
190 		dev_err(&dev->dev, "Malformed reg property on %s\n",
191 				dev->dev.of_node->full_name);
192 		err = -EINVAL;
193 		goto err_flash_remove;
194 	}
195 	count /= reg_tuple_size;
196 
197 	map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
198 
199 	err = -ENOMEM;
200 	info = devm_kzalloc(&dev->dev,
201 			    sizeof(struct of_flash) +
202 			    sizeof(struct of_flash_list) * count, GFP_KERNEL);
203 	if (!info)
204 		goto err_flash_remove;
205 
206 	dev_set_drvdata(&dev->dev, info);
207 
208 	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
209 	if (!mtd_list)
210 		goto err_flash_remove;
211 
212 	for (i = 0; i < count; i++) {
213 		err = -ENXIO;
214 		if (of_address_to_resource(dp, i, &res)) {
215 			/*
216 			 * Continue with next register tuple if this
217 			 * one is not mappable
218 			 */
219 			continue;
220 		}
221 
222 		dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
223 
224 		err = -EBUSY;
225 		res_size = resource_size(&res);
226 		info->list[i].res = request_mem_region(res.start, res_size,
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 		}
238 
239 		info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
240 		info->list[i].map.phys = res.start;
241 		info->list[i].map.size = res_size;
242 		info->list[i].map.bankwidth = be32_to_cpup(width);
243 		info->list[i].map.device_node = dp;
244 
245 		err = -ENOMEM;
246 		info->list[i].map.virt = ioremap(info->list[i].map.phys,
247 						 info->list[i].map.size);
248 		if (!info->list[i].map.virt) {
249 			dev_err(&dev->dev, "Failed to ioremap() flash"
250 				" region\n");
251 			goto err_out;
252 		}
253 
254 		simple_map_init(&info->list[i].map);
255 
256 		/*
257 		 * On some platforms (e.g. MPC5200) a direct 1:1 mapping
258 		 * may cause problems with JFFS2 usage, as the local bus (LPB)
259 		 * doesn't support unaligned accesses as implemented in the
260 		 * JFFS2 code via memcpy(). By setting NO_XIP, the
261 		 * flash will not be exposed directly to the MTD users
262 		 * (e.g. JFFS2) any more.
263 		 */
264 		if (map_indirect)
265 			info->list[i].map.phys = NO_XIP;
266 
267 		if (probe_type) {
268 			info->list[i].mtd = do_map_probe(probe_type,
269 							 &info->list[i].map);
270 		} else {
271 			info->list[i].mtd = obsolete_probe(dev,
272 							   &info->list[i].map);
273 		}
274 		mtd_list[i] = info->list[i].mtd;
275 
276 		err = -ENXIO;
277 		if (!info->list[i].mtd) {
278 			dev_err(&dev->dev, "do_map_probe() failed\n");
279 			goto err_out;
280 		} else {
281 			info->list_size++;
282 		}
283 		info->list[i].mtd->owner = THIS_MODULE;
284 		info->list[i].mtd->dev.parent = &dev->dev;
285 	}
286 
287 	err = 0;
288 	info->cmtd = NULL;
289 	if (info->list_size == 1) {
290 		info->cmtd = info->list[0].mtd;
291 	} else if (info->list_size > 1) {
292 		/*
293 		 * We detected multiple devices. Concatenate them together.
294 		 */
295 		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
296 					       dev_name(&dev->dev));
297 	}
298 	if (info->cmtd == NULL)
299 		err = -ENXIO;
300 
301 	if (err)
302 		goto err_out;
303 
304 	ppdata.of_node = dp;
305 	part_probe_types = of_get_probes(dp);
306 	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
307 			NULL, 0);
308 	of_free_probes(part_probe_types);
309 
310 	kfree(mtd_list);
311 
312 	return 0;
313 
314 err_out:
315 	kfree(mtd_list);
316 err_flash_remove:
317 	of_flash_remove(dev);
318 
319 	return err;
320 }
321 
322 static struct of_device_id of_flash_match[] = {
323 	{
324 		.compatible	= "cfi-flash",
325 		.data		= (void *)"cfi_probe",
326 	},
327 	{
328 		/* FIXME: JEDEC chips can't be safely and reliably
329 		 * probed, although the mtd code gets it right in
330 		 * practice most of the time.  We should use the
331 		 * vendor and device ids specified by the binding to
332 		 * bypass the heuristic probe code, but the mtd layer
333 		 * provides, at present, no interface for doing so
334 		 * :(. */
335 		.compatible	= "jedec-flash",
336 		.data		= (void *)"jedec_probe",
337 	},
338 	{
339 		.compatible     = "mtd-ram",
340 		.data           = (void *)"map_ram",
341 	},
342 	{
343 		.compatible     = "mtd-rom",
344 		.data           = (void *)"map_rom",
345 	},
346 	{
347 		.type		= "rom",
348 		.compatible	= "direct-mapped"
349 	},
350 	{ },
351 };
352 MODULE_DEVICE_TABLE(of, of_flash_match);
353 
354 static struct platform_driver of_flash_driver = {
355 	.driver = {
356 		.name = "of-flash",
357 		.owner = THIS_MODULE,
358 		.of_match_table = of_flash_match,
359 	},
360 	.probe		= of_flash_probe,
361 	.remove		= of_flash_remove,
362 };
363 
364 module_platform_driver(of_flash_driver);
365 
366 MODULE_LICENSE("GPL");
367 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
368 MODULE_DESCRIPTION("Device tree based MTD map driver");
369