Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.21 379 lines 7.9 kB view raw
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 __writeb(u8 val, void __iomem *addr) 106{ 107 void __iomem *a = __isamem_convert_addr(addr); 108 109 if ((unsigned long)addr & 1) 110 __raw_writel(val, a); 111 else 112 __raw_writeb(val, a); 113} 114 115void __writew(u16 val, void __iomem *addr) 116{ 117 void __iomem *a = __isamem_convert_addr(addr); 118 119 if ((unsigned long)addr & 1) 120 BUG(); 121 122 __raw_writew(val, a); 123} 124 125void __writel(u32 val, void __iomem *addr) 126{ 127 void __iomem *a = __isamem_convert_addr(addr); 128 129 if ((unsigned long)addr & 3) 130 BUG(); 131 132 __raw_writew(val, a); 133 __raw_writew(val >> 16, a + 4); 134} 135 136EXPORT_SYMBOL(__writeb); 137EXPORT_SYMBOL(__writew); 138EXPORT_SYMBOL(__writel); 139 140#define SUPERIO_PORT(p) \ 141 (((p) >> 3) == (0x3f8 >> 3) || \ 142 ((p) >> 3) == (0x2f8 >> 3) || \ 143 ((p) >> 3) == (0x378 >> 3)) 144 145/* 146 * We're addressing an 8 or 16-bit peripheral which tranfers 147 * odd addresses on the low ISA byte lane. 148 */ 149u8 __inb8(unsigned int port) 150{ 151 u32 ret; 152 153 /* 154 * The SuperIO registers use sane addressing techniques... 155 */ 156 if (SUPERIO_PORT(port)) 157 ret = __raw_readb((void __iomem *)ISAIO_BASE + (port << 2)); 158 else { 159 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 160 161 /* 162 * Shame nothing else does 163 */ 164 if (port & 1) 165 ret = __raw_readl(a); 166 else 167 ret = __raw_readb(a); 168 } 169 return ret; 170} 171 172/* 173 * We're addressing a 16-bit peripheral which transfers odd 174 * addresses on the high ISA byte lane. 175 */ 176u8 __inb16(unsigned int port) 177{ 178 unsigned int offset; 179 180 /* 181 * The SuperIO registers use sane addressing techniques... 182 */ 183 if (SUPERIO_PORT(port)) 184 offset = port << 2; 185 else 186 offset = (port & ~1) << 1 | (port & 1); 187 188 return __raw_readb((void __iomem *)ISAIO_BASE + offset); 189} 190 191u16 __inw(unsigned int port) 192{ 193 unsigned int offset; 194 195 /* 196 * The SuperIO registers use sane addressing techniques... 197 */ 198 if (SUPERIO_PORT(port)) 199 offset = port << 2; 200 else { 201 offset = port << 1; 202 BUG_ON(port & 1); 203 } 204 return __raw_readw((void __iomem *)ISAIO_BASE + offset); 205} 206 207/* 208 * Fake a 32-bit read with two 16-bit reads. Needed for 3c589. 209 */ 210u32 __inl(unsigned int port) 211{ 212 void __iomem *a; 213 214 if (SUPERIO_PORT(port) || port & 3) 215 BUG(); 216 217 a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 218 219 return __raw_readw(a) | __raw_readw(a + 4) << 16; 220} 221 222EXPORT_SYMBOL(__inb8); 223EXPORT_SYMBOL(__inb16); 224EXPORT_SYMBOL(__inw); 225EXPORT_SYMBOL(__inl); 226 227void __outb8(u8 val, unsigned int port) 228{ 229 /* 230 * The SuperIO registers use sane addressing techniques... 231 */ 232 if (SUPERIO_PORT(port)) 233 __raw_writeb(val, (void __iomem *)ISAIO_BASE + (port << 2)); 234 else { 235 void __iomem *a = (void __iomem *)ISAIO_BASE + ((port & ~1) << 1); 236 237 /* 238 * Shame nothing else does 239 */ 240 if (port & 1) 241 __raw_writel(val, a); 242 else 243 __raw_writeb(val, a); 244 } 245} 246 247void __outb16(u8 val, unsigned int port) 248{ 249 unsigned int offset; 250 251 /* 252 * The SuperIO registers use sane addressing techniques... 253 */ 254 if (SUPERIO_PORT(port)) 255 offset = port << 2; 256 else 257 offset = (port & ~1) << 1 | (port & 1); 258 259 __raw_writeb(val, (void __iomem *)ISAIO_BASE + offset); 260} 261 262void __outw(u16 val, unsigned int port) 263{ 264 unsigned int offset; 265 266 /* 267 * The SuperIO registers use sane addressing techniques... 268 */ 269 if (SUPERIO_PORT(port)) 270 offset = port << 2; 271 else { 272 offset = port << 1; 273 BUG_ON(port & 1); 274 } 275 __raw_writew(val, (void __iomem *)ISAIO_BASE + offset); 276} 277 278void __outl(u32 val, unsigned int port) 279{ 280 BUG(); 281} 282 283EXPORT_SYMBOL(__outb8); 284EXPORT_SYMBOL(__outb16); 285EXPORT_SYMBOL(__outw); 286EXPORT_SYMBOL(__outl); 287 288void outsb(unsigned int port, const void *from, int len) 289{ 290 u32 off; 291 292 if (SUPERIO_PORT(port)) 293 off = port << 2; 294 else { 295 off = (port & ~1) << 1; 296 if (port & 1) 297 BUG(); 298 } 299 300 __raw_writesb((void __iomem *)ISAIO_BASE + off, from, len); 301} 302 303void insb(unsigned int port, void *from, int len) 304{ 305 u32 off; 306 307 if (SUPERIO_PORT(port)) 308 off = port << 2; 309 else { 310 off = (port & ~1) << 1; 311 if (port & 1) 312 BUG(); 313 } 314 315 __raw_readsb((void __iomem *)ISAIO_BASE + off, from, len); 316} 317 318EXPORT_SYMBOL(outsb); 319EXPORT_SYMBOL(insb); 320 321void outsw(unsigned int port, const void *from, int len) 322{ 323 u32 off; 324 325 if (SUPERIO_PORT(port)) 326 off = port << 2; 327 else { 328 off = (port & ~1) << 1; 329 if (port & 1) 330 BUG(); 331 } 332 333 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len); 334} 335 336void insw(unsigned int port, void *from, int len) 337{ 338 u32 off; 339 340 if (SUPERIO_PORT(port)) 341 off = port << 2; 342 else { 343 off = (port & ~1) << 1; 344 if (port & 1) 345 BUG(); 346 } 347 348 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len); 349} 350 351EXPORT_SYMBOL(outsw); 352EXPORT_SYMBOL(insw); 353 354/* 355 * We implement these as 16-bit insw/outsw, mainly for 356 * 3c589 cards. 357 */ 358void outsl(unsigned int port, const void *from, int len) 359{ 360 u32 off = port << 1; 361 362 if (SUPERIO_PORT(port) || port & 3) 363 BUG(); 364 365 __raw_writesw((void __iomem *)ISAIO_BASE + off, from, len << 1); 366} 367 368void insl(unsigned int port, void *from, int len) 369{ 370 u32 off = port << 1; 371 372 if (SUPERIO_PORT(port) || port & 3) 373 BUG(); 374 375 __raw_readsw((void __iomem *)ISAIO_BASE + off, from, len << 1); 376} 377 378EXPORT_SYMBOL(outsl); 379EXPORT_SYMBOL(insl);