4 * Normal mappings of chips in physical memory
5 * $Id: amd76xrom.c,v 1.12 2004/07/14 14:44:31 thayne Exp $
8 #include <linux/module.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/init.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>
20 #define xstr(s) str(s)
22 #define MOD_NAME xstr(KBUILD_BASENAME)
24 #define MTD_DEV_NAME_LENGTH 16
26 struct amd76xrom_map_info
{
29 void __iomem
* window_addr
;
30 u32 window_start
, window_size
;
32 struct resource window_rsrc
;
33 struct resource rom_rsrc
;
34 char mtd_name
[MTD_DEV_NAME_LENGTH
];
38 static struct amd76xrom_map_info amd76xrom_map
= {
44 /* remaining fields of structure are initialized to 0 */
48 static void amd76xrom_cleanup(struct amd76xrom_map_info
*info
)
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);
57 del_mtd_device(info
->mtd
);
58 map_destroy(info
->mtd
);
60 info
->map
.virt
= NULL
;
62 if (info
->rom_rsrc
.parent
)
63 release_resource(&info
->rom_rsrc
);
64 if (info
->window_rsrc
.parent
)
65 release_resource(&info
->window_rsrc
);
67 if (info
->window_addr
) {
68 iounmap(info
->window_addr
);
69 info
->window_addr
= NULL
;
74 static int __devinit
amd76xrom_init_one (struct pci_dev
*pdev
,
75 const struct pci_device_id
*ent
)
82 static struct rom_window rom_window
[] = {
84 * Need the 5MiB window for chips that have block lock/unlock
85 * registers located below 4MiB window.
87 { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
88 { 0xffc00000, 4*1024*1024, (1<<7), },
89 { 0xffff0000, 64*1024, 0 },
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
};
97 struct amd76xrom_map_info
*info
= &amd76xrom_map
;
98 struct rom_window
*window
;
103 window
= &rom_window
[0];
105 while (window
->size
) {
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.
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",
123 info
->window_rsrc
.start
, info
->window_rsrc
.end
);
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
);
130 /* Enable writes through the rom window */
131 pci_read_config_byte(pdev
, 0x40, &byte
);
132 pci_write_config_byte(pdev
, 0x40, byte
| 1);
134 /* FIXME handle registers 0x80 - 0x8C the bios region locks */
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
,
142 if (!info
->window_addr
) {
143 printk(KERN_ERR
"Failed to ioremap\n");
149 for(i
= 0; (rom_size
= rom_probe_sizes
[i
]); i
++) {
151 if (rom_size
> window
->size
) {
154 info
->map
.phys
= window
->start
+ window
->size
- rom_size
;
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
);
163 if (info
->mtd
) goto found_mtd
;
165 iounmap(info
->window_addr
);
166 info
->window_addr
= NULL
;
168 /* Disable writes through the rom window */
169 pci_read_config_byte(pdev
, 0x40, &byte
);
170 pci_write_config_byte(pdev
, 0x40, byte
& ~1);
177 printk(KERN_NOTICE MOD_NAME
" chip at offset: 0x%x\n",
178 window
->size
- rom_size
);
180 info
->mtd
->owner
= THIS_MODULE
;
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");
193 * The BIOS e820 usually reserves this so it isn't
201 add_mtd_device(info
->mtd
);
202 info
->window_start
= window
->start
;
203 info
->window_size
= window
->size
;
205 if (info
->window_rsrc
.parent
) {
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.
211 snprintf(info
->mtd_name
, MTD_DEV_NAME_LENGTH
,
212 "mtd%d", info
->mtd
->index
);
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
;
228 amd76xrom_cleanup(info
);
233 static void __devexit
amd76xrom_remove_one (struct pci_dev
*pdev
)
235 struct amd76xrom_map_info
*info
= &amd76xrom_map
;
237 amd76xrom_cleanup(info
);
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 */
249 MODULE_DEVICE_TABLE(pci
, amd76xrom_pci_tbl
);
252 static struct pci_driver amd76xrom_driver
= {
254 .id_table
= amd76xrom_pci_tbl
,
255 .probe
= amd76xrom_init_one
,
256 .remove
= amd76xrom_remove_one
,
260 int __init
init_amd76xrom(void)
262 struct pci_dev
*pdev
;
263 struct pci_device_id
*id
;
265 for(id
= amd76xrom_pci_tbl
; id
->vendor
; id
++) {
266 pdev
= pci_find_device(id
->vendor
, id
->device
, NULL
);
272 amd76xrom_map
.pdev
= pdev
;
273 return amd76xrom_init_one(pdev
, &amd76xrom_pci_tbl
[0]);
277 return pci_module_init(&amd76xrom_driver
);
281 static void __exit
cleanup_amd76xrom(void)
283 amd76xrom_remove_one(amd76xrom_map
.pdev
);
286 module_init(init_amd76xrom
);
287 module_exit(cleanup_amd76xrom
);
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");