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