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