0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/module.h>
0015 #include <linux/types.h>
0016 #include <linux/kernel.h>
0017 #include <linux/init.h>
0018 #include <linux/slab.h>
0019 #include <asm/io.h>
0020 #include <linux/mtd/mtd.h>
0021 #include <linux/mtd/map.h>
0022 #include <linux/mtd/cfi.h>
0023 #include <linux/mtd/flashchip.h>
0024 #include <linux/pci.h>
0025 #include <linux/pci_ids.h>
0026 #include <linux/list.h>
0027
0028 #define MOD_NAME KBUILD_BASENAME
0029
0030 #define ADDRESS_NAME_LEN 18
0031
0032 #define ROM_PROBE_STEP_SIZE (64*1024)
0033
0034 #define BIOS_CNTL 0xDC
0035 #define BIOS_LOCK_ENABLE 0x02
0036 #define BIOS_WRITE_ENABLE 0x01
0037
0038
0039 #define FWH_DEC_EN1 0xD8
0040 #define FWH_F8_EN 0x8000
0041 #define FWH_F0_EN 0x4000
0042 #define FWH_E8_EN 0x2000
0043 #define FWH_E0_EN 0x1000
0044 #define FWH_D8_EN 0x0800
0045 #define FWH_D0_EN 0x0400
0046 #define FWH_C8_EN 0x0200
0047 #define FWH_C0_EN 0x0100
0048 #define FWH_LEGACY_F_EN 0x0080
0049 #define FWH_LEGACY_E_EN 0x0040
0050
0051 #define FWH_70_EN 0x0008
0052 #define FWH_60_EN 0x0004
0053 #define FWH_50_EN 0x0002
0054 #define FWH_40_EN 0x0001
0055
0056
0057 #define FWH_SEL1 0xD0
0058 #define FWH_SEL2 0xD4
0059
0060 #define FWH_8MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0061 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
0062 FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN)
0063
0064 #define FWH_7MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0065 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
0066 FWH_70_EN | FWH_60_EN | FWH_50_EN)
0067
0068 #define FWH_6MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0069 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
0070 FWH_70_EN | FWH_60_EN)
0071
0072 #define FWH_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0073 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
0074 FWH_70_EN)
0075
0076 #define FWH_4MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0077 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN)
0078
0079 #define FWH_3_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0080 FWH_D8_EN | FWH_D0_EN | FWH_C8_EN)
0081
0082 #define FWH_3MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0083 FWH_D8_EN | FWH_D0_EN)
0084
0085 #define FWH_2_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
0086 FWH_D8_EN)
0087
0088 #define FWH_2MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN)
0089
0090 #define FWH_1_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN)
0091
0092 #define FWH_1MiB (FWH_F8_EN | FWH_F0_EN)
0093
0094 #define FWH_0_5MiB (FWH_F8_EN)
0095
0096
0097 struct esb2rom_window {
0098 void __iomem* virt;
0099 unsigned long phys;
0100 unsigned long size;
0101 struct list_head maps;
0102 struct resource rsrc;
0103 struct pci_dev *pdev;
0104 };
0105
0106 struct esb2rom_map_info {
0107 struct list_head list;
0108 struct map_info map;
0109 struct mtd_info *mtd;
0110 struct resource rsrc;
0111 char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
0112 };
0113
0114 static struct esb2rom_window esb2rom_window = {
0115 .maps = LIST_HEAD_INIT(esb2rom_window.maps),
0116 };
0117
0118 static void esb2rom_cleanup(struct esb2rom_window *window)
0119 {
0120 struct esb2rom_map_info *map, *scratch;
0121 u8 byte;
0122
0123
0124 pci_read_config_byte(window->pdev, BIOS_CNTL, &byte);
0125 pci_write_config_byte(window->pdev, BIOS_CNTL,
0126 byte & ~BIOS_WRITE_ENABLE);
0127
0128
0129 list_for_each_entry_safe(map, scratch, &window->maps, list) {
0130 if (map->rsrc.parent)
0131 release_resource(&map->rsrc);
0132 mtd_device_unregister(map->mtd);
0133 map_destroy(map->mtd);
0134 list_del(&map->list);
0135 kfree(map);
0136 }
0137 if (window->rsrc.parent)
0138 release_resource(&window->rsrc);
0139 if (window->virt) {
0140 iounmap(window->virt);
0141 window->virt = NULL;
0142 window->phys = 0;
0143 window->size = 0;
0144 }
0145 pci_dev_put(window->pdev);
0146 }
0147
0148 static int __init esb2rom_init_one(struct pci_dev *pdev,
0149 const struct pci_device_id *ent)
0150 {
0151 static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
0152 struct esb2rom_window *window = &esb2rom_window;
0153 struct esb2rom_map_info *map = NULL;
0154 unsigned long map_top;
0155 u8 byte;
0156 u16 word;
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 window->pdev = pci_dev_get(pdev);
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 window->phys = 0;
0188 pci_read_config_word(pdev, FWH_DEC_EN1, &word);
0189 printk(KERN_DEBUG "pci_read_config_word : %x\n", word);
0190
0191 if ((word & FWH_8MiB) == FWH_8MiB)
0192 window->phys = 0xff400000;
0193 else if ((word & FWH_7MiB) == FWH_7MiB)
0194 window->phys = 0xff500000;
0195 else if ((word & FWH_6MiB) == FWH_6MiB)
0196 window->phys = 0xff600000;
0197 else if ((word & FWH_5MiB) == FWH_5MiB)
0198 window->phys = 0xFF700000;
0199 else if ((word & FWH_4MiB) == FWH_4MiB)
0200 window->phys = 0xffc00000;
0201 else if ((word & FWH_3_5MiB) == FWH_3_5MiB)
0202 window->phys = 0xffc80000;
0203 else if ((word & FWH_3MiB) == FWH_3MiB)
0204 window->phys = 0xffd00000;
0205 else if ((word & FWH_2_5MiB) == FWH_2_5MiB)
0206 window->phys = 0xffd80000;
0207 else if ((word & FWH_2MiB) == FWH_2MiB)
0208 window->phys = 0xffe00000;
0209 else if ((word & FWH_1_5MiB) == FWH_1_5MiB)
0210 window->phys = 0xffe80000;
0211 else if ((word & FWH_1MiB) == FWH_1MiB)
0212 window->phys = 0xfff00000;
0213 else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
0214 window->phys = 0xfff80000;
0215
0216 if (window->phys == 0) {
0217 printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
0218 goto out;
0219 }
0220
0221
0222 window->phys -= 0x400000UL;
0223 window->size = (0xffffffffUL - window->phys) + 1UL;
0224
0225
0226 pci_read_config_byte(pdev, BIOS_CNTL, &byte);
0227 if (!(byte & BIOS_WRITE_ENABLE) && (byte & (BIOS_LOCK_ENABLE))) {
0228
0229
0230
0231 printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
0232 goto out;
0233 }
0234 pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE);
0235
0236
0237
0238
0239
0240 window->rsrc.name = MOD_NAME;
0241 window->rsrc.start = window->phys;
0242 window->rsrc.end = window->phys + window->size - 1;
0243 window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0244 if (request_resource(&iomem_resource, &window->rsrc)) {
0245 window->rsrc.parent = NULL;
0246 printk(KERN_DEBUG MOD_NAME ": "
0247 "%s(): Unable to register resource %pR - kernel bug?\n",
0248 __func__, &window->rsrc);
0249 }
0250
0251
0252 window->virt = ioremap(window->phys, window->size);
0253 if (!window->virt) {
0254 printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
0255 window->phys, window->size);
0256 goto out;
0257 }
0258
0259
0260 map_top = window->phys;
0261 if ((window->phys & 0x3fffff) != 0) {
0262
0263 map_top = window->phys + 0x400000;
0264 }
0265 #if 1
0266
0267
0268
0269
0270
0271 if (map_top < 0xffc00000)
0272 map_top = 0xffc00000;
0273 #endif
0274
0275 while ((map_top - 1) < 0xffffffffUL) {
0276 struct cfi_private *cfi;
0277 unsigned long offset;
0278 int i;
0279
0280 if (!map) {
0281 map = kmalloc(sizeof(*map), GFP_KERNEL);
0282 if (!map)
0283 goto out;
0284 }
0285 memset(map, 0, sizeof(*map));
0286 INIT_LIST_HEAD(&map->list);
0287 map->map.name = map->map_name;
0288 map->map.phys = map_top;
0289 offset = map_top - window->phys;
0290 map->map.virt = (void __iomem *)
0291 (((unsigned long)(window->virt)) + offset);
0292 map->map.size = 0xffffffffUL - map_top + 1UL;
0293
0294 sprintf(map->map_name, "%s @%08Lx",
0295 MOD_NAME, (unsigned long long)map->map.phys);
0296
0297
0298
0299
0300
0301 for(map->map.bankwidth = 32; map->map.bankwidth;
0302 map->map.bankwidth >>= 1) {
0303 char **probe_type;
0304
0305 if (!map_bankwidth_supported(map->map.bankwidth))
0306 continue;
0307
0308
0309 simple_map_init(&map->map);
0310
0311
0312 probe_type = rom_probe_types;
0313 for(; *probe_type; probe_type++) {
0314 map->mtd = do_map_probe(*probe_type, &map->map);
0315 if (map->mtd)
0316 goto found;
0317 }
0318 }
0319 map_top += ROM_PROBE_STEP_SIZE;
0320 continue;
0321 found:
0322
0323 if (map->mtd->size > map->map.size) {
0324 printk(KERN_WARNING MOD_NAME
0325 " rom(%llu) larger than window(%lu). fixing...\n",
0326 (unsigned long long)map->mtd->size, map->map.size);
0327 map->mtd->size = map->map.size;
0328 }
0329 if (window->rsrc.parent) {
0330
0331
0332
0333
0334
0335 map->rsrc.name = map->map_name;
0336 map->rsrc.start = map->map.phys;
0337 map->rsrc.end = map->map.phys + map->mtd->size - 1;
0338 map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
0339 if (request_resource(&window->rsrc, &map->rsrc)) {
0340 printk(KERN_ERR MOD_NAME
0341 ": cannot reserve MTD resource\n");
0342 map->rsrc.parent = NULL;
0343 }
0344 }
0345
0346
0347 map->map.virt = window->virt;
0348 map->map.phys = window->phys;
0349 cfi = map->map.fldrv_priv;
0350 for(i = 0; i < cfi->numchips; i++)
0351 cfi->chips[i].start += offset;
0352
0353
0354 map->mtd->owner = THIS_MODULE;
0355 if (mtd_device_register(map->mtd, NULL, 0)) {
0356 map_destroy(map->mtd);
0357 map->mtd = NULL;
0358 goto out;
0359 }
0360
0361
0362 map_top += map->mtd->size;
0363
0364
0365 list_add(&map->list, &window->maps);
0366 map = NULL;
0367 }
0368
0369 out:
0370
0371 kfree(map);
0372
0373
0374 if (list_empty(&window->maps)) {
0375 esb2rom_cleanup(window);
0376 return -ENODEV;
0377 }
0378 return 0;
0379 }
0380
0381 static void esb2rom_remove_one(struct pci_dev *pdev)
0382 {
0383 struct esb2rom_window *window = &esb2rom_window;
0384 esb2rom_cleanup(window);
0385 }
0386
0387 static const struct pci_device_id esb2rom_pci_tbl[] = {
0388 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
0389 PCI_ANY_ID, PCI_ANY_ID, },
0390 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
0391 PCI_ANY_ID, PCI_ANY_ID, },
0392 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
0393 PCI_ANY_ID, PCI_ANY_ID, },
0394 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
0395 PCI_ANY_ID, PCI_ANY_ID, },
0396 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
0397 PCI_ANY_ID, PCI_ANY_ID, },
0398 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
0399 PCI_ANY_ID, PCI_ANY_ID, },
0400 { 0, },
0401 };
0402
0403 #if 0
0404 MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl);
0405
0406 static struct pci_driver esb2rom_driver = {
0407 .name = MOD_NAME,
0408 .id_table = esb2rom_pci_tbl,
0409 .probe = esb2rom_init_one,
0410 .remove = esb2rom_remove_one,
0411 };
0412 #endif
0413
0414 static int __init init_esb2rom(void)
0415 {
0416 struct pci_dev *pdev;
0417 const struct pci_device_id *id;
0418 int retVal;
0419
0420 pdev = NULL;
0421 for (id = esb2rom_pci_tbl; id->vendor; id++) {
0422 printk(KERN_DEBUG "device id = %x\n", id->device);
0423 pdev = pci_get_device(id->vendor, id->device, NULL);
0424 if (pdev) {
0425 printk(KERN_DEBUG "matched device = %x\n", id->device);
0426 break;
0427 }
0428 }
0429 if (pdev) {
0430 printk(KERN_DEBUG "matched device id %x\n", id->device);
0431 retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]);
0432 pci_dev_put(pdev);
0433 printk(KERN_DEBUG "retVal = %d\n", retVal);
0434 return retVal;
0435 }
0436 return -ENXIO;
0437 #if 0
0438 return pci_register_driver(&esb2rom_driver);
0439 #endif
0440 }
0441
0442 static void __exit cleanup_esb2rom(void)
0443 {
0444 esb2rom_remove_one(esb2rom_window.pdev);
0445 }
0446
0447 module_init(init_esb2rom);
0448 module_exit(cleanup_esb2rom);
0449
0450 MODULE_LICENSE("GPL");
0451 MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>");
0452 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge");