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