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