blob: 1ed7f880b8c722142deb87cbdbb7be501c0caf94 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/sh/kernel/io_microdev.c
3 *
4 * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
5 * Copyright (C) 2003, 2004 SuperH, Inc.
6 * Copyright (C) 2004 Paul Mundt
7 *
8 * SuperH SH4-202 MicroDev board support.
9 *
10 * May be copied or modified under the terms of the GNU General Public
11 * License. See linux/COPYING for more information.
12 */
13
14#include <linux/config.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17#include <linux/wait.h>
18#include <asm/io.h>
Paul Mundt74017292006-02-01 03:05:59 -080019#include <asm/microdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
21 /*
22 * we need to have a 'safe' address to re-direct all I/O requests
23 * that we do not explicitly wish to handle. This safe address
24 * must have the following properies:
25 *
26 * * writes are ignored (no exception)
27 * * reads are benign (no side-effects)
28 * * accesses of width 1, 2 and 4-bytes are all valid.
29 *
30 * The Processor Version Register (PVR) has these properties.
31 */
32#define PVR 0xff000030 /* Processor Version Register */
33
34
35#define IO_IDE2_BASE 0x170ul /* I/O base for SMSC FDC37C93xAPM IDE #2 */
36#define IO_IDE1_BASE 0x1f0ul /* I/O base for SMSC FDC37C93xAPM IDE #1 */
37#define IO_ISP1161_BASE 0x290ul /* I/O port for Philips ISP1161x USB chip */
38#define IO_SERIAL2_BASE 0x2f8ul /* I/O base for SMSC FDC37C93xAPM Serial #2 */
39#define IO_LAN91C111_BASE 0x300ul /* I/O base for SMSC LAN91C111 Ethernet chip */
40#define IO_IDE2_MISC 0x376ul /* I/O misc for SMSC FDC37C93xAPM IDE #2 */
41#define IO_SUPERIO_BASE 0x3f0ul /* I/O base for SMSC FDC37C93xAPM SuperIO chip */
42#define IO_IDE1_MISC 0x3f6ul /* I/O misc for SMSC FDC37C93xAPM IDE #1 */
43#define IO_SERIAL1_BASE 0x3f8ul /* I/O base for SMSC FDC37C93xAPM Serial #1 */
44
45#define IO_ISP1161_EXTENT 0x04ul /* I/O extent for Philips ISP1161x USB chip */
46#define IO_LAN91C111_EXTENT 0x10ul /* I/O extent for SMSC LAN91C111 Ethernet chip */
47#define IO_SUPERIO_EXTENT 0x02ul /* I/O extent for SMSC FDC37C93xAPM SuperIO chip */
48#define IO_IDE_EXTENT 0x08ul /* I/O extent for IDE Task Register set */
49#define IO_SERIAL_EXTENT 0x10ul
50
51#define IO_LAN91C111_PHYS 0xa7500000ul /* Physical address of SMSC LAN91C111 Ethernet chip */
52#define IO_ISP1161_PHYS 0xa7700000ul /* Physical address of Philips ISP1161x USB chip */
53#define IO_SUPERIO_PHYS 0xa7800000ul /* Physical address of SMSC FDC37C93xAPM SuperIO chip */
54
Paul Mundt74017292006-02-01 03:05:59 -080055/*
56 * map I/O ports to memory-mapped addresses
57 */
58static unsigned long microdev_isa_port2addr(unsigned long offset)
59{
60 unsigned long result;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Paul Mundt74017292006-02-01 03:05:59 -080062 if ((offset >= IO_LAN91C111_BASE) &&
63 (offset < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
64 /*
65 * SMSC LAN91C111 Ethernet chip
66 */
67 result = IO_LAN91C111_PHYS + offset - IO_LAN91C111_BASE;
68 } else if ((offset >= IO_SUPERIO_BASE) &&
69 (offset < IO_SUPERIO_BASE + IO_SUPERIO_EXTENT)) {
70 /*
71 * SMSC FDC37C93xAPM SuperIO chip
72 *
73 * Configuration Registers
74 */
75 result = IO_SUPERIO_PHYS + (offset << 1);
76#if 0
77 } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
78 offset == KBD_STATUS_REG) {
79 /*
80 * SMSC FDC37C93xAPM SuperIO chip
81 *
82 * PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
83 */
84 result = IO_SUPERIO_PHYS + (offset << 1);
85#endif
86 } else if (((offset >= IO_IDE1_BASE) &&
87 (offset < IO_IDE1_BASE + IO_IDE_EXTENT)) ||
88 (offset == IO_IDE1_MISC)) {
89 /*
90 * SMSC FDC37C93xAPM SuperIO chip
91 *
92 * IDE #1
93 */
94 result = IO_SUPERIO_PHYS + (offset << 1);
95 } else if (((offset >= IO_IDE2_BASE) &&
96 (offset < IO_IDE2_BASE + IO_IDE_EXTENT)) ||
97 (offset == IO_IDE2_MISC)) {
98 /*
99 * SMSC FDC37C93xAPM SuperIO chip
100 *
101 * IDE #2
102 */
103 result = IO_SUPERIO_PHYS + (offset << 1);
104 } else if ((offset >= IO_SERIAL1_BASE) &&
105 (offset < IO_SERIAL1_BASE + IO_SERIAL_EXTENT)) {
106 /*
107 * SMSC FDC37C93xAPM SuperIO chip
108 *
109 * Serial #1
110 */
111 result = IO_SUPERIO_PHYS + (offset << 1);
112 } else if ((offset >= IO_SERIAL2_BASE) &&
113 (offset < IO_SERIAL2_BASE + IO_SERIAL_EXTENT)) {
114 /*
115 * SMSC FDC37C93xAPM SuperIO chip
116 *
117 * Serial #2
118 */
119 result = IO_SUPERIO_PHYS + (offset << 1);
120 } else if ((offset >= IO_ISP1161_BASE) &&
121 (offset < IO_ISP1161_BASE + IO_ISP1161_EXTENT)) {
122 /*
123 * Philips USB ISP1161x chip
124 */
125 result = IO_ISP1161_PHYS + offset - IO_ISP1161_BASE;
126 } else {
127 /*
128 * safe default.
129 */
130 printk("Warning: unexpected port in %s( offset = 0x%lx )\n",
131 __FUNCTION__, offset);
132 result = PVR;
133 }
134
135 return result;
136}
137
138#define PORT2ADDR(x) (microdev_isa_port2addr(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140static inline void delay(void)
141{
142#if defined(CONFIG_PCI)
143 /* System board present, just make a dummy SRAM access. (CS0 will be
144 mapped to PCI memory, probably good to avoid it.) */
145 ctrl_inw(0xa6800000);
146#else
147 /* CS0 will be mapped to flash, ROM etc so safe to access it. */
148 ctrl_inw(0xa0000000);
149#endif
150}
151
152unsigned char microdev_inb(unsigned long port)
153{
154#ifdef CONFIG_PCI
155 if (port >= PCIBIOS_MIN_IO)
156 return microdev_pci_inb(port);
157#endif
158 return *(volatile unsigned char*)PORT2ADDR(port);
159}
160
161unsigned short microdev_inw(unsigned long port)
162{
163#ifdef CONFIG_PCI
164 if (port >= PCIBIOS_MIN_IO)
165 return microdev_pci_inw(port);
166#endif
167 return *(volatile unsigned short*)PORT2ADDR(port);
168}
169
170unsigned int microdev_inl(unsigned long port)
171{
172#ifdef CONFIG_PCI
173 if (port >= PCIBIOS_MIN_IO)
174 return microdev_pci_inl(port);
175#endif
176 return *(volatile unsigned int*)PORT2ADDR(port);
177}
178
Paul Mundt74017292006-02-01 03:05:59 -0800179void microdev_outw(unsigned short b, unsigned long port)
180{
181#ifdef CONFIG_PCI
182 if (port >= PCIBIOS_MIN_IO) {
183 microdev_pci_outw(b, port);
184 return;
185 }
186#endif
187 *(volatile unsigned short*)PORT2ADDR(port) = b;
188}
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190void microdev_outb(unsigned char b, unsigned long port)
191{
192#ifdef CONFIG_PCI
193 if (port >= PCIBIOS_MIN_IO) {
194 microdev_pci_outb(b, port);
195 return;
196 }
197#endif
198
199 /*
200 * There is a board feature with the current SH4-202 MicroDev in
201 * that the 2 byte enables (nBE0 and nBE1) are tied together (and
202 * to the Chip Select Line (Ethernet_CS)). Due to this conectivity,
203 * it is not possible to safely perform 8-bit writes to the
204 * Ethernet registers, as 16-bits will be consumed from the Data
205 * lines (corrupting the other byte). Hence, this function is
206 * written to impliment 16-bit read/modify/write for all byte-wide
207 * acceses.
208 *
209 * Note: there is no problem with byte READS (even or odd).
210 *
211 * Sean McGoogan - 16th June 2003.
212 */
213 if ((port >= IO_LAN91C111_BASE) &&
214 (port < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
215 /*
216 * Then are trying to perform a byte-write to the
217 * LAN91C111. This needs special care.
218 */
219 if (port % 2 == 1) { /* is the port odd ? */
220 /* unset bit-0, i.e. make even */
221 const unsigned long evenPort = port-1;
222 unsigned short word;
223
224 /*
225 * do a 16-bit read/write to write to 'port',
226 * preserving even byte.
227 *
228 * Even addresses are bits 0-7
229 * Odd addresses are bits 8-15
230 */
231 word = microdev_inw(evenPort);
232 word = (word & 0xffu) | (b << 8);
233 microdev_outw(word, evenPort);
234 } else {
235 /* else, we are trying to do an even byte write */
236 unsigned short word;
237
238 /*
239 * do a 16-bit read/write to write to 'port',
240 * preserving odd byte.
241 *
242 * Even addresses are bits 0-7
243 * Odd addresses are bits 8-15
244 */
245 word = microdev_inw(port);
246 word = (word & 0xff00u) | (b);
247 microdev_outw(word, port);
248 }
249 } else {
250 *(volatile unsigned char*)PORT2ADDR(port) = b;
251 }
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254void microdev_outl(unsigned int b, unsigned long port)
255{
256#ifdef CONFIG_PCI
257 if (port >= PCIBIOS_MIN_IO) {
258 microdev_pci_outl(b, port);
259 return;
260 }
261#endif
262 *(volatile unsigned int*)PORT2ADDR(port) = b;
263}
264
265unsigned char microdev_inb_p(unsigned long port)
266{
267 unsigned char v = microdev_inb(port);
268 delay();
269 return v;
270}
271
272unsigned short microdev_inw_p(unsigned long port)
273{
274 unsigned short v = microdev_inw(port);
275 delay();
276 return v;
277}
278
279unsigned int microdev_inl_p(unsigned long port)
280{
281 unsigned int v = microdev_inl(port);
282 delay();
283 return v;
284}
285
286void microdev_outb_p(unsigned char b, unsigned long port)
287{
288 microdev_outb(b, port);
289 delay();
290}
291
292void microdev_outw_p(unsigned short b, unsigned long port)
293{
294 microdev_outw(b, port);
295 delay();
296}
297
298void microdev_outl_p(unsigned int b, unsigned long port)
299{
300 microdev_outl(b, port);
301 delay();
302}
303
304void microdev_insb(unsigned long port, void *buffer, unsigned long count)
305{
306 volatile unsigned char *port_addr;
307 unsigned char *buf = buffer;
308
309 port_addr = (volatile unsigned char *)PORT2ADDR(port);
310
311 while (count--)
312 *buf++ = *port_addr;
313}
314
315void microdev_insw(unsigned long port, void *buffer, unsigned long count)
316{
317 volatile unsigned short *port_addr;
318 unsigned short *buf = buffer;
319
320 port_addr = (volatile unsigned short *)PORT2ADDR(port);
321
322 while (count--)
323 *buf++ = *port_addr;
324}
325
326void microdev_insl(unsigned long port, void *buffer, unsigned long count)
327{
328 volatile unsigned long *port_addr;
329 unsigned int *buf = buffer;
330
331 port_addr = (volatile unsigned long *)PORT2ADDR(port);
332
333 while (count--)
334 *buf++ = *port_addr;
335}
336
337void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
338{
339 volatile unsigned char *port_addr;
340 const unsigned char *buf = buffer;
341
342 port_addr = (volatile unsigned char *)PORT2ADDR(port);
343
344 while (count--)
345 *port_addr = *buf++;
346}
347
348void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
349{
350 volatile unsigned short *port_addr;
351 const unsigned short *buf = buffer;
352
353 port_addr = (volatile unsigned short *)PORT2ADDR(port);
354
355 while (count--)
356 *port_addr = *buf++;
357}
358
359void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
360{
361 volatile unsigned long *port_addr;
362 const unsigned int *buf = buffer;
363
364 port_addr = (volatile unsigned long *)PORT2ADDR(port);
365
366 while (count--)
367 *port_addr = *buf++;
368}