0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/pci.h>
0014 #include <linux/slab.h>
0015
0016 #include <linux/mtd/mtd.h>
0017 #include <linux/mtd/map.h>
0018 #include <linux/mtd/partitions.h>
0019
0020 struct map_pci_info;
0021
0022 struct mtd_pci_info {
0023 int (*init)(struct pci_dev *dev, struct map_pci_info *map);
0024 void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
0025 unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
0026 const char *map_name;
0027 };
0028
0029 struct map_pci_info {
0030 struct map_info map;
0031 void __iomem *base;
0032 void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
0033 unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
0034 struct pci_dev *dev;
0035 };
0036
0037 static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
0038 {
0039 struct map_pci_info *map = (struct map_pci_info *)_map;
0040 map_word val;
0041 val.x[0]= readb(map->base + map->translate(map, ofs));
0042 return val;
0043 }
0044
0045 static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)
0046 {
0047 struct map_pci_info *map = (struct map_pci_info *)_map;
0048 map_word val;
0049 val.x[0] = readl(map->base + map->translate(map, ofs));
0050 return val;
0051 }
0052
0053 static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
0054 {
0055 struct map_pci_info *map = (struct map_pci_info *)_map;
0056 memcpy_fromio(to, map->base + map->translate(map, from), len);
0057 }
0058
0059 static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)
0060 {
0061 struct map_pci_info *map = (struct map_pci_info *)_map;
0062 writeb(val.x[0], map->base + map->translate(map, ofs));
0063 }
0064
0065 static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)
0066 {
0067 struct map_pci_info *map = (struct map_pci_info *)_map;
0068 writel(val.x[0], map->base + map->translate(map, ofs));
0069 }
0070
0071 static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
0072 {
0073 struct map_pci_info *map = (struct map_pci_info *)_map;
0074 memcpy_toio(map->base + map->translate(map, to), from, len);
0075 }
0076
0077 static const struct map_info mtd_pci_map = {
0078 .phys = NO_XIP,
0079 .copy_from = mtd_pci_copyfrom,
0080 .copy_to = mtd_pci_copyto,
0081 };
0082
0083
0084
0085
0086
0087 static int
0088 intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
0089 {
0090 u32 win_base;
0091
0092 map->map.bankwidth = 1;
0093 map->map.read = mtd_pci_read8;
0094 map->map.write = mtd_pci_write8;
0095
0096 map->map.size = 0x00800000;
0097 map->base = ioremap(pci_resource_start(dev, 0),
0098 pci_resource_len(dev, 0));
0099
0100 if (!map->base)
0101 return -ENOMEM;
0102
0103
0104
0105
0106
0107 pci_read_config_dword(dev, 0x44, &win_base);
0108 pci_write_config_dword(dev, 0x44, 0);
0109
0110 map->map.map_priv_2 = win_base;
0111
0112 return 0;
0113 }
0114
0115 static void
0116 intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
0117 {
0118 if (map->base)
0119 iounmap(map->base);
0120 pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
0121 }
0122
0123 static unsigned long
0124 intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)
0125 {
0126 unsigned long page_addr = ofs & 0x00400000;
0127
0128
0129
0130
0131
0132 if (page_addr) {
0133 writel(0x00000008, map->base + 0x1558);
0134 writel(0x00000000, map->base + 0x1550);
0135 } else {
0136 writel(0x00000007, map->base + 0x1558);
0137 writel(0x00800000, map->base + 0x1550);
0138 ofs += 0x00800000;
0139 }
0140
0141 return ofs;
0142 }
0143
0144 static struct mtd_pci_info intel_iq80310_info = {
0145 .init = intel_iq80310_init,
0146 .exit = intel_iq80310_exit,
0147 .translate = intel_iq80310_translate,
0148 .map_name = "cfi_probe",
0149 };
0150
0151
0152
0153
0154
0155 static int
0156 intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
0157 {
0158 unsigned long base, len;
0159
0160 base = pci_resource_start(dev, PCI_ROM_RESOURCE);
0161 len = pci_resource_len(dev, PCI_ROM_RESOURCE);
0162
0163 if (!len || !base) {
0164
0165
0166
0167 base = pci_resource_start(dev, 2);
0168 len = pci_resource_len(dev, 2);
0169
0170
0171
0172
0173
0174 } else {
0175
0176
0177
0178
0179
0180 pci_enable_rom(dev);
0181 printk("%s: enabling expansion ROM\n", pci_name(dev));
0182 }
0183
0184 if (!len || !base)
0185 return -ENXIO;
0186
0187 map->map.bankwidth = 4;
0188 map->map.read = mtd_pci_read32;
0189 map->map.write = mtd_pci_write32;
0190 map->map.size = len;
0191 map->base = ioremap(base, len);
0192
0193 if (!map->base)
0194 return -ENOMEM;
0195
0196 return 0;
0197 }
0198
0199 static void
0200 intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
0201 {
0202 if (map->base)
0203 iounmap(map->base);
0204
0205
0206
0207
0208 pci_disable_rom(dev);
0209 }
0210
0211 static unsigned long
0212 intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)
0213 {
0214 return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));
0215 }
0216
0217 static struct mtd_pci_info intel_dc21285_info = {
0218 .init = intel_dc21285_init,
0219 .exit = intel_dc21285_exit,
0220 .translate = intel_dc21285_translate,
0221 .map_name = "jedec_probe",
0222 };
0223
0224
0225
0226
0227
0228 static const struct pci_device_id mtd_pci_ids[] = {
0229 {
0230 .vendor = PCI_VENDOR_ID_INTEL,
0231 .device = 0x530d,
0232 .subvendor = PCI_ANY_ID,
0233 .subdevice = PCI_ANY_ID,
0234 .class = PCI_CLASS_MEMORY_OTHER << 8,
0235 .class_mask = 0xffff00,
0236 .driver_data = (unsigned long)&intel_iq80310_info,
0237 },
0238 {
0239 .vendor = PCI_VENDOR_ID_DEC,
0240 .device = PCI_DEVICE_ID_DEC_21285,
0241 .subvendor = 0,
0242 .subdevice = 0,
0243 .driver_data = (unsigned long)&intel_dc21285_info,
0244 },
0245 { 0, }
0246 };
0247
0248
0249
0250
0251
0252 static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
0253 {
0254 struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
0255 struct map_pci_info *map = NULL;
0256 struct mtd_info *mtd = NULL;
0257 int err;
0258
0259 err = pci_enable_device(dev);
0260 if (err)
0261 goto out;
0262
0263 err = pci_request_regions(dev, "pci mtd");
0264 if (err)
0265 goto out;
0266
0267 map = kmalloc(sizeof(*map), GFP_KERNEL);
0268 err = -ENOMEM;
0269 if (!map)
0270 goto release;
0271
0272 map->map = mtd_pci_map;
0273 map->map.name = pci_name(dev);
0274 map->dev = dev;
0275 map->exit = info->exit;
0276 map->translate = info->translate;
0277
0278 err = info->init(dev, map);
0279 if (err)
0280 goto release;
0281
0282 mtd = do_map_probe(info->map_name, &map->map);
0283 err = -ENODEV;
0284 if (!mtd)
0285 goto release;
0286
0287 mtd->owner = THIS_MODULE;
0288 mtd_device_register(mtd, NULL, 0);
0289
0290 pci_set_drvdata(dev, mtd);
0291
0292 return 0;
0293
0294 release:
0295 if (map) {
0296 map->exit(dev, map);
0297 kfree(map);
0298 }
0299
0300 pci_release_regions(dev);
0301 out:
0302 return err;
0303 }
0304
0305 static void mtd_pci_remove(struct pci_dev *dev)
0306 {
0307 struct mtd_info *mtd = pci_get_drvdata(dev);
0308 struct map_pci_info *map = mtd->priv;
0309
0310 mtd_device_unregister(mtd);
0311 map_destroy(mtd);
0312 map->exit(dev, map);
0313 kfree(map);
0314
0315 pci_release_regions(dev);
0316 }
0317
0318 static struct pci_driver mtd_pci_driver = {
0319 .name = "MTD PCI",
0320 .probe = mtd_pci_probe,
0321 .remove = mtd_pci_remove,
0322 .id_table = mtd_pci_ids,
0323 };
0324
0325 module_pci_driver(mtd_pci_driver);
0326
0327 MODULE_LICENSE("GPL");
0328 MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
0329 MODULE_DESCRIPTION("Generic PCI map driver");
0330 MODULE_DEVICE_TABLE(pci, mtd_pci_ids);