1*1da177e4SLinus Torvalds /* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $ 2*1da177e4SLinus Torvalds * 3*1da177e4SLinus Torvalds * sun_uflash - Driver implementation for user-programmable flash 4*1da177e4SLinus Torvalds * present on many Sun Microsystems SME boardsets. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * This driver does NOT provide access to the OBP-flash for 7*1da177e4SLinus Torvalds * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * Copyright (c) 2001 Eric Brower (ebrower@usa.net) 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds */ 12*1da177e4SLinus Torvalds 13*1da177e4SLinus Torvalds #include <linux/kernel.h> 14*1da177e4SLinus Torvalds #include <linux/module.h> 15*1da177e4SLinus Torvalds #include <linux/fs.h> 16*1da177e4SLinus Torvalds #include <linux/errno.h> 17*1da177e4SLinus Torvalds #include <linux/init.h> 18*1da177e4SLinus Torvalds #include <linux/ioport.h> 19*1da177e4SLinus Torvalds #include <asm/ebus.h> 20*1da177e4SLinus Torvalds #include <asm/oplib.h> 21*1da177e4SLinus Torvalds #include <asm/uaccess.h> 22*1da177e4SLinus Torvalds #include <asm/io.h> 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 25*1da177e4SLinus Torvalds #include <linux/mtd/map.h> 26*1da177e4SLinus Torvalds 27*1da177e4SLinus Torvalds #define UFLASH_OBPNAME "flashprom" 28*1da177e4SLinus Torvalds #define UFLASH_DEVNAME "userflash" 29*1da177e4SLinus Torvalds 30*1da177e4SLinus Torvalds #define UFLASH_WINDOW_SIZE 0x200000 31*1da177e4SLinus Torvalds #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ 32*1da177e4SLinus Torvalds 33*1da177e4SLinus Torvalds MODULE_AUTHOR 34*1da177e4SLinus Torvalds ("Eric Brower <ebrower@usa.net>"); 35*1da177e4SLinus Torvalds MODULE_DESCRIPTION 36*1da177e4SLinus Torvalds ("User-programmable flash device on Sun Microsystems boardsets"); 37*1da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE 38*1da177e4SLinus Torvalds ("userflash"); 39*1da177e4SLinus Torvalds MODULE_LICENSE 40*1da177e4SLinus Torvalds ("GPL"); 41*1da177e4SLinus Torvalds 42*1da177e4SLinus Torvalds static LIST_HEAD(device_list); 43*1da177e4SLinus Torvalds struct uflash_dev { 44*1da177e4SLinus Torvalds char * name; /* device name */ 45*1da177e4SLinus Torvalds struct map_info map; /* mtd map info */ 46*1da177e4SLinus Torvalds struct mtd_info * mtd; /* mtd info */ 47*1da177e4SLinus Torvalds struct list_head list; 48*1da177e4SLinus Torvalds }; 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds struct map_info uflash_map_templ = { 52*1da177e4SLinus Torvalds .name = "SUNW,???-????", 53*1da177e4SLinus Torvalds .size = UFLASH_WINDOW_SIZE, 54*1da177e4SLinus Torvalds .bankwidth = UFLASH_BUSWIDTH, 55*1da177e4SLinus Torvalds }; 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds int uflash_devinit(struct linux_ebus_device* edev) 58*1da177e4SLinus Torvalds { 59*1da177e4SLinus Torvalds int iTmp, nregs; 60*1da177e4SLinus Torvalds struct linux_prom_registers regs[2]; 61*1da177e4SLinus Torvalds struct uflash_dev *pdev; 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds iTmp = prom_getproperty( 64*1da177e4SLinus Torvalds edev->prom_node, "reg", (void *)regs, sizeof(regs)); 65*1da177e4SLinus Torvalds if ((iTmp % sizeof(regs[0])) != 0) { 66*1da177e4SLinus Torvalds printk("%s: Strange reg property size %d\n", 67*1da177e4SLinus Torvalds UFLASH_DEVNAME, iTmp); 68*1da177e4SLinus Torvalds return -ENODEV; 69*1da177e4SLinus Torvalds } 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds nregs = iTmp / sizeof(regs[0]); 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds if (nregs != 1) { 74*1da177e4SLinus Torvalds /* Non-CFI userflash device-- once I find one we 75*1da177e4SLinus Torvalds * can work on supporting it. 76*1da177e4SLinus Torvalds */ 77*1da177e4SLinus Torvalds printk("%s: unsupported device at 0x%lx (%d regs): " \ 78*1da177e4SLinus Torvalds "email ebrower@usa.net\n", 79*1da177e4SLinus Torvalds UFLASH_DEVNAME, edev->resource[0].start, nregs); 80*1da177e4SLinus Torvalds return -ENODEV; 81*1da177e4SLinus Torvalds } 82*1da177e4SLinus Torvalds 83*1da177e4SLinus Torvalds if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) { 84*1da177e4SLinus Torvalds printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); 85*1da177e4SLinus Torvalds return(-ENOMEM); 86*1da177e4SLinus Torvalds } 87*1da177e4SLinus Torvalds 88*1da177e4SLinus Torvalds /* copy defaults and tweak parameters */ 89*1da177e4SLinus Torvalds memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); 90*1da177e4SLinus Torvalds pdev->map.size = regs[0].reg_size; 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds iTmp = prom_getproplen(edev->prom_node, "model"); 93*1da177e4SLinus Torvalds pdev->name = kmalloc(iTmp, GFP_KERNEL); 94*1da177e4SLinus Torvalds prom_getstring(edev->prom_node, "model", pdev->name, iTmp); 95*1da177e4SLinus Torvalds if(0 != pdev->name && 0 < strlen(pdev->name)) { 96*1da177e4SLinus Torvalds pdev->map.name = pdev->name; 97*1da177e4SLinus Torvalds } 98*1da177e4SLinus Torvalds pdev->map.phys = edev->resource[0].start; 99*1da177e4SLinus Torvalds pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size); 100*1da177e4SLinus Torvalds if(0 == pdev->map.virt) { 101*1da177e4SLinus Torvalds printk("%s: failed to map device\n", __FUNCTION__); 102*1da177e4SLinus Torvalds kfree(pdev->name); 103*1da177e4SLinus Torvalds kfree(pdev); 104*1da177e4SLinus Torvalds return(-1); 105*1da177e4SLinus Torvalds } 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvalds simple_map_init(&pdev->map); 108*1da177e4SLinus Torvalds 109*1da177e4SLinus Torvalds /* MTD registration */ 110*1da177e4SLinus Torvalds pdev->mtd = do_map_probe("cfi_probe", &pdev->map); 111*1da177e4SLinus Torvalds if(0 == pdev->mtd) { 112*1da177e4SLinus Torvalds iounmap(pdev->map.virt); 113*1da177e4SLinus Torvalds kfree(pdev->name); 114*1da177e4SLinus Torvalds kfree(pdev); 115*1da177e4SLinus Torvalds return(-ENXIO); 116*1da177e4SLinus Torvalds } 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds list_add(&pdev->list, &device_list); 119*1da177e4SLinus Torvalds 120*1da177e4SLinus Torvalds pdev->mtd->owner = THIS_MODULE; 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds add_mtd_device(pdev->mtd); 123*1da177e4SLinus Torvalds return(0); 124*1da177e4SLinus Torvalds } 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds static int __init uflash_init(void) 127*1da177e4SLinus Torvalds { 128*1da177e4SLinus Torvalds struct linux_ebus *ebus = NULL; 129*1da177e4SLinus Torvalds struct linux_ebus_device *edev = NULL; 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds for_each_ebus(ebus) { 132*1da177e4SLinus Torvalds for_each_ebusdev(edev, ebus) { 133*1da177e4SLinus Torvalds if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) { 134*1da177e4SLinus Torvalds if(0 > prom_getproplen(edev->prom_node, "user")) { 135*1da177e4SLinus Torvalds DEBUG(2, "%s: ignoring device at 0x%lx\n", 136*1da177e4SLinus Torvalds UFLASH_DEVNAME, edev->resource[0].start); 137*1da177e4SLinus Torvalds } else { 138*1da177e4SLinus Torvalds uflash_devinit(edev); 139*1da177e4SLinus Torvalds } 140*1da177e4SLinus Torvalds } 141*1da177e4SLinus Torvalds } 142*1da177e4SLinus Torvalds } 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds if(list_empty(&device_list)) { 145*1da177e4SLinus Torvalds printk("%s: unable to locate device\n", UFLASH_DEVNAME); 146*1da177e4SLinus Torvalds return -ENODEV; 147*1da177e4SLinus Torvalds } 148*1da177e4SLinus Torvalds return(0); 149*1da177e4SLinus Torvalds } 150*1da177e4SLinus Torvalds 151*1da177e4SLinus Torvalds static void __exit uflash_cleanup(void) 152*1da177e4SLinus Torvalds { 153*1da177e4SLinus Torvalds struct list_head *udevlist; 154*1da177e4SLinus Torvalds struct uflash_dev *udev; 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds list_for_each(udevlist, &device_list) { 157*1da177e4SLinus Torvalds udev = list_entry(udevlist, struct uflash_dev, list); 158*1da177e4SLinus Torvalds DEBUG(2, "%s: removing device %s\n", 159*1da177e4SLinus Torvalds UFLASH_DEVNAME, udev->name); 160*1da177e4SLinus Torvalds 161*1da177e4SLinus Torvalds if(0 != udev->mtd) { 162*1da177e4SLinus Torvalds del_mtd_device(udev->mtd); 163*1da177e4SLinus Torvalds map_destroy(udev->mtd); 164*1da177e4SLinus Torvalds } 165*1da177e4SLinus Torvalds if(0 != udev->map.virt) { 166*1da177e4SLinus Torvalds iounmap(udev->map.virt); 167*1da177e4SLinus Torvalds udev->map.virt = NULL; 168*1da177e4SLinus Torvalds } 169*1da177e4SLinus Torvalds if(0 != udev->name) { 170*1da177e4SLinus Torvalds kfree(udev->name); 171*1da177e4SLinus Torvalds } 172*1da177e4SLinus Torvalds kfree(udev); 173*1da177e4SLinus Torvalds } 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds module_init(uflash_init); 177*1da177e4SLinus Torvalds module_exit(uflash_cleanup); 178