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