1 | /* $NetBSD: am79c930.c,v 1.16 2008/04/28 20:23:49 martin Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1999 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Bill Sommerfeld |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Am79c930 chip driver. |
34 | * |
35 | * This is used by the awi driver to use the shared |
36 | * memory attached to the 79c930 to communicate with the firmware running |
37 | * in the 930's on-board 80188 core. |
38 | * |
39 | * The 79c930 can be mapped into just I/O space, or also have a |
40 | * memory mapping; the mapping must be set up by the bus front-end |
41 | * before am79c930_init is called. |
42 | */ |
43 | |
44 | /* |
45 | * operations: |
46 | * |
47 | * read_8, read_16, read_32, read_64, read_bytes |
48 | * write_8, write_16, write_32, write_64, write_bytes |
49 | * (two versions, depending on whether memory-space or i/o space is in use). |
50 | * |
51 | * interrupt E.C. |
52 | * start isr |
53 | * end isr |
54 | */ |
55 | |
56 | #include <sys/cdefs.h> |
57 | #ifdef __NetBSD__ |
58 | __KERNEL_RCSID(0, "$NetBSD: am79c930.c,v 1.16 2008/04/28 20:23:49 martin Exp $" ); |
59 | #endif |
60 | #ifdef __FreeBSD__ |
61 | __FBSDID("$FreeBSD$" ); |
62 | #endif |
63 | |
64 | #include <sys/param.h> |
65 | #include <sys/systm.h> |
66 | #include <sys/endian.h> |
67 | #ifndef __FreeBSD__ |
68 | #include <sys/device.h> |
69 | #endif |
70 | |
71 | #include <sys/cpu.h> |
72 | #ifdef __FreeBSD__ |
73 | #include <machine/bus_pio.h> |
74 | #include <machine/bus_memio.h> |
75 | #endif |
76 | #include <sys/bus.h> |
77 | #ifdef __NetBSD__ |
78 | #include <sys/intr.h> |
79 | #endif |
80 | |
81 | #ifdef __NetBSD__ |
82 | #include <dev/ic/am79c930reg.h> |
83 | #include <dev/ic/am79c930var.h> |
84 | #endif |
85 | #ifdef __FreeBSD__ |
86 | #include <dev/awi/am79c930reg.h> |
87 | #include <dev/awi/am79c930var.h> |
88 | #endif |
89 | |
90 | #define AM930_DELAY(x) /*nothing*/ |
91 | |
92 | #ifndef __BUS_SPACE_HAS_STREAM_METHODS |
93 | #define bus_space_read_stream_2 bus_space_read_2 |
94 | #define bus_space_read_stream_4 bus_space_read_4 |
95 | #define bus_space_write_stream_2 bus_space_write_2 |
96 | #define bus_space_write_stream_4 bus_space_write_4 |
97 | #endif /* __BUS_SPACE_HAS_STREAM_METHODS */ |
98 | |
99 | void am79c930_regdump(struct am79c930_softc *sc); |
100 | |
101 | static void io_write_1(struct am79c930_softc *, u_int32_t, u_int8_t); |
102 | static void io_write_2(struct am79c930_softc *, u_int32_t, u_int16_t); |
103 | static void io_write_4(struct am79c930_softc *, u_int32_t, u_int32_t); |
104 | static void io_write_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); |
105 | |
106 | static u_int8_t io_read_1(struct am79c930_softc *, u_int32_t); |
107 | static u_int16_t io_read_2(struct am79c930_softc *, u_int32_t); |
108 | static u_int32_t io_read_4(struct am79c930_softc *, u_int32_t); |
109 | static void io_read_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); |
110 | |
111 | static void mem_write_1(struct am79c930_softc *, u_int32_t, u_int8_t); |
112 | static void mem_write_2(struct am79c930_softc *, u_int32_t, u_int16_t); |
113 | static void mem_write_4(struct am79c930_softc *, u_int32_t, u_int32_t); |
114 | static void mem_write_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); |
115 | |
116 | static u_int8_t mem_read_1(struct am79c930_softc *, u_int32_t); |
117 | static u_int16_t mem_read_2(struct am79c930_softc *, u_int32_t); |
118 | static u_int32_t mem_read_4(struct am79c930_softc *, u_int32_t); |
119 | static void mem_read_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); |
120 | |
121 | static struct am79c930_ops iospace_ops = { |
122 | io_write_1, |
123 | io_write_2, |
124 | io_write_4, |
125 | io_write_bytes, |
126 | io_read_1, |
127 | io_read_2, |
128 | io_read_4, |
129 | io_read_bytes |
130 | }; |
131 | |
132 | struct am79c930_ops memspace_ops = { |
133 | mem_write_1, |
134 | mem_write_2, |
135 | mem_write_4, |
136 | mem_write_bytes, |
137 | mem_read_1, |
138 | mem_read_2, |
139 | mem_read_4, |
140 | mem_read_bytes |
141 | }; |
142 | |
143 | static void |
144 | io_write_1( struct am79c930_softc *sc, u_int32_t off, u_int8_t val) |
145 | { |
146 | AM930_DELAY(1); |
147 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
148 | ((off>>8)& 0x7f)); |
149 | AM930_DELAY(1); |
150 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); |
151 | AM930_DELAY(1); |
152 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA, val); |
153 | AM930_DELAY(1); |
154 | } |
155 | |
156 | static void |
157 | io_write_2(struct am79c930_softc *sc, u_int32_t off, u_int16_t val) |
158 | { |
159 | AM930_DELAY(1); |
160 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
161 | ((off>>8)& 0x7f)); |
162 | AM930_DELAY(1); |
163 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); |
164 | AM930_DELAY(1); |
165 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA, val & 0xff); |
166 | AM930_DELAY(1); |
167 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA, (val>>8)&0xff); |
168 | AM930_DELAY(1); |
169 | } |
170 | |
171 | static void |
172 | io_write_4(struct am79c930_softc *sc, u_int32_t off, u_int32_t val) |
173 | { |
174 | AM930_DELAY(1); |
175 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
176 | ((off>>8)& 0x7f)); |
177 | AM930_DELAY(1); |
178 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); |
179 | AM930_DELAY(1); |
180 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,val & 0xff); |
181 | AM930_DELAY(1); |
182 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>8)&0xff); |
183 | AM930_DELAY(1); |
184 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>16)&0xff); |
185 | AM930_DELAY(1); |
186 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,(val>>24)&0xff); |
187 | AM930_DELAY(1); |
188 | } |
189 | |
190 | static void |
191 | io_write_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, |
192 | size_t len) |
193 | { |
194 | int i; |
195 | |
196 | AM930_DELAY(1); |
197 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
198 | ((off>>8)& 0x7f)); |
199 | AM930_DELAY(1); |
200 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_LMA_LO, (off&0xff)); |
201 | AM930_DELAY(1); |
202 | for (i=0; i<len; i++) |
203 | bus_space_write_1(sc->sc_iot,sc->sc_ioh,AM79C930_IODPA,ptr[i]); |
204 | } |
205 | |
206 | static u_int8_t |
207 | io_read_1(struct am79c930_softc *sc, u_int32_t off) |
208 | { |
209 | u_int8_t val; |
210 | |
211 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
212 | ((off>>8)& 0x7f)); |
213 | AM930_DELAY(1); |
214 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); |
215 | AM930_DELAY(1); |
216 | val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); |
217 | AM930_DELAY(1); |
218 | return val; |
219 | } |
220 | |
221 | static u_int16_t |
222 | io_read_2(struct am79c930_softc *sc, u_int32_t off) |
223 | { |
224 | u_int16_t val; |
225 | |
226 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
227 | ((off>>8)& 0x7f)); |
228 | AM930_DELAY(1); |
229 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); |
230 | AM930_DELAY(1); |
231 | val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); |
232 | AM930_DELAY(1); |
233 | val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8; |
234 | AM930_DELAY(1); |
235 | return val; |
236 | } |
237 | |
238 | static u_int32_t |
239 | io_read_4(struct am79c930_softc *sc, u_int32_t off) |
240 | { |
241 | u_int32_t val; |
242 | |
243 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
244 | ((off>>8)& 0x7f)); |
245 | AM930_DELAY(1); |
246 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); |
247 | AM930_DELAY(1); |
248 | val = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA); |
249 | AM930_DELAY(1); |
250 | val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 8; |
251 | AM930_DELAY(1); |
252 | val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 16; |
253 | AM930_DELAY(1); |
254 | val |= bus_space_read_1(sc->sc_iot, sc->sc_ioh, AM79C930_IODPA) << 24; |
255 | AM930_DELAY(1); |
256 | return val; |
257 | } |
258 | |
259 | static void |
260 | io_read_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, |
261 | size_t len) |
262 | { |
263 | int i; |
264 | |
265 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_HI, |
266 | ((off>>8)& 0x7f)); |
267 | AM930_DELAY(1); |
268 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_LMA_LO, (off&0xff)); |
269 | AM930_DELAY(1); |
270 | for (i=0; i<len; i++) |
271 | ptr[i] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, |
272 | AM79C930_IODPA); |
273 | } |
274 | |
275 | static void |
276 | mem_write_1(struct am79c930_softc *sc, u_int32_t off, u_int8_t val) |
277 | { |
278 | bus_space_write_1(sc->sc_memt, sc->sc_memh, off, val); |
279 | } |
280 | |
281 | static void |
282 | mem_write_2(struct am79c930_softc *sc, u_int32_t off, u_int16_t val) |
283 | { |
284 | bus_space_tag_t t = sc->sc_memt; |
285 | bus_space_handle_t h = sc->sc_memh; |
286 | |
287 | /* could be unaligned */ |
288 | if ((off & 0x1) == 0) |
289 | bus_space_write_stream_2(t, h, off, htole16(val)); |
290 | else { |
291 | bus_space_write_1(t, h, off, val & 0xff); |
292 | bus_space_write_1(t, h, off+1, (val >> 8) & 0xff); |
293 | } |
294 | } |
295 | |
296 | static void |
297 | mem_write_4(struct am79c930_softc *sc, u_int32_t off, u_int32_t val) |
298 | { |
299 | bus_space_tag_t t = sc->sc_memt; |
300 | bus_space_handle_t h = sc->sc_memh; |
301 | |
302 | /* could be unaligned */ |
303 | if ((off & 0x3) == 0) |
304 | bus_space_write_stream_4(t, h, off, htole32(val)); |
305 | else { |
306 | bus_space_write_1(t, h, off, val & 0xff); |
307 | bus_space_write_1(t, h, off+1, (val >> 8) & 0xff); |
308 | bus_space_write_1(t, h, off+2, (val >> 16) & 0xff); |
309 | bus_space_write_1(t, h, off+3, (val >> 24) & 0xff); |
310 | } |
311 | } |
312 | |
313 | static void |
314 | mem_write_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, |
315 | size_t len) |
316 | { |
317 | bus_space_write_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); |
318 | } |
319 | |
320 | static u_int8_t |
321 | mem_read_1(struct am79c930_softc *sc, u_int32_t off) |
322 | { |
323 | return bus_space_read_1(sc->sc_memt, sc->sc_memh, off); |
324 | } |
325 | |
326 | static u_int16_t |
327 | mem_read_2(struct am79c930_softc *sc, u_int32_t off) |
328 | { |
329 | /* could be unaligned */ |
330 | if ((off & 0x1) == 0) |
331 | return le16toh(bus_space_read_stream_2(sc->sc_memt, |
332 | sc->sc_memh, off)); |
333 | else |
334 | return |
335 | bus_space_read_1(sc->sc_memt, sc->sc_memh, off ) | |
336 | (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) << 8); |
337 | } |
338 | |
339 | static u_int32_t |
340 | mem_read_4(struct am79c930_softc *sc, u_int32_t off) |
341 | { |
342 | /* could be unaligned */ |
343 | if ((off & 0x3) == 0) |
344 | return le32toh(bus_space_read_stream_4(sc->sc_memt, sc->sc_memh, |
345 | off)); |
346 | else |
347 | return |
348 | bus_space_read_1(sc->sc_memt, sc->sc_memh, off ) | |
349 | (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+1) << 8) | |
350 | (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+2) <<16) | |
351 | (bus_space_read_1(sc->sc_memt, sc->sc_memh, off+3) <<24); |
352 | } |
353 | |
354 | static void |
355 | mem_read_bytes(struct am79c930_softc *sc, u_int32_t off, u_int8_t *ptr, |
356 | size_t len) |
357 | { |
358 | bus_space_read_region_1 (sc->sc_memt, sc->sc_memh, off, ptr, len); |
359 | } |
360 | |
361 | |
362 | /* |
363 | * Set bits in GCR. |
364 | */ |
365 | |
366 | void |
367 | am79c930_gcr_setbits(struct am79c930_softc *sc, u_int8_t bits) |
368 | { |
369 | u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); |
370 | |
371 | gcr |= bits; |
372 | |
373 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr); |
374 | } |
375 | |
376 | /* |
377 | * Clear bits in GCR. |
378 | */ |
379 | |
380 | void |
381 | am79c930_gcr_clearbits(struct am79c930_softc *sc, u_int8_t bits) |
382 | { |
383 | u_int8_t gcr = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); |
384 | |
385 | gcr &= ~bits; |
386 | |
387 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_GCR, gcr); |
388 | } |
389 | |
390 | u_int8_t |
391 | am79c930_gcr_read(struct am79c930_softc *sc) |
392 | { |
393 | return bus_space_read_1 (sc->sc_iot, sc->sc_ioh, AM79C930_GCR); |
394 | } |
395 | |
396 | #if 0 |
397 | void |
398 | am79c930_regdump(struct am79c930_softc *sc) |
399 | { |
400 | u_int8_t buf[8]; |
401 | int i; |
402 | |
403 | AM930_DELAY(5); |
404 | for (i=0; i<8; i++) { |
405 | buf[i] = bus_space_read_1 (sc->sc_iot, sc->sc_ioh, i); |
406 | AM930_DELAY(5); |
407 | } |
408 | printf("am79c930: regdump:" ); |
409 | for (i=0; i<8; i++) { |
410 | printf(" %02x" , buf[i]); |
411 | } |
412 | printf("\n" ); |
413 | } |
414 | #endif |
415 | |
416 | void |
417 | am79c930_chip_init(struct am79c930_softc *sc, int how) |
418 | { |
419 | /* zero the bank select register, and leave it that way.. */ |
420 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, AM79C930_BSS, 0); |
421 | if (how) |
422 | sc->sc_ops = &memspace_ops; |
423 | else |
424 | sc->sc_ops = &iospace_ops; |
425 | } |
426 | |