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