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