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