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