io.c revision 3b11e449b3a8d9b912d80e28f62985f22a70e87f
1/* 2 * linux/arch/arm/mach-ebsa110/isamem.c 3 * 4 * Copyright (C) 2001 Russell King 5 * 6 * Perform "ISA" memory and IO accesses. The EBSA110 has some "peculiarities" 7 * in the way it handles accesses to odd IO ports on 16-bit devices. These 8 * devices have their D0-D15 lines connected to the processors D0-D15 lines. 9 * Since they expect all byte IO operations to be performed on D0-D7, and the 10 * StrongARM expects to transfer the byte to these odd addresses on D8-D15, 11 * we must use a trick to get the required behaviour. 12 * 13 * The trick employed here is to use long word stores to odd address -1. The 14 * glue logic picks this up as a "trick" access, and asserts the LSB of the 15 * peripherals address bus, thereby accessing the odd IO port. Meanwhile, the 16 * StrongARM transfers its data on D0-D7 as expected. 17 * 18 * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller 19 * wiring was screwed in such a way that it had limited memory space access. 20 * Luckily, the work-around for this is not too horrible. See 21 * __isamem_convert_addr for the details. 22 */ 23#include <linux/module.h> 24#include <linux/kernel.h> 25#include <linux/types.h> 26 27#include <asm/hardware.h> 28#include <asm/io.h> 29#include <asm/page.h> 30 31static void __iomem *__isamem_convert_addr(const volatile void __iomem *addr) 32{ 33 u32 ret, a = (u32 __force) addr; 34 35 /* 36 * The PCMCIA controller is wired up as follows: 37 * +---------+---------+---------+---------+---------+---------+ 38 * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1 | | | 39 * | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 | 40 * +---------+---------+---------+---------+---------+---------+ 41 * CPU | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1 | | | 42 * | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x | 43 * +---------+---------+---------+---------+---------+---------+ 44 * 45 * This means that we can access PCMCIA regions as follows: 46 * 0x*10000 -> 0x*1ffff 47 * 0x*70000 -> 0x*7ffff 48 * 0x*90000 -> 0x*9ffff 49 * 0x*f0000 -> 0x*fffff 50 */ 51 ret = (a & 0xf803fe) << 1; 52 ret |= (a & 0x03fc00) << 2; 53 54 ret += 0xe8000000; 55 56 if ((a & 0x20000) == (a & 0x40000) >> 1) 57 return (void __iomem *)ret; 58 59 BUG(); 60 return NULL; 61} 62 63/* 64 * read[bwl] and write[bwl] 65 */ 66u8 __readb(const volatile void __iomem *addr) 67{ 68 void __iomem *a = __isamem_convert_addr(addr); 69 u32 ret; 70 71 if ((unsigned long)addr & 1) 72 ret = __raw_readl(a); 73 else 74 ret = __raw_readb(a); 75 return ret; 76} 77 78u16 __readw(const volatile void __iomem *addr) 79{ 80 void __iomem *a = __isamem_convert_addr(addr); 81 82 if ((unsigned long)addr & 1) 83 BUG(); 84 85 return __raw_readw(a); 86} 87 88u32 __readl(const volatile void __iomem *addr) 89{ 90 void __iomem *a = __isamem_convert_addr(addr); 91 u32 ret; 92 93 if ((unsigned long)addr & 3) 94 BUG(); 95 96 ret = __raw_readw(a); 97 ret |= __raw_readw(a + 4) << 16; 98 return ret; 99} 100 101EXPORT_SYMBOL(__readb); 102EXPORT_SYMBOL(__readw); 103EXPORT_SYMBOL(__readl); 104 105void readsw(const void __iomem *addr, void *data, int len) 106{ 107 void __iomem *a = __isamem_convert_addr(addr); 108 109 BUG_ON((unsigned long)addr & 1); 110 111 __raw_readsw(a, data, len); 112} 113EXPORT_SYMBOL(readsw); 114 115void readsl(const void __iomem *addr, void *data, int len) 116{ 117 void __iomem *a = __isamem_convert_addr(addr); 118 119 BUG_ON((unsigned long)addr & 3); 120 121 __raw_readsl(a, data, len); 122} 123EXPORT_SYMBOL(readsl); 124 125void __writeb(u8 val, void __iomem *addr) 126{ 127 void __iomem *a = __isamem_convert_addr(addr); 128 129 if ((unsigned long)addr & 1) 130 __raw_writel(val, a); 131 else 132 __raw_writeb(val, a); 133} 134 135void __writew(u16 val, void __iomem *addr) 136{ 137 void __iomem *a = __isamem_convert_addr(addr); 138 139 if ((unsigned long)addr & 1) 140 BUG(); 141 142 __raw_writew(val, a); 143} 144 145void __writel(u32 val, void __iomem *addr) 146{ 147 void __iomem *a = __isamem_convert_addr(addr); 148 149 if ((unsigned long)addr & 3) 150 BUG(); 151 152 __raw_writew(val, a); 153 __raw_writew(val >> 16, a + 4); 154} 155 156EXPORT_SYMBOL(__writeb); 157EXPORT_SYMBOL(__writew); 158EXPORT_SYMBOL(__writel); 159 160void writesw(void __iomem *addr, const void *data, int len) 161{ 162 void __iomem *a = __isamem_convert_addr(addr); 163 164 BUG_ON((unsigned long)addr & 1); 165 166 __raw_writesw(a, data, len); 167} 168EXPORT_SYMBOL(writesw); 169 170void writesl(void __iomem *addr, const void *data, int len) 171{ 172 void __iomem *a = __isamem_convert_addr(addr); 173 174 BUG_ON((unsigned long)addr & 3); 175 176 __raw_writesl(a, data, len); 177} 178EXPORT_SYMBOL(writesl); 179 180#define SUPERIO_PORT(p) \ 181 (((p) >> 3) == (0x3f8 >> 3) || \ 182 ((p) >> 3) == (0x2f8 >> 3) || \ 183 ((p) >> 3) == (0x378 >> 3)) 184 185/* 186 * We're addressing an 8 or 16-bit peripheral which tranfers 187 * odd addresses on the low ISA byte lane. 188 */ 189u8 __inb8(unsigned int port) 190{ 191 u32 ret; 192 193 /* 194 * The SuperIO registers use sane addressing techniques... 195 */ 196 if (SUPERIO_PORT(port)) 197 ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2)); 198 else { 199 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 200 201 /* 202 * Shame nothing else does 203 */ 204 if (port & 1) 205 ret = __raw_readl(a); 206 else 207 ret = __raw_readb(a); 208 } 209 return ret; 210} 211 212/* 213 * We're addressing a 16-bit peripheral which transfers odd 214 * addresses on the high ISA byte lane. 215 */ 216u8 __inb16(unsigned int port) 217{ 218 unsigned int offset; 219 220 /* 221 * The SuperIO registers use sane addressing techniques... 222 */ 223 if (SUPERIO_PORT(port)) 224 offset = port << 2; 225 else 226 offset = (port & ~1) << 1 | (port & 1); 227 228 return __raw_readb((void __iomem *)ISAIO_BASE + offset); 229} 230 231u16 __inw(unsigned int port) 232{ 233 unsigned int offset; 234 235 /* 236 * The SuperIO registers use sane addressing techniques... 237 */ 238 if (SUPERIO_PORT(port)) 239 offset = port << 2; 240 else { 241 offset = port << 1; 242 BUG_ON(port & 1); 243 } 244 return __raw_readw((void __iomem *)ISAIO_BASE + offset); 245} 246 247/* 248 * Fake a 32-bit read with two 16-bit reads. Needed for 3c589. 249 */ 250u32 __inl(unsigned int port) 251{ 252 void __iomem *a; 253 254 if (SUPERIO_PORT(port) || port & 3) 255 BUG(); 256 257 a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 258 259 return __raw_readw(a) | __raw_readw(a + 4) << 16; 260} 261 262EXPORT_SYMBOL(__inb8); 263EXPORT_SYMBOL(__inb16); 264EXPORT_SYMBOL(__inw); 265EXPORT_SYMBOL(__inl); 266 267void __outb8(u8 val, unsigned int port) 268{ 269 /* 270 * The SuperIO registers use sane addressing techniques... 271 */ 272 if (SUPERIO_PORT(port)) 273 __raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2)); 274 else { 275 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 276 277 /* 278 * Shame nothing else does 279 */ 280 if (port & 1) 281 __raw_writel(val, a); 282 else 283 __raw_writeb(val, a); 284 } 285} 286 287void __outb16(u8 val, unsigned int port) 288{ 289 unsigned int offset; 290 291 /* 292 * The SuperIO registers use sane addressing techniques... 293 */ 294 if (SUPERIO_PORT(port)) 295 offset = port << 2; 296 else 297 offset = (port & ~1) << 1 | (port & 1); 298 299 __raw_writeb(val, (void __iomem *)ISAIO_BASE + offset); 300} 301 302void __outw(u16 val, unsigned int port) 303{ 304 unsigned int offset; 305 306 /* 307 * The SuperIO registers use sane addressing techniques... 308 */ 309 if (SUPERIO_PORT(port)) 310 offset = port << 2; 311 else { 312 offset = port << 1; 313 BUG_ON(port & 1); 314 } 315 __raw_writew(val, (void __iomem *)ISAIO_BASE + offset); 316} 317 318void __outl(u32 val, unsigned int port) 319{ 320 BUG(); 321} 322 323EXPORT_SYMBOL(__outb8); 324EXPORT_SYMBOL(__outb16); 325EXPORT_SYMBOL(__outw); 326EXPORT_SYMBOL(__outl); 327 328void outsb(unsigned int port, const void *from, int len) 329{ 330 u32 off; 331 332 if (SUPERIO_PORT(port)) 333 off = port << 2; 334 else { 335 off = (port & ~1) << 1; 336 if (port & 1) 337 BUG(); 338 } 339 340 __raw_writesb((void __iomem *)ISAIO_BASE + off, from, len); 341} 342 343void insb(unsigned int port, void *from, int len) 344{ 345 u32 off; 346 347 if (SUPERIO_PORT(port)) 348 off = port << 2; 349 else { 350 off = (port & ~1) << 1; 351 if (port & 1) 352 BUG(); 353 } 354 355 __raw_readsb((void __iomem *)ISAIO_BASE + off, from, len); 356} 357 358EXPORT_SYMBOL(outsb); 359EXPORT_SYMBOL(insb); 360 361void outsw(unsigned int port, const void *from, int len) 362{ 363 u32 off; 364 365 if (SUPERIO_PORT(port)) 366 off = port << 2; 367 else { 368 off = (port & ~1) << 1; 369 if (port & 1) 370 BUG(); 371 } 372 373 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len); 374} 375 376void insw(unsigned int port, void *from, int len) 377{ 378 u32 off; 379 380 if (SUPERIO_PORT(port)) 381 off = port << 2; 382 else { 383 off = (port & ~1) << 1; 384 if (port & 1) 385 BUG(); 386 } 387 388 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len); 389} 390 391EXPORT_SYMBOL(outsw); 392EXPORT_SYMBOL(insw); 393 394/* 395 * We implement these as 16-bit insw/outsw, mainly for 396 * 3c589 cards. 397 */ 398void outsl(unsigned int port, const void *from, int len) 399{ 400 u32 off = port << 1; 401 402 if (SUPERIO_PORT(port) || port & 3) 403 BUG(); 404 405 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len << 1); 406} 407 408void insl(unsigned int port, void *from, int len) 409{ 410 u32 off = port << 1; 411 412 if (SUPERIO_PORT(port) || port & 3) 413 BUG(); 414 415 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len << 1); 416} 417 418EXPORT_SYMBOL(outsl); 419EXPORT_SYMBOL(insl); 420