Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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