diff options
author | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-10-19 03:49:07 -0400 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@bootlin.com> | 2018-11-05 16:24:43 -0500 |
commit | ba32ce95cbd9876eb7f5ec39af87829c8f13a337 (patch) | |
tree | b6c2a959057771e1fb774f9537da2d71dc47529a | |
parent | 3edf4b9f381efdb09299a5f928d4f35609d5f530 (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/Kconfig | 19 | ||||
-rw-r--r-- | drivers/mtd/maps/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/maps/gpio-addr-flash.c | 281 | ||||
-rw-r--r-- | drivers/mtd/maps/physmap-core.c | 150 |
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 | ||
97 | config 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 | |||
97 | config MTD_PMC_MSP_EVM | 106 | config 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 | ||
337 | config 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 | |||
347 | config MTD_UCLINUX | 346 | config 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 | |||
43 | obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o | 43 | obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o |
44 | obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o | 44 | obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o |
45 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o | 45 | obj-$(CONFIG_MTD_VMU) += vmu-flash.o |
46 | obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o | ||
47 | obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o | 46 | obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o |
48 | obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o | 47 | obj-$(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 | */ | ||
41 | struct 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 | */ | ||
59 | static 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 | */ | ||
83 | static 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 | */ | ||
106 | static 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 | */ | ||
132 | static 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 | */ | ||
152 | static 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 | |||
174 | static 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 | */ | ||
209 | static 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 | |||
260 | static 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 | |||
269 | static 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 | |||
277 | module_platform_driver(gpio_flash_driver); | ||
278 | |||
279 | MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); | ||
280 | MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios"); | ||
281 | MODULE_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 | ||
50 | static int physmap_flash_remove(struct platform_device *dev) | 62 | static 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) | ||
120 | static 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 | |||
139 | static 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 | |||
156 | static 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 | |||
178 | static 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 | |||
193 | static 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 | |||
215 | static 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 | ||
226 | static 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) |
108 | static const struct of_device_id of_flash_match[] = { | 233 | static 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); | |||
497 | MODULE_LICENSE("GPL"); | 642 | MODULE_LICENSE("GPL"); |
498 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); | 643 | MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); |
499 | MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); | 644 | MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>"); |
645 | MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); | ||
500 | MODULE_DESCRIPTION("Generic configurable MTD map driver"); | 646 | MODULE_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 */ |