Merge branch 'origin'
[pandora-kernel.git] / arch / sh / boards / superh / microdev / io.c
1 /*
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>
19 #include <asm/microdev.h>
20
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
55 /*
56  * map I/O ports to memory-mapped addresses
57  */
58 static unsigned long microdev_isa_port2addr(unsigned long offset)
59 {
60         unsigned long result;
61
62         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))
139
140 static 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
152 unsigned 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
161 unsigned 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
170 unsigned 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
179 void 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
190 void 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
254 void 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
265 unsigned char microdev_inb_p(unsigned long port)
266 {
267         unsigned char v = microdev_inb(port);
268         delay();
269         return v;
270 }
271
272 unsigned short microdev_inw_p(unsigned long port)
273 {
274         unsigned short v = microdev_inw(port);
275         delay();
276         return v;
277 }
278
279 unsigned int microdev_inl_p(unsigned long port)
280 {
281         unsigned int v = microdev_inl(port);
282         delay();
283         return v;
284 }
285
286 void microdev_outb_p(unsigned char b, unsigned long port)
287 {
288         microdev_outb(b, port);
289         delay();
290 }
291
292 void microdev_outw_p(unsigned short b, unsigned long port)
293 {
294         microdev_outw(b, port);
295         delay();
296 }
297
298 void microdev_outl_p(unsigned int b, unsigned long port)
299 {
300         microdev_outl(b, port);
301         delay();
302 }
303
304 void 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
315 void 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
326 void 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
337 void 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
348 void 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
359 void 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 }