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