vserver 1.9.3
[linux-2.6.git] / drivers / mtd / maps / amd76xrom.c
1 /*
2  * amd76xrom.c
3  *
4  * Normal mappings of chips in physical memory
5  * $Id: amd76xrom.c,v 1.12 2004/07/14 14:44:31 thayne Exp $
6  */
7
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <asm/io.h>
13 #include <linux/mtd/mtd.h>
14 #include <linux/mtd/map.h>
15 #include <linux/config.h>
16 #include <linux/pci.h>
17 #include <linux/pci_ids.h>
18
19
20 #define xstr(s) str(s)
21 #define str(s) #s
22 #define MOD_NAME xstr(KBUILD_BASENAME)
23
24 #define MTD_DEV_NAME_LENGTH 16
25
26 struct amd76xrom_map_info {
27         struct map_info map;
28         struct mtd_info *mtd;
29         void __iomem * window_addr;
30         u32 window_start, window_size;
31         struct pci_dev *pdev;
32         struct resource window_rsrc;
33         struct resource rom_rsrc;
34         char mtd_name[MTD_DEV_NAME_LENGTH];
35 };
36
37
38 static struct amd76xrom_map_info amd76xrom_map = {
39         .map = {
40                 .name = MOD_NAME,
41                 .size = 0,
42                 .bankwidth = 1,
43         }
44         /* remaining fields of structure are initialized to 0 */
45 };
46
47
48 static void amd76xrom_cleanup(struct amd76xrom_map_info *info)
49 {
50         u8 byte;
51
52         /* Disable writes through the rom window */
53         pci_read_config_byte(info->pdev, 0x40, &byte);
54         pci_write_config_byte(info->pdev, 0x40, byte & ~1);
55
56         if (info->mtd) {
57                 del_mtd_device(info->mtd);
58                 map_destroy(info->mtd);
59                 info->mtd = NULL;
60                 info->map.virt = NULL;
61         }
62         if (info->rom_rsrc.parent)
63                 release_resource(&info->rom_rsrc);
64         if (info->window_rsrc.parent)
65                 release_resource(&info->window_rsrc);
66
67         if (info->window_addr) {
68                 iounmap(info->window_addr);
69                 info->window_addr = NULL;
70         }
71 }
72
73
74 static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
75         const struct pci_device_id *ent)
76 {
77         struct rom_window {
78                 u32 start;
79                 u32 size;
80                 u8 segen_bits;
81         };
82         static struct rom_window rom_window[] = {
83                 /*
84                  * Need the 5MiB window for chips that have block lock/unlock
85                  * registers located below 4MiB window.
86                  */
87                 { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
88                 { 0xffc00000, 4*1024*1024, (1<<7), },
89                 { 0xffff0000, 64*1024,     0 },
90                 { 0         , 0,           0 },
91         };
92         static const u32 rom_probe_sizes[] = { 
93                 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
94                 256*1024, 128*1024, 64*1024, 0};
95         static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
96         u8 byte;
97         struct amd76xrom_map_info *info = &amd76xrom_map;
98         struct rom_window *window;
99         int i;
100         u32 rom_size;
101
102         info->pdev = pdev;
103         window = &rom_window[0];
104
105         while (window->size) {
106                 /*
107                  * Try to reserve the window mem region.  If this fails then
108                  * it is likely due to a fragment of the window being
109                  * "reseved" by the BIOS.  In the case that the
110                  * request_mem_region() fails then once the rom size is
111                  * discovered we will try to reserve the unreserved fragment.
112                  */
113                 info->window_rsrc.name = MOD_NAME;
114                 info->window_rsrc.start = window->start;
115                 info->window_rsrc.end = window->start + window->size - 1;
116                 info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
117                 if (request_resource(&iomem_resource, &info->window_rsrc)) {
118                         info->window_rsrc.parent = NULL;
119                         printk(KERN_ERR MOD_NAME
120                                " %s(): Unable to register resource"
121                                " 0x%.08lx-0x%.08lx - kernel bug?\n",
122                                __func__,
123                                info->window_rsrc.start, info->window_rsrc.end);
124                 }
125
126                 /* Enable the selected rom window */
127                 pci_read_config_byte(pdev, 0x43, &byte);
128                 pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
129
130                 /* Enable writes through the rom window */
131                 pci_read_config_byte(pdev, 0x40, &byte);
132                 pci_write_config_byte(pdev, 0x40, byte | 1);
133
134                 /* FIXME handle registers 0x80 - 0x8C the bios region locks */
135
136                 printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", 
137                        window->size, window->start);
138                 /* For write accesses caches are useless */
139                 info->window_addr = ioremap_nocache(window->start,
140                                                        window->size);
141
142                 if (!info->window_addr) {
143                         printk(KERN_ERR "Failed to ioremap\n");
144                         continue;
145                 }
146
147                 info->mtd = NULL;
148
149                 for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
150                         char **chip_type;
151                         if (rom_size > window->size) {
152                                 continue;
153                         }
154                         info->map.phys = window->start + window->size - rom_size;
155                         info->map.virt = 
156                                 info->window_addr + window->size - rom_size;
157                         info->map.size = rom_size;
158                         simple_map_init(&info->map);
159                         chip_type = rom_probe_types;
160                         for(; !info->mtd && *chip_type; chip_type++) {
161                                 info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
162                         }
163                         if (info->mtd) goto found_mtd;
164                 }
165                 iounmap(info->window_addr);
166                 info->window_addr = NULL;
167
168                 /* Disable writes through the rom window */
169                 pci_read_config_byte(pdev, 0x40, &byte);
170                 pci_write_config_byte(pdev, 0x40, byte & ~1);
171
172                 window++;
173         }
174         goto failed;
175
176  found_mtd:
177         printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n",
178                 window->size - rom_size);
179
180         info->mtd->owner = THIS_MODULE;
181
182         if (!info->window_rsrc.parent) {
183                 /* failed to reserve entire window - try fragments */
184                 info->window_rsrc.name = MOD_NAME;
185                 info->window_rsrc.start = window->start;
186                 info->window_rsrc.end = window->start + window->size - rom_size - 1;
187                 info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
188                 if (request_resource(&iomem_resource, &info->window_rsrc)) {
189                         printk(KERN_ERR MOD_NAME
190                                ": cannot reserve window resource fragment\n");
191 #if 0
192                         /*
193                          * The BIOS e820 usually reserves this so it isn't
194                          * usually an error.
195                          */
196                         goto failed;
197 #endif
198                 }
199         }
200
201         add_mtd_device(info->mtd);
202         info->window_start = window->start;
203         info->window_size = window->size;
204
205         if (info->window_rsrc.parent) {
206                 /*
207                  * Registering the MTD device in iomem may not be possible
208                  * if there is a BIOS "reserved" and BUSY range.  If this
209                  * fails then continue anyway.
210                  */
211                 snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
212                          "mtd%d", info->mtd->index);
213
214                 info->rom_rsrc.name = info->mtd_name;
215                 info->rom_rsrc.start = window->start + window->size - rom_size;
216                 info->rom_rsrc.end = window->start + window->size - 1;
217                 info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
218                 if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
219                         printk(KERN_ERR MOD_NAME
220                                ": cannot reserve MTD resource\n");
221                         info->rom_rsrc.parent = NULL;
222                 }
223         }
224
225         return 0;
226
227  failed:
228         amd76xrom_cleanup(info);
229         return -ENODEV;
230 }
231
232
233 static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
234 {
235         struct amd76xrom_map_info *info = &amd76xrom_map;
236
237         amd76xrom_cleanup(info);
238 }
239
240 static struct pci_device_id amd76xrom_pci_tbl[] = {
241         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
242                 PCI_ANY_ID, PCI_ANY_ID, },
243         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
244                 PCI_ANY_ID, PCI_ANY_ID, },
245         { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
246         { 0, }
247 };
248
249 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
250
251 #if 0
252 static struct pci_driver amd76xrom_driver = {
253         .name =         MOD_NAME,
254         .id_table =     amd76xrom_pci_tbl,
255         .probe =        amd76xrom_init_one,
256         .remove =       amd76xrom_remove_one,
257 };
258 #endif
259
260 int __init init_amd76xrom(void)
261 {
262         struct pci_dev *pdev;
263         struct pci_device_id *id;
264         pdev = NULL;
265         for(id = amd76xrom_pci_tbl; id->vendor; id++) {
266                 pdev = pci_find_device(id->vendor, id->device, NULL);
267                 if (pdev) {
268                         break;
269                 }
270         }
271         if (pdev) {
272                 amd76xrom_map.pdev = pdev;
273                 return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
274         }
275         return -ENXIO;
276 #if 0
277         return pci_module_init(&amd76xrom_driver);
278 #endif
279 }
280
281 static void __exit cleanup_amd76xrom(void)
282 {
283         amd76xrom_remove_one(amd76xrom_map.pdev);
284 }
285
286 module_init(init_amd76xrom);
287 module_exit(cleanup_amd76xrom);
288
289 MODULE_LICENSE("GPL");
290 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
291 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
292