0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 #include <linux/module.h>
0049 #include <linux/types.h>
0050 #include <linux/kernel.h>
0051 #include <asm/io.h>
0052 #include <linux/mtd/mtd.h>
0053 #include <linux/mtd/map.h>
0054 #include <linux/mtd/cfi.h>
0055 #include <linux/pci.h>
0056 #include <linux/pci_ids.h>
0057
0058 #define MODNAME "scb2_flash"
0059 #define SCB2_ADDR 0xfff00000
0060 #define SCB2_WINDOW 0x00100000
0061
0062
0063 static void __iomem *scb2_ioaddr;
0064 static struct mtd_info *scb2_mtd;
0065 static struct map_info scb2_map = {
0066 .name = "SCB2 BIOS Flash",
0067 .size = 0,
0068 .bankwidth = 1,
0069 };
0070 static int region_fail;
0071
0072 static int scb2_fixup_mtd(struct mtd_info *mtd)
0073 {
0074 int i;
0075 int done = 0;
0076 struct map_info *map = mtd->priv;
0077 struct cfi_private *cfi = map->fldrv_priv;
0078
0079
0080 if (cfi->cfiq->InterfaceDesc != CFI_INTERFACE_X16_ASYNC) {
0081 printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
0082 cfi->cfiq->InterfaceDesc);
0083 return -1;
0084 }
0085
0086
0087
0088
0089 mtd->size = map->size;
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 mtd->erasesize /= 2;
0105 for (i = 0; i < mtd->numeraseregions; i++) {
0106 struct mtd_erase_region_info *region = &mtd->eraseregions[i];
0107 region->erasesize /= 2;
0108 }
0109
0110
0111
0112
0113
0114
0115
0116 for (i = 0; !done && i < mtd->numeraseregions; i++) {
0117 struct mtd_erase_region_info *region = &mtd->eraseregions[i];
0118
0119 if (region->numblocks * region->erasesize > mtd->size) {
0120 region->numblocks = ((unsigned long)mtd->size /
0121 region->erasesize);
0122 done = 1;
0123 } else {
0124 region->numblocks = 0;
0125 }
0126 region->offset = 0;
0127 }
0128
0129 return 0;
0130 }
0131
0132
0133 #define CSB5_FCR 0x41
0134 #define CSB5_FCR_DECODE_ALL 0x0e
0135 static int scb2_flash_probe(struct pci_dev *dev,
0136 const struct pci_device_id *ent)
0137 {
0138 u8 reg;
0139
0140
0141 pci_read_config_byte(dev, CSB5_FCR, ®);
0142 pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
0143
0144 if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
0145
0146
0147
0148
0149 printk(KERN_WARNING MODNAME
0150 ": warning - can't reserve rom window, continuing\n");
0151 region_fail = 1;
0152 }
0153
0154
0155 scb2_ioaddr = ioremap(SCB2_ADDR, SCB2_WINDOW);
0156 if (!scb2_ioaddr) {
0157 printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
0158 if (!region_fail)
0159 release_mem_region(SCB2_ADDR, SCB2_WINDOW);
0160 return -ENOMEM;
0161 }
0162
0163 scb2_map.phys = SCB2_ADDR;
0164 scb2_map.virt = scb2_ioaddr;
0165 scb2_map.size = SCB2_WINDOW;
0166
0167 simple_map_init(&scb2_map);
0168
0169
0170 scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
0171
0172 if (!scb2_mtd) {
0173 printk(KERN_ERR MODNAME ": flash probe failed!\n");
0174 iounmap(scb2_ioaddr);
0175 if (!region_fail)
0176 release_mem_region(SCB2_ADDR, SCB2_WINDOW);
0177 return -ENODEV;
0178 }
0179
0180 scb2_mtd->owner = THIS_MODULE;
0181 if (scb2_fixup_mtd(scb2_mtd) < 0) {
0182 mtd_device_unregister(scb2_mtd);
0183 map_destroy(scb2_mtd);
0184 iounmap(scb2_ioaddr);
0185 if (!region_fail)
0186 release_mem_region(SCB2_ADDR, SCB2_WINDOW);
0187 return -ENODEV;
0188 }
0189
0190 printk(KERN_NOTICE MODNAME ": chip size 0x%llx at offset 0x%llx\n",
0191 (unsigned long long)scb2_mtd->size,
0192 (unsigned long long)(SCB2_WINDOW - scb2_mtd->size));
0193
0194 mtd_device_register(scb2_mtd, NULL, 0);
0195
0196 return 0;
0197 }
0198
0199 static void scb2_flash_remove(struct pci_dev *dev)
0200 {
0201 if (!scb2_mtd)
0202 return;
0203
0204
0205 mtd_lock(scb2_mtd, 0, scb2_mtd->size);
0206
0207 mtd_device_unregister(scb2_mtd);
0208 map_destroy(scb2_mtd);
0209
0210 iounmap(scb2_ioaddr);
0211 scb2_ioaddr = NULL;
0212
0213 if (!region_fail)
0214 release_mem_region(SCB2_ADDR, SCB2_WINDOW);
0215 }
0216
0217 static struct pci_device_id scb2_flash_pci_ids[] = {
0218 {
0219 .vendor = PCI_VENDOR_ID_SERVERWORKS,
0220 .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
0221 .subvendor = PCI_ANY_ID,
0222 .subdevice = PCI_ANY_ID
0223 },
0224 { 0, }
0225 };
0226
0227 static struct pci_driver scb2_flash_driver = {
0228 .name = "Intel SCB2 BIOS Flash",
0229 .id_table = scb2_flash_pci_ids,
0230 .probe = scb2_flash_probe,
0231 .remove = scb2_flash_remove,
0232 };
0233
0234 module_pci_driver(scb2_flash_driver);
0235
0236 MODULE_LICENSE("GPL");
0237 MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
0238 MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
0239 MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);