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