summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Brezillon <boris.brezillon@bootlin.com>2018-10-19 03:49:07 -0400
committerBoris Brezillon <boris.brezillon@bootlin.com>2018-11-05 16:24:43 -0500
commitba32ce95cbd9876eb7f5ec39af87829c8f13a337 (patch)
treeb6c2a959057771e1fb774f9537da2d71dc47529a
parent3edf4b9f381efdb09299a5f928d4f35609d5f530 (diff)
mtd: maps: Merge gpio-addr-flash.c into physmap-core.c
Controlling some MSB address lines using GPIOs is just a small deviation from the generic physmap logic, and merging those two drivers allows us to share most of the probe logic, which is a good thing. Also, the gpio-addr-flash driver is unused since the removal of the blackfin arch in v4.17, so we can safely remove the old driver without risking breaking existing boards. Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com> Reviewed-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Tested-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Acked-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/mtd/maps/Kconfig19
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c281
-rw-r--r--drivers/mtd/maps/physmap-core.c150
4 files changed, 157 insertions, 294 deletions
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index bb0d64e3fcd6..93b7ae32e277 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -94,6 +94,15 @@ config MTD_PHYSMAP_GEMINI
94 platforms, some detection and setting up parallel mode on the 94 platforms, some detection and setting up parallel mode on the
95 external interface. 95 external interface.
96 96
97config MTD_PHYSMAP_GPIO_ADDR
98 bool "GPIO-assisted Flash Chip Support"
99 depends on MTD_PHYSMAP
100 depends on GPIOLIB || COMPILE_TEST
101 depends on MTD_COMPLEX_MAPPINGS
102 help
103 Extend the physmap driver to allow flashes to be partially
104 physically addressed and assisted by GPIOs.
105
97config MTD_PMC_MSP_EVM 106config MTD_PMC_MSP_EVM
98 tristate "CFI Flash device mapped on PMC-Sierra MSP" 107 tristate "CFI Flash device mapped on PMC-Sierra MSP"
99 depends on PMC_MSP && MTD_CFI 108 depends on PMC_MSP && MTD_CFI
@@ -334,16 +343,6 @@ config MTD_PCMCIA_ANONYMOUS
334 343
335 If unsure, say N. 344 If unsure, say N.
336 345
337config MTD_GPIO_ADDR
338 tristate "GPIO-assisted Flash Chip Support"
339 depends on GPIOLIB || COMPILE_TEST
340 depends on MTD_COMPLEX_MAPPINGS
341 help
342 Map driver which allows flashes to be partially physically addressed
343 and assisted by GPIOs.
344
345 If compiled as a module, it will be called gpio-addr-flash.
346
347config MTD_UCLINUX 346config MTD_UCLINUX
348 bool "Generic uClinux RAM/ROM filesystem support" 347 bool "Generic uClinux RAM/ROM filesystem support"
349 depends on (MTD_RAM=y || MTD_ROM=y) && (!MMU || COLDFIRE) 348 depends on (MTD_RAM=y || MTD_ROM=y) && (!MMU || COLDFIRE)
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index ce737e15b7cf..ed1ef75244db 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -43,6 +43,5 @@ obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
43obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o 43obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
44obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o 44obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
45obj-$(CONFIG_MTD_VMU) += vmu-flash.o 45obj-$(CONFIG_MTD_VMU) += vmu-flash.o
46obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
47obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o 46obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
48obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o 47obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
deleted file mode 100644
index a20e85aa770e..000000000000
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ /dev/null
@@ -1,281 +0,0 @@
1/*
2 * drivers/mtd/maps/gpio-addr-flash.c
3 *
4 * Handle the case where a flash device is mostly addressed using physical
5 * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash
6 * to a 2MiB memory range and use the GPIOs to select a particular range.
7 *
8 * Copyright © 2000 Nicolas Pitre <nico@cam.org>
9 * Copyright © 2005-2009 Analog Devices Inc.
10 *
11 * Enter bugs at http://blackfin.uclinux.org/
12 *
13 * Licensed under the GPL-2 or later.
14 */
15
16#include <linux/gpio.h>
17#include <linux/gpio/consumer.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/mtd/mtd.h>
22#include <linux/mtd/map.h>
23#include <linux/mtd/partitions.h>
24#include <linux/mtd/physmap.h>
25#include <linux/platform_device.h>
26#include <linux/slab.h>
27#include <linux/types.h>
28
29#define win_mask(x) ((BIT(x)) - 1)
30
31#define DRIVER_NAME "gpio-addr-flash"
32
33/**
34 * struct async_state - keep GPIO flash state
35 * @mtd: MTD state for this mapping
36 * @map: MTD map state for this flash
37 * @gpios: Struct containing the array of GPIO descriptors
38 * @gpio_values: cached GPIO values
39 * @win_order: dedicated memory size (if no GPIOs)
40 */
41struct async_state {
42 struct mtd_info *mtd;
43 struct map_info map;
44 struct gpio_descs *gpios;
45 unsigned int gpio_values;
46 unsigned int win_order;
47};
48#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
49
50/**
51 * gf_set_gpios() - set GPIO address lines to access specified flash offset
52 * @state: GPIO flash state
53 * @ofs: desired offset to access
54 *
55 * Rather than call the GPIO framework every time, cache the last-programmed
56 * value. This speeds up sequential accesses (which are by far the most common
57 * type).
58 */
59static void gf_set_gpios(struct async_state *state, unsigned long ofs)
60{
61 int i;
62
63 ofs >>= state->win_order;
64
65 if (ofs == state->gpio_values)
66 return;
67
68 for (i = 0; i < state->gpios->ndescs; i++) {
69 if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
70 continue;
71
72 gpiod_set_value(state->gpios->desc[i], !!(ofs & BIT(i)));
73 }
74
75 state->gpio_values = ofs;
76}
77
78/**
79 * gf_read() - read a word at the specified offset
80 * @map: MTD map state
81 * @ofs: desired offset to read
82 */
83static map_word gf_read(struct map_info *map, unsigned long ofs)
84{
85 struct async_state *state = gf_map_info_to_state(map);
86 uint16_t word;
87 map_word test;
88
89 gf_set_gpios(state, ofs);
90
91 word = readw(map->virt + (ofs & win_mask(state->win_order)));
92 test.x[0] = word;
93 return test;
94}
95
96/**
97 * gf_copy_from() - copy a chunk of data from the flash
98 * @map: MTD map state
99 * @to: memory to copy to
100 * @from: flash offset to copy from
101 * @len: how much to copy
102 *
103 * The "from" region may straddle more than one window, so toggle the GPIOs for
104 * each window region before reading its data.
105 */
106static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
107{
108 struct async_state *state = gf_map_info_to_state(map);
109
110 int this_len;
111
112 while (len) {
113 this_len = from & win_mask(state->win_order);
114 this_len = BIT(state->win_order) - this_len;
115 this_len = min_t(int, len, this_len);
116
117 gf_set_gpios(state, from);
118 memcpy_fromio(to,
119 map->virt + (from & win_mask(state->win_order)),
120 this_len);
121 len -= this_len;
122 from += this_len;
123 to += this_len;
124 }
125}
126
127/**
128 * gf_write() - write a word at the specified offset
129 * @map: MTD map state
130 * @ofs: desired offset to write
131 */
132static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
133{
134 struct async_state *state = gf_map_info_to_state(map);
135 uint16_t d;
136
137 gf_set_gpios(state, ofs);
138
139 d = d1.x[0];
140 writew(d, map->virt + (ofs & win_mask(state->win_order)));
141}
142
143/**
144 * gf_copy_to() - copy a chunk of data to the flash
145 * @map: MTD map state
146 * @to: flash offset to copy to
147 * @from: memory to copy from
148 * @len: how much to copy
149 *
150 * See gf_copy_from() caveat.
151 */
152static void gf_copy_to(struct map_info *map, unsigned long to,
153 const void *from, ssize_t len)
154{
155 struct async_state *state = gf_map_info_to_state(map);
156
157 int this_len;
158
159 while (len) {
160 this_len = to & win_mask(state->win_order);
161 this_len = BIT(state->win_order) - this_len;
162 this_len = min_t(int, len, this_len);
163
164 gf_set_gpios(state, to);
165 memcpy_toio(map->virt + (to & win_mask(state->win_order)),
166 from, len);
167
168 len -= this_len;
169 to += this_len;
170 from += this_len;
171 }
172}
173
174static const char * const part_probe_types[] = {
175 "cmdlinepart", "RedBoot", NULL };
176
177/**
178 * gpio_flash_probe() - setup a mapping for a GPIO assisted flash
179 * @pdev: platform device
180 *
181 * The platform resource layout expected looks something like:
182 * struct mtd_partition partitions[] = { ... };
183 * struct physmap_flash_data flash_data = { ... };
184 * static struct gpiod_lookup_table addr_flash_gpios = {
185 * .dev_id = "gpio-addr-flash.0",
186 * .table = {
187 * GPIO_LOOKUP_IDX("gpio.0", 15, "addr", 0, GPIO_ACTIVE_HIGH),
188 * GPIO_LOOKUP_IDX("gpio.0", 16, "addr", 1, GPIO_ACTIVE_HIGH),
189 * );
190 * };
191 * gpiod_add_lookup_table(&addr_flash_gpios);
192 *
193 * struct resource flash_resource[] = {
194 * {
195 * .name = "cfi_probe",
196 * .start = 0x20000000,
197 * .end = 0x201fffff,
198 * .flags = IORESOURCE_MEM,
199 * },
200 * };
201 * struct platform_device flash_device = {
202 * .name = "gpio-addr-flash",
203 * .dev = { .platform_data = &flash_data, },
204 * .num_resources = ARRAY_SIZE(flash_resource),
205 * .resource = flash_resource,
206 * ...
207 * };
208 */
209static int gpio_flash_probe(struct platform_device *pdev)
210{
211 struct physmap_flash_data *pdata;
212 struct resource *memory;
213 struct async_state *state;
214
215 pdata = dev_get_platdata(&pdev->dev);
216 memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
217
218 if (!memory)
219 return -EINVAL;
220
221 state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
222 if (!state)
223 return -ENOMEM;
224
225 state->gpios = devm_gpiod_get_array(&pdev->dev, "addr", GPIOD_OUT_LOW);
226 if (IS_ERR(state->gpios))
227 return PTR_ERR(state->gpios);
228
229 state->win_order = get_bitmask_order(resource_size(memory)) - 1;
230
231 state->map.name = DRIVER_NAME;
232 state->map.read = gf_read;
233 state->map.copy_from = gf_copy_from;
234 state->map.write = gf_write;
235 state->map.copy_to = gf_copy_to;
236 state->map.bankwidth = pdata->width;
237 state->map.size = BIT(state->win_order + state->gpios->ndescs);
238 state->map.virt = devm_ioremap_resource(&pdev->dev, memory);
239 if (IS_ERR(state->map.virt))
240 return PTR_ERR(state->map.virt);
241
242 state->map.phys = NO_XIP;
243 state->map.map_priv_1 = (unsigned long)state;
244
245 platform_set_drvdata(pdev, state);
246
247 dev_notice(&pdev->dev, "probing %d-bit flash bus\n",
248 state->map.bankwidth * 8);
249 state->mtd = do_map_probe(memory->name, &state->map);
250 if (!state->mtd)
251 return -ENXIO;
252 state->mtd->dev.parent = &pdev->dev;
253
254 mtd_device_parse_register(state->mtd, part_probe_types, NULL,
255 pdata->parts, pdata->nr_parts);
256
257 return 0;
258}
259
260static int gpio_flash_remove(struct platform_device *pdev)
261{
262 struct async_state *state = platform_get_drvdata(pdev);
263
264 mtd_device_unregister(state->mtd);
265 map_destroy(state->mtd);
266 return 0;
267}
268
269static struct platform_driver gpio_flash_driver = {
270 .probe = gpio_flash_probe,
271 .remove = gpio_flash_remove,
272 .driver = {
273 .name = DRIVER_NAME,
274 },
275};
276
277module_platform_driver(gpio_flash_driver);
278
279MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
280MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios");
281MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/physmap-core.c b/drivers/mtd/maps/physmap-core.c
index 8a8af37576ff..11e6239aadc7 100644
--- a/drivers/mtd/maps/physmap-core.c
+++ b/drivers/mtd/maps/physmap-core.c
@@ -13,6 +13,14 @@
13 * 13 *
14 * Revised to handle newer style flash binding by: 14 * Revised to handle newer style flash binding by:
15 * Copyright (C) 2007 David Gibson, IBM Corporation. 15 * Copyright (C) 2007 David Gibson, IBM Corporation.
16 *
17 * GPIO address extension:
18 * Handle the case where a flash device is mostly addressed using physical
19 * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash
20 * to a 2MiB memory range and use the GPIOs to select a particular range.
21 *
22 * Copyright © 2000 Nicolas Pitre <nico@cam.org>
23 * Copyright © 2005-2009 Analog Devices Inc.
16 */ 24 */
17 25
18#include <linux/module.h> 26#include <linux/module.h>
@@ -30,6 +38,7 @@
30#include <linux/mtd/cfi_endian.h> 38#include <linux/mtd/cfi_endian.h>
31#include <linux/io.h> 39#include <linux/io.h>
32#include <linux/of_device.h> 40#include <linux/of_device.h>
41#include <linux/gpio/consumer.h>
33 42
34#include "physmap-gemini.h" 43#include "physmap-gemini.h"
35#include "physmap-versatile.h" 44#include "physmap-versatile.h"
@@ -45,6 +54,9 @@ struct physmap_flash_info {
45 const char * const *part_types; 54 const char * const *part_types;
46 unsigned int nparts; 55 unsigned int nparts;
47 const struct mtd_partition *parts; 56 const struct mtd_partition *parts;
57 struct gpio_descs *gpios;
58 unsigned int gpio_values;
59 unsigned int win_order;
48}; 60};
49 61
50static int physmap_flash_remove(struct platform_device *dev) 62static int physmap_flash_remove(struct platform_device *dev)
@@ -104,6 +116,119 @@ static void physmap_set_vpp(struct map_info *map, int state)
104 spin_unlock_irqrestore(&info->vpp_lock, flags); 116 spin_unlock_irqrestore(&info->vpp_lock, flags);
105} 117}
106 118
119#if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
120static void physmap_set_addr_gpios(struct physmap_flash_info *info,
121 unsigned long ofs)
122{
123 unsigned int i;
124
125 ofs >>= info->win_order;
126 if (info->gpio_values == ofs)
127 return;
128
129 for (i = 0; i < info->gpios->ndescs; i++) {
130 if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
131 continue;
132
133 gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
134 }
135}
136
137#define win_mask(order) (BIT(order) - 1)
138
139static map_word physmap_addr_gpios_read(struct map_info *map,
140 unsigned long ofs)
141{
142 struct platform_device *pdev;
143 struct physmap_flash_info *info;
144 map_word mw;
145 u16 word;
146
147 pdev = (struct platform_device *)map->map_priv_1;
148 info = platform_get_drvdata(pdev);
149 physmap_set_addr_gpios(info, ofs);
150
151 word = readw(map->virt + (ofs & win_mask(info->win_order)));
152 mw.x[0] = word;
153 return mw;
154}
155
156static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
157 unsigned long ofs, ssize_t len)
158{
159 struct platform_device *pdev;
160 struct physmap_flash_info *info;
161
162 pdev = (struct platform_device *)map->map_priv_1;
163 info = platform_get_drvdata(pdev);
164
165 while (len) {
166 unsigned int winofs = ofs & win_mask(info->win_order);
167 unsigned int chunklen = min_t(unsigned int, len,
168 BIT(info->win_order) - winofs);
169
170 physmap_set_addr_gpios(info, ofs);
171 memcpy_fromio(buf, map->virt + winofs, chunklen);
172 len -= chunklen;
173 buf += chunklen;
174 ofs += chunklen;
175 }
176}
177
178static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
179 unsigned long ofs)
180{
181 struct platform_device *pdev;
182 struct physmap_flash_info *info;
183 u16 word;
184
185 pdev = (struct platform_device *)map->map_priv_1;
186 info = platform_get_drvdata(pdev);
187 physmap_set_addr_gpios(info, ofs);
188
189 word = mw.x[0];
190 writew(word, map->virt + (ofs & win_mask(info->win_order)));
191}
192
193static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
194 const void *buf, ssize_t len)
195{
196 struct platform_device *pdev;
197 struct physmap_flash_info *info;
198
199 pdev = (struct platform_device *)map->map_priv_1;
200 info = platform_get_drvdata(pdev);
201
202 while (len) {
203 unsigned int winofs = ofs & win_mask(info->win_order);
204 unsigned int chunklen = min_t(unsigned int, len,
205 BIT(info->win_order) - winofs);
206
207 physmap_set_addr_gpios(info, ofs);
208 memcpy_toio(map->virt + winofs, buf, chunklen);
209 len -= chunklen;
210 buf += chunklen;
211 ofs += chunklen;
212 }
213}
214
215static int physmap_addr_gpios_map_init(struct map_info *map)
216{
217 map->phys = NO_XIP;
218 map->read = physmap_addr_gpios_read;
219 map->copy_from = physmap_addr_gpios_copy_from;
220 map->write = physmap_addr_gpios_write;
221 map->copy_to = physmap_addr_gpios_copy_to;
222
223 return 0;
224}
225#else
226static int physmap_addr_gpios_map_init(struct map_info *map)
227{
228 return -ENOTSUPP;
229}
230#endif
231
107#if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) 232#if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
108static const struct of_device_id of_flash_match[] = { 233static const struct of_device_id of_flash_match[] = {
109 { 234 {
@@ -343,6 +468,16 @@ static int physmap_flash_probe(struct platform_device *dev)
343 468
344 platform_set_drvdata(dev, info); 469 platform_set_drvdata(dev, info);
345 470
471 info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
472 GPIOD_OUT_LOW);
473 if (IS_ERR(info->gpios))
474 return PTR_ERR(info->gpios);
475
476 if (info->gpios && info->nmaps > 1) {
477 dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
478 return -EINVAL;
479 }
480
346 if (dev->dev.of_node) 481 if (dev->dev.of_node)
347 err = physmap_flash_of_init(dev); 482 err = physmap_flash_of_init(dev);
348 else 483 else
@@ -369,10 +504,20 @@ static int physmap_flash_probe(struct platform_device *dev)
369 if (!info->maps[i].phys) 504 if (!info->maps[i].phys)
370 info->maps[i].phys = res->start; 505 info->maps[i].phys = res->start;
371 506
372 info->maps[i].size = resource_size(res); 507 info->win_order = get_bitmask_order(resource_size(res)) - 1;
508 info->maps[i].size = BIT(info->win_order +
509 (info->gpios ?
510 info->gpios->ndescs : 0));
511
373 info->maps[i].map_priv_1 = (unsigned long)dev; 512 info->maps[i].map_priv_1 = (unsigned long)dev;
374 513
375 simple_map_init(&info->maps[i]); 514 if (info->gpios) {
515 err = physmap_addr_gpios_map_init(&info->maps[i]);
516 if (err)
517 goto err_out;
518 } else {
519 simple_map_init(&info->maps[i]);
520 }
376 521
377 probe_type = rom_probe_types; 522 probe_type = rom_probe_types;
378 if (!info->probe_type) { 523 if (!info->probe_type) {
@@ -497,6 +642,7 @@ module_exit(physmap_exit);
497MODULE_LICENSE("GPL"); 642MODULE_LICENSE("GPL");
498MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 643MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
499MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); 644MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
645MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
500MODULE_DESCRIPTION("Generic configurable MTD map driver"); 646MODULE_DESCRIPTION("Generic configurable MTD map driver");
501 647
502/* legacy platform drivers can't hotplug or coldplg */ 648/* legacy platform drivers can't hotplug or coldplg */