1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * iomap.c - Implement iomap interface for PA-RISC |
4 | * Copyright (c) 2004 Matthew Wilcox |
5 | */ |
6 | |
7 | #include <linux/ioport.h> |
8 | #include <linux/pci.h> |
9 | #include <linux/export.h> |
10 | #include <asm/io.h> |
11 | |
12 | /* |
13 | * The iomap space on 32-bit PA-RISC is intended to look like this: |
14 | * 00000000-7fffffff virtual mapped IO |
15 | * 80000000-8fffffff ISA/EISA port space that can't be virtually mapped |
16 | * 90000000-9fffffff Dino port space |
17 | * a0000000-afffffff Astro port space |
18 | * b0000000-bfffffff PAT port space |
19 | * c0000000-cfffffff non-swapped memory IO |
20 | * f0000000-ffffffff legacy IO memory pointers |
21 | * |
22 | * For the moment, here's what it looks like: |
23 | * 80000000-8fffffff All ISA/EISA port space |
24 | * f0000000-ffffffff legacy IO memory pointers |
25 | * |
26 | * On 64-bit, everything is extended, so: |
27 | * 8000000000000000-8fffffffffffffff All ISA/EISA port space |
28 | * f000000000000000-ffffffffffffffff legacy IO memory pointers |
29 | */ |
30 | |
31 | /* |
32 | * Technically, this should be 'if (VMALLOC_START < addr < VMALLOC_END), |
33 | * but that's slow and we know it'll be within the first 2GB. |
34 | */ |
35 | #ifdef CONFIG_64BIT |
36 | #define INDIRECT_ADDR(addr) (((unsigned long)(addr) & 1UL<<63) != 0) |
37 | #define ADDR_TO_REGION(addr) (((unsigned long)addr >> 60) & 7) |
38 | #define IOPORT_MAP_BASE (8UL << 60) |
39 | #else |
40 | #define INDIRECT_ADDR(addr) (((unsigned long)(addr) & 1UL<<31) != 0) |
41 | #define ADDR_TO_REGION(addr) (((unsigned long)addr >> 28) & 7) |
42 | #define IOPORT_MAP_BASE (8UL << 28) |
43 | #endif |
44 | |
45 | struct iomap_ops { |
46 | unsigned int (*read8)(const void __iomem *); |
47 | unsigned int (*read16)(const void __iomem *); |
48 | unsigned int (*read16be)(const void __iomem *); |
49 | unsigned int (*read32)(const void __iomem *); |
50 | unsigned int (*read32be)(const void __iomem *); |
51 | #ifdef CONFIG_64BIT |
52 | u64 (*read64)(const void __iomem *); |
53 | u64 (*read64be)(const void __iomem *); |
54 | #endif |
55 | void (*write8)(u8, void __iomem *); |
56 | void (*write16)(u16, void __iomem *); |
57 | void (*write16be)(u16, void __iomem *); |
58 | void (*write32)(u32, void __iomem *); |
59 | void (*write32be)(u32, void __iomem *); |
60 | #ifdef CONFIG_64BIT |
61 | void (*write64)(u64, void __iomem *); |
62 | void (*write64be)(u64, void __iomem *); |
63 | #endif |
64 | void (*read8r)(const void __iomem *, void *, unsigned long); |
65 | void (*read16r)(const void __iomem *, void *, unsigned long); |
66 | void (*read32r)(const void __iomem *, void *, unsigned long); |
67 | void (*write8r)(void __iomem *, const void *, unsigned long); |
68 | void (*write16r)(void __iomem *, const void *, unsigned long); |
69 | void (*write32r)(void __iomem *, const void *, unsigned long); |
70 | }; |
71 | |
72 | /* Generic ioport ops. To be replaced later by specific dino/elroy/wax code */ |
73 | |
74 | #define ADDR2PORT(addr) ((unsigned long __force)(addr) & 0xffffff) |
75 | |
76 | static unsigned int ioport_read8(const void __iomem *addr) |
77 | { |
78 | return inb(ADDR2PORT(addr)); |
79 | } |
80 | |
81 | static unsigned int ioport_read16(const void __iomem *addr) |
82 | { |
83 | return inw(ADDR2PORT(addr)); |
84 | } |
85 | |
86 | static unsigned int ioport_read32(const void __iomem *addr) |
87 | { |
88 | return inl(ADDR2PORT(addr)); |
89 | } |
90 | |
91 | static void ioport_write8(u8 datum, void __iomem *addr) |
92 | { |
93 | outb(value: datum, ADDR2PORT(addr)); |
94 | } |
95 | |
96 | static void ioport_write16(u16 datum, void __iomem *addr) |
97 | { |
98 | outw(value: datum, ADDR2PORT(addr)); |
99 | } |
100 | |
101 | static void ioport_write32(u32 datum, void __iomem *addr) |
102 | { |
103 | outl(value: datum, ADDR2PORT(addr)); |
104 | } |
105 | |
106 | static void ioport_read8r(const void __iomem *addr, void *dst, unsigned long count) |
107 | { |
108 | insb(ADDR2PORT(addr), addr: dst, count); |
109 | } |
110 | |
111 | static void ioport_read16r(const void __iomem *addr, void *dst, unsigned long count) |
112 | { |
113 | insw(ADDR2PORT(addr), addr: dst, count); |
114 | } |
115 | |
116 | static void ioport_read32r(const void __iomem *addr, void *dst, unsigned long count) |
117 | { |
118 | insl(ADDR2PORT(addr), addr: dst, count); |
119 | } |
120 | |
121 | static void ioport_write8r(void __iomem *addr, const void *s, unsigned long n) |
122 | { |
123 | outsb(ADDR2PORT(addr), addr: s, count: n); |
124 | } |
125 | |
126 | static void ioport_write16r(void __iomem *addr, const void *s, unsigned long n) |
127 | { |
128 | outsw(ADDR2PORT(addr), addr: s, count: n); |
129 | } |
130 | |
131 | static void ioport_write32r(void __iomem *addr, const void *s, unsigned long n) |
132 | { |
133 | outsl(ADDR2PORT(addr), addr: s, count: n); |
134 | } |
135 | |
136 | static const struct iomap_ops ioport_ops = { |
137 | .read8 = ioport_read8, |
138 | .read16 = ioport_read16, |
139 | .read16be = ioport_read16, |
140 | .read32 = ioport_read32, |
141 | .read32be = ioport_read32, |
142 | .write8 = ioport_write8, |
143 | .write16 = ioport_write16, |
144 | .write16be = ioport_write16, |
145 | .write32 = ioport_write32, |
146 | .write32be = ioport_write32, |
147 | .read8r = ioport_read8r, |
148 | .read16r = ioport_read16r, |
149 | .read32r = ioport_read32r, |
150 | .write8r = ioport_write8r, |
151 | .write16r = ioport_write16r, |
152 | .write32r = ioport_write32r, |
153 | }; |
154 | |
155 | /* Legacy I/O memory ops */ |
156 | |
157 | static unsigned int iomem_read8(const void __iomem *addr) |
158 | { |
159 | return readb(addr); |
160 | } |
161 | |
162 | static unsigned int iomem_read16(const void __iomem *addr) |
163 | { |
164 | return readw(addr); |
165 | } |
166 | |
167 | static unsigned int iomem_read16be(const void __iomem *addr) |
168 | { |
169 | return __raw_readw(addr); |
170 | } |
171 | |
172 | static unsigned int iomem_read32(const void __iomem *addr) |
173 | { |
174 | return readl(addr); |
175 | } |
176 | |
177 | static unsigned int iomem_read32be(const void __iomem *addr) |
178 | { |
179 | return __raw_readl(addr); |
180 | } |
181 | |
182 | #ifdef CONFIG_64BIT |
183 | static u64 iomem_read64(const void __iomem *addr) |
184 | { |
185 | return readq(addr); |
186 | } |
187 | |
188 | static u64 iomem_read64be(const void __iomem *addr) |
189 | { |
190 | return __raw_readq(addr); |
191 | } |
192 | #endif |
193 | |
194 | static void iomem_write8(u8 datum, void __iomem *addr) |
195 | { |
196 | writeb(val: datum, addr); |
197 | } |
198 | |
199 | static void iomem_write16(u16 datum, void __iomem *addr) |
200 | { |
201 | writew(val: datum, addr); |
202 | } |
203 | |
204 | static void iomem_write16be(u16 datum, void __iomem *addr) |
205 | { |
206 | __raw_writew(val: datum, addr); |
207 | } |
208 | |
209 | static void iomem_write32(u32 datum, void __iomem *addr) |
210 | { |
211 | writel(val: datum, addr); |
212 | } |
213 | |
214 | static void iomem_write32be(u32 datum, void __iomem *addr) |
215 | { |
216 | __raw_writel(val: datum, addr); |
217 | } |
218 | |
219 | #ifdef CONFIG_64BIT |
220 | static void iomem_write64(u64 datum, void __iomem *addr) |
221 | { |
222 | writeq(val: datum, addr); |
223 | } |
224 | |
225 | static void iomem_write64be(u64 datum, void __iomem *addr) |
226 | { |
227 | __raw_writeq(val: datum, addr); |
228 | } |
229 | #endif |
230 | |
231 | static void iomem_read8r(const void __iomem *addr, void *dst, unsigned long count) |
232 | { |
233 | while (count--) { |
234 | *(u8 *)dst = __raw_readb(addr); |
235 | dst++; |
236 | } |
237 | } |
238 | |
239 | static void iomem_read16r(const void __iomem *addr, void *dst, unsigned long count) |
240 | { |
241 | while (count--) { |
242 | *(u16 *)dst = __raw_readw(addr); |
243 | dst += 2; |
244 | } |
245 | } |
246 | |
247 | static void iomem_read32r(const void __iomem *addr, void *dst, unsigned long count) |
248 | { |
249 | while (count--) { |
250 | *(u32 *)dst = __raw_readl(addr); |
251 | dst += 4; |
252 | } |
253 | } |
254 | |
255 | static void iomem_write8r(void __iomem *addr, const void *s, unsigned long n) |
256 | { |
257 | while (n--) { |
258 | __raw_writeb(val: *(u8 *)s, addr); |
259 | s++; |
260 | } |
261 | } |
262 | |
263 | static void iomem_write16r(void __iomem *addr, const void *s, unsigned long n) |
264 | { |
265 | while (n--) { |
266 | __raw_writew(val: *(u16 *)s, addr); |
267 | s += 2; |
268 | } |
269 | } |
270 | |
271 | static void iomem_write32r(void __iomem *addr, const void *s, unsigned long n) |
272 | { |
273 | while (n--) { |
274 | __raw_writel(val: *(u32 *)s, addr); |
275 | s += 4; |
276 | } |
277 | } |
278 | |
279 | static const struct iomap_ops iomem_ops = { |
280 | .read8 = iomem_read8, |
281 | .read16 = iomem_read16, |
282 | .read16be = iomem_read16be, |
283 | .read32 = iomem_read32, |
284 | .read32be = iomem_read32be, |
285 | #ifdef CONFIG_64BIT |
286 | .read64 = iomem_read64, |
287 | .read64be = iomem_read64be, |
288 | #endif |
289 | .write8 = iomem_write8, |
290 | .write16 = iomem_write16, |
291 | .write16be = iomem_write16be, |
292 | .write32 = iomem_write32, |
293 | .write32be = iomem_write32be, |
294 | #ifdef CONFIG_64BIT |
295 | .write64 = iomem_write64, |
296 | .write64be = iomem_write64be, |
297 | #endif |
298 | .read8r = iomem_read8r, |
299 | .read16r = iomem_read16r, |
300 | .read32r = iomem_read32r, |
301 | .write8r = iomem_write8r, |
302 | .write16r = iomem_write16r, |
303 | .write32r = iomem_write32r, |
304 | }; |
305 | |
306 | static const struct iomap_ops *iomap_ops[8] = { |
307 | [0] = &ioport_ops, |
308 | [7] = &iomem_ops |
309 | }; |
310 | |
311 | |
312 | unsigned int ioread8(const void __iomem *addr) |
313 | { |
314 | if (unlikely(INDIRECT_ADDR(addr))) |
315 | return iomap_ops[ADDR_TO_REGION(addr)]->read8(addr); |
316 | return *((u8 *)addr); |
317 | } |
318 | |
319 | unsigned int ioread16(const void __iomem *addr) |
320 | { |
321 | if (unlikely(INDIRECT_ADDR(addr))) |
322 | return iomap_ops[ADDR_TO_REGION(addr)]->read16(addr); |
323 | return le16_to_cpup(p: (u16 *)addr); |
324 | } |
325 | |
326 | unsigned int ioread16be(const void __iomem *addr) |
327 | { |
328 | if (unlikely(INDIRECT_ADDR(addr))) |
329 | return iomap_ops[ADDR_TO_REGION(addr)]->read16be(addr); |
330 | return *((u16 *)addr); |
331 | } |
332 | |
333 | unsigned int ioread32(const void __iomem *addr) |
334 | { |
335 | if (unlikely(INDIRECT_ADDR(addr))) |
336 | return iomap_ops[ADDR_TO_REGION(addr)]->read32(addr); |
337 | return le32_to_cpup(p: (u32 *)addr); |
338 | } |
339 | |
340 | unsigned int ioread32be(const void __iomem *addr) |
341 | { |
342 | if (unlikely(INDIRECT_ADDR(addr))) |
343 | return iomap_ops[ADDR_TO_REGION(addr)]->read32be(addr); |
344 | return *((u32 *)addr); |
345 | } |
346 | |
347 | #ifdef CONFIG_64BIT |
348 | u64 ioread64(const void __iomem *addr) |
349 | { |
350 | if (unlikely(INDIRECT_ADDR(addr))) |
351 | return iomap_ops[ADDR_TO_REGION(addr)]->read64(addr); |
352 | return le64_to_cpup(p: (u64 *)addr); |
353 | } |
354 | |
355 | u64 ioread64be(const void __iomem *addr) |
356 | { |
357 | if (unlikely(INDIRECT_ADDR(addr))) |
358 | return iomap_ops[ADDR_TO_REGION(addr)]->read64be(addr); |
359 | return *((u64 *)addr); |
360 | } |
361 | #endif |
362 | |
363 | void iowrite8(u8 datum, void __iomem *addr) |
364 | { |
365 | if (unlikely(INDIRECT_ADDR(addr))) { |
366 | iomap_ops[ADDR_TO_REGION(addr)]->write8(datum, addr); |
367 | } else { |
368 | *((u8 *)addr) = datum; |
369 | } |
370 | } |
371 | |
372 | void iowrite16(u16 datum, void __iomem *addr) |
373 | { |
374 | if (unlikely(INDIRECT_ADDR(addr))) { |
375 | iomap_ops[ADDR_TO_REGION(addr)]->write16(datum, addr); |
376 | } else { |
377 | *((u16 *)addr) = cpu_to_le16(datum); |
378 | } |
379 | } |
380 | |
381 | void iowrite16be(u16 datum, void __iomem *addr) |
382 | { |
383 | if (unlikely(INDIRECT_ADDR(addr))) { |
384 | iomap_ops[ADDR_TO_REGION(addr)]->write16be(datum, addr); |
385 | } else { |
386 | *((u16 *)addr) = datum; |
387 | } |
388 | } |
389 | |
390 | void iowrite32(u32 datum, void __iomem *addr) |
391 | { |
392 | if (unlikely(INDIRECT_ADDR(addr))) { |
393 | iomap_ops[ADDR_TO_REGION(addr)]->write32(datum, addr); |
394 | } else { |
395 | *((u32 *)addr) = cpu_to_le32(datum); |
396 | } |
397 | } |
398 | |
399 | void iowrite32be(u32 datum, void __iomem *addr) |
400 | { |
401 | if (unlikely(INDIRECT_ADDR(addr))) { |
402 | iomap_ops[ADDR_TO_REGION(addr)]->write32be(datum, addr); |
403 | } else { |
404 | *((u32 *)addr) = datum; |
405 | } |
406 | } |
407 | |
408 | #ifdef CONFIG_64BIT |
409 | void iowrite64(u64 datum, void __iomem *addr) |
410 | { |
411 | if (unlikely(INDIRECT_ADDR(addr))) { |
412 | iomap_ops[ADDR_TO_REGION(addr)]->write64(datum, addr); |
413 | } else { |
414 | *((u64 *)addr) = cpu_to_le64(datum); |
415 | } |
416 | } |
417 | |
418 | void iowrite64be(u64 datum, void __iomem *addr) |
419 | { |
420 | if (unlikely(INDIRECT_ADDR(addr))) { |
421 | iomap_ops[ADDR_TO_REGION(addr)]->write64be(datum, addr); |
422 | } else { |
423 | *((u64 *)addr) = datum; |
424 | } |
425 | } |
426 | #endif |
427 | |
428 | /* Repeating interfaces */ |
429 | |
430 | void ioread8_rep(const void __iomem *addr, void *dst, unsigned long count) |
431 | { |
432 | if (unlikely(INDIRECT_ADDR(addr))) { |
433 | iomap_ops[ADDR_TO_REGION(addr)]->read8r(addr, dst, count); |
434 | } else { |
435 | while (count--) { |
436 | *(u8 *)dst = *(u8 *)addr; |
437 | dst++; |
438 | } |
439 | } |
440 | } |
441 | |
442 | void ioread16_rep(const void __iomem *addr, void *dst, unsigned long count) |
443 | { |
444 | if (unlikely(INDIRECT_ADDR(addr))) { |
445 | iomap_ops[ADDR_TO_REGION(addr)]->read16r(addr, dst, count); |
446 | } else { |
447 | while (count--) { |
448 | *(u16 *)dst = *(u16 *)addr; |
449 | dst += 2; |
450 | } |
451 | } |
452 | } |
453 | |
454 | void ioread32_rep(const void __iomem *addr, void *dst, unsigned long count) |
455 | { |
456 | if (unlikely(INDIRECT_ADDR(addr))) { |
457 | iomap_ops[ADDR_TO_REGION(addr)]->read32r(addr, dst, count); |
458 | } else { |
459 | while (count--) { |
460 | *(u32 *)dst = *(u32 *)addr; |
461 | dst += 4; |
462 | } |
463 | } |
464 | } |
465 | |
466 | void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count) |
467 | { |
468 | if (unlikely(INDIRECT_ADDR(addr))) { |
469 | iomap_ops[ADDR_TO_REGION(addr)]->write8r(addr, src, count); |
470 | } else { |
471 | while (count--) { |
472 | *(u8 *)addr = *(u8 *)src; |
473 | src++; |
474 | } |
475 | } |
476 | } |
477 | |
478 | void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count) |
479 | { |
480 | if (unlikely(INDIRECT_ADDR(addr))) { |
481 | iomap_ops[ADDR_TO_REGION(addr)]->write16r(addr, src, count); |
482 | } else { |
483 | while (count--) { |
484 | *(u16 *)addr = *(u16 *)src; |
485 | src += 2; |
486 | } |
487 | } |
488 | } |
489 | |
490 | void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count) |
491 | { |
492 | if (unlikely(INDIRECT_ADDR(addr))) { |
493 | iomap_ops[ADDR_TO_REGION(addr)]->write32r(addr, src, count); |
494 | } else { |
495 | while (count--) { |
496 | *(u32 *)addr = *(u32 *)src; |
497 | src += 4; |
498 | } |
499 | } |
500 | } |
501 | |
502 | /* Mapping interfaces */ |
503 | |
504 | void __iomem *ioport_map(unsigned long port, unsigned int nr) |
505 | { |
506 | return (void __iomem *)(IOPORT_MAP_BASE | port); |
507 | } |
508 | |
509 | void ioport_unmap(void __iomem *addr) |
510 | { |
511 | if (!INDIRECT_ADDR(addr)) { |
512 | iounmap(addr); |
513 | } |
514 | } |
515 | |
516 | #ifdef CONFIG_PCI |
517 | void pci_iounmap(struct pci_dev *dev, void __iomem * addr) |
518 | { |
519 | if (!INDIRECT_ADDR(addr)) { |
520 | iounmap(addr); |
521 | } |
522 | } |
523 | EXPORT_SYMBOL(pci_iounmap); |
524 | #endif |
525 | |
526 | EXPORT_SYMBOL(ioread8); |
527 | EXPORT_SYMBOL(ioread16); |
528 | EXPORT_SYMBOL(ioread16be); |
529 | EXPORT_SYMBOL(ioread32); |
530 | EXPORT_SYMBOL(ioread32be); |
531 | #ifdef CONFIG_64BIT |
532 | EXPORT_SYMBOL(ioread64); |
533 | EXPORT_SYMBOL(ioread64be); |
534 | #endif |
535 | EXPORT_SYMBOL(iowrite8); |
536 | EXPORT_SYMBOL(iowrite16); |
537 | EXPORT_SYMBOL(iowrite16be); |
538 | EXPORT_SYMBOL(iowrite32); |
539 | EXPORT_SYMBOL(iowrite32be); |
540 | #ifdef CONFIG_64BIT |
541 | EXPORT_SYMBOL(iowrite64); |
542 | EXPORT_SYMBOL(iowrite64be); |
543 | #endif |
544 | EXPORT_SYMBOL(ioread8_rep); |
545 | EXPORT_SYMBOL(ioread16_rep); |
546 | EXPORT_SYMBOL(ioread32_rep); |
547 | EXPORT_SYMBOL(iowrite8_rep); |
548 | EXPORT_SYMBOL(iowrite16_rep); |
549 | EXPORT_SYMBOL(iowrite32_rep); |
550 | EXPORT_SYMBOL(ioport_map); |
551 | EXPORT_SYMBOL(ioport_unmap); |
552 | |