linux-old/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   $Id: scx200_docflash.c,v 1.1 2003/01/24 13:20:40 dwmw2 Exp $ 
   6
   7   National Semiconductor SCx200 flash mapped with DOCCS
   8*/
   9
  10#include <linux/module.h>
  11#include <linux/config.h>
  12#include <linux/types.h>
  13#include <linux/kernel.h>
  14#include <asm/io.h>
  15#include <linux/mtd/mtd.h>
  16#include <linux/mtd/map.h>
  17#include <linux/mtd/partitions.h>
  18
  19#include <linux/pci.h>
  20#include <linux/scx200.h>
  21
  22#define NAME "scx200_docflash"
  23
  24MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
  25MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
  26MODULE_LICENSE("GPL");
  27
  28/* Set this to one if you want to partition the flash */
  29#define PARTITION 1
  30
  31MODULE_PARM(probe, "i");
  32MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
  33MODULE_PARM(size, "i");
  34MODULE_PARM_DESC(size, "Size of the flash mapping");
  35MODULE_PARM(width, "i");
  36MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
  37MODULE_PARM(flashtype, "s");
  38MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
  39
  40static int probe = 0;           /* Don't autoprobe */
  41static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
  42static unsigned width = 8;      /* Default to 8 bits wide */
  43static char *flashtype = "cfi_probe";
  44
  45static struct resource docmem = {
  46        .flags = IORESOURCE_MEM,
  47        .name  = "NatSemi SCx200 DOCCS Flash",
  48};
  49
  50static struct mtd_info *mymtd;
  51
  52#if PARTITION
  53static struct mtd_partition partition_info[] = {
  54        { 
  55                .name   = "DOCCS Boot kernel", 
  56                .offset = 0, 
  57                .size   = 0xc0000
  58        },
  59        { 
  60                .name   = "DOCCS Low BIOS", 
  61                .offset = 0xc0000, 
  62                .size   = 0x40000
  63        },
  64        { 
  65                .name   = "DOCCS File system", 
  66                .offset = 0x100000, 
  67                .size   = ~0    /* calculate from flash size */
  68        },
  69        { 
  70                .name   = "DOCCS High BIOS", 
  71                .offset = ~0,   /* calculate from flash size */
  72                .size   = 0x80000
  73        },
  74};
  75#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
  76#endif
  77
  78static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
  79{
  80        return __raw_readb(map->map_priv_1 + ofs);
  81}
  82
  83static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
  84{
  85        return __raw_readw(map->map_priv_1 + ofs);
  86}
  87
  88static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
  89{
  90        memcpy_fromio(to, map->map_priv_1 + from, len);
  91}
  92
  93static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
  94{
  95        __raw_writeb(d, map->map_priv_1 + adr);
  96        mb();
  97}
  98
  99static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
 100{
 101        __raw_writew(d, map->map_priv_1 + adr);
 102        mb();
 103}
 104
 105static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 106{
 107        memcpy_toio(map->map_priv_1 + to, from, len);
 108}
 109
 110static struct map_info scx200_docflash_map = {
 111        .name      = "NatSemi SCx200 DOCCS Flash",
 112        .read8     = scx200_docflash_read8,
 113        .read16    = scx200_docflash_read16,
 114        .copy_from = scx200_docflash_copy_from,
 115        .write8    = scx200_docflash_write8,
 116        .write16   = scx200_docflash_write16,
 117        .copy_to   = scx200_docflash_copy_to
 118};
 119
 120int __init init_scx200_docflash(void)
 121{
 122        unsigned u;
 123        unsigned base;
 124        unsigned ctrl;
 125        unsigned pmr;
 126        struct pci_dev *bridge;
 127
 128        printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
 129
 130        if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
 131                                      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
 132                                      NULL)) == NULL)
 133                return -ENODEV;
 134        
 135        if (!scx200_cb_probe(SCx200_CB_BASE)) {
 136                printk(KERN_WARNING NAME ": no configuration block found\n");
 137                return -ENODEV;
 138        }
 139
 140        if (probe) {
 141                /* Try to use the present flash mapping if any */
 142                pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
 143                pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
 144                pmr = inl(SCx200_CB_BASE + SCx200_PMR);
 145
 146                if (base == 0
 147                    || (ctrl & 0x07000000) != 0x07000000
 148                    || (ctrl & 0x0007ffff) == 0)
 149                        return -ENODEV;
 150
 151                size = ((ctrl&0x1fff)<<13) + (1<<13);
 152
 153                for (u = size; u > 1; u >>= 1)
 154                        ;
 155                if (u != 1)
 156                        return -ENODEV;
 157
 158                if (pmr & (1<<6))
 159                        width = 16;
 160                else
 161                        width = 8;
 162
 163                docmem.start = base;
 164                docmem.end = base + size;
 165
 166                if (request_resource(&iomem_resource, &docmem)) {
 167                        printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
 168                        return -ENOMEM;
 169                }
 170        } else {
 171                for (u = size; u > 1; u >>= 1)
 172                        ;
 173                if (u != 1) {
 174                        printk(KERN_ERR NAME ": invalid size for flash mapping\n");
 175                        return -EINVAL;
 176                }
 177                
 178                if (width != 8 && width != 16) {
 179                        printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
 180                        return -EINVAL;
 181                }
 182                
 183                if (allocate_resource(&iomem_resource, &docmem, 
 184                                      size,
 185                                      0xc0000000, 0xffffffff, 
 186                                      size, NULL, NULL)) {
 187                        printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
 188                        return -ENOMEM;
 189                }
 190                
 191                ctrl = 0x07000000 | ((size-1) >> 13);
 192
 193                printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
 194                
 195                pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
 196                pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
 197                pmr = inl(SCx200_CB_BASE + SCx200_PMR);
 198                
 199                if (width == 8) {
 200                        pmr &= ~(1<<6);
 201                } else {
 202                        pmr |= (1<<6);
 203                }
 204                outl(pmr, SCx200_CB_BASE + SCx200_PMR);
 205        }
 206        
 207        printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
 208               docmem.start, docmem.end, width);
 209
 210        scx200_docflash_map.size = size;
 211        if (width == 8)
 212                scx200_docflash_map.buswidth = 1;
 213        else
 214                scx200_docflash_map.buswidth = 2;
 215
 216        scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
 217        if (!scx200_docflash_map.map_priv_1) {
 218                printk(KERN_ERR NAME ": failed to ioremap the flash\n");
 219                release_resource(&docmem);
 220                return -EIO;
 221        }
 222
 223        mymtd = do_map_probe(flashtype, &scx200_docflash_map);
 224        if (!mymtd) {
 225                printk(KERN_ERR NAME ": unable to detect flash\n");
 226                iounmap((void *)scx200_docflash_map.map_priv_1);
 227                release_resource(&docmem);
 228                return -ENXIO;
 229        }
 230
 231        if (size < mymtd->size)
 232                printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
 233
 234        mymtd->module = THIS_MODULE;
 235
 236#if PARTITION
 237        partition_info[3].offset = mymtd->size-partition_info[3].size;
 238        partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
 239        add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
 240#else
 241        add_mtd_device(mymtd);
 242#endif
 243        return 0;
 244}
 245
 246static void __exit cleanup_scx200_docflash(void)
 247{
 248        if (mymtd) {
 249#if PARTITION
 250                del_mtd_partitions(mymtd);
 251#else
 252                del_mtd_device(mymtd);
 253#endif
 254                map_destroy(mymtd);
 255        }
 256        if (scx200_docflash_map.map_priv_1) {
 257                iounmap((void *)scx200_docflash_map.map_priv_1);
 258                release_resource(&docmem);
 259        }
 260}
 261
 262module_init(init_scx200_docflash);
 263module_exit(cleanup_scx200_docflash);
 264
 265/*
 266    Local variables:
 267        compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
 268        c-basic-offset: 8
 269    End:
 270*/
 271