Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.30-rc3 247 lines 6.4 kB view raw
1/* ###################################################################### 2 3 Octagon 5066 MTD Driver. 4 5 The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It 6 comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that 7 is replacable by flash. Both units are mapped through a multiplexer 8 into a 32k memory window at 0xe8000. The control register for the 9 multiplexing unit is located at IO 0x208 with a bit map of 10 0-5 Page Selection in 32k increments 11 6-7 Device selection: 12 00 SSD off 13 01 SSD 0 (Socket) 14 10 SSD 1 (Flash chip) 15 11 undefined 16 17 On each SSD, the first 128k is reserved for use by the bios 18 (actually it IS the bios..) This only matters if you are booting off the 19 flash, you must not put a file system starting there. 20 21 The driver tries to do a detection algorithm to guess what sort of devices 22 are plugged into the sockets. 23 24 ##################################################################### */ 25 26#include <linux/module.h> 27#include <linux/slab.h> 28#include <linux/ioport.h> 29#include <linux/init.h> 30#include <asm/io.h> 31 32#include <linux/mtd/map.h> 33#include <linux/mtd/mtd.h> 34 35#define WINDOW_START 0xe8000 36#define WINDOW_LENGTH 0x8000 37#define WINDOW_SHIFT 27 38#define WINDOW_MASK 0x7FFF 39#define PAGE_IO 0x208 40 41static volatile char page_n_dev = 0; 42static unsigned long iomapadr; 43static DEFINE_SPINLOCK(oct5066_spin); 44 45/* 46 * We use map_priv_1 to identify which device we are. 47 */ 48 49static void __oct5066_page(struct map_info *map, __u8 byte) 50{ 51 outb(byte,PAGE_IO); 52 page_n_dev = byte; 53} 54 55static inline void oct5066_page(struct map_info *map, unsigned long ofs) 56{ 57 __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); 58 59 if (page_n_dev != byte) 60 __oct5066_page(map, byte); 61} 62 63 64static map_word oct5066_read8(struct map_info *map, unsigned long ofs) 65{ 66 map_word ret; 67 spin_lock(&oct5066_spin); 68 oct5066_page(map, ofs); 69 ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK)); 70 spin_unlock(&oct5066_spin); 71 return ret; 72} 73 74static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 75{ 76 while(len) { 77 unsigned long thislen = len; 78 if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) 79 thislen = WINDOW_LENGTH-(from & WINDOW_MASK); 80 81 spin_lock(&oct5066_spin); 82 oct5066_page(map, from); 83 memcpy_fromio(to, iomapadr + from, thislen); 84 spin_unlock(&oct5066_spin); 85 to += thislen; 86 from += thislen; 87 len -= thislen; 88 } 89} 90 91static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr) 92{ 93 spin_lock(&oct5066_spin); 94 oct5066_page(map, adr); 95 writeb(d.x[0], iomapadr + (adr & WINDOW_MASK)); 96 spin_unlock(&oct5066_spin); 97} 98 99static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 100{ 101 while(len) { 102 unsigned long thislen = len; 103 if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) 104 thislen = WINDOW_LENGTH-(to & WINDOW_MASK); 105 106 spin_lock(&oct5066_spin); 107 oct5066_page(map, to); 108 memcpy_toio(iomapadr + to, from, thislen); 109 spin_unlock(&oct5066_spin); 110 to += thislen; 111 from += thislen; 112 len -= thislen; 113 } 114} 115 116static struct map_info oct5066_map[2] = { 117 { 118 .name = "Octagon 5066 Socket", 119 .phys = NO_XIP, 120 .size = 512 * 1024, 121 .bankwidth = 1, 122 .read = oct5066_read8, 123 .copy_from = oct5066_copy_from, 124 .write = oct5066_write8, 125 .copy_to = oct5066_copy_to, 126 .map_priv_1 = 1<<6 127 }, 128 { 129 .name = "Octagon 5066 Internal Flash", 130 .phys = NO_XIP, 131 .size = 2 * 1024 * 1024, 132 .bankwidth = 1, 133 .read = oct5066_read8, 134 .copy_from = oct5066_copy_from, 135 .write = oct5066_write8, 136 .copy_to = oct5066_copy_to, 137 .map_priv_1 = 2<<6 138 } 139}; 140 141static struct mtd_info *oct5066_mtd[2] = {NULL, NULL}; 142 143// OctProbe - Sense if this is an octagon card 144// --------------------------------------------------------------------- 145/* Perform a simple validity test, we map the window select SSD0 and 146 change pages while monitoring the window. A change in the window, 147 controlled by the PAGE_IO port is a functioning 5066 board. This will 148 fail if the thing in the socket is set to a uniform value. */ 149static int __init OctProbe(void) 150{ 151 unsigned int Base = (1 << 6); 152 unsigned long I; 153 unsigned long Values[10]; 154 for (I = 0; I != 20; I++) 155 { 156 outb(Base + (I%10),PAGE_IO); 157 if (I < 10) 158 { 159 // Record the value and check for uniqueness 160 Values[I%10] = readl(iomapadr); 161 if (I > 0 && Values[I%10] == Values[0]) 162 return -EAGAIN; 163 } 164 else 165 { 166 // Make sure we get the same values on the second pass 167 if (Values[I%10] != readl(iomapadr)) 168 return -EAGAIN; 169 } 170 } 171 return 0; 172} 173 174void cleanup_oct5066(void) 175{ 176 int i; 177 for (i=0; i<2; i++) { 178 if (oct5066_mtd[i]) { 179 del_mtd_device(oct5066_mtd[i]); 180 map_destroy(oct5066_mtd[i]); 181 } 182 } 183 iounmap((void *)iomapadr); 184 release_region(PAGE_IO, 1); 185} 186 187static int __init init_oct5066(void) 188{ 189 int i; 190 int ret = 0; 191 192 // Do an autoprobe sequence 193 if (!request_region(PAGE_IO,1,"Octagon SSD")) { 194 printk(KERN_NOTICE "5066: Page Register in Use\n"); 195 return -EAGAIN; 196 } 197 iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); 198 if (!iomapadr) { 199 printk(KERN_NOTICE "Failed to ioremap memory region\n"); 200 ret = -EIO; 201 goto out_rel; 202 } 203 if (OctProbe() != 0) { 204 printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n"); 205 iounmap((void *)iomapadr); 206 ret = -EAGAIN; 207 goto out_unmap; 208 } 209 210 // Print out our little header.. 211 printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, 212 WINDOW_START+WINDOW_LENGTH); 213 214 for (i=0; i<2; i++) { 215 oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]); 216 if (!oct5066_mtd[i]) 217 oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]); 218 if (!oct5066_mtd[i]) 219 oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]); 220 if (!oct5066_mtd[i]) 221 oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]); 222 if (oct5066_mtd[i]) { 223 oct5066_mtd[i]->owner = THIS_MODULE; 224 add_mtd_device(oct5066_mtd[i]); 225 } 226 } 227 228 if (!oct5066_mtd[0] && !oct5066_mtd[1]) { 229 cleanup_oct5066(); 230 return -ENXIO; 231 } 232 233 return 0; 234 235 out_unmap: 236 iounmap((void *)iomapadr); 237 out_rel: 238 release_region(PAGE_IO, 1); 239 return ret; 240} 241 242module_init(init_oct5066); 243module_exit(cleanup_oct5066); 244 245MODULE_LICENSE("GPL"); 246MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>"); 247MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");