1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Normal mappings of chips in physical memory
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2003 MontaVista Software Inc.
6*4882a593Smuzhiyun * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * 031022 - [jsun] add run-time configure and partition setup
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Device tree support:
11*4882a593Smuzhiyun * Copyright (C) 2006 MontaVista Software Inc.
12*4882a593Smuzhiyun * Author: Vitaly Wool <vwool@ru.mvista.com>
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Revised to handle newer style flash binding by:
15*4882a593Smuzhiyun * Copyright (C) 2007 David Gibson, IBM Corporation.
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * GPIO address extension:
18*4882a593Smuzhiyun * Handle the case where a flash device is mostly addressed using physical
19*4882a593Smuzhiyun * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash
20*4882a593Smuzhiyun * to a 2MiB memory range and use the GPIOs to select a particular range.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * Copyright © 2000 Nicolas Pitre <nico@cam.org>
23*4882a593Smuzhiyun * Copyright © 2005-2009 Analog Devices Inc.
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/types.h>
28*4882a593Smuzhiyun #include <linux/kernel.h>
29*4882a593Smuzhiyun #include <linux/init.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun #include <linux/device.h>
32*4882a593Smuzhiyun #include <linux/platform_device.h>
33*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
34*4882a593Smuzhiyun #include <linux/mtd/map.h>
35*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
36*4882a593Smuzhiyun #include <linux/mtd/physmap.h>
37*4882a593Smuzhiyun #include <linux/mtd/concat.h>
38*4882a593Smuzhiyun #include <linux/mtd/cfi_endian.h>
39*4882a593Smuzhiyun #include <linux/io.h>
40*4882a593Smuzhiyun #include <linux/of_device.h>
41*4882a593Smuzhiyun #include <linux/pm_runtime.h>
42*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include "physmap-bt1-rom.h"
45*4882a593Smuzhiyun #include "physmap-gemini.h"
46*4882a593Smuzhiyun #include "physmap-ixp4xx.h"
47*4882a593Smuzhiyun #include "physmap-versatile.h"
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun struct physmap_flash_info {
50*4882a593Smuzhiyun unsigned int nmaps;
51*4882a593Smuzhiyun struct mtd_info **mtds;
52*4882a593Smuzhiyun struct mtd_info *cmtd;
53*4882a593Smuzhiyun struct map_info *maps;
54*4882a593Smuzhiyun spinlock_t vpp_lock;
55*4882a593Smuzhiyun int vpp_refcnt;
56*4882a593Smuzhiyun const char *probe_type;
57*4882a593Smuzhiyun const char * const *part_types;
58*4882a593Smuzhiyun unsigned int nparts;
59*4882a593Smuzhiyun const struct mtd_partition *parts;
60*4882a593Smuzhiyun struct gpio_descs *gpios;
61*4882a593Smuzhiyun unsigned int gpio_values;
62*4882a593Smuzhiyun unsigned int win_order;
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
physmap_flash_remove(struct platform_device * dev)65*4882a593Smuzhiyun static int physmap_flash_remove(struct platform_device *dev)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct physmap_flash_info *info;
68*4882a593Smuzhiyun struct physmap_flash_data *physmap_data;
69*4882a593Smuzhiyun int i, err = 0;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun info = platform_get_drvdata(dev);
72*4882a593Smuzhiyun if (!info) {
73*4882a593Smuzhiyun err = -EINVAL;
74*4882a593Smuzhiyun goto out;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (info->cmtd) {
78*4882a593Smuzhiyun err = mtd_device_unregister(info->cmtd);
79*4882a593Smuzhiyun if (err)
80*4882a593Smuzhiyun goto out;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (info->cmtd != info->mtds[0])
83*4882a593Smuzhiyun mtd_concat_destroy(info->cmtd);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun for (i = 0; i < info->nmaps; i++) {
87*4882a593Smuzhiyun if (info->mtds[i])
88*4882a593Smuzhiyun map_destroy(info->mtds[i]);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun physmap_data = dev_get_platdata(&dev->dev);
92*4882a593Smuzhiyun if (physmap_data && physmap_data->exit)
93*4882a593Smuzhiyun physmap_data->exit(dev);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun out:
96*4882a593Smuzhiyun pm_runtime_put(&dev->dev);
97*4882a593Smuzhiyun pm_runtime_disable(&dev->dev);
98*4882a593Smuzhiyun return err;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
physmap_set_vpp(struct map_info * map,int state)101*4882a593Smuzhiyun static void physmap_set_vpp(struct map_info *map, int state)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct platform_device *pdev;
104*4882a593Smuzhiyun struct physmap_flash_data *physmap_data;
105*4882a593Smuzhiyun struct physmap_flash_info *info;
106*4882a593Smuzhiyun unsigned long flags;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun pdev = (struct platform_device *)map->map_priv_1;
109*4882a593Smuzhiyun physmap_data = dev_get_platdata(&pdev->dev);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (!physmap_data->set_vpp)
112*4882a593Smuzhiyun return;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun info = platform_get_drvdata(pdev);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun spin_lock_irqsave(&info->vpp_lock, flags);
117*4882a593Smuzhiyun if (state) {
118*4882a593Smuzhiyun if (++info->vpp_refcnt == 1) /* first nested 'on' */
119*4882a593Smuzhiyun physmap_data->set_vpp(pdev, 1);
120*4882a593Smuzhiyun } else {
121*4882a593Smuzhiyun if (--info->vpp_refcnt == 0) /* last nested 'off' */
122*4882a593Smuzhiyun physmap_data->set_vpp(pdev, 0);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun spin_unlock_irqrestore(&info->vpp_lock, flags);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
physmap_set_addr_gpios(struct physmap_flash_info * info,unsigned long ofs)128*4882a593Smuzhiyun static void physmap_set_addr_gpios(struct physmap_flash_info *info,
129*4882a593Smuzhiyun unsigned long ofs)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun unsigned int i;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun ofs >>= info->win_order;
134*4882a593Smuzhiyun if (info->gpio_values == ofs)
135*4882a593Smuzhiyun return;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun for (i = 0; i < info->gpios->ndescs; i++) {
138*4882a593Smuzhiyun if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
139*4882a593Smuzhiyun continue;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun info->gpio_values = ofs;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun #define win_mask(order) (BIT(order) - 1)
148*4882a593Smuzhiyun
physmap_addr_gpios_read(struct map_info * map,unsigned long ofs)149*4882a593Smuzhiyun static map_word physmap_addr_gpios_read(struct map_info *map,
150*4882a593Smuzhiyun unsigned long ofs)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun struct platform_device *pdev;
153*4882a593Smuzhiyun struct physmap_flash_info *info;
154*4882a593Smuzhiyun map_word mw;
155*4882a593Smuzhiyun u16 word;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun pdev = (struct platform_device *)map->map_priv_1;
158*4882a593Smuzhiyun info = platform_get_drvdata(pdev);
159*4882a593Smuzhiyun physmap_set_addr_gpios(info, ofs);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun word = readw(map->virt + (ofs & win_mask(info->win_order)));
162*4882a593Smuzhiyun mw.x[0] = word;
163*4882a593Smuzhiyun return mw;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
physmap_addr_gpios_copy_from(struct map_info * map,void * buf,unsigned long ofs,ssize_t len)166*4882a593Smuzhiyun static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
167*4882a593Smuzhiyun unsigned long ofs, ssize_t len)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct platform_device *pdev;
170*4882a593Smuzhiyun struct physmap_flash_info *info;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun pdev = (struct platform_device *)map->map_priv_1;
173*4882a593Smuzhiyun info = platform_get_drvdata(pdev);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun while (len) {
176*4882a593Smuzhiyun unsigned int winofs = ofs & win_mask(info->win_order);
177*4882a593Smuzhiyun unsigned int chunklen = min_t(unsigned int, len,
178*4882a593Smuzhiyun BIT(info->win_order) - winofs);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun physmap_set_addr_gpios(info, ofs);
181*4882a593Smuzhiyun memcpy_fromio(buf, map->virt + winofs, chunklen);
182*4882a593Smuzhiyun len -= chunklen;
183*4882a593Smuzhiyun buf += chunklen;
184*4882a593Smuzhiyun ofs += chunklen;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
physmap_addr_gpios_write(struct map_info * map,map_word mw,unsigned long ofs)188*4882a593Smuzhiyun static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
189*4882a593Smuzhiyun unsigned long ofs)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct platform_device *pdev;
192*4882a593Smuzhiyun struct physmap_flash_info *info;
193*4882a593Smuzhiyun u16 word;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun pdev = (struct platform_device *)map->map_priv_1;
196*4882a593Smuzhiyun info = platform_get_drvdata(pdev);
197*4882a593Smuzhiyun physmap_set_addr_gpios(info, ofs);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun word = mw.x[0];
200*4882a593Smuzhiyun writew(word, map->virt + (ofs & win_mask(info->win_order)));
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
physmap_addr_gpios_copy_to(struct map_info * map,unsigned long ofs,const void * buf,ssize_t len)203*4882a593Smuzhiyun static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
204*4882a593Smuzhiyun const void *buf, ssize_t len)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun struct platform_device *pdev;
207*4882a593Smuzhiyun struct physmap_flash_info *info;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun pdev = (struct platform_device *)map->map_priv_1;
210*4882a593Smuzhiyun info = platform_get_drvdata(pdev);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun while (len) {
213*4882a593Smuzhiyun unsigned int winofs = ofs & win_mask(info->win_order);
214*4882a593Smuzhiyun unsigned int chunklen = min_t(unsigned int, len,
215*4882a593Smuzhiyun BIT(info->win_order) - winofs);
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun physmap_set_addr_gpios(info, ofs);
218*4882a593Smuzhiyun memcpy_toio(map->virt + winofs, buf, chunklen);
219*4882a593Smuzhiyun len -= chunklen;
220*4882a593Smuzhiyun buf += chunklen;
221*4882a593Smuzhiyun ofs += chunklen;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
physmap_addr_gpios_map_init(struct map_info * map)225*4882a593Smuzhiyun static int physmap_addr_gpios_map_init(struct map_info *map)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun map->phys = NO_XIP;
228*4882a593Smuzhiyun map->read = physmap_addr_gpios_read;
229*4882a593Smuzhiyun map->copy_from = physmap_addr_gpios_copy_from;
230*4882a593Smuzhiyun map->write = physmap_addr_gpios_write;
231*4882a593Smuzhiyun map->copy_to = physmap_addr_gpios_copy_to;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun return 0;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun #else
physmap_addr_gpios_map_init(struct map_info * map)236*4882a593Smuzhiyun static int physmap_addr_gpios_map_init(struct map_info *map)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun return -ENOTSUPP;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun #endif
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
243*4882a593Smuzhiyun static const struct of_device_id of_flash_match[] = {
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun .compatible = "cfi-flash",
246*4882a593Smuzhiyun .data = "cfi_probe",
247*4882a593Smuzhiyun },
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun /*
250*4882a593Smuzhiyun * FIXME: JEDEC chips can't be safely and reliably
251*4882a593Smuzhiyun * probed, although the mtd code gets it right in
252*4882a593Smuzhiyun * practice most of the time. We should use the
253*4882a593Smuzhiyun * vendor and device ids specified by the binding to
254*4882a593Smuzhiyun * bypass the heuristic probe code, but the mtd layer
255*4882a593Smuzhiyun * provides, at present, no interface for doing so
256*4882a593Smuzhiyun * :(.
257*4882a593Smuzhiyun */
258*4882a593Smuzhiyun .compatible = "jedec-flash",
259*4882a593Smuzhiyun .data = "jedec_probe",
260*4882a593Smuzhiyun },
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun .compatible = "mtd-ram",
263*4882a593Smuzhiyun .data = "map_ram",
264*4882a593Smuzhiyun },
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun .compatible = "mtd-rom",
267*4882a593Smuzhiyun .data = "map_rom",
268*4882a593Smuzhiyun },
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun .type = "rom",
271*4882a593Smuzhiyun .compatible = "direct-mapped"
272*4882a593Smuzhiyun },
273*4882a593Smuzhiyun { /* sentinel */ },
274*4882a593Smuzhiyun };
275*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_flash_match);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun static const char * const of_default_part_probes[] = {
278*4882a593Smuzhiyun "cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL
279*4882a593Smuzhiyun };
280*4882a593Smuzhiyun
of_get_part_probes(struct platform_device * dev)281*4882a593Smuzhiyun static const char * const *of_get_part_probes(struct platform_device *dev)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun struct device_node *dp = dev->dev.of_node;
284*4882a593Smuzhiyun const char **res;
285*4882a593Smuzhiyun int count;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun count = of_property_count_strings(dp, "linux,part-probe");
288*4882a593Smuzhiyun if (count < 0)
289*4882a593Smuzhiyun return of_default_part_probes;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL);
292*4882a593Smuzhiyun if (!res)
293*4882a593Smuzhiyun return NULL;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun count = of_property_read_string_array(dp, "linux,part-probe", res,
296*4882a593Smuzhiyun count);
297*4882a593Smuzhiyun if (count < 0)
298*4882a593Smuzhiyun return NULL;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun return res;
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
of_select_probe_type(struct platform_device * dev)303*4882a593Smuzhiyun static const char *of_select_probe_type(struct platform_device *dev)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun struct device_node *dp = dev->dev.of_node;
306*4882a593Smuzhiyun const struct of_device_id *match;
307*4882a593Smuzhiyun const char *probe_type;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun match = of_match_device(of_flash_match, &dev->dev);
310*4882a593Smuzhiyun probe_type = match->data;
311*4882a593Smuzhiyun if (probe_type)
312*4882a593Smuzhiyun return probe_type;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun dev_warn(&dev->dev,
315*4882a593Smuzhiyun "Device tree uses obsolete \"direct-mapped\" flash binding\n");
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun of_property_read_string(dp, "probe-type", &probe_type);
318*4882a593Smuzhiyun if (!probe_type)
319*4882a593Smuzhiyun return NULL;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (!strcmp(probe_type, "CFI")) {
322*4882a593Smuzhiyun probe_type = "cfi_probe";
323*4882a593Smuzhiyun } else if (!strcmp(probe_type, "JEDEC")) {
324*4882a593Smuzhiyun probe_type = "jedec_probe";
325*4882a593Smuzhiyun } else if (!strcmp(probe_type, "ROM")) {
326*4882a593Smuzhiyun probe_type = "map_rom";
327*4882a593Smuzhiyun } else {
328*4882a593Smuzhiyun dev_warn(&dev->dev,
329*4882a593Smuzhiyun "obsolete_probe: don't know probe type '%s', mapping as rom\n",
330*4882a593Smuzhiyun probe_type);
331*4882a593Smuzhiyun probe_type = "map_rom";
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun return probe_type;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
physmap_flash_of_init(struct platform_device * dev)337*4882a593Smuzhiyun static int physmap_flash_of_init(struct platform_device *dev)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun struct physmap_flash_info *info = platform_get_drvdata(dev);
340*4882a593Smuzhiyun struct device_node *dp = dev->dev.of_node;
341*4882a593Smuzhiyun const char *mtd_name = NULL;
342*4882a593Smuzhiyun int err, swap = 0;
343*4882a593Smuzhiyun bool map_indirect;
344*4882a593Smuzhiyun unsigned int i;
345*4882a593Smuzhiyun u32 bankwidth;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun if (!dp)
348*4882a593Smuzhiyun return -EINVAL;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun info->probe_type = of_select_probe_type(dev);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun info->part_types = of_get_part_probes(dev);
353*4882a593Smuzhiyun if (!info->part_types)
354*4882a593Smuzhiyun return -ENOMEM;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun of_property_read_string(dp, "linux,mtd-name", &mtd_name);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun err = of_property_read_u32(dp, "bank-width", &bankwidth);
361*4882a593Smuzhiyun if (err) {
362*4882a593Smuzhiyun dev_err(&dev->dev, "Can't get bank width from device tree\n");
363*4882a593Smuzhiyun return err;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (of_property_read_bool(dp, "big-endian"))
367*4882a593Smuzhiyun swap = CFI_BIG_ENDIAN;
368*4882a593Smuzhiyun else if (of_property_read_bool(dp, "little-endian"))
369*4882a593Smuzhiyun swap = CFI_LITTLE_ENDIAN;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun for (i = 0; i < info->nmaps; i++) {
372*4882a593Smuzhiyun info->maps[i].name = mtd_name;
373*4882a593Smuzhiyun info->maps[i].swap = swap;
374*4882a593Smuzhiyun info->maps[i].bankwidth = bankwidth;
375*4882a593Smuzhiyun info->maps[i].device_node = dp;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
378*4882a593Smuzhiyun if (err)
379*4882a593Smuzhiyun return err;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
382*4882a593Smuzhiyun if (err)
383*4882a593Smuzhiyun return err;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]);
386*4882a593Smuzhiyun if (err)
387*4882a593Smuzhiyun return err;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
390*4882a593Smuzhiyun if (err)
391*4882a593Smuzhiyun return err;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /*
394*4882a593Smuzhiyun * On some platforms (e.g. MPC5200) a direct 1:1 mapping
395*4882a593Smuzhiyun * may cause problems with JFFS2 usage, as the local bus (LPB)
396*4882a593Smuzhiyun * doesn't support unaligned accesses as implemented in the
397*4882a593Smuzhiyun * JFFS2 code via memcpy(). By setting NO_XIP, the
398*4882a593Smuzhiyun * flash will not be exposed directly to the MTD users
399*4882a593Smuzhiyun * (e.g. JFFS2) any more.
400*4882a593Smuzhiyun */
401*4882a593Smuzhiyun if (map_indirect)
402*4882a593Smuzhiyun info->maps[i].phys = NO_XIP;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun return 0;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun #else /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
408*4882a593Smuzhiyun #define of_flash_match NULL
409*4882a593Smuzhiyun
physmap_flash_of_init(struct platform_device * dev)410*4882a593Smuzhiyun static int physmap_flash_of_init(struct platform_device *dev)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun return -ENOTSUPP;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun #endif /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun static const char * const rom_probe_types[] = {
417*4882a593Smuzhiyun "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom",
418*4882a593Smuzhiyun };
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun static const char * const part_probe_types[] = {
421*4882a593Smuzhiyun "cmdlinepart", "RedBoot", "afs", NULL
422*4882a593Smuzhiyun };
423*4882a593Smuzhiyun
physmap_flash_pdata_init(struct platform_device * dev)424*4882a593Smuzhiyun static int physmap_flash_pdata_init(struct platform_device *dev)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun struct physmap_flash_info *info = platform_get_drvdata(dev);
427*4882a593Smuzhiyun struct physmap_flash_data *physmap_data;
428*4882a593Smuzhiyun unsigned int i;
429*4882a593Smuzhiyun int err;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun physmap_data = dev_get_platdata(&dev->dev);
432*4882a593Smuzhiyun if (!physmap_data)
433*4882a593Smuzhiyun return -EINVAL;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun info->probe_type = physmap_data->probe_type;
436*4882a593Smuzhiyun info->part_types = physmap_data->part_probe_types ? : part_probe_types;
437*4882a593Smuzhiyun info->parts = physmap_data->parts;
438*4882a593Smuzhiyun info->nparts = physmap_data->nr_parts;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (physmap_data->init) {
441*4882a593Smuzhiyun err = physmap_data->init(dev);
442*4882a593Smuzhiyun if (err)
443*4882a593Smuzhiyun return err;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun for (i = 0; i < info->nmaps; i++) {
447*4882a593Smuzhiyun info->maps[i].bankwidth = physmap_data->width;
448*4882a593Smuzhiyun info->maps[i].pfow_base = physmap_data->pfow_base;
449*4882a593Smuzhiyun info->maps[i].set_vpp = physmap_set_vpp;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun return 0;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
physmap_flash_probe(struct platform_device * dev)455*4882a593Smuzhiyun static int physmap_flash_probe(struct platform_device *dev)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun struct physmap_flash_info *info;
458*4882a593Smuzhiyun int err = 0;
459*4882a593Smuzhiyun int i;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun if (!dev->dev.of_node && !dev_get_platdata(&dev->dev))
462*4882a593Smuzhiyun return -EINVAL;
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
465*4882a593Smuzhiyun if (!info)
466*4882a593Smuzhiyun return -ENOMEM;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps))
469*4882a593Smuzhiyun info->nmaps++;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun if (!info->nmaps)
472*4882a593Smuzhiyun return -ENODEV;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun info->maps = devm_kzalloc(&dev->dev,
475*4882a593Smuzhiyun sizeof(*info->maps) * info->nmaps,
476*4882a593Smuzhiyun GFP_KERNEL);
477*4882a593Smuzhiyun if (!info->maps)
478*4882a593Smuzhiyun return -ENOMEM;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun info->mtds = devm_kzalloc(&dev->dev,
481*4882a593Smuzhiyun sizeof(*info->mtds) * info->nmaps,
482*4882a593Smuzhiyun GFP_KERNEL);
483*4882a593Smuzhiyun if (!info->mtds)
484*4882a593Smuzhiyun return -ENOMEM;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun platform_set_drvdata(dev, info);
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
489*4882a593Smuzhiyun GPIOD_OUT_LOW);
490*4882a593Smuzhiyun if (IS_ERR(info->gpios))
491*4882a593Smuzhiyun return PTR_ERR(info->gpios);
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (info->gpios && info->nmaps > 1) {
494*4882a593Smuzhiyun dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
495*4882a593Smuzhiyun return -EINVAL;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun pm_runtime_enable(&dev->dev);
499*4882a593Smuzhiyun pm_runtime_get_sync(&dev->dev);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun if (dev->dev.of_node)
502*4882a593Smuzhiyun err = physmap_flash_of_init(dev);
503*4882a593Smuzhiyun else
504*4882a593Smuzhiyun err = physmap_flash_pdata_init(dev);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun if (err) {
507*4882a593Smuzhiyun pm_runtime_put(&dev->dev);
508*4882a593Smuzhiyun pm_runtime_disable(&dev->dev);
509*4882a593Smuzhiyun return err;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun for (i = 0; i < info->nmaps; i++) {
513*4882a593Smuzhiyun struct resource *res;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun res = platform_get_resource(dev, IORESOURCE_MEM, i);
516*4882a593Smuzhiyun info->maps[i].virt = devm_ioremap_resource(&dev->dev, res);
517*4882a593Smuzhiyun if (IS_ERR(info->maps[i].virt)) {
518*4882a593Smuzhiyun err = PTR_ERR(info->maps[i].virt);
519*4882a593Smuzhiyun goto err_out;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
523*4882a593Smuzhiyun res);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (!info->maps[i].name)
526*4882a593Smuzhiyun info->maps[i].name = dev_name(&dev->dev);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (!info->maps[i].phys)
529*4882a593Smuzhiyun info->maps[i].phys = res->start;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun info->win_order = get_bitmask_order(resource_size(res)) - 1;
532*4882a593Smuzhiyun info->maps[i].size = BIT(info->win_order +
533*4882a593Smuzhiyun (info->gpios ?
534*4882a593Smuzhiyun info->gpios->ndescs : 0));
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun info->maps[i].map_priv_1 = (unsigned long)dev;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (info->gpios) {
539*4882a593Smuzhiyun err = physmap_addr_gpios_map_init(&info->maps[i]);
540*4882a593Smuzhiyun if (err)
541*4882a593Smuzhiyun goto err_out;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
545*4882a593Smuzhiyun /*
546*4882a593Smuzhiyun * Only use the simple_map implementation if map hooks are not
547*4882a593Smuzhiyun * implemented. Since map->read() is mandatory checking for its
548*4882a593Smuzhiyun * presence is enough.
549*4882a593Smuzhiyun */
550*4882a593Smuzhiyun if (!info->maps[i].read)
551*4882a593Smuzhiyun simple_map_init(&info->maps[i]);
552*4882a593Smuzhiyun #else
553*4882a593Smuzhiyun simple_map_init(&info->maps[i]);
554*4882a593Smuzhiyun #endif
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (info->probe_type) {
557*4882a593Smuzhiyun info->mtds[i] = do_map_probe(info->probe_type,
558*4882a593Smuzhiyun &info->maps[i]);
559*4882a593Smuzhiyun } else {
560*4882a593Smuzhiyun int j;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) {
563*4882a593Smuzhiyun info->mtds[i] = do_map_probe(rom_probe_types[j],
564*4882a593Smuzhiyun &info->maps[i]);
565*4882a593Smuzhiyun if (info->mtds[i])
566*4882a593Smuzhiyun break;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (!info->mtds[i]) {
571*4882a593Smuzhiyun dev_err(&dev->dev, "map_probe failed\n");
572*4882a593Smuzhiyun err = -ENXIO;
573*4882a593Smuzhiyun goto err_out;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun info->mtds[i]->dev.parent = &dev->dev;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun if (info->nmaps == 1) {
579*4882a593Smuzhiyun info->cmtd = info->mtds[0];
580*4882a593Smuzhiyun } else {
581*4882a593Smuzhiyun /*
582*4882a593Smuzhiyun * We detected multiple devices. Concatenate them together.
583*4882a593Smuzhiyun */
584*4882a593Smuzhiyun info->cmtd = mtd_concat_create(info->mtds, info->nmaps,
585*4882a593Smuzhiyun dev_name(&dev->dev));
586*4882a593Smuzhiyun if (!info->cmtd)
587*4882a593Smuzhiyun err = -ENXIO;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun if (err)
590*4882a593Smuzhiyun goto err_out;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun spin_lock_init(&info->vpp_lock);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun mtd_set_of_node(info->cmtd, dev->dev.of_node);
595*4882a593Smuzhiyun err = mtd_device_parse_register(info->cmtd, info->part_types, NULL,
596*4882a593Smuzhiyun info->parts, info->nparts);
597*4882a593Smuzhiyun if (err)
598*4882a593Smuzhiyun goto err_out;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun return 0;
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun err_out:
603*4882a593Smuzhiyun physmap_flash_remove(dev);
604*4882a593Smuzhiyun return err;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun #ifdef CONFIG_PM
physmap_flash_shutdown(struct platform_device * dev)608*4882a593Smuzhiyun static void physmap_flash_shutdown(struct platform_device *dev)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun struct physmap_flash_info *info = platform_get_drvdata(dev);
611*4882a593Smuzhiyun int i;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun for (i = 0; i < info->nmaps && info->mtds[i]; i++)
614*4882a593Smuzhiyun if (mtd_suspend(info->mtds[i]) == 0)
615*4882a593Smuzhiyun mtd_resume(info->mtds[i]);
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun #else
618*4882a593Smuzhiyun #define physmap_flash_shutdown NULL
619*4882a593Smuzhiyun #endif
620*4882a593Smuzhiyun
621*4882a593Smuzhiyun static struct platform_driver physmap_flash_driver = {
622*4882a593Smuzhiyun .probe = physmap_flash_probe,
623*4882a593Smuzhiyun .remove = physmap_flash_remove,
624*4882a593Smuzhiyun .shutdown = physmap_flash_shutdown,
625*4882a593Smuzhiyun .driver = {
626*4882a593Smuzhiyun .name = "physmap-flash",
627*4882a593Smuzhiyun .of_match_table = of_flash_match,
628*4882a593Smuzhiyun },
629*4882a593Smuzhiyun };
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun #ifdef CONFIG_MTD_PHYSMAP_COMPAT
632*4882a593Smuzhiyun static struct physmap_flash_data physmap_flash_data = {
633*4882a593Smuzhiyun .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
634*4882a593Smuzhiyun };
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun static struct resource physmap_flash_resource = {
637*4882a593Smuzhiyun .start = CONFIG_MTD_PHYSMAP_START,
638*4882a593Smuzhiyun .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
639*4882a593Smuzhiyun .flags = IORESOURCE_MEM,
640*4882a593Smuzhiyun };
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun static struct platform_device physmap_flash = {
643*4882a593Smuzhiyun .name = "physmap-flash",
644*4882a593Smuzhiyun .id = 0,
645*4882a593Smuzhiyun .dev = {
646*4882a593Smuzhiyun .platform_data = &physmap_flash_data,
647*4882a593Smuzhiyun },
648*4882a593Smuzhiyun .num_resources = 1,
649*4882a593Smuzhiyun .resource = &physmap_flash_resource,
650*4882a593Smuzhiyun };
651*4882a593Smuzhiyun #endif
652*4882a593Smuzhiyun
physmap_init(void)653*4882a593Smuzhiyun static int __init physmap_init(void)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun int err;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun err = platform_driver_register(&physmap_flash_driver);
658*4882a593Smuzhiyun #ifdef CONFIG_MTD_PHYSMAP_COMPAT
659*4882a593Smuzhiyun if (err == 0) {
660*4882a593Smuzhiyun err = platform_device_register(&physmap_flash);
661*4882a593Smuzhiyun if (err)
662*4882a593Smuzhiyun platform_driver_unregister(&physmap_flash_driver);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun #endif
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun return err;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
physmap_exit(void)669*4882a593Smuzhiyun static void __exit physmap_exit(void)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun #ifdef CONFIG_MTD_PHYSMAP_COMPAT
672*4882a593Smuzhiyun platform_device_unregister(&physmap_flash);
673*4882a593Smuzhiyun #endif
674*4882a593Smuzhiyun platform_driver_unregister(&physmap_flash_driver);
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun module_init(physmap_init);
678*4882a593Smuzhiyun module_exit(physmap_exit);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun MODULE_LICENSE("GPL");
681*4882a593Smuzhiyun MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
682*4882a593Smuzhiyun MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
683*4882a593Smuzhiyun MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
684*4882a593Smuzhiyun MODULE_DESCRIPTION("Generic configurable MTD map driver");
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* legacy platform drivers can't hotplug or coldplg */
687*4882a593Smuzhiyun #ifndef CONFIG_MTD_PHYSMAP_COMPAT
688*4882a593Smuzhiyun /* work with hotplug and coldplug */
689*4882a593Smuzhiyun MODULE_ALIAS("platform:physmap-flash");
690*4882a593Smuzhiyun #endif
691