added mtd driver
[linux-2.4.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.1 2002/10/18 22:45:48 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 amd76xrom_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 amd76xrom_read8(struct map_info *map, unsigned long ofs)
28 {
29         return __raw_readb(map->map_priv_1 + ofs);
30 }
31
32 static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs)
33 {
34         return __raw_readw(map->map_priv_1 + ofs);
35 }
36
37 static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs)
38 {
39         return __raw_readl(map->map_priv_1 + ofs);
40 }
41
42 static void amd76xrom_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 amd76xrom_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 amd76xrom_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 amd76xrom_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 amd76xrom_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 amd76xrom_map_info amd76xrom_map = {
71         map: {
72                 name: "AMD76X rom",
73                 size: 0,
74                 buswidth: 1,
75                 read8: amd76xrom_read8,
76                 read16: amd76xrom_read16,
77                 read32: amd76xrom_read32,
78                 copy_from: amd76xrom_copy_from,
79                 write8: amd76xrom_write8,
80                 write16: amd76xrom_write16,
81                 write32: amd76xrom_write32,
82                 copy_to: amd76xrom_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 amd76xrom_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 amd76xrom_map_info *info = &amd76xrom_map;
111         struct rom_window *window;
112         int i;
113         u32 rom_size;
114
115         window = &rom_window[0];
116 #if 0
117         while(window->size) {
118                 if (request_mem_region(window->start, window->size, "amd76xrom")) {
119                         break;
120                 }
121                 window++;
122         }
123         if (!window->size) {
124                 printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
125                 goto err_out_none;
126         }
127 #endif
128
129         /* Enable the selected rom window */
130         pci_read_config_byte(pdev, 0x43, &byte);
131         pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
132
133         /* Enable writes through the rom window */
134         pci_read_config_byte(pdev, 0x40, &byte);
135         pci_write_config_byte(pdev, 0x40, byte | 1);
136
137         /* FIXME handle registers 0x80 - 0x8C the bios region locks */
138
139         printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
140                 window->size, window->start);
141         /* For write accesses caches are useless */
142         info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
143
144         if (!info->window_addr) {
145                 printk(KERN_ERR "Failed to ioremap\n");
146                 goto err_out_free_mmio_region;
147         }
148         info->mtd = 0;
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.map_priv_1 = 
155                         info->window_addr + window->size - rom_size;
156                 info->map.size = rom_size;
157                 chip_type = rom_probe_types;
158                 for(; !info->mtd && *chip_type; chip_type++) {
159                         info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
160                 }
161                 if (info->mtd) {
162                         break;
163                 }
164         }
165         if (!info->mtd) {
166                 goto err_out_iounmap;
167         }
168         printk(KERN_NOTICE "amd76xrom chip at offset: %x\n",
169                 window->size - rom_size);
170                 
171         info->mtd->module = THIS_MODULE;
172         add_mtd_device(info->mtd);
173         info->window_start = window->start;
174         info->window_size = window->size;
175         return 0;
176
177 err_out_iounmap:
178         iounmap((void *)(info->window_addr));
179 err_out_free_mmio_region:
180         release_mem_region(window->start, window->size);
181 //err_out_none:
182         return -ENODEV;
183 }
184
185
186 static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
187 {
188         struct amd76xrom_map_info *info = &amd76xrom_map;
189         u8 byte;
190
191         del_mtd_device(info->mtd);
192         map_destroy(info->mtd);
193         info->mtd = 0;
194         info->map.map_priv_1 = 0;
195
196         iounmap((void *)(info->window_addr));
197         info->window_addr = 0;
198
199         /* Disable writes through the rom window */
200         pci_read_config_byte(pdev, 0x40, &byte);
201         pci_write_config_byte(pdev, 0x40, byte & ~1);
202         
203         release_mem_region(info->window_start, info->window_size);
204 }
205
206 static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
207         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
208                 PCI_ANY_ID, PCI_ANY_ID, },
209         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
210                 PCI_ANY_ID, PCI_ANY_ID, },
211         { 0, }
212 };
213
214 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
215
216 #if 0
217 static struct pci_driver amd76xrom_driver = {
218         name:     "amd76xrom",
219         id_table: amd76xrom_pci_tbl,
220         probe:    amd76xrom_init_one,
221         remove:   amd76xrom_remove_one,
222 };
223 #endif
224
225 int __init init_amd76xrom(void)
226 {
227         struct pci_dev *pdev;
228         struct pci_device_id *id;
229         pdev = 0;
230         for(id = amd76xrom_pci_tbl; id->vendor; id++) {
231                 pdev = pci_find_device(id->vendor, id->device, 0);
232                 if (pdev) {
233                         break;
234                 }
235         }
236         if (pdev) {
237                 amd76xrom_map.pdev = pdev;
238                 return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
239         }
240         return -ENXIO;
241 #if 0
242         return pci_module_init(&amd76xrom_driver);
243 #endif
244 }
245
246 static void __exit cleanup_amd76xrom(void)
247 {
248         amd76xrom_remove_one(amd76xrom_map.pdev);
249 }
250
251 module_init(init_amd76xrom);
252 module_exit(cleanup_amd76xrom);
253
254 MODULE_LICENSE("GPL");
255 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
256 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
257