1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/drivers/mtd/maps/pci.c |
4 | * |
5 | * Copyright (C) 2001 Russell King, All rights reserved. |
6 | * |
7 | * Generic PCI memory map driver. We support the following boards: |
8 | * - Intel IQ80310 ATU. |
9 | * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 |
10 | */ |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/slab.h> |
15 | |
16 | #include <linux/mtd/mtd.h> |
17 | #include <linux/mtd/map.h> |
18 | #include <linux/mtd/partitions.h> |
19 | |
20 | struct map_pci_info; |
21 | |
22 | struct mtd_pci_info { |
23 | int (*init)(struct pci_dev *dev, struct map_pci_info *map); |
24 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); |
25 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); |
26 | const char *map_name; |
27 | }; |
28 | |
29 | struct map_pci_info { |
30 | struct map_info map; |
31 | void __iomem *base; |
32 | void (*exit)(struct pci_dev *dev, struct map_pci_info *map); |
33 | unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); |
34 | struct pci_dev *dev; |
35 | }; |
36 | |
37 | static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) |
38 | { |
39 | struct map_pci_info *map = (struct map_pci_info *)_map; |
40 | map_word val; |
41 | val.x[0]= readb(addr: map->base + map->translate(map, ofs)); |
42 | return val; |
43 | } |
44 | |
45 | static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs) |
46 | { |
47 | struct map_pci_info *map = (struct map_pci_info *)_map; |
48 | map_word val; |
49 | val.x[0] = readl(addr: map->base + map->translate(map, ofs)); |
50 | return val; |
51 | } |
52 | |
53 | static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len) |
54 | { |
55 | struct map_pci_info *map = (struct map_pci_info *)_map; |
56 | memcpy_fromio(to, map->base + map->translate(map, from), len); |
57 | } |
58 | |
59 | static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs) |
60 | { |
61 | struct map_pci_info *map = (struct map_pci_info *)_map; |
62 | writeb(val: val.x[0], addr: map->base + map->translate(map, ofs)); |
63 | } |
64 | |
65 | static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs) |
66 | { |
67 | struct map_pci_info *map = (struct map_pci_info *)_map; |
68 | writel(val: val.x[0], addr: map->base + map->translate(map, ofs)); |
69 | } |
70 | |
71 | static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len) |
72 | { |
73 | struct map_pci_info *map = (struct map_pci_info *)_map; |
74 | memcpy_toio(map->base + map->translate(map, to), from, len); |
75 | } |
76 | |
77 | static const struct map_info mtd_pci_map = { |
78 | .phys = NO_XIP, |
79 | .copy_from = mtd_pci_copyfrom, |
80 | .copy_to = mtd_pci_copyto, |
81 | }; |
82 | |
83 | /* |
84 | * Intel IOP80310 Flash driver |
85 | */ |
86 | |
87 | static int |
88 | intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map) |
89 | { |
90 | u32 win_base; |
91 | |
92 | map->map.bankwidth = 1; |
93 | map->map.read = mtd_pci_read8; |
94 | map->map.write = mtd_pci_write8; |
95 | |
96 | map->map.size = 0x00800000; |
97 | map->base = ioremap(pci_resource_start(dev, 0), |
98 | pci_resource_len(dev, 0)); |
99 | |
100 | if (!map->base) |
101 | return -ENOMEM; |
102 | |
103 | /* |
104 | * We want to base the memory window at Xscale |
105 | * bus address 0, not 0x1000. |
106 | */ |
107 | pci_read_config_dword(dev, where: 0x44, val: &win_base); |
108 | pci_write_config_dword(dev, where: 0x44, val: 0); |
109 | |
110 | map->map.map_priv_2 = win_base; |
111 | |
112 | return 0; |
113 | } |
114 | |
115 | static void |
116 | intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map) |
117 | { |
118 | if (map->base) |
119 | iounmap(addr: map->base); |
120 | pci_write_config_dword(dev, where: 0x44, val: map->map.map_priv_2); |
121 | } |
122 | |
123 | static unsigned long |
124 | intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs) |
125 | { |
126 | unsigned long page_addr = ofs & 0x00400000; |
127 | |
128 | /* |
129 | * This mundges the flash location so we avoid |
130 | * the first 80 bytes (they appear to read nonsense). |
131 | */ |
132 | if (page_addr) { |
133 | writel(val: 0x00000008, addr: map->base + 0x1558); |
134 | writel(val: 0x00000000, addr: map->base + 0x1550); |
135 | } else { |
136 | writel(val: 0x00000007, addr: map->base + 0x1558); |
137 | writel(val: 0x00800000, addr: map->base + 0x1550); |
138 | ofs += 0x00800000; |
139 | } |
140 | |
141 | return ofs; |
142 | } |
143 | |
144 | static struct mtd_pci_info intel_iq80310_info = { |
145 | .init = intel_iq80310_init, |
146 | .exit = intel_iq80310_exit, |
147 | .translate = intel_iq80310_translate, |
148 | .map_name = "cfi_probe" , |
149 | }; |
150 | |
151 | /* |
152 | * Intel DC21285 driver |
153 | */ |
154 | |
155 | static int |
156 | intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) |
157 | { |
158 | unsigned long base, len; |
159 | |
160 | base = pci_resource_start(dev, PCI_ROM_RESOURCE); |
161 | len = pci_resource_len(dev, PCI_ROM_RESOURCE); |
162 | |
163 | if (!len || !base) { |
164 | /* |
165 | * No ROM resource |
166 | */ |
167 | base = pci_resource_start(dev, 2); |
168 | len = pci_resource_len(dev, 2); |
169 | |
170 | /* |
171 | * We need to re-allocate PCI BAR2 address range to the |
172 | * PCI ROM BAR, and disable PCI BAR2. |
173 | */ |
174 | } else { |
175 | /* |
176 | * Hmm, if an address was allocated to the ROM resource, but |
177 | * not enabled, should we be allocating a new resource for it |
178 | * or simply enabling it? |
179 | */ |
180 | pci_enable_rom(pdev: dev); |
181 | printk("%s: enabling expansion ROM\n" , pci_name(dev)); |
182 | } |
183 | |
184 | if (!len || !base) |
185 | return -ENXIO; |
186 | |
187 | map->map.bankwidth = 4; |
188 | map->map.read = mtd_pci_read32; |
189 | map->map.write = mtd_pci_write32; |
190 | map->map.size = len; |
191 | map->base = ioremap(offset: base, size: len); |
192 | |
193 | if (!map->base) |
194 | return -ENOMEM; |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | static void |
200 | intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) |
201 | { |
202 | if (map->base) |
203 | iounmap(addr: map->base); |
204 | |
205 | /* |
206 | * We need to undo the PCI BAR2/PCI ROM BAR address alteration. |
207 | */ |
208 | pci_disable_rom(pdev: dev); |
209 | } |
210 | |
211 | static unsigned long |
212 | intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs) |
213 | { |
214 | return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5)); |
215 | } |
216 | |
217 | static struct mtd_pci_info intel_dc21285_info = { |
218 | .init = intel_dc21285_init, |
219 | .exit = intel_dc21285_exit, |
220 | .translate = intel_dc21285_translate, |
221 | .map_name = "jedec_probe" , |
222 | }; |
223 | |
224 | /* |
225 | * PCI device ID table |
226 | */ |
227 | |
228 | static const struct pci_device_id mtd_pci_ids[] = { |
229 | { |
230 | .vendor = PCI_VENDOR_ID_INTEL, |
231 | .device = 0x530d, |
232 | .subvendor = PCI_ANY_ID, |
233 | .subdevice = PCI_ANY_ID, |
234 | .class = PCI_CLASS_MEMORY_OTHER << 8, |
235 | .class_mask = 0xffff00, |
236 | .driver_data = (unsigned long)&intel_iq80310_info, |
237 | }, |
238 | { |
239 | .vendor = PCI_VENDOR_ID_DEC, |
240 | .device = PCI_DEVICE_ID_DEC_21285, |
241 | .subvendor = 0, /* DC21285 defaults to 0 on reset */ |
242 | .subdevice = 0, /* DC21285 defaults to 0 on reset */ |
243 | .driver_data = (unsigned long)&intel_dc21285_info, |
244 | }, |
245 | { 0, } |
246 | }; |
247 | |
248 | /* |
249 | * Generic code follows. |
250 | */ |
251 | |
252 | static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) |
253 | { |
254 | struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; |
255 | struct map_pci_info *map = NULL; |
256 | struct mtd_info *mtd = NULL; |
257 | int err; |
258 | |
259 | err = pci_enable_device(dev); |
260 | if (err) |
261 | goto out; |
262 | |
263 | err = pci_request_regions(dev, "pci mtd" ); |
264 | if (err) |
265 | goto out; |
266 | |
267 | map = kmalloc(size: sizeof(*map), GFP_KERNEL); |
268 | err = -ENOMEM; |
269 | if (!map) |
270 | goto release; |
271 | |
272 | map->map = mtd_pci_map; |
273 | map->map.name = pci_name(pdev: dev); |
274 | map->dev = dev; |
275 | map->exit = info->exit; |
276 | map->translate = info->translate; |
277 | |
278 | err = info->init(dev, map); |
279 | if (err) |
280 | goto release; |
281 | |
282 | mtd = do_map_probe(name: info->map_name, map: &map->map); |
283 | err = -ENODEV; |
284 | if (!mtd) |
285 | goto release; |
286 | |
287 | mtd->owner = THIS_MODULE; |
288 | mtd_device_register(mtd, NULL, 0); |
289 | |
290 | pci_set_drvdata(pdev: dev, data: mtd); |
291 | |
292 | return 0; |
293 | |
294 | release: |
295 | if (map) { |
296 | map->exit(dev, map); |
297 | kfree(objp: map); |
298 | } |
299 | |
300 | pci_release_regions(dev); |
301 | out: |
302 | return err; |
303 | } |
304 | |
305 | static void mtd_pci_remove(struct pci_dev *dev) |
306 | { |
307 | struct mtd_info *mtd = pci_get_drvdata(pdev: dev); |
308 | struct map_pci_info *map = mtd->priv; |
309 | |
310 | mtd_device_unregister(master: mtd); |
311 | map_destroy(mtd); |
312 | map->exit(dev, map); |
313 | kfree(objp: map); |
314 | |
315 | pci_release_regions(dev); |
316 | } |
317 | |
318 | static struct pci_driver mtd_pci_driver = { |
319 | .name = "MTD PCI" , |
320 | .probe = mtd_pci_probe, |
321 | .remove = mtd_pci_remove, |
322 | .id_table = mtd_pci_ids, |
323 | }; |
324 | |
325 | module_pci_driver(mtd_pci_driver); |
326 | |
327 | MODULE_LICENSE("GPL" ); |
328 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>" ); |
329 | MODULE_DESCRIPTION("Generic PCI map driver" ); |
330 | MODULE_DEVICE_TABLE(pci, mtd_pci_ids); |
331 | |