Commit | Line | Data |
---|---|---|
9c57548f PM |
1 | /* |
2 | * arch/sh/kernel/io_generic.c | |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 2000 Niibe Yutaka | |
9c57548f | 5 | * Copyright (C) 2005 - 2007 Paul Mundt |
1da177e4 LT |
6 | * |
7 | * Generic I/O routine. These can be used where a machine specific version | |
8 | * is not required. | |
9 | * | |
10 | * This file is subject to the terms and conditions of the GNU General Public | |
11 | * License. See the file "COPYING" in the main directory of this archive | |
12 | * for more details. | |
1da177e4 | 13 | */ |
b66c1a39 | 14 | #include <linux/module.h> |
9c57548f | 15 | #include <linux/io.h> |
1da177e4 | 16 | #include <asm/machvec.h> |
1da177e4 | 17 | |
b66c1a39 PM |
18 | #ifdef CONFIG_CPU_SH3 |
19 | /* SH3 has a PCMCIA bug that needs a dummy read from area 6 for a | |
20 | * workaround. */ | |
1da177e4 | 21 | /* I'm not sure SH7709 has this kind of bug */ |
b66c1a39 PM |
22 | #define dummy_read() ctrl_inb(0xba000000) |
23 | #else | |
24 | #define dummy_read() | |
1da177e4 LT |
25 | #endif |
26 | ||
1da177e4 LT |
27 | unsigned long generic_io_base; |
28 | ||
29 | static inline void delay(void) | |
30 | { | |
31 | ctrl_inw(0xa0000000); | |
32 | } | |
33 | ||
b66c1a39 | 34 | u8 generic_inb(unsigned long port) |
1da177e4 | 35 | { |
b66c1a39 | 36 | return ctrl_inb((unsigned long __force)ioport_map(port, 1)); |
1da177e4 LT |
37 | } |
38 | ||
b66c1a39 | 39 | u16 generic_inw(unsigned long port) |
1da177e4 | 40 | { |
b66c1a39 | 41 | return ctrl_inw((unsigned long __force)ioport_map(port, 2)); |
1da177e4 LT |
42 | } |
43 | ||
b66c1a39 | 44 | u32 generic_inl(unsigned long port) |
1da177e4 | 45 | { |
b66c1a39 | 46 | return ctrl_inl((unsigned long __force)ioport_map(port, 4)); |
1da177e4 LT |
47 | } |
48 | ||
b66c1a39 | 49 | u8 generic_inb_p(unsigned long port) |
1da177e4 | 50 | { |
b66c1a39 | 51 | unsigned long v = generic_inb(port); |
1da177e4 LT |
52 | |
53 | delay(); | |
54 | return v; | |
55 | } | |
56 | ||
b66c1a39 | 57 | u16 generic_inw_p(unsigned long port) |
1da177e4 | 58 | { |
b66c1a39 | 59 | unsigned long v = generic_inw(port); |
1da177e4 LT |
60 | |
61 | delay(); | |
62 | return v; | |
63 | } | |
64 | ||
b66c1a39 | 65 | u32 generic_inl_p(unsigned long port) |
1da177e4 | 66 | { |
b66c1a39 | 67 | unsigned long v = generic_inl(port); |
1da177e4 LT |
68 | |
69 | delay(); | |
70 | return v; | |
71 | } | |
72 | ||
73 | /* | |
74 | * insb/w/l all read a series of bytes/words/longs from a fixed port | |
75 | * address. However as the port address doesn't change we only need to | |
76 | * convert the port address to real address once. | |
77 | */ | |
78 | ||
b66c1a39 | 79 | void generic_insb(unsigned long port, void *dst, unsigned long count) |
1da177e4 | 80 | { |
b66c1a39 PM |
81 | volatile u8 *port_addr; |
82 | u8 *buf = dst; | |
1da177e4 | 83 | |
b66c1a39 PM |
84 | port_addr = (volatile u8 *)ioport_map(port, 1); |
85 | while (count--) | |
86 | *buf++ = *port_addr; | |
1da177e4 LT |
87 | } |
88 | ||
b66c1a39 | 89 | void generic_insw(unsigned long port, void *dst, unsigned long count) |
1da177e4 | 90 | { |
b66c1a39 PM |
91 | volatile u16 *port_addr; |
92 | u16 *buf = dst; | |
1da177e4 | 93 | |
b66c1a39 PM |
94 | port_addr = (volatile u16 *)ioport_map(port, 2); |
95 | while (count--) | |
96 | *buf++ = *port_addr; | |
1da177e4 | 97 | |
b66c1a39 | 98 | dummy_read(); |
1da177e4 LT |
99 | } |
100 | ||
b66c1a39 | 101 | void generic_insl(unsigned long port, void *dst, unsigned long count) |
1da177e4 | 102 | { |
b66c1a39 PM |
103 | volatile u32 *port_addr; |
104 | u32 *buf = dst; | |
1da177e4 | 105 | |
b66c1a39 PM |
106 | port_addr = (volatile u32 *)ioport_map(port, 4); |
107 | while (count--) | |
108 | *buf++ = *port_addr; | |
1da177e4 | 109 | |
b66c1a39 | 110 | dummy_read(); |
1da177e4 LT |
111 | } |
112 | ||
b66c1a39 | 113 | void generic_outb(u8 b, unsigned long port) |
1da177e4 | 114 | { |
b66c1a39 | 115 | ctrl_outb(b, (unsigned long __force)ioport_map(port, 1)); |
1da177e4 LT |
116 | } |
117 | ||
b66c1a39 | 118 | void generic_outw(u16 b, unsigned long port) |
1da177e4 | 119 | { |
b66c1a39 | 120 | ctrl_outw(b, (unsigned long __force)ioport_map(port, 2)); |
1da177e4 LT |
121 | } |
122 | ||
b66c1a39 | 123 | void generic_outl(u32 b, unsigned long port) |
1da177e4 | 124 | { |
b66c1a39 | 125 | ctrl_outl(b, (unsigned long __force)ioport_map(port, 4)); |
1da177e4 LT |
126 | } |
127 | ||
b66c1a39 | 128 | void generic_outb_p(u8 b, unsigned long port) |
1da177e4 | 129 | { |
b66c1a39 | 130 | generic_outb(b, port); |
1da177e4 LT |
131 | delay(); |
132 | } | |
133 | ||
b66c1a39 | 134 | void generic_outw_p(u16 b, unsigned long port) |
1da177e4 | 135 | { |
b66c1a39 | 136 | generic_outw(b, port); |
1da177e4 LT |
137 | delay(); |
138 | } | |
139 | ||
b66c1a39 | 140 | void generic_outl_p(u32 b, unsigned long port) |
1da177e4 | 141 | { |
b66c1a39 | 142 | generic_outl(b, port); |
1da177e4 LT |
143 | delay(); |
144 | } | |
145 | ||
146 | /* | |
147 | * outsb/w/l all write a series of bytes/words/longs to a fixed port | |
148 | * address. However as the port address doesn't change we only need to | |
149 | * convert the port address to real address once. | |
150 | */ | |
b66c1a39 | 151 | void generic_outsb(unsigned long port, const void *src, unsigned long count) |
1da177e4 | 152 | { |
b66c1a39 PM |
153 | volatile u8 *port_addr; |
154 | const u8 *buf = src; | |
1da177e4 | 155 | |
b66c1a39 | 156 | port_addr = (volatile u8 __force *)ioport_map(port, 1); |
1da177e4 | 157 | |
b66c1a39 PM |
158 | while (count--) |
159 | *port_addr = *buf++; | |
1da177e4 LT |
160 | } |
161 | ||
b66c1a39 | 162 | void generic_outsw(unsigned long port, const void *src, unsigned long count) |
1da177e4 | 163 | { |
b66c1a39 PM |
164 | volatile u16 *port_addr; |
165 | const u16 *buf = src; | |
1da177e4 | 166 | |
b66c1a39 | 167 | port_addr = (volatile u16 __force *)ioport_map(port, 2); |
1da177e4 | 168 | |
b66c1a39 PM |
169 | while (count--) |
170 | *port_addr = *buf++; | |
1da177e4 | 171 | |
b66c1a39 | 172 | dummy_read(); |
1da177e4 LT |
173 | } |
174 | ||
b66c1a39 | 175 | void generic_outsl(unsigned long port, const void *src, unsigned long count) |
1da177e4 | 176 | { |
b66c1a39 PM |
177 | volatile u32 *port_addr; |
178 | const u32 *buf = src; | |
1da177e4 | 179 | |
b66c1a39 PM |
180 | port_addr = (volatile u32 __force *)ioport_map(port, 4); |
181 | while (count--) | |
182 | *port_addr = *buf++; | |
1da177e4 | 183 | |
b66c1a39 | 184 | dummy_read(); |
1da177e4 LT |
185 | } |
186 | ||
b66c1a39 | 187 | u8 generic_readb(void __iomem *addr) |
1da177e4 | 188 | { |
b66c1a39 | 189 | return ctrl_inb((unsigned long __force)addr); |
1da177e4 LT |
190 | } |
191 | ||
b66c1a39 | 192 | u16 generic_readw(void __iomem *addr) |
1da177e4 | 193 | { |
b66c1a39 | 194 | return ctrl_inw((unsigned long __force)addr); |
1da177e4 LT |
195 | } |
196 | ||
b66c1a39 | 197 | u32 generic_readl(void __iomem *addr) |
1da177e4 | 198 | { |
b66c1a39 | 199 | return ctrl_inl((unsigned long __force)addr); |
1da177e4 LT |
200 | } |
201 | ||
b66c1a39 | 202 | void generic_writeb(u8 b, void __iomem *addr) |
1da177e4 | 203 | { |
b66c1a39 | 204 | ctrl_outb(b, (unsigned long __force)addr); |
1da177e4 LT |
205 | } |
206 | ||
b66c1a39 | 207 | void generic_writew(u16 b, void __iomem *addr) |
1da177e4 | 208 | { |
b66c1a39 | 209 | ctrl_outw(b, (unsigned long __force)addr); |
1da177e4 LT |
210 | } |
211 | ||
b66c1a39 | 212 | void generic_writel(u32 b, void __iomem *addr) |
1da177e4 | 213 | { |
b66c1a39 | 214 | ctrl_outl(b, (unsigned long __force)addr); |
1da177e4 | 215 | } |
1da177e4 | 216 | |
b66c1a39 | 217 | void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) |
1da177e4 | 218 | { |
b66c1a39 | 219 | return (void __iomem *)(addr + generic_io_base); |
1da177e4 | 220 | } |
1da177e4 | 221 | |
b66c1a39 | 222 | void generic_ioport_unmap(void __iomem *addr) |
1da177e4 | 223 | { |
1da177e4 | 224 | } |