• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/mtd/maps/
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/init.h>
19#include <linux/device.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/map.h>
22#include <linux/mtd/partitions.h>
23#include <linux/mtd/concat.h>
24#include <linux/of.h>
25#include <linux/of_address.h>
26#include <linux/of_platform.h>
27#include <linux/slab.h>
28
29struct of_flash_list {
30	struct mtd_info *mtd;
31	struct map_info map;
32	struct resource *res;
33};
34
35struct of_flash {
36	struct mtd_info		*cmtd;
37#ifdef CONFIG_MTD_PARTITIONS
38	struct mtd_partition	*parts;
39#endif
40	int list_size; /* number of elements in of_flash_list */
41	struct of_flash_list	list[0];
42};
43
44#ifdef CONFIG_MTD_PARTITIONS
45#define OF_FLASH_PARTS(info)	((info)->parts)
46
47static int parse_obsolete_partitions(struct platform_device *dev,
48				     struct of_flash *info,
49				     struct device_node *dp)
50{
51	int i, plen, nr_parts;
52	const struct {
53		u32 offset, len;
54	} *part;
55	const char *names;
56
57	part = of_get_property(dp, "partitions", &plen);
58	if (!part)
59		return 0; /* No partitions found */
60
61	dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
62
63	nr_parts = plen / sizeof(part[0]);
64
65	info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
66	if (!info->parts)
67		return -ENOMEM;
68
69	names = of_get_property(dp, "partition-names", &plen);
70
71	for (i = 0; i < nr_parts; i++) {
72		info->parts[i].offset = part->offset;
73		info->parts[i].size   = part->len & ~1;
74		if (part->len & 1) /* bit 0 set signifies read only partition */
75			info->parts[i].mask_flags = MTD_WRITEABLE;
76
77		if (names && (plen > 0)) {
78			int len = strlen(names) + 1;
79
80			info->parts[i].name = (char *)names;
81			plen -= len;
82			names += len;
83		} else {
84			info->parts[i].name = "unnamed";
85		}
86
87		part++;
88	}
89
90	return nr_parts;
91}
92#else /* MTD_PARTITIONS */
93#define	OF_FLASH_PARTS(info)		(0)
94#define parse_partitions(info, dev)	(0)
95#endif /* MTD_PARTITIONS */
96
97static int of_flash_remove(struct platform_device *dev)
98{
99	struct of_flash *info;
100	int i;
101
102	info = dev_get_drvdata(&dev->dev);
103	if (!info)
104		return 0;
105	dev_set_drvdata(&dev->dev, NULL);
106
107#ifdef CONFIG_MTD_CONCAT
108	if (info->cmtd != info->list[0].mtd) {
109		del_mtd_device(info->cmtd);
110		mtd_concat_destroy(info->cmtd);
111	}
112#endif
113
114	if (info->cmtd) {
115		if (OF_FLASH_PARTS(info)) {
116			del_mtd_partitions(info->cmtd);
117			kfree(OF_FLASH_PARTS(info));
118		} else {
119			del_mtd_device(info->cmtd);
120		}
121	}
122
123	for (i = 0; i < info->list_size; i++) {
124		if (info->list[i].mtd)
125			map_destroy(info->list[i].mtd);
126
127		if (info->list[i].map.virt)
128			iounmap(info->list[i].map.virt);
129
130		if (info->list[i].res) {
131			release_resource(info->list[i].res);
132			kfree(info->list[i].res);
133		}
134	}
135
136	kfree(info);
137
138	return 0;
139}
140
141/* Helper function to handle probing of the obsolete "direct-mapped"
142 * compatible binding, which has an extra "probe-type" property
143 * describing the type of flash probe necessary. */
144static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
145						  struct map_info *map)
146{
147	struct device_node *dp = dev->dev.of_node;
148	const char *of_probe;
149	struct mtd_info *mtd;
150	static const char *rom_probe_types[]
151		= { "cfi_probe", "jedec_probe", "map_rom"};
152	int i;
153
154	dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
155		 "flash binding\n");
156
157	of_probe = of_get_property(dp, "probe-type", NULL);
158	if (!of_probe) {
159		for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
160			mtd = do_map_probe(rom_probe_types[i], map);
161			if (mtd)
162				return mtd;
163		}
164		return NULL;
165	} else if (strcmp(of_probe, "CFI") == 0) {
166		return do_map_probe("cfi_probe", map);
167	} else if (strcmp(of_probe, "JEDEC") == 0) {
168		return do_map_probe("jedec_probe", map);
169	} else {
170		if (strcmp(of_probe, "ROM") != 0)
171			dev_warn(&dev->dev, "obsolete_probe: don't know probe "
172				 "type '%s', mapping as rom\n", of_probe);
173		return do_map_probe("mtd_rom", map);
174	}
175}
176
177#ifdef CONFIG_MTD_PARTITIONS
178/* When partitions are set we look for a linux,part-probe property which
179   specifies the list of partition probers to use. If none is given then the
180   default is use. These take precedence over other device tree
181   information. */
182static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
183static const char ** __devinit of_get_probes(struct device_node *dp)
184{
185	const char *cp;
186	int cplen;
187	unsigned int l;
188	unsigned int count;
189	const char **res;
190
191	cp = of_get_property(dp, "linux,part-probe", &cplen);
192	if (cp == NULL)
193		return part_probe_types_def;
194
195	count = 0;
196	for (l = 0; l != cplen; l++)
197		if (cp[l] == 0)
198			count++;
199
200	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
201	count = 0;
202	while (cplen > 0) {
203		res[count] = cp;
204		l = strlen(cp) + 1;
205		cp += l;
206		cplen -= l;
207		count++;
208	}
209	return res;
210}
211
212static void __devinit of_free_probes(const char **probes)
213{
214	if (probes != part_probe_types_def)
215		kfree(probes);
216}
217#endif
218
219static int __devinit of_flash_probe(struct platform_device *dev,
220				    const struct of_device_id *match)
221{
222#ifdef CONFIG_MTD_PARTITIONS
223	const char **part_probe_types;
224#endif
225	struct device_node *dp = dev->dev.of_node;
226	struct resource res;
227	struct of_flash *info;
228	const char *probe_type = match->data;
229	const u32 *width;
230	int err;
231	int i;
232	int count;
233	const u32 *p;
234	int reg_tuple_size;
235	struct mtd_info **mtd_list = NULL;
236	resource_size_t res_size;
237
238	reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
239
240	/*
241	 * Get number of "reg" tuples. Scan for MTD devices on area's
242	 * described by each "reg" region. This makes it possible (including
243	 * the concat support) to support the Intel P30 48F4400 chips which
244	 * consists internally of 2 non-identical NOR chips on one die.
245	 */
246	p = of_get_property(dp, "reg", &count);
247	if (count % reg_tuple_size != 0) {
248		dev_err(&dev->dev, "Malformed reg property on %s\n",
249				dev->dev.of_node->full_name);
250		err = -EINVAL;
251		goto err_flash_remove;
252	}
253	count /= reg_tuple_size;
254
255	err = -ENOMEM;
256	info = kzalloc(sizeof(struct of_flash) +
257		       sizeof(struct of_flash_list) * count, GFP_KERNEL);
258	if (!info)
259		goto err_flash_remove;
260
261	dev_set_drvdata(&dev->dev, info);
262
263	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
264	if (!mtd_list)
265		goto err_flash_remove;
266
267	for (i = 0; i < count; i++) {
268		err = -ENXIO;
269		if (of_address_to_resource(dp, i, &res)) {
270			dev_err(&dev->dev, "Can't get IO address from device"
271				" tree\n");
272			goto err_out;
273		}
274
275		dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
276			(unsigned long long)res.start,
277			(unsigned long long)res.end);
278
279		err = -EBUSY;
280		res_size = resource_size(&res);
281		info->list[i].res = request_mem_region(res.start, res_size,
282						       dev_name(&dev->dev));
283		if (!info->list[i].res)
284			goto err_out;
285
286		err = -ENXIO;
287		width = of_get_property(dp, "bank-width", NULL);
288		if (!width) {
289			dev_err(&dev->dev, "Can't get bank width from device"
290				" tree\n");
291			goto err_out;
292		}
293
294		info->list[i].map.name = dev_name(&dev->dev);
295		info->list[i].map.phys = res.start;
296		info->list[i].map.size = res_size;
297		info->list[i].map.bankwidth = *width;
298
299		err = -ENOMEM;
300		info->list[i].map.virt = ioremap(info->list[i].map.phys,
301						 info->list[i].map.size);
302		if (!info->list[i].map.virt) {
303			dev_err(&dev->dev, "Failed to ioremap() flash"
304				" region\n");
305			goto err_out;
306		}
307
308		simple_map_init(&info->list[i].map);
309
310		if (probe_type) {
311			info->list[i].mtd = do_map_probe(probe_type,
312							 &info->list[i].map);
313		} else {
314			info->list[i].mtd = obsolete_probe(dev,
315							   &info->list[i].map);
316		}
317		mtd_list[i] = info->list[i].mtd;
318
319		err = -ENXIO;
320		if (!info->list[i].mtd) {
321			dev_err(&dev->dev, "do_map_probe() failed\n");
322			goto err_out;
323		} else {
324			info->list_size++;
325		}
326		info->list[i].mtd->owner = THIS_MODULE;
327		info->list[i].mtd->dev.parent = &dev->dev;
328	}
329
330	err = 0;
331	if (info->list_size == 1) {
332		info->cmtd = info->list[0].mtd;
333	} else if (info->list_size > 1) {
334		/*
335		 * We detected multiple devices. Concatenate them together.
336		 */
337#ifdef CONFIG_MTD_CONCAT
338		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
339					       dev_name(&dev->dev));
340		if (info->cmtd == NULL)
341			err = -ENXIO;
342#else
343		printk(KERN_ERR "physmap_of: multiple devices "
344		       "found but MTD concat support disabled.\n");
345		err = -ENXIO;
346#endif
347	}
348	if (err)
349		goto err_out;
350
351#ifdef CONFIG_MTD_PARTITIONS
352	part_probe_types = of_get_probes(dp);
353	err = parse_mtd_partitions(info->cmtd, part_probe_types,
354				   &info->parts, 0);
355	if (err < 0) {
356		of_free_probes(part_probe_types);
357		goto err_out;
358	}
359	of_free_probes(part_probe_types);
360
361#ifdef CONFIG_MTD_OF_PARTS
362	if (err == 0) {
363		err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
364		if (err < 0)
365			goto err_out;
366	}
367#endif
368
369	if (err == 0) {
370		err = parse_obsolete_partitions(dev, info, dp);
371		if (err < 0)
372			goto err_out;
373	}
374
375	if (err > 0)
376		add_mtd_partitions(info->cmtd, info->parts, err);
377	else
378#endif
379		add_mtd_device(info->cmtd);
380
381	kfree(mtd_list);
382
383	return 0;
384
385err_out:
386	kfree(mtd_list);
387err_flash_remove:
388	of_flash_remove(dev);
389
390	return err;
391}
392
393static struct of_device_id of_flash_match[] = {
394	{
395		.compatible	= "cfi-flash",
396		.data		= (void *)"cfi_probe",
397	},
398	{
399		.compatible	= "jedec-flash",
400		.data		= (void *)"jedec_probe",
401	},
402	{
403		.compatible     = "mtd-ram",
404		.data           = (void *)"map_ram",
405	},
406	{
407		.type		= "rom",
408		.compatible	= "direct-mapped"
409	},
410	{ },
411};
412MODULE_DEVICE_TABLE(of, of_flash_match);
413
414static struct of_platform_driver of_flash_driver = {
415	.driver = {
416		.name = "of-flash",
417		.owner = THIS_MODULE,
418		.of_match_table = of_flash_match,
419	},
420	.probe		= of_flash_probe,
421	.remove		= of_flash_remove,
422};
423
424static int __init of_flash_init(void)
425{
426	return of_register_platform_driver(&of_flash_driver);
427}
428
429static void __exit of_flash_exit(void)
430{
431	of_unregister_platform_driver(&of_flash_driver);
432}
433
434module_init(of_flash_init);
435module_exit(of_flash_exit);
436
437MODULE_LICENSE("GPL");
438MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
439MODULE_DESCRIPTION("Device tree based MTD map driver");
440