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 #include <linux/module.h>
0031 #include <linux/kernel.h>
0032 #include <linux/slab.h>
0033 #include <linux/pci.h>
0034 #include <linux/mtd/mtd.h>
0035 #include <linux/mtd/map.h>
0036 #include <linux/mtd/partitions.h>
0037 #include <linux/mtd/cfi.h>
0038 #include <linux/mtd/flashchip.h>
0039
0040 #define DRV_NAME "vr_nor"
0041
0042 struct vr_nor_mtd {
0043 void __iomem *csr_base;
0044 struct map_info map;
0045 struct mtd_info *info;
0046 struct pci_dev *dev;
0047 };
0048
0049
0050 #define EXP_CSR_MBAR 0
0051
0052 #define EXP_WIN_MBAR 1
0053
0054 #define CS0_SIZE 0x04000000
0055
0056 #define CS0_START 0x0
0057
0058 #define EXP_TIMING_CS0 0x00
0059 #define TIMING_CS_EN (1 << 31)
0060 #define TIMING_BOOT_ACCEL_DIS (1 << 8)
0061 #define TIMING_WR_EN (1 << 1)
0062 #define TIMING_BYTE_EN (1 << 0)
0063 #define TIMING_MASK 0x3FFF0000
0064
0065 static void vr_nor_destroy_partitions(struct vr_nor_mtd *p)
0066 {
0067 mtd_device_unregister(p->info);
0068 }
0069
0070 static int vr_nor_init_partitions(struct vr_nor_mtd *p)
0071 {
0072
0073
0074 return mtd_device_register(p->info, NULL, 0);
0075 }
0076
0077 static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
0078 {
0079 map_destroy(p->info);
0080 }
0081
0082 static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
0083 {
0084 static const char * const probe_types[] =
0085 { "cfi_probe", "jedec_probe", NULL };
0086 const char * const *type;
0087
0088 for (type = probe_types; !p->info && *type; type++)
0089 p->info = do_map_probe(*type, &p->map);
0090 if (!p->info)
0091 return -ENODEV;
0092
0093 p->info->dev.parent = &p->dev->dev;
0094
0095 return 0;
0096 }
0097
0098 static void vr_nor_destroy_maps(struct vr_nor_mtd *p)
0099 {
0100 unsigned int exp_timing_cs0;
0101
0102
0103 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
0104 exp_timing_cs0 &= ~TIMING_WR_EN;
0105 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
0106
0107
0108 iounmap(p->map.virt);
0109
0110
0111 iounmap(p->csr_base);
0112 }
0113
0114
0115
0116
0117
0118 static int vr_nor_init_maps(struct vr_nor_mtd *p)
0119 {
0120 unsigned long csr_phys, csr_len;
0121 unsigned long win_phys, win_len;
0122 unsigned int exp_timing_cs0;
0123 int err;
0124
0125 csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR);
0126 csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR);
0127 win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR);
0128 win_len = pci_resource_len(p->dev, EXP_WIN_MBAR);
0129
0130 if (!csr_phys || !csr_len || !win_phys || !win_len)
0131 return -ENODEV;
0132
0133 if (win_len < (CS0_START + CS0_SIZE))
0134 return -ENXIO;
0135
0136 p->csr_base = ioremap(csr_phys, csr_len);
0137 if (!p->csr_base)
0138 return -ENOMEM;
0139
0140 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
0141 if (!(exp_timing_cs0 & TIMING_CS_EN)) {
0142 dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
0143 "is disabled.\n");
0144 err = -ENODEV;
0145 goto release;
0146 }
0147 if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) {
0148 dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
0149 "is configured for maximally slow access times.\n");
0150 }
0151 p->map.name = DRV_NAME;
0152 p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2;
0153 p->map.phys = win_phys + CS0_START;
0154 p->map.size = CS0_SIZE;
0155 p->map.virt = ioremap(p->map.phys, p->map.size);
0156 if (!p->map.virt) {
0157 err = -ENOMEM;
0158 goto release;
0159 }
0160 simple_map_init(&p->map);
0161
0162
0163 exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN;
0164 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
0165
0166 return 0;
0167
0168 release:
0169 iounmap(p->csr_base);
0170 return err;
0171 }
0172
0173 static const struct pci_device_id vr_nor_pci_ids[] = {
0174 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)},
0175 {0,}
0176 };
0177
0178 static void vr_nor_pci_remove(struct pci_dev *dev)
0179 {
0180 struct vr_nor_mtd *p = pci_get_drvdata(dev);
0181
0182 vr_nor_destroy_partitions(p);
0183 vr_nor_destroy_mtd_setup(p);
0184 vr_nor_destroy_maps(p);
0185 kfree(p);
0186 pci_release_regions(dev);
0187 pci_disable_device(dev);
0188 }
0189
0190 static int vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
0191 {
0192 struct vr_nor_mtd *p = NULL;
0193 unsigned int exp_timing_cs0;
0194 int err;
0195
0196 err = pci_enable_device(dev);
0197 if (err)
0198 goto out;
0199
0200 err = pci_request_regions(dev, DRV_NAME);
0201 if (err)
0202 goto disable_dev;
0203
0204 p = kzalloc(sizeof(*p), GFP_KERNEL);
0205 err = -ENOMEM;
0206 if (!p)
0207 goto release;
0208
0209 p->dev = dev;
0210
0211 err = vr_nor_init_maps(p);
0212 if (err)
0213 goto release;
0214
0215 err = vr_nor_mtd_setup(p);
0216 if (err)
0217 goto destroy_maps;
0218
0219 err = vr_nor_init_partitions(p);
0220 if (err)
0221 goto destroy_mtd_setup;
0222
0223 pci_set_drvdata(dev, p);
0224
0225 return 0;
0226
0227 destroy_mtd_setup:
0228 map_destroy(p->info);
0229
0230 destroy_maps:
0231
0232 exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
0233 exp_timing_cs0 &= ~TIMING_WR_EN;
0234 writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
0235
0236
0237 iounmap(p->map.virt);
0238
0239
0240 iounmap(p->csr_base);
0241
0242 release:
0243 kfree(p);
0244 pci_release_regions(dev);
0245
0246 disable_dev:
0247 pci_disable_device(dev);
0248
0249 out:
0250 return err;
0251 }
0252
0253 static struct pci_driver vr_nor_pci_driver = {
0254 .name = DRV_NAME,
0255 .probe = vr_nor_pci_probe,
0256 .remove = vr_nor_pci_remove,
0257 .id_table = vr_nor_pci_ids,
0258 };
0259
0260 module_pci_driver(vr_nor_pci_driver);
0261
0262 MODULE_AUTHOR("Andy Lowe");
0263 MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
0264 MODULE_LICENSE("GPL");
0265 MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids);