Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #ifndef __ALPHA_JENSEN_H |
| 2 | #define __ALPHA_JENSEN_H |
| 3 | |
| 4 | #include <asm/compiler.h> |
| 5 | |
| 6 | /* |
| 7 | * Defines for the AlphaPC EISA IO and memory address space. |
| 8 | */ |
| 9 | |
| 10 | /* |
| 11 | * NOTE! The memory operations do not set any memory barriers, as it's |
| 12 | * not needed for cases like a frame buffer that is essentially memory-like. |
| 13 | * You need to do them by hand if the operations depend on ordering. |
| 14 | * |
| 15 | * Similarly, the port IO operations do a "mb" only after a write operation: |
| 16 | * if an mb is needed before (as in the case of doing memory mapped IO |
| 17 | * first, and then a port IO operation to the same device), it needs to be |
| 18 | * done by hand. |
| 19 | * |
| 20 | * After the above has bitten me 100 times, I'll give up and just do the |
| 21 | * mb all the time, but right now I'm hoping this will work out. Avoiding |
| 22 | * mb's may potentially be a noticeable speed improvement, but I can't |
| 23 | * honestly say I've tested it. |
| 24 | * |
| 25 | * Handling interrupts that need to do mb's to synchronize to non-interrupts |
| 26 | * is another fun race area. Don't do it (because if you do, I'll have to |
| 27 | * do *everything* with interrupts disabled, ugh). |
| 28 | */ |
| 29 | |
| 30 | /* |
| 31 | * EISA Interrupt Acknowledge address |
| 32 | */ |
| 33 | #define EISA_INTA (IDENT_ADDR + 0x100000000UL) |
| 34 | |
| 35 | /* |
| 36 | * FEPROM addresses |
| 37 | */ |
| 38 | #define EISA_FEPROM0 (IDENT_ADDR + 0x180000000UL) |
| 39 | #define EISA_FEPROM1 (IDENT_ADDR + 0x1A0000000UL) |
| 40 | |
| 41 | /* |
| 42 | * VL82C106 base address |
| 43 | */ |
| 44 | #define EISA_VL82C106 (IDENT_ADDR + 0x1C0000000UL) |
| 45 | |
| 46 | /* |
| 47 | * EISA "Host Address Extension" address (bits 25-31 of the EISA address) |
| 48 | */ |
| 49 | #define EISA_HAE (IDENT_ADDR + 0x1D0000000UL) |
| 50 | |
| 51 | /* |
| 52 | * "SYSCTL" register address |
| 53 | */ |
| 54 | #define EISA_SYSCTL (IDENT_ADDR + 0x1E0000000UL) |
| 55 | |
| 56 | /* |
| 57 | * "spare" register address |
| 58 | */ |
| 59 | #define EISA_SPARE (IDENT_ADDR + 0x1F0000000UL) |
| 60 | |
| 61 | /* |
| 62 | * EISA memory address offset |
| 63 | */ |
| 64 | #define EISA_MEM (IDENT_ADDR + 0x200000000UL) |
| 65 | |
| 66 | /* |
| 67 | * EISA IO address offset |
| 68 | */ |
| 69 | #define EISA_IO (IDENT_ADDR + 0x300000000UL) |
| 70 | |
| 71 | |
| 72 | #ifdef __KERNEL__ |
| 73 | |
| 74 | #ifndef __EXTERN_INLINE |
| 75 | #define __EXTERN_INLINE extern inline |
| 76 | #define __IO_EXTERN_INLINE |
| 77 | #endif |
| 78 | |
| 79 | /* |
| 80 | * Handle the "host address register". This needs to be set |
| 81 | * to the high 7 bits of the EISA address. This is also needed |
| 82 | * for EISA IO addresses, which are only 16 bits wide (the |
| 83 | * hae needs to be set to 0). |
| 84 | * |
| 85 | * HAE isn't needed for the local IO operations, though. |
| 86 | */ |
| 87 | |
| 88 | #define JENSEN_HAE_ADDRESS EISA_HAE |
| 89 | #define JENSEN_HAE_MASK 0x1ffffff |
| 90 | |
| 91 | __EXTERN_INLINE void jensen_set_hae(unsigned long addr) |
| 92 | { |
| 93 | /* hae on the Jensen is bits 31:25 shifted right */ |
| 94 | addr >>= 25; |
| 95 | if (addr != alpha_mv.hae_cache) |
| 96 | set_hae(addr); |
| 97 | } |
| 98 | |
| 99 | #define vuip volatile unsigned int * |
| 100 | |
| 101 | /* |
| 102 | * IO functions |
| 103 | * |
| 104 | * The "local" functions are those that don't go out to the EISA bus, |
| 105 | * but instead act on the VL82C106 chip directly.. This is mainly the |
| 106 | * keyboard, RTC, printer and first two serial lines.. |
| 107 | * |
| 108 | * The local stuff makes for some complications, but it seems to be |
| 109 | * gone in the PCI version. I hope I can get DEC suckered^H^H^H^H^H^H^H^H |
| 110 | * convinced that I need one of the newer machines. |
| 111 | */ |
| 112 | |
| 113 | static inline unsigned int jensen_local_inb(unsigned long addr) |
| 114 | { |
| 115 | return 0xff & *(vuip)((addr << 9) + EISA_VL82C106); |
| 116 | } |
| 117 | |
| 118 | static inline void jensen_local_outb(u8 b, unsigned long addr) |
| 119 | { |
| 120 | *(vuip)((addr << 9) + EISA_VL82C106) = b; |
| 121 | mb(); |
| 122 | } |
| 123 | |
| 124 | static inline unsigned int jensen_bus_inb(unsigned long addr) |
| 125 | { |
| 126 | long result; |
| 127 | |
| 128 | jensen_set_hae(0); |
| 129 | result = *(volatile int *)((addr << 7) + EISA_IO + 0x00); |
| 130 | return __kernel_extbl(result, addr & 3); |
| 131 | } |
| 132 | |
| 133 | static inline void jensen_bus_outb(u8 b, unsigned long addr) |
| 134 | { |
| 135 | jensen_set_hae(0); |
| 136 | *(vuip)((addr << 7) + EISA_IO + 0x00) = b * 0x01010101; |
| 137 | mb(); |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | * It seems gcc is not very good at optimizing away logical |
| 142 | * operations that result in operations across inline functions. |
| 143 | * Which is why this is a macro. |
| 144 | */ |
| 145 | |
| 146 | #define jensen_is_local(addr) ( \ |
| 147 | /* keyboard */ (addr == 0x60 || addr == 0x64) || \ |
| 148 | /* RTC */ (addr == 0x170 || addr == 0x171) || \ |
| 149 | /* mb COM2 */ (addr >= 0x2f8 && addr <= 0x2ff) || \ |
| 150 | /* mb LPT1 */ (addr >= 0x3bc && addr <= 0x3be) || \ |
| 151 | /* mb COM2 */ (addr >= 0x3f8 && addr <= 0x3ff)) |
| 152 | |
| 153 | __EXTERN_INLINE u8 jensen_inb(unsigned long addr) |
| 154 | { |
| 155 | if (jensen_is_local(addr)) |
| 156 | return jensen_local_inb(addr); |
| 157 | else |
| 158 | return jensen_bus_inb(addr); |
| 159 | } |
| 160 | |
| 161 | __EXTERN_INLINE void jensen_outb(u8 b, unsigned long addr) |
| 162 | { |
| 163 | if (jensen_is_local(addr)) |
| 164 | jensen_local_outb(b, addr); |
| 165 | else |
| 166 | jensen_bus_outb(b, addr); |
| 167 | } |
| 168 | |
| 169 | __EXTERN_INLINE u16 jensen_inw(unsigned long addr) |
| 170 | { |
| 171 | long result; |
| 172 | |
| 173 | jensen_set_hae(0); |
| 174 | result = *(volatile int *) ((addr << 7) + EISA_IO + 0x20); |
| 175 | result >>= (addr & 3) * 8; |
| 176 | return 0xffffUL & result; |
| 177 | } |
| 178 | |
| 179 | __EXTERN_INLINE u32 jensen_inl(unsigned long addr) |
| 180 | { |
| 181 | jensen_set_hae(0); |
| 182 | return *(vuip) ((addr << 7) + EISA_IO + 0x60); |
| 183 | } |
| 184 | |
| 185 | __EXTERN_INLINE void jensen_outw(u16 b, unsigned long addr) |
| 186 | { |
| 187 | jensen_set_hae(0); |
| 188 | *(vuip) ((addr << 7) + EISA_IO + 0x20) = b * 0x00010001; |
| 189 | mb(); |
| 190 | } |
| 191 | |
| 192 | __EXTERN_INLINE void jensen_outl(u32 b, unsigned long addr) |
| 193 | { |
| 194 | jensen_set_hae(0); |
| 195 | *(vuip) ((addr << 7) + EISA_IO + 0x60) = b; |
| 196 | mb(); |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | * Memory functions. |
| 201 | */ |
| 202 | |
| 203 | __EXTERN_INLINE u8 jensen_readb(const volatile void __iomem *xaddr) |
| 204 | { |
| 205 | unsigned long addr = (unsigned long) xaddr; |
| 206 | long result; |
| 207 | |
| 208 | jensen_set_hae(addr); |
| 209 | addr &= JENSEN_HAE_MASK; |
| 210 | result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x00); |
| 211 | result >>= (addr & 3) * 8; |
| 212 | return 0xffUL & result; |
| 213 | } |
| 214 | |
| 215 | __EXTERN_INLINE u16 jensen_readw(const volatile void __iomem *xaddr) |
| 216 | { |
| 217 | unsigned long addr = (unsigned long) xaddr; |
| 218 | long result; |
| 219 | |
| 220 | jensen_set_hae(addr); |
| 221 | addr &= JENSEN_HAE_MASK; |
| 222 | result = *(volatile int *) ((addr << 7) + EISA_MEM + 0x20); |
| 223 | result >>= (addr & 3) * 8; |
| 224 | return 0xffffUL & result; |
| 225 | } |
| 226 | |
| 227 | __EXTERN_INLINE u32 jensen_readl(const volatile void __iomem *xaddr) |
| 228 | { |
| 229 | unsigned long addr = (unsigned long) xaddr; |
| 230 | jensen_set_hae(addr); |
| 231 | addr &= JENSEN_HAE_MASK; |
| 232 | return *(vuip) ((addr << 7) + EISA_MEM + 0x60); |
| 233 | } |
| 234 | |
| 235 | __EXTERN_INLINE u64 jensen_readq(const volatile void __iomem *xaddr) |
| 236 | { |
| 237 | unsigned long addr = (unsigned long) xaddr; |
| 238 | unsigned long r0, r1; |
| 239 | |
| 240 | jensen_set_hae(addr); |
| 241 | addr &= JENSEN_HAE_MASK; |
| 242 | addr = (addr << 7) + EISA_MEM + 0x60; |
| 243 | r0 = *(vuip) (addr); |
| 244 | r1 = *(vuip) (addr + (4 << 7)); |
| 245 | return r1 << 32 | r0; |
| 246 | } |
| 247 | |
| 248 | __EXTERN_INLINE void jensen_writeb(u8 b, volatile void __iomem *xaddr) |
| 249 | { |
| 250 | unsigned long addr = (unsigned long) xaddr; |
| 251 | jensen_set_hae(addr); |
| 252 | addr &= JENSEN_HAE_MASK; |
| 253 | *(vuip) ((addr << 7) + EISA_MEM + 0x00) = b * 0x01010101; |
| 254 | } |
| 255 | |
| 256 | __EXTERN_INLINE void jensen_writew(u16 b, volatile void __iomem *xaddr) |
| 257 | { |
| 258 | unsigned long addr = (unsigned long) xaddr; |
| 259 | jensen_set_hae(addr); |
| 260 | addr &= JENSEN_HAE_MASK; |
| 261 | *(vuip) ((addr << 7) + EISA_MEM + 0x20) = b * 0x00010001; |
| 262 | } |
| 263 | |
| 264 | __EXTERN_INLINE void jensen_writel(u32 b, volatile void __iomem *xaddr) |
| 265 | { |
| 266 | unsigned long addr = (unsigned long) xaddr; |
| 267 | jensen_set_hae(addr); |
| 268 | addr &= JENSEN_HAE_MASK; |
| 269 | *(vuip) ((addr << 7) + EISA_MEM + 0x60) = b; |
| 270 | } |
| 271 | |
| 272 | __EXTERN_INLINE void jensen_writeq(u64 b, volatile void __iomem *xaddr) |
| 273 | { |
| 274 | unsigned long addr = (unsigned long) xaddr; |
| 275 | jensen_set_hae(addr); |
| 276 | addr &= JENSEN_HAE_MASK; |
| 277 | addr = (addr << 7) + EISA_MEM + 0x60; |
| 278 | *(vuip) (addr) = b; |
| 279 | *(vuip) (addr + (4 << 7)) = b >> 32; |
| 280 | } |
| 281 | |
| 282 | __EXTERN_INLINE void __iomem *jensen_ioportmap(unsigned long addr) |
| 283 | { |
| 284 | return (void __iomem *)addr; |
| 285 | } |
| 286 | |
| 287 | __EXTERN_INLINE void __iomem *jensen_ioremap(unsigned long addr, |
| 288 | unsigned long size) |
| 289 | { |
| 290 | return (void __iomem *)(addr + 0x100000000ul); |
| 291 | } |
| 292 | |
| 293 | __EXTERN_INLINE int jensen_is_ioaddr(unsigned long addr) |
| 294 | { |
| 295 | return (long)addr >= 0; |
| 296 | } |
| 297 | |
| 298 | __EXTERN_INLINE int jensen_is_mmio(const volatile void __iomem *addr) |
| 299 | { |
| 300 | return (unsigned long)addr >= 0x100000000ul; |
| 301 | } |
| 302 | |
| 303 | /* New-style ioread interface. All the routines are so ugly for Jensen |
| 304 | that it doesn't make sense to merge them. */ |
| 305 | |
| 306 | #define IOPORT(OS, NS) \ |
| 307 | __EXTERN_INLINE unsigned int jensen_ioread##NS(void __iomem *xaddr) \ |
| 308 | { \ |
| 309 | if (jensen_is_mmio(xaddr)) \ |
| 310 | return jensen_read##OS(xaddr - 0x100000000ul); \ |
| 311 | else \ |
| 312 | return jensen_in##OS((unsigned long)xaddr); \ |
| 313 | } \ |
| 314 | __EXTERN_INLINE void jensen_iowrite##NS(u##NS b, void __iomem *xaddr) \ |
| 315 | { \ |
| 316 | if (jensen_is_mmio(xaddr)) \ |
| 317 | jensen_write##OS(b, xaddr - 0x100000000ul); \ |
| 318 | else \ |
| 319 | jensen_out##OS(b, (unsigned long)xaddr); \ |
| 320 | } |
| 321 | |
| 322 | IOPORT(b, 8) |
| 323 | IOPORT(w, 16) |
| 324 | IOPORT(l, 32) |
| 325 | |
| 326 | #undef IOPORT |
| 327 | |
| 328 | #undef vuip |
| 329 | |
| 330 | #undef __IO_PREFIX |
| 331 | #define __IO_PREFIX jensen |
| 332 | #define jensen_trivial_rw_bw 0 |
| 333 | #define jensen_trivial_rw_lq 0 |
| 334 | #define jensen_trivial_io_bw 0 |
| 335 | #define jensen_trivial_io_lq 0 |
| 336 | #define jensen_trivial_iounmap 1 |
| 337 | #include <asm/io_trivial.h> |
| 338 | |
| 339 | #ifdef __IO_EXTERN_INLINE |
| 340 | #undef __EXTERN_INLINE |
| 341 | #undef __IO_EXTERN_INLINE |
| 342 | #endif |
| 343 | |
| 344 | #endif /* __KERNEL__ */ |
| 345 | |
| 346 | #endif /* __ALPHA_JENSEN_H */ |