ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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.8 2003/05/28 15:44:28 dwmw2 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 struct amd76xrom_map_info {
21         struct map_info map;
22         struct mtd_info *mtd;
23         unsigned long window_addr;
24         u32 window_start, window_size;
25         struct pci_dev *pdev;
26 };
27
28
29 static struct amd76xrom_map_info amd76xrom_map = {
30         .map = {
31                 .name = "AMD76X rom",
32                 .size = 0,
33                 .buswidth = 1,
34         },
35         .mtd = 0,
36         .window_addr = 0,
37 };
38
39 static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
40         const struct pci_device_id *ent)
41 {
42         struct rom_window {
43                 u32 start;
44                 u32 size;
45                 u8 segen_bits;
46         };
47         static struct rom_window rom_window[] = {
48                 { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
49                 { 0xffc00000, 4*1024*1024, (1<<7), },
50                 { 0xffff0000, 64*1024,     0 },
51                 { 0         , 0,           0 },
52         };
53         static const u32 rom_probe_sizes[] = { 
54                 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
55                 256*1024, 128*1024, 64*1024, 0};
56         static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
57         u8 byte;
58         struct amd76xrom_map_info *info = &amd76xrom_map;
59         struct rom_window *window;
60         int i;
61         u32 rom_size;
62
63         window = &rom_window[0];
64
65         /* disabled because it fights with BIOS reserved regions */
66 #define REQUEST_MEM_REGION 0
67 #if REQUEST_MEM_REGION
68         while(window->size) {
69                 if (request_mem_region(window->start, window->size, "amd76xrom")) {
70                         break;
71                 }
72                 window++;
73         }
74         if (!window->size) {
75                 printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
76                 goto err_out_none;
77         }
78 #endif /* REQUEST_MEM_REGION */
79
80         /* Enable the selected rom window */
81         pci_read_config_byte(pdev, 0x43, &byte);
82         pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
83
84         /* Enable writes through the rom window */
85         pci_read_config_byte(pdev, 0x40, &byte);
86         pci_write_config_byte(pdev, 0x40, byte | 1);
87
88         /* FIXME handle registers 0x80 - 0x8C the bios region locks */
89
90         printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
91                 window->size, window->start);
92         /* For write accesses caches are useless */
93         info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
94
95         if (!info->window_addr) {
96                 printk(KERN_ERR "Failed to ioremap\n");
97                 goto err_out_free_mmio_region;
98         }
99         info->mtd = 0;
100         for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
101                 char **chip_type;
102                 if (rom_size > window->size) {
103                         continue;
104                 }
105                 info->map.phys = window->start + window->size - rom_size;
106                 info->map.virt = 
107                         info->window_addr + window->size - rom_size;
108                 info->map.size = rom_size;
109                 simple_map_init(&info->map);
110                 chip_type = rom_probe_types;
111                 for(; !info->mtd && *chip_type; chip_type++) {
112                         info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
113                 }
114                 if (info->mtd) {
115                         break;
116                 }
117         }
118         if (!info->mtd) {
119                 goto err_out_iounmap;
120         }
121         printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n",
122                 window->size - rom_size);
123                 
124         info->mtd->owner = THIS_MODULE;
125         add_mtd_device(info->mtd);
126         info->window_start = window->start;
127         info->window_size = window->size;
128         return 0;
129
130 err_out_iounmap:
131         iounmap((void *)(info->window_addr));
132 err_out_free_mmio_region:
133 #if REQUEST_MEM_REGION
134         release_mem_region(window->start, window->size);
135 err_out_none:
136 #endif /* REQUEST_MEM_REGION */
137         return -ENODEV;
138 }
139
140
141 static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
142 {
143         struct amd76xrom_map_info *info = &amd76xrom_map;
144         u8 byte;
145
146         del_mtd_device(info->mtd);
147         map_destroy(info->mtd);
148         info->mtd = 0;
149         info->map.virt = 0;
150
151         iounmap((void *)(info->window_addr));
152         info->window_addr = 0;
153
154         /* Disable writes through the rom window */
155         pci_read_config_byte(pdev, 0x40, &byte);
156         pci_write_config_byte(pdev, 0x40, byte & ~1);
157
158 #if REQUEST_MEM_REGION
159         release_mem_region(info->window_start, info->window_size);
160 #endif /* REQUEST_MEM_REGION */
161 }
162
163 static struct pci_device_id amd76xrom_pci_tbl[] = {
164         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
165                 PCI_ANY_ID, PCI_ANY_ID, },
166         { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
167                 PCI_ANY_ID, PCI_ANY_ID, },
168         { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
169         { 0, }
170 };
171
172 MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
173
174 #if 0
175 static struct pci_driver amd76xrom_driver = {
176         .name =         "amd76xrom",
177         .id_table =     amd76xrom_pci_tbl,
178         .probe =        amd76xrom_init_one,
179         .remove =       amd76xrom_remove_one,
180 };
181 #endif
182
183 int __init init_amd76xrom(void)
184 {
185         struct pci_dev *pdev;
186         struct pci_device_id *id;
187         pdev = 0;
188         for(id = amd76xrom_pci_tbl; id->vendor; id++) {
189                 pdev = pci_find_device(id->vendor, id->device, 0);
190                 if (pdev) {
191                         break;
192                 }
193         }
194         if (pdev) {
195                 amd76xrom_map.pdev = pdev;
196                 return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
197         }
198         return -ENXIO;
199 #if 0
200         return pci_module_init(&amd76xrom_driver);
201 #endif
202 }
203
204 static void __exit cleanup_amd76xrom(void)
205 {
206         amd76xrom_remove_one(amd76xrom_map.pdev);
207 }
208
209 module_init(init_amd76xrom);
210 module_exit(cleanup_amd76xrom);
211
212 MODULE_LICENSE("GPL");
213 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
214 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
215