4 * Normal mappings of chips in physical memory
5 * $Id: ichxrom.c,v 1.8 2004/07/16 17:43:11 dwmw2 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>
18 #include <linux/mtd/cfi.h>
20 #define xstr(s) str(s)
22 #define MOD_NAME xstr(KBUILD_BASENAME)
24 #define MTD_DEV_NAME_LENGTH 16
26 #define RESERVE_MEM_REGION 0
29 #define MANUFACTURER_INTEL 0x0089
30 #define I82802AB 0x00ad
31 #define I82802AC 0x00ac
33 #define ICHX_FWH_REGION_START 0xFF000000UL
34 #define ICHX_FWH_REGION_SIZE 0x01000000UL
35 #define BIOS_CNTL 0x4e
36 #define FWH_DEC_EN1 0xE3
37 #define FWH_DEC_EN2 0xF0
41 struct ichxrom_map_info
{
44 unsigned long window_addr
;
46 struct resource window_rsrc
;
47 struct resource rom_rsrc
;
48 char mtd_name
[MTD_DEV_NAME_LENGTH
];
51 static inline unsigned long addr(struct map_info
*map
, unsigned long ofs
)
54 offset
= ((8*1024*1024) - map
->size
) + ofs
;
55 if (offset
>= (4*1024*1024)) {
58 return map
->map_priv_1
+ 0x400000 + offset
;
61 static inline unsigned long dbg_addr(struct map_info
*map
, unsigned long addr
)
63 return addr
- map
->map_priv_1
+ ICHX_FWH_REGION_START
;
66 static map_word
ichxrom_read(struct map_info
*map
, unsigned long ofs
)
70 switch(map
->bankwidth
) {
71 case 1: val
.x
[0] = __raw_readb(addr(map
, ofs
)); break;
72 case 2: val
.x
[0] = __raw_readw(addr(map
, ofs
)); break;
73 case 4: val
.x
[0] = __raw_readl(addr(map
, ofs
)); break;
74 #if BITS_PER_LONG >= 64
75 case 8: val
.x
[0] = __raw_readq(addr(map
, ofs
)); break;
77 default: val
.x
[0] = 0; break;
79 for(i
= 1; i
< map_words(map
); i
++) {
85 static void ichxrom_copy_from(struct map_info
*map
, void *to
, unsigned long from
, ssize_t len
)
87 memcpy_fromio(to
, addr(map
, from
), len
);
90 static void ichxrom_write(struct map_info
*map
, map_word d
, unsigned long ofs
)
92 switch(map
->bankwidth
) {
93 case 1: __raw_writeb(d
.x
[0], addr(map
,ofs
)); break;
94 case 2: __raw_writew(d
.x
[0], addr(map
,ofs
)); break;
95 case 4: __raw_writel(d
.x
[0], addr(map
,ofs
)); break;
96 #if BITS_PER_LONG >= 64
97 case 8: __raw_writeq(d
.x
[0], addr(map
,ofs
)); break;
103 static void ichxrom_copy_to(struct map_info
*map
, unsigned long to
, const void *from
, ssize_t len
)
105 memcpy_toio(addr(map
, to
), from
, len
);
108 static struct ichxrom_map_info ichxrom_map
= {
114 .read
= ichxrom_read
,
115 .copy_from
= ichxrom_copy_from
,
116 .write
= ichxrom_write
,
117 .copy_to
= ichxrom_copy_to
,
118 /* Firmware hubs only use vpp when being programmed
119 * in a factory setting. So in-place programming
120 * needs to use a different method.
123 /* remaining fields of structure are initialized to 0 */
126 enum fwh_lock_state
{
132 static void ichxrom_cleanup(struct ichxrom_map_info
*info
)
136 /* Disable writes through the rom window */
137 pci_read_config_word(info
->pdev
, BIOS_CNTL
, &word
);
138 pci_write_config_word(info
->pdev
, BIOS_CNTL
, word
& ~1);
141 del_mtd_device(info
->mtd
);
142 map_destroy(info
->mtd
);
146 if (info
->rom_rsrc
.parent
)
147 release_resource(&info
->rom_rsrc
);
148 if (info
->window_rsrc
.parent
)
149 release_resource(&info
->window_rsrc
);
151 if (info
->window_addr
) {
152 iounmap((void *)(info
->window_addr
));
153 info
->window_addr
= 0;
158 static int ichxrom_set_lock_state(struct mtd_info
*mtd
, loff_t ofs
, size_t len
,
159 enum fwh_lock_state state
)
161 struct map_info
*map
= mtd
->priv
;
162 unsigned long start
= ofs
;
163 unsigned long end
= start
+ len
-1;
165 /* FIXME do I need to guard against concurrency here? */
166 /* round down to 64K boundaries */
167 start
= start
& ~0xFFFF;
169 while (start
<= end
) {
170 unsigned long ctrl_addr
;
171 ctrl_addr
= addr(map
, start
) - 0x400000 + 2;
172 writeb(state
, ctrl_addr
);
173 start
= start
+ 0x10000;
178 static int ichxrom_lock(struct mtd_info
*mtd
, loff_t ofs
, size_t len
)
180 return ichxrom_set_lock_state(mtd
, ofs
, len
, FWH_DENY_WRITE
);
183 static int ichxrom_unlock(struct mtd_info
*mtd
, loff_t ofs
, size_t len
)
185 return ichxrom_set_lock_state(mtd
, ofs
, len
, 0);
188 static int __devinit
ichxrom_init_one (struct pci_dev
*pdev
,
189 const struct pci_device_id
*ent
)
192 struct ichxrom_map_info
*info
= &ichxrom_map
;
193 unsigned long map_size
;
194 static char *probes
[] = { "cfi_probe", "jedec_probe" };
195 struct cfi_private
*cfi
;
197 /* For now I just handle the ichx and I assume there
198 * are not a lot of resources up at the top of the address
199 * space. It is possible to handle other devices in the
200 * top 16MB but it is very painful. Also since
201 * you can only really attach a FWH to an ICHX there
202 * a number of simplifications you can make.
204 * Also you can page firmware hubs if an 8MB window isn't enough
205 * but don't currently handle that case either.
211 * Try to reserve the window mem region. If this fails then
212 * it is likely due to the window being "reseved" by the BIOS.
214 info
->window_rsrc
.name
= MOD_NAME
;
215 info
->window_rsrc
.start
= ICHX_FWH_REGION_START
;
216 info
->window_rsrc
.end
= ICHX_FWH_REGION_START
+ ICHX_FWH_REGION_SIZE
- 1;
217 info
->window_rsrc
.flags
= IORESOURCE_MEM
| IORESOURCE_BUSY
;
218 if (request_resource(&iomem_resource
, &info
->window_rsrc
)) {
219 info
->window_rsrc
.parent
= NULL
;
220 printk(KERN_ERR MOD_NAME
221 " %s(): Unable to register resource"
222 " 0x%.08lx-0x%.08lx - kernel bug?\n",
224 info
->window_rsrc
.start
, info
->window_rsrc
.end
);
227 /* Enable writes through the rom window */
228 pci_read_config_word(pdev
, BIOS_CNTL
, &word
);
229 if (!(word
& 1) && (word
& (1<<1))) {
230 /* The BIOS will generate an error if I enable
231 * this device, so don't even try.
233 printk(KERN_ERR MOD_NAME
": firmware access control, I can't enable writes\n");
236 pci_write_config_word(pdev
, BIOS_CNTL
, word
| 1);
239 /* Map the firmware hub into my address space. */
240 /* Does this use too much virtual address space? */
241 info
->window_addr
= (unsigned long)ioremap(
242 ICHX_FWH_REGION_START
, ICHX_FWH_REGION_SIZE
);
243 if (!info
->window_addr
) {
244 printk(KERN_ERR
"Failed to ioremap\n");
248 /* For now assume the firmware has setup all relevant firmware
249 * windows. We don't have enough information to handle this case
253 /* FIXME select the firmware hub and enable a window to it. */
256 info
->map
.map_priv_1
= info
->window_addr
;
258 /* Loop through the possible bankwidths */
259 for(ichxrom_map
.map
.bankwidth
= 4; ichxrom_map
.map
.bankwidth
; ichxrom_map
.map
.bankwidth
>>= 1) {
260 map_size
= ICHX_FWH_REGION_SIZE
;
261 while(!info
->mtd
&& (map_size
> 0)) {
263 info
->map
.size
= map_size
;
264 for(i
= 0; i
< sizeof(probes
)/sizeof(char *); i
++) {
265 info
->mtd
= do_map_probe(probes
[i
], &ichxrom_map
.map
);
269 map_size
-= 512*1024;
277 cfi
= ichxrom_map
.map
.fldrv_priv
;
278 if ((cfi
->mfr
== MANUFACTURER_INTEL
) && (
279 (cfi
->id
== I82802AB
) ||
280 (cfi
->id
== I82802AC
)))
282 /* If it is a firmware hub put in the special lock
283 * and unlock routines.
285 info
->mtd
->lock
= ichxrom_lock
;
286 info
->mtd
->unlock
= ichxrom_unlock
;
288 if (info
->mtd
->size
> info
->map
.size
) {
289 printk(KERN_WARNING MOD_NAME
" rom(%u) larger than window(%lu). fixing...\n",
290 info
->mtd
->size
, info
->map
.size
);
291 info
->mtd
->size
= info
->map
.size
;
294 info
->mtd
->owner
= THIS_MODULE
;
295 add_mtd_device(info
->mtd
);
297 if (info
->window_rsrc
.parent
) {
299 * Registering the MTD device in iomem may not be possible
300 * if there is a BIOS "reserved" and BUSY range. If this
301 * fails then continue anyway.
303 snprintf(info
->mtd_name
, MTD_DEV_NAME_LENGTH
,
304 "mtd%d", info
->mtd
->index
);
306 info
->rom_rsrc
.name
= info
->mtd_name
;
307 info
->rom_rsrc
.start
= ICHX_FWH_REGION_START
308 + ICHX_FWH_REGION_SIZE
- map_size
;
309 info
->rom_rsrc
.end
= ICHX_FWH_REGION_START
310 + ICHX_FWH_REGION_SIZE
;
311 info
->rom_rsrc
.flags
= IORESOURCE_MEM
| IORESOURCE_BUSY
;
312 if (request_resource(&info
->window_rsrc
, &info
->rom_rsrc
)) {
313 printk(KERN_ERR MOD_NAME
314 ": cannot reserve MTD resource\n");
315 info
->rom_rsrc
.parent
= NULL
;
322 ichxrom_cleanup(info
);
327 static void __devexit
ichxrom_remove_one (struct pci_dev
*pdev
)
329 struct ichxrom_map_info
*info
= &ichxrom_map
;
332 del_mtd_device(info
->mtd
);
333 map_destroy(info
->mtd
);
335 info
->map
.map_priv_1
= 0;
337 iounmap((void *)(info
->window_addr
));
338 info
->window_addr
= 0;
340 /* Disable writes through the rom window */
341 pci_read_config_word(pdev
, BIOS_CNTL
, &word
);
342 pci_write_config_word(pdev
, BIOS_CNTL
, word
& ~1);
344 #if RESERVE_MEM_REGION
345 release_mem_region(ICHX_FWH_REGION_START
, ICHX_FWH_REGION_SIZE
);
349 static struct pci_device_id ichxrom_pci_tbl
[] __devinitdata
= {
350 { PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_82801BA_0
,
351 PCI_ANY_ID
, PCI_ANY_ID
, },
352 { PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_82801CA_0
,
353 PCI_ANY_ID
, PCI_ANY_ID
, },
354 { PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_82801DB_0
,
355 PCI_ANY_ID
, PCI_ANY_ID
, },
356 { PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_82801EB_0
,
357 PCI_ANY_ID
, PCI_ANY_ID
, },
358 { PCI_VENDOR_ID_INTEL
, PCI_DEVICE_ID_INTEL_ESB_1
,
359 PCI_ANY_ID
, PCI_ANY_ID
, },
363 MODULE_DEVICE_TABLE(pci
, ichxrom_pci_tbl
);
366 static struct pci_driver ichxrom_driver
= {
368 .id_table
= ichxrom_pci_tbl
,
369 .probe
= ichxrom_init_one
,
370 .remove
= ichxrom_remove_one
,
374 static struct pci_dev
*mydev
;
375 int __init
init_ichxrom(void)
377 struct pci_dev
*pdev
;
378 struct pci_device_id
*id
;
381 for (id
= ichxrom_pci_tbl
; id
->vendor
; id
++) {
382 pdev
= pci_find_device(id
->vendor
, id
->device
, NULL
);
389 return ichxrom_init_one(pdev
, &ichxrom_pci_tbl
[0]);
393 return pci_module_init(&ichxrom_driver
);
397 static void __exit
cleanup_ichxrom(void)
399 ichxrom_remove_one(mydev
);
402 module_init(init_ichxrom
);
403 module_exit(cleanup_ichxrom
);
405 MODULE_LICENSE("GPL");
406 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
407 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");