VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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         unsigned long 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 = 0;
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((void *)(info->window_addr));
69                 info->window_addr = 0;
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 =
140                         (unsigned long)ioremap_nocache(window->start,
141                                                        window->size);
142
143                 if (!info->window_addr) {
144                         printk(KERN_ERR "Failed to ioremap\n");
145                         continue;
146                 }
147
148                 info->mtd = NULL;
149
150                 for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
151                         char **chip_type;
152                         if (rom_size > window->size) {
153                                 continue;
154                         }
155                         info->map.phys = window->start + window->size - rom_size;
156                         info->map.virt = 
157                                 info->window_addr + window->size - rom_size;
158                         info->map.size = rom_size;
159                         simple_map_init(&info->map);
160                         chip_type = rom_probe_types;
161                         for(; !info->mtd && *chip_type; chip_type++) {
162                                 info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
163                         }
164                         if (info->mtd) goto found_mtd;
165                 }
166                 iounmap((void *)(info->window_addr));
167                 info->window_addr = 0;
168
169                 /* Disable writes through the rom window */
170                 pci_read_config_byte(pdev, 0x40, &byte);
171                 pci_write_config_byte(pdev, 0x40, byte & ~1);
172
173                 window++;
174         }
175         goto failed;
176
177  found_mtd:
178         printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n",
179                 window->size - rom_size);
180
181         info->mtd->owner = THIS_MODULE;
182
183         if (!info->window_rsrc.parent) {
184                 /* failed to reserve entire window - try fragments */
185                 info->window_rsrc.name = MOD_NAME;
186                 info->window_rsrc.start = window->start;
187                 info->window_rsrc.end = window->start + window->size - rom_size - 1;
188                 info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
189                 if (request_resource(&iomem_resource, &info->window_rsrc)) {
190                         printk(KERN_ERR MOD_NAME
191                                ": cannot reserve window resource fragment\n");
192 #if 0
193                         /*
194                          * The BIOS e820 usually reserves this so it isn't
195                          * usually an error.
196                          */
197                         goto failed;
198 #endif
199                 }
200         }
201
202         add_mtd_device(info->mtd);
203         info->window_start = window->start;
204         info->window_size = window->size;
205
206         if (info->window_rsrc.parent) {
207                 /*
208                  * Registering the MTD device in iomem may not be possible
209                  * if there is a BIOS "reserved" and BUSY range.  If this
210                  * fails then continue anyway.
211                  */
212                 snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
213                          "mtd%d", info->mtd->index);
214
215                 info->rom_rsrc.name = info->mtd_name;
216                 info->rom_rsrc.start = window->start + window->size - rom_size;
217                 info->rom_rsrc.end = window->start + window->size - 1;
218                 info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
219                 if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
220                         printk(KERN_ERR MOD_NAME
221                                ": cannot reserve MTD resource\n");
222                         info->rom_rsrc.parent = NULL;
223                 }
224         }
225
226         return 0;
227
228  failed:
229         amd76xrom_cleanup(info);
230         return -ENODEV;
231 }
232
233
234 static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
235 {
236         struct amd76xrom_map_info *info = &amd76xrom_map;
237
238         amd76xrom_cleanup(info);
239 }
240
241 static struct pci_device_id amd76xrom_pci_tbl[] = {
242         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
243                 PCI_ANY_ID, PCI_ANY_ID, },
244         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
245                 PCI_ANY_ID, PCI_ANY_ID, },
246         { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
247         { 0, }
248 };
249
250 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
251
252 #if 0
253 static struct pci_driver amd76xrom_driver = {
254         .name =         MOD_NAME,
255         .id_table =     amd76xrom_pci_tbl,
256         .probe =        amd76xrom_init_one,
257         .remove =       amd76xrom_remove_one,
258 };
259 #endif
260
261 int __init init_amd76xrom(void)
262 {
263         struct pci_dev *pdev;
264         struct pci_device_id *id;
265         pdev = NULL;
266         for(id = amd76xrom_pci_tbl; id->vendor; id++) {
267                 pdev = pci_find_device(id->vendor, id->device, NULL);
268                 if (pdev) {
269                         break;
270                 }
271         }
272         if (pdev) {
273                 amd76xrom_map.pdev = pdev;
274                 return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
275         }
276         return -ENXIO;
277 #if 0
278         return pci_module_init(&amd76xrom_driver);
279 #endif
280 }
281
282 static void __exit cleanup_amd76xrom(void)
283 {
284         amd76xrom_remove_one(amd76xrom_map.pdev);
285 }
286
287 module_init(init_amd76xrom);
288 module_exit(cleanup_amd76xrom);
289
290 MODULE_LICENSE("GPL");
291 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
292 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
293