special usb hub handling, IDE disks, and retries all over the place
[linux-2.4.git] / drivers / mtd / maps / amd766rom.c
1 /*
2  * amd766rom.c
3  *
4  * Normal mappings of chips in physical memory
5  * $Id: amd766rom.c,v 1.1 2002/01/10 22:59:13 eric Exp $
6  */
7
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <asm/io.h>
12 #include <linux/mtd/mtd.h>
13 #include <linux/mtd/map.h>
14 #include <linux/config.h>
15 #include <linux/pci.h>
16 #include <linux/pci_ids.h>
17
18
19 struct amd766rom_map_info {
20         struct map_info map;
21         struct mtd_info *mtd;
22         unsigned long window_addr;
23         u32 window_start, window_size;
24         struct pci_dev *pdev;
25 };
26
27 static __u8 amd766rom_read8(struct map_info *map, unsigned long ofs)
28 {
29         return __raw_readb(map->map_priv_1 + ofs);
30 }
31
32 static __u16 amd766rom_read16(struct map_info *map, unsigned long ofs)
33 {
34         return __raw_readw(map->map_priv_1 + ofs);
35 }
36
37 static __u32 amd766rom_read32(struct map_info *map, unsigned long ofs)
38 {
39         return __raw_readl(map->map_priv_1 + ofs);
40 }
41
42 static void amd766rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
43 {
44         memcpy_fromio(to, map->map_priv_1 + from, len);
45 }
46
47 static void amd766rom_write8(struct map_info *map, __u8 d, unsigned long adr)
48 {
49         __raw_writeb(d, map->map_priv_1 + adr);
50         mb();
51 }
52
53 static void amd766rom_write16(struct map_info *map, __u16 d, unsigned long adr)
54 {
55         __raw_writew(d, map->map_priv_1 + adr);
56         mb();
57 }
58
59 static void amd766rom_write32(struct map_info *map, __u32 d, unsigned long adr)
60 {
61         __raw_writel(d, map->map_priv_1 + adr);
62         mb();
63 }
64
65 static void amd766rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
66 {
67         memcpy_toio(map->map_priv_1 + to, from, len);
68 }
69
70 static struct amd766rom_map_info amd766rom_map = {
71         map: {
72                 name: "AMD766 rom",
73                 size: 0,
74                 buswidth: 1,
75                 read8: amd766rom_read8,
76                 read16: amd766rom_read16,
77                 read32: amd766rom_read32,
78                 copy_from: amd766rom_copy_from,
79                 write8: amd766rom_write8,
80                 write16: amd766rom_write16,
81                 write32: amd766rom_write32,
82                 copy_to: amd766rom_copy_to,
83                 /* The standard rom socket is for single power supply chips
84                  * that don't have an extra vpp.
85                  */
86         },
87         mtd: 0,
88         window_addr: 0,
89 };
90
91 static int __devinit amd766rom_init_one (struct pci_dev *pdev,
92         const struct pci_device_id *ent)
93 {
94         struct rom_window {
95                 u32 start;
96                 u32 size;
97                 u8 segen_bits;
98         };
99         static struct rom_window rom_window[] = {
100                 { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
101                 { 0xffc00000, 4*1024*1024, (1<<7), },
102                 { 0xffff0000, 64*1024,     0 },
103                 { 0         , 0,           0 },
104         };
105         static const u32 rom_probe_sizes[] = { 
106                 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
107                 256*1024, 128*1024, 64*1024, 0};
108         static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
109         u8 byte;
110         struct amd766rom_map_info *info = &amd766rom_map;
111         struct rom_window *window;
112         int i;
113         u32 rom_size;
114
115         window = &rom_window[0];
116         while(window->size) {
117                 if (request_mem_region(window->start, window->size, "amd766rom")) {
118                         break;
119                 }
120                 window++;
121         }
122         if (!window->size) {
123                 printk(KERN_ERR "amd766rom: cannot reserve rom window");
124                 goto err_out_none;
125         }
126
127         /* Enable the selected rom window */
128         pci_read_config_byte(pdev, 0x43, &byte);
129         pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
130
131         /* Enable writes through the rom window */
132         pci_read_config_byte(pdev, 0x40, &byte);
133         pci_write_config_byte(pdev, 0x40, byte | 1);
134
135         /* FIXME handle registers 0x80 - 0x8C the bios region locks */
136
137         printk(KERN_NOTICE "amd766rom window : %x at %x\n", 
138                 window->size, window->start);
139         /* For write accesses caches are useless */
140         info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
141
142         if (!info->window_addr) {
143                 printk(KERN_ERR "Failed to ioremap\n");
144                 goto err_out_free_mmio_region;
145         }
146         info->mtd = 0;
147         for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
148                 char **chip_type;
149                 if (rom_size > window->size) {
150                         continue;
151                 }
152                 info->map.map_priv_1 = 
153                         info->window_addr + window->size - rom_size;
154                 info->map.size = rom_size;
155                 chip_type = rom_probe_types;
156                 for(; !info->mtd && *chip_type; chip_type++) {
157                         info->mtd = do_map_probe(*chip_type, &amd766rom_map.map);
158                 }
159                 if (info->mtd) {
160                         break;
161                 }
162         }
163         if (!info->mtd) {
164                 goto err_out_iounmap;
165         }
166         printk(KERN_NOTICE "amd766rom chip at offset: %x\n",
167                 window->size - rom_size);
168                 
169         info->mtd->module = THIS_MODULE;
170         add_mtd_device(info->mtd);
171         info->window_start = window->start;
172         info->window_size = window->size;
173         return 0;
174
175 err_out_iounmap:
176         iounmap((void *)(info->window_addr));
177 err_out_free_mmio_region:
178         release_mem_region(window->start, window->size);
179 err_out_none:
180         return -ENODEV;
181 }
182
183
184 static void __devexit amd766rom_remove_one (struct pci_dev *pdev)
185 {
186         struct amd766rom_map_info *info = &amd766rom_map;
187         u8 byte;
188
189         del_mtd_device(info->mtd);
190         map_destroy(info->mtd);
191         info->mtd = 0;
192         info->map.map_priv_1 = 0;
193
194         iounmap((void *)(info->window_addr));
195         info->window_addr = 0;
196
197         /* Disable writes through the rom window */
198         pci_read_config_byte(pdev, 0x40, &byte);
199         pci_write_config_byte(pdev, 0x40, byte & ~1);
200         
201         release_mem_region(info->window_start, info->window_size);
202 }
203
204 static struct pci_device_id amd766rom_pci_tbl[] __devinitdata = {
205         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 
206           PCI_ANY_ID, PCI_ANY_ID, },
207 };
208
209 MODULE_DEVICE_TABLE(pci, amd766rom_pci_tbl);
210
211 #if 0
212 static struct pci_driver amd766rom_driver = {
213         name:     "amd766rom",
214         id_table: amd766rom_pci_tbl,
215         probe:    amd766rom_init_one,
216         remove:   amd766rom_remove_one,
217 };
218 #endif
219
220 int __init init_amd766rom(void)
221 {
222         struct pci_dev *pdev;
223         pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, 0);
224         if (pdev) {
225                 amd766rom_map.pdev = pdev;
226                 return amd766rom_init_one(pdev, &amd766rom_pci_tbl[0]);
227         }
228         return -ENXIO;
229 #if 0
230         return pci_module_init(&amd766rom_driver);
231 #endif
232 }
233
234 static void __exit cleanup_amd766rom(void)
235 {
236         amd766rom_remove_one(amd766rom_map.pdev);
237 }
238
239 module_init(init_amd766rom);
240 module_exit(cleanup_amd766rom);
241
242 MODULE_LICENSE("GPL");
243 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
244 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD766 southbridge");
245