Linux Audio

Check our new training course

Loading...
  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	int list_size; /* number of elements in of_flash_list */
 38	struct of_flash_list	list[0];
 39};
 40
 41static int of_flash_remove(struct platform_device *dev)
 42{
 43	struct of_flash *info;
 44	int i;
 45
 46	info = dev_get_drvdata(&dev->dev);
 47	if (!info)
 48		return 0;
 49	dev_set_drvdata(&dev->dev, NULL);
 50
 51	if (info->cmtd != info->list[0].mtd) {
 52		mtd_device_unregister(info->cmtd);
 53		mtd_concat_destroy(info->cmtd);
 54	}
 55
 56	if (info->cmtd)
 57		mtd_device_unregister(info->cmtd);
 58
 59	for (i = 0; i < info->list_size; i++) {
 60		if (info->list[i].mtd)
 61			map_destroy(info->list[i].mtd);
 62
 63		if (info->list[i].map.virt)
 64			iounmap(info->list[i].map.virt);
 65
 66		if (info->list[i].res) {
 67			release_resource(info->list[i].res);
 68			kfree(info->list[i].res);
 69		}
 70	}
 71
 72	kfree(info);
 73
 74	return 0;
 75}
 76
 77/* Helper function to handle probing of the obsolete "direct-mapped"
 78 * compatible binding, which has an extra "probe-type" property
 79 * describing the type of flash probe necessary. */
 80static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
 81						  struct map_info *map)
 82{
 83	struct device_node *dp = dev->dev.of_node;
 84	const char *of_probe;
 85	struct mtd_info *mtd;
 86	static const char *rom_probe_types[]
 87		= { "cfi_probe", "jedec_probe", "map_rom"};
 88	int i;
 89
 90	dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
 91		 "flash binding\n");
 92
 93	of_probe = of_get_property(dp, "probe-type", NULL);
 94	if (!of_probe) {
 95		for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
 96			mtd = do_map_probe(rom_probe_types[i], map);
 97			if (mtd)
 98				return mtd;
 99		}
100		return NULL;
101	} else if (strcmp(of_probe, "CFI") == 0) {
102		return do_map_probe("cfi_probe", map);
103	} else if (strcmp(of_probe, "JEDEC") == 0) {
104		return do_map_probe("jedec_probe", map);
105	} else {
106		if (strcmp(of_probe, "ROM") != 0)
107			dev_warn(&dev->dev, "obsolete_probe: don't know probe "
108				 "type '%s', mapping as rom\n", of_probe);
109		return do_map_probe("mtd_rom", map);
110	}
111}
112
113/* When partitions are set we look for a linux,part-probe property which
114   specifies the list of partition probers to use. If none is given then the
115   default is use. These take precedence over other device tree
116   information. */
117static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
118					"ofpart", "ofoldpart", NULL };
119static const char ** __devinit of_get_probes(struct device_node *dp)
120{
121	const char *cp;
122	int cplen;
123	unsigned int l;
124	unsigned int count;
125	const char **res;
126
127	cp = of_get_property(dp, "linux,part-probe", &cplen);
128	if (cp == NULL)
129		return part_probe_types_def;
130
131	count = 0;
132	for (l = 0; l != cplen; l++)
133		if (cp[l] == 0)
134			count++;
135
136	res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
137	count = 0;
138	while (cplen > 0) {
139		res[count] = cp;
140		l = strlen(cp) + 1;
141		cp += l;
142		cplen -= l;
143		count++;
144	}
145	return res;
146}
147
148static void __devinit of_free_probes(const char **probes)
149{
150	if (probes != part_probe_types_def)
151		kfree(probes);
152}
153
154static struct of_device_id of_flash_match[];
155static int __devinit of_flash_probe(struct platform_device *dev)
156{
157	const char **part_probe_types;
158	const struct of_device_id *match;
159	struct device_node *dp = dev->dev.of_node;
160	struct resource res;
161	struct of_flash *info;
162	const char *probe_type;
163	const __be32 *width;
164	int err;
165	int i;
166	int count;
167	const __be32 *p;
168	int reg_tuple_size;
169	struct mtd_info **mtd_list = NULL;
170	resource_size_t res_size;
171	struct mtd_part_parser_data ppdata;
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	/*
181	 * Get number of "reg" tuples. Scan for MTD devices on area's
182	 * described by each "reg" region. This makes it possible (including
183	 * the concat support) to support the Intel P30 48F4400 chips which
184	 * consists internally of 2 non-identical NOR chips on one die.
185	 */
186	p = of_get_property(dp, "reg", &count);
187	if (count % reg_tuple_size != 0) {
188		dev_err(&dev->dev, "Malformed reg property on %s\n",
189				dev->dev.of_node->full_name);
190		err = -EINVAL;
191		goto err_flash_remove;
192	}
193	count /= reg_tuple_size;
194
195	err = -ENOMEM;
196	info = kzalloc(sizeof(struct of_flash) +
197		       sizeof(struct of_flash_list) * count, GFP_KERNEL);
198	if (!info)
199		goto err_flash_remove;
200
201	dev_set_drvdata(&dev->dev, info);
202
203	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
204	if (!mtd_list)
205		goto err_flash_remove;
206
207	for (i = 0; i < count; i++) {
208		err = -ENXIO;
209		if (of_address_to_resource(dp, i, &res)) {
210			/*
211			 * Continue with next register tuple if this
212			 * one is not mappable
213			 */
214			continue;
215		}
216
217		dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
218
219		err = -EBUSY;
220		res_size = resource_size(&res);
221		info->list[i].res = request_mem_region(res.start, res_size,
222						       dev_name(&dev->dev));
223		if (!info->list[i].res)
224			goto err_out;
225
226		err = -ENXIO;
227		width = of_get_property(dp, "bank-width", NULL);
228		if (!width) {
229			dev_err(&dev->dev, "Can't get bank width from device"
230				" tree\n");
231			goto err_out;
232		}
233
234		info->list[i].map.name = dev_name(&dev->dev);
235		info->list[i].map.phys = res.start;
236		info->list[i].map.size = res_size;
237		info->list[i].map.bankwidth = be32_to_cpup(width);
238
239		err = -ENOMEM;
240		info->list[i].map.virt = ioremap(info->list[i].map.phys,
241						 info->list[i].map.size);
242		if (!info->list[i].map.virt) {
243			dev_err(&dev->dev, "Failed to ioremap() flash"
244				" region\n");
245			goto err_out;
246		}
247
248		simple_map_init(&info->list[i].map);
249
250		if (probe_type) {
251			info->list[i].mtd = do_map_probe(probe_type,
252							 &info->list[i].map);
253		} else {
254			info->list[i].mtd = obsolete_probe(dev,
255							   &info->list[i].map);
256		}
257		mtd_list[i] = info->list[i].mtd;
258
259		err = -ENXIO;
260		if (!info->list[i].mtd) {
261			dev_err(&dev->dev, "do_map_probe() failed\n");
262			goto err_out;
263		} else {
264			info->list_size++;
265		}
266		info->list[i].mtd->owner = THIS_MODULE;
267		info->list[i].mtd->dev.parent = &dev->dev;
268	}
269
270	err = 0;
271	if (info->list_size == 1) {
272		info->cmtd = info->list[0].mtd;
273	} else if (info->list_size > 1) {
274		/*
275		 * We detected multiple devices. Concatenate them together.
276		 */
277		info->cmtd = mtd_concat_create(mtd_list, info->list_size,
278					       dev_name(&dev->dev));
279		if (info->cmtd == NULL)
280			err = -ENXIO;
281	}
282	if (err)
283		goto err_out;
284
285	ppdata.of_node = dp;
286	part_probe_types = of_get_probes(dp);
287	mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata,
288			NULL, 0);
289	of_free_probes(part_probe_types);
290
291	kfree(mtd_list);
292
293	return 0;
294
295err_out:
296	kfree(mtd_list);
297err_flash_remove:
298	of_flash_remove(dev);
299
300	return err;
301}
302
303static struct of_device_id of_flash_match[] = {
304	{
305		.compatible	= "cfi-flash",
306		.data		= (void *)"cfi_probe",
307	},
308	{
309		/* FIXME: JEDEC chips can't be safely and reliably
310		 * probed, although the mtd code gets it right in
311		 * practice most of the time.  We should use the
312		 * vendor and device ids specified by the binding to
313		 * bypass the heuristic probe code, but the mtd layer
314		 * provides, at present, no interface for doing so
315		 * :(. */
316		.compatible	= "jedec-flash",
317		.data		= (void *)"jedec_probe",
318	},
319	{
320		.compatible     = "mtd-ram",
321		.data           = (void *)"map_ram",
322	},
323	{
324		.type		= "rom",
325		.compatible	= "direct-mapped"
326	},
327	{ },
328};
329MODULE_DEVICE_TABLE(of, of_flash_match);
330
331static struct platform_driver of_flash_driver = {
332	.driver = {
333		.name = "of-flash",
334		.owner = THIS_MODULE,
335		.of_match_table = of_flash_match,
336	},
337	.probe		= of_flash_probe,
338	.remove		= of_flash_remove,
339};
340
341module_platform_driver(of_flash_driver);
342
343MODULE_LICENSE("GPL");
344MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
345MODULE_DESCRIPTION("Device tree based MTD map driver");