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