1 /*
2 * linux/arch/sh/kernel/io_microdev.c
3 *
4 * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
5 *
6 * SuperH SH4-202 MicroDev board support.
7 *
8 * May be copied or modified under the terms of the GNU General Public
9 * License. See linux/COPYING for more information.
10 */
11
12 #include <linux/config.h>
13 #include <linux/init.h>
14 #include <asm/io.h>
15
16
17 /*
18 * we need to have a 'safe' address to re-direct all I/O requests
19 * that we do not explicitly wish to handle. This safe address
20 * must have the following properies:
21 *
22 * * writes are ignored (no exception)
23 * * reads are benign (no side-effects)
24 * * accesses of width 1, 2 and 4-bytes are all valid.
25 *
26 * The Processor Version Register (PVR) has these properties.
27 */
28 #define PVR 0xff000030 /* Processor Version Register */
29
30
31 #define IO_LAN91C111 0x300ul /* I/O port for SMSC LAN91C111 Ethernet chip */
32
33 #define PORT2ADDR(x) (microdev_isa_port2addr(x))
34
35
delay(void)36 static inline void delay(void)
37 {
38 ctrl_inw(0xa0000000);
39 }
40
microdev_inb(unsigned long port)41 unsigned char microdev_inb(unsigned long port)
42 {
43 return *(volatile unsigned char*)PORT2ADDR(port);
44 }
45
microdev_inw(unsigned long port)46 unsigned short microdev_inw(unsigned long port)
47 {
48 return *(volatile unsigned short*)PORT2ADDR(port);
49 }
50
microdev_inl(unsigned long port)51 unsigned int microdev_inl(unsigned long port)
52 {
53 return *(volatile unsigned int*)PORT2ADDR(port);
54 }
55
microdev_outb(unsigned char b,unsigned long port)56 void microdev_outb(unsigned char b, unsigned long port)
57 {
58 /*
59 * There is a board feature with the current SH4-202 MicroDev
60 * in that the 2 byte enables (nBE0 and nBE1) are tied together (and to the
61 * Chip Select Line (Ethernet_CS)). Due to this conectivity, it is not possible
62 * to safely perform 8-bit writes to the Ethernet registers, as 16-bits
63 * will be consumed from the Data lines (corrupting the other byte).
64 * Hence, this function is written to impliment 16-bit read/modify/write
65 * for all byte-wide acceses.
66 *
67 * Note: there is no problem with byte READS (even or odd).
68 *
69 * Sean McGoogan - 16th June 2003.
70 */
71 if ( (port>=IO_LAN91C111) && (port<IO_LAN91C111+0x10ul) )
72 {
73 /*
74 * Then are trying to perform a byte-write to the LAN91C111.
75 * This needs special care.
76 */
77 if (port%2==1) /* is the port odd ? */
78 {
79 const unsigned long evenPort = port-1; /* unset bit-0, i.e. make even */
80 unsigned short word; /* temp variable */
81 /*
82 * do a 16-bit read/write to write to 'port', preserving even byte.
83 * Even addresses are bits 0-7
84 * Odd addresses are bits 8-15
85 */
86 word = microdev_inw(evenPort);
87 word = (word & 0xffu) | (b << 8);
88 microdev_outw(word, evenPort);
89 }
90 else /* else, we are trying to do an even byte write */
91 {
92 unsigned short word; /* temp variable */
93 /*
94 * do a 16-bit read/write to write to 'port', preserving odd byte.
95 * Even addresses are bits 0-7
96 * Odd addresses are bits 8-15
97 */
98 word = microdev_inw(port);
99 word = (word & 0xff00u) | (b);
100 microdev_outw(word, port);
101 }
102 }
103 else
104 {
105 *(volatile unsigned char*)PORT2ADDR(port) = b;
106 }
107 }
108
microdev_outw(unsigned short b,unsigned long port)109 void microdev_outw(unsigned short b, unsigned long port)
110 {
111 *(volatile unsigned short*)PORT2ADDR(port) = b;
112 }
113
microdev_outl(unsigned int b,unsigned long port)114 void microdev_outl(unsigned int b, unsigned long port)
115 {
116 *(volatile unsigned int*)PORT2ADDR(port) = b;
117 }
118
microdev_inb_p(unsigned long port)119 unsigned char microdev_inb_p(unsigned long port)
120 {
121 unsigned char v = microdev_inb(port);
122 delay();
123 return v;
124 }
125
microdev_inw_p(unsigned long port)126 unsigned short microdev_inw_p(unsigned long port)
127 {
128 unsigned short v = microdev_inw(port);
129 delay();
130 return v;
131 }
132
microdev_inl_p(unsigned long port)133 unsigned int microdev_inl_p(unsigned long port)
134 {
135 unsigned int v = microdev_inl(port);
136 delay();
137 return v;
138 }
139
microdev_outb_p(unsigned char b,unsigned long port)140 void microdev_outb_p(unsigned char b, unsigned long port)
141 {
142 microdev_outb(b, port);
143 delay();
144 }
145
microdev_outw_p(unsigned short b,unsigned long port)146 void microdev_outw_p(unsigned short b, unsigned long port)
147 {
148 microdev_outw(b, port);
149 delay();
150 }
151
microdev_outl_p(unsigned int b,unsigned long port)152 void microdev_outl_p(unsigned int b, unsigned long port)
153 {
154 microdev_outl(b, port);
155 delay();
156 }
157
microdev_insb(unsigned long port,void * buffer,unsigned long count)158 void microdev_insb(unsigned long port, void *buffer, unsigned long count)
159 {
160 unsigned char *buf=buffer;
161 while(count--) *buf++=microdev_inb(port);
162 }
163
microdev_insw(unsigned long port,void * buffer,unsigned long count)164 void microdev_insw(unsigned long port, void *buffer, unsigned long count)
165 {
166 unsigned short *buf=buffer;
167 while(count--) *buf++=microdev_inw(port);
168 }
169
microdev_insl(unsigned long port,void * buffer,unsigned long count)170 void microdev_insl(unsigned long port, void *buffer, unsigned long count)
171 {
172 unsigned int *buf=buffer;
173 while(count--) *buf++=microdev_inl(port);
174 }
175
microdev_outsb(unsigned long port,const void * buffer,unsigned long count)176 void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
177 {
178 const unsigned char *buf=buffer;
179 while(count--) microdev_outb(*buf++, port);
180 }
181
microdev_outsw(unsigned long port,const void * buffer,unsigned long count)182 void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
183 {
184 const unsigned short *buf=buffer;
185 while(count--) microdev_outw(*buf++, port);
186 }
187
microdev_outsl(unsigned long port,const void * buffer,unsigned long count)188 void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
189 {
190 const unsigned int *buf=buffer;
191 while(count--) microdev_outl(*buf++, port);
192 }
193
194
195 /*
196 * map I/O ports to memory-mapped addresses
197 */
microdev_isa_port2addr(unsigned long offset)198 unsigned long microdev_isa_port2addr(unsigned long offset)
199 {
200 unsigned long result;
201
202 if ( (offset>=IO_LAN91C111) && (offset<IO_LAN91C111+0x10ul) )
203 {
204 /*
205 * SMSC LAN91C111 Ethernet chip
206 */
207 result = 0xa7500000ul + offset - IO_LAN91C111;
208 }
209 else /* if (offset <= 0xfffful) */
210 {
211 /*
212 * safe default.
213 */
214 result = PVR;
215 }
216
217 return result;
218 }
219
220