1/* 2 * linux/drivers/mtd/maps/pci.c 3 * 4 * Copyright (C) 2001 Russell King, All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Generic PCI memory map driver. We support the following boards: 11 * - Intel IQ80310 ATU. 12 * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 13 */ 14#include <linux/module.h> 15#include <linux/kernel.h> 16#include <linux/pci.h> 17#include <linux/init.h> 18#include <linux/slab.h> 19 20#include <linux/mtd/mtd.h> 21#include <linux/mtd/map.h> 22#include <linux/mtd/partitions.h> 23 24struct map_pci_info; 25 26struct mtd_pci_info { 27 int (*init)(struct pci_dev *dev, struct map_pci_info *map); 28 void (*exit)(struct pci_dev *dev, struct map_pci_info *map); 29 unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); 30 const char *map_name; 31}; 32 33struct map_pci_info { 34 struct map_info map; 35 void __iomem *base; 36 void (*exit)(struct pci_dev *dev, struct map_pci_info *map); 37 unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); 38 struct pci_dev *dev; 39}; 40 41static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs) 42{ 43 struct map_pci_info *map = (struct map_pci_info *)_map; 44 map_word val; 45 val.x[0]= readb(map->base + map->translate(map, ofs)); 46// printk("read8 : %08lx => %02x\n", ofs, val.x[0]); 47 return val; 48} 49 50static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs) 51{ 52 struct map_pci_info *map = (struct map_pci_info *)_map; 53 map_word val; 54 val.x[0] = readl(map->base + map->translate(map, ofs)); 55// printk("read32: %08lx => %08x\n", ofs, val.x[0]); 56 return val; 57} 58 59static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len) 60{ 61 struct map_pci_info *map = (struct map_pci_info *)_map; 62 memcpy_fromio(to, map->base + map->translate(map, from), len); 63} 64 65static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs) 66{ 67 struct map_pci_info *map = (struct map_pci_info *)_map; 68// printk("write8 : %08lx <= %02x\n", ofs, val.x[0]); 69 writeb(val.x[0], map->base + map->translate(map, ofs)); 70} 71 72static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs) 73{ 74 struct map_pci_info *map = (struct map_pci_info *)_map; 75// printk("write32: %08lx <= %08x\n", ofs, val.x[0]); 76 writel(val.x[0], map->base + map->translate(map, ofs)); 77} 78 79static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len) 80{ 81 struct map_pci_info *map = (struct map_pci_info *)_map; 82 memcpy_toio(map->base + map->translate(map, to), from, len); 83} 84 85static const struct map_info mtd_pci_map = { 86 .phys = NO_XIP, 87 .copy_from = mtd_pci_copyfrom, 88 .copy_to = mtd_pci_copyto, 89}; 90 91/* 92 * Intel IOP80310 Flash driver 93 */ 94 95static int 96intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map) 97{ 98 u32 win_base; 99 100 map->map.bankwidth = 1; 101 map->map.read = mtd_pci_read8, 102 map->map.write = mtd_pci_write8, 103 104 map->map.size = 0x00800000; 105 map->base = ioremap_nocache(pci_resource_start(dev, 0), 106 pci_resource_len(dev, 0)); 107 108 if (!map->base) 109 return -ENOMEM; 110 111 /* 112 * We want to base the memory window at Xscale 113 * bus address 0, not 0x1000. 114 */ 115 pci_read_config_dword(dev, 0x44, &win_base); 116 pci_write_config_dword(dev, 0x44, 0); 117 118 map->map.map_priv_2 = win_base; 119 120 return 0; 121} 122 123static void 124intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map) 125{ 126 if (map->base) 127 iounmap(map->base); 128 pci_write_config_dword(dev, 0x44, map->map.map_priv_2); 129} 130 131static unsigned long 132intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs) 133{ 134 unsigned long page_addr = ofs & 0x00400000; 135 136 /* 137 * This mundges the flash location so we avoid 138 * the first 80 bytes (they appear to read nonsense). 139 */ 140 if (page_addr) { 141 writel(0x00000008, map->base + 0x1558); 142 writel(0x00000000, map->base + 0x1550); 143 } else { 144 writel(0x00000007, map->base + 0x1558); 145 writel(0x00800000, map->base + 0x1550); 146 ofs += 0x00800000; 147 } 148 149 return ofs; 150} 151 152static struct mtd_pci_info intel_iq80310_info = { 153 .init = intel_iq80310_init, 154 .exit = intel_iq80310_exit, 155 .translate = intel_iq80310_translate, 156 .map_name = "cfi_probe", 157}; 158 159/* 160 * Intel DC21285 driver 161 */ 162 163static int 164intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) 165{ 166 unsigned long base, len; 167 168 base = pci_resource_start(dev, PCI_ROM_RESOURCE); 169 len = pci_resource_len(dev, PCI_ROM_RESOURCE); 170 171 if (!len || !base) { 172 /* 173 * No ROM resource 174 */ 175 base = pci_resource_start(dev, 2); 176 len = pci_resource_len(dev, 2); 177 178 /* 179 * We need to re-allocate PCI BAR2 address range to the 180 * PCI ROM BAR, and disable PCI BAR2. 181 */ 182 } else { 183 /* 184 * Hmm, if an address was allocated to the ROM resource, but 185 * not enabled, should we be allocating a new resource for it 186 * or simply enabling it? 187 */ 188 pci_enable_rom(dev); 189 printk("%s: enabling expansion ROM\n", pci_name(dev)); 190 } 191 192 if (!len || !base) 193 return -ENXIO; 194 195 map->map.bankwidth = 4; 196 map->map.read = mtd_pci_read32, 197 map->map.write = mtd_pci_write32, 198 map->map.size = len; 199 map->base = ioremap_nocache(base, len); 200 201 if (!map->base) 202 return -ENOMEM; 203 204 return 0; 205} 206 207static void 208intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) 209{ 210 if (map->base) 211 iounmap(map->base); 212 213 /* 214 * We need to undo the PCI BAR2/PCI ROM BAR address alteration. 215 */ 216 pci_disable_rom(dev); 217} 218 219static unsigned long 220intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs) 221{ 222 return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5)); 223} 224 225static struct mtd_pci_info intel_dc21285_info = { 226 .init = intel_dc21285_init, 227 .exit = intel_dc21285_exit, 228 .translate = intel_dc21285_translate, 229 .map_name = "jedec_probe", 230}; 231 232/* 233 * PCI device ID table 234 */ 235 236static struct pci_device_id mtd_pci_ids[] = { 237 { 238 .vendor = PCI_VENDOR_ID_INTEL, 239 .device = 0x530d, 240 .subvendor = PCI_ANY_ID, 241 .subdevice = PCI_ANY_ID, 242 .class = PCI_CLASS_MEMORY_OTHER << 8, 243 .class_mask = 0xffff00, 244 .driver_data = (unsigned long)&intel_iq80310_info, 245 }, 246 { 247 .vendor = PCI_VENDOR_ID_DEC, 248 .device = PCI_DEVICE_ID_DEC_21285, 249 .subvendor = 0, /* DC21285 defaults to 0 on reset */ 250 .subdevice = 0, /* DC21285 defaults to 0 on reset */ 251 .driver_data = (unsigned long)&intel_dc21285_info, 252 }, 253 { 0, } 254}; 255 256/* 257 * Generic code follows. 258 */ 259 260static int __devinit 261mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 262{ 263 struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; 264 struct map_pci_info *map = NULL; 265 struct mtd_info *mtd = NULL; 266 int err; 267 268 err = pci_enable_device(dev); 269 if (err) 270 goto out; 271 272 err = pci_request_regions(dev, "pci mtd"); 273 if (err) 274 goto out; 275 276 map = kmalloc(sizeof(*map), GFP_KERNEL); 277 err = -ENOMEM; 278 if (!map) 279 goto release; 280 281 map->map = mtd_pci_map; 282 map->map.name = pci_name(dev); 283 map->dev = dev; 284 map->exit = info->exit; 285 map->translate = info->translate; 286 287 err = info->init(dev, map); 288 if (err) 289 goto release; 290 291 /* tsk - do_map_probe should take const char * */ 292 mtd = do_map_probe((char *)info->map_name, &map->map); 293 err = -ENODEV; 294 if (!mtd) 295 goto release; 296 297 mtd->owner = THIS_MODULE; 298 add_mtd_device(mtd); 299 300 pci_set_drvdata(dev, mtd); 301 302 return 0; 303 304release: 305 if (map) { 306 map->exit(dev, map); 307 kfree(map); 308 } 309 310 pci_release_regions(dev); 311out: 312 return err; 313} 314 315static void __devexit 316mtd_pci_remove(struct pci_dev *dev) 317{ 318 struct mtd_info *mtd = pci_get_drvdata(dev); 319 struct map_pci_info *map = mtd->priv; 320 321 del_mtd_device(mtd); 322 map_destroy(mtd); 323 map->exit(dev, map); 324 kfree(map); 325 326 pci_set_drvdata(dev, NULL); 327 pci_release_regions(dev); 328} 329 330static struct pci_driver mtd_pci_driver = { 331 .name = "MTD PCI", 332 .probe = mtd_pci_probe, 333 .remove = __devexit_p(mtd_pci_remove), 334 .id_table = mtd_pci_ids, 335}; 336 337static int __init mtd_pci_maps_init(void) 338{ 339 return pci_register_driver(&mtd_pci_driver); 340} 341 342static void __exit mtd_pci_maps_exit(void) 343{ 344 pci_unregister_driver(&mtd_pci_driver); 345} 346 347module_init(mtd_pci_maps_init); 348module_exit(mtd_pci_maps_exit); 349 350MODULE_LICENSE("GPL"); 351MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); 352MODULE_DESCRIPTION("Generic PCI map driver"); 353MODULE_DEVICE_TABLE(pci, mtd_pci_ids); 354