linux/drivers/mtd/maps/scx200_docflash.c
<<
>>
Prefs
   1/* linux/drivers/mtd/maps/scx200_docflash.c
   2
   3   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
   4
   5   National Semiconductor SCx200 flash mapped with DOCCS
   6*/
   7
   8#include <linux/module.h>
   9#include <linux/types.h>
  10#include <linux/kernel.h>
  11#include <linux/init.h>
  12#include <asm/io.h>
  13#include <linux/mtd/mtd.h>
  14#include <linux/mtd/map.h>
  15#include <linux/mtd/partitions.h>
  16
  17#include <linux/pci.h>
  18#include <linux/scx200.h>
  19
  20#define NAME "scx200_docflash"
  21
  22MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
  23MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
  24MODULE_LICENSE("GPL");
  25
  26static int probe = 0;           /* Don't autoprobe */
  27static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
  28static unsigned width = 8;      /* Default to 8 bits wide */
  29static char *flashtype = "cfi_probe";
  30
  31module_param(probe, int, 0);
  32MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
  33module_param(size, int, 0);
  34MODULE_PARM_DESC(size, "Size of the flash mapping");
  35module_param(width, int, 0);
  36MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
  37module_param(flashtype, charp, 0);
  38MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
  39
  40static struct resource docmem = {
  41        .flags = IORESOURCE_MEM,
  42        .name  = "NatSemi SCx200 DOCCS Flash",
  43};
  44
  45static struct mtd_info *mymtd;
  46
  47static struct mtd_partition partition_info[] = {
  48        {
  49                .name   = "DOCCS Boot kernel",
  50                .offset = 0,
  51                .size   = 0xc0000
  52        },
  53        {
  54                .name   = "DOCCS Low BIOS",
  55                .offset = 0xc0000,
  56                .size   = 0x40000
  57        },
  58        {
  59                .name   = "DOCCS File system",
  60                .offset = 0x100000,
  61                .size   = ~0    /* calculate from flash size */
  62        },
  63        {
  64                .name   = "DOCCS High BIOS",
  65                .offset = ~0,   /* calculate from flash size */
  66                .size   = 0x80000
  67        },
  68};
  69#define NUM_PARTITIONS ARRAY_SIZE(partition_info)
  70
  71static struct map_info scx200_docflash_map = {
  72        .name      = "NatSemi SCx200 DOCCS Flash",
  73};
  74
  75static int __init init_scx200_docflash(void)
  76{
  77        unsigned u;
  78        unsigned base;
  79        unsigned ctrl;
  80        unsigned pmr;
  81        struct pci_dev *bridge;
  82
  83        printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
  84
  85        if ((bridge = pci_get_device(PCI_VENDOR_ID_NS,
  86                                      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
  87                                      NULL)) == NULL)
  88                return -ENODEV;
  89
  90        /* check that we have found the configuration block */
  91        if (!scx200_cb_present()) {
  92                pci_dev_put(bridge);
  93                return -ENODEV;
  94        }
  95
  96        if (probe) {
  97                /* Try to use the present flash mapping if any */
  98                pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
  99                pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
 100                pci_dev_put(bridge);
 101
 102                pmr = inl(scx200_cb_base + SCx200_PMR);
 103
 104                if (base == 0
 105                    || (ctrl & 0x07000000) != 0x07000000
 106                    || (ctrl & 0x0007ffff) == 0)
 107                        return -ENODEV;
 108
 109                size = ((ctrl&0x1fff)<<13) + (1<<13);
 110
 111                for (u = size; u > 1; u >>= 1)
 112                        ;
 113                if (u != 1)
 114                        return -ENODEV;
 115
 116                if (pmr & (1<<6))
 117                        width = 16;
 118                else
 119                        width = 8;
 120
 121                docmem.start = base;
 122                docmem.end = base + size;
 123
 124                if (request_resource(&iomem_resource, &docmem)) {
 125                        printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
 126                        return -ENOMEM;
 127                }
 128        } else {
 129                pci_dev_put(bridge);
 130                for (u = size; u > 1; u >>= 1)
 131                        ;
 132                if (u != 1) {
 133                        printk(KERN_ERR NAME ": invalid size for flash mapping\n");
 134                        return -EINVAL;
 135                }
 136
 137                if (width != 8 && width != 16) {
 138                        printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
 139                        return -EINVAL;
 140                }
 141
 142                if (allocate_resource(&iomem_resource, &docmem,
 143                                      size,
 144                                      0xc0000000, 0xffffffff,
 145                                      size, NULL, NULL)) {
 146                        printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
 147                        return -ENOMEM;
 148                }
 149
 150                ctrl = 0x07000000 | ((size-1) >> 13);
 151
 152                printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
 153
 154                pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
 155                pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
 156                pmr = inl(scx200_cb_base + SCx200_PMR);
 157
 158                if (width == 8) {
 159                        pmr &= ~(1<<6);
 160                } else {
 161                        pmr |= (1<<6);
 162                }
 163                outl(pmr, scx200_cb_base + SCx200_PMR);
 164        }
 165
 166        printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n",
 167               &docmem, width);
 168
 169        scx200_docflash_map.size = size;
 170        if (width == 8)
 171                scx200_docflash_map.bankwidth = 1;
 172        else
 173                scx200_docflash_map.bankwidth = 2;
 174
 175        simple_map_init(&scx200_docflash_map);
 176
 177        scx200_docflash_map.phys = docmem.start;
 178        scx200_docflash_map.virt = ioremap(docmem.start, scx200_docflash_map.size);
 179        if (!scx200_docflash_map.virt) {
 180                printk(KERN_ERR NAME ": failed to ioremap the flash\n");
 181                release_resource(&docmem);
 182                return -EIO;
 183        }
 184
 185        mymtd = do_map_probe(flashtype, &scx200_docflash_map);
 186        if (!mymtd) {
 187                printk(KERN_ERR NAME ": unable to detect flash\n");
 188                iounmap(scx200_docflash_map.virt);
 189                release_resource(&docmem);
 190                return -ENXIO;
 191        }
 192
 193        if (size < mymtd->size)
 194                printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
 195
 196        mymtd->owner = THIS_MODULE;
 197
 198        partition_info[3].offset = mymtd->size-partition_info[3].size;
 199        partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
 200        mtd_device_register(mymtd, partition_info, NUM_PARTITIONS);
 201
 202        return 0;
 203}
 204
 205static void __exit cleanup_scx200_docflash(void)
 206{
 207        if (mymtd) {
 208                mtd_device_unregister(mymtd);
 209                map_destroy(mymtd);
 210        }
 211        if (scx200_docflash_map.virt) {
 212                iounmap(scx200_docflash_map.virt);
 213                release_resource(&docmem);
 214        }
 215}
 216
 217module_init(init_scx200_docflash);
 218module_exit(cleanup_scx200_docflash);
 219
 220/*
 221    Local variables:
 222        compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
 223        c-basic-offset: 8
 224    End:
 225*/
 226