1/* $NetBSD: am79c930.c,v 1.15 2007/10/19 11:59:47 ad 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.15 2007/10/19 11:59:47 ad 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 99void am79c930_regdump(struct am79c930_softc *sc); 100 101static void io_write_1(struct am79c930_softc *, u_int32_t, u_int8_t); 102static void io_write_2(struct am79c930_softc *, u_int32_t, u_int16_t); 103static void io_write_4(struct am79c930_softc *, u_int32_t, u_int32_t); 104static void io_write_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); 105 106static u_int8_t io_read_1(struct am79c930_softc *, u_int32_t); 107static u_int16_t io_read_2(struct am79c930_softc *, u_int32_t); 108static u_int32_t io_read_4(struct am79c930_softc *, u_int32_t); 109static void io_read_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); 110 111static void mem_write_1(struct am79c930_softc *, u_int32_t, u_int8_t); 112static void mem_write_2(struct am79c930_softc *, u_int32_t, u_int16_t); 113static void mem_write_4(struct am79c930_softc *, u_int32_t, u_int32_t); 114static void mem_write_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); 115 116static u_int8_t mem_read_1(struct am79c930_softc *, u_int32_t); 117static u_int16_t mem_read_2(struct am79c930_softc *, u_int32_t); 118static u_int32_t mem_read_4(struct am79c930_softc *, u_int32_t); 119static void mem_read_bytes(struct am79c930_softc *, u_int32_t, u_int8_t *, size_t); 120 121static 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 132struct 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 143static void 144io_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 156static void 157io_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 171static void 172io_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 190static void 191io_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 206static u_int8_t 207io_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 221static u_int16_t 222io_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 238static u_int32_t 239io_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 259static void 260io_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 275static void 276mem_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 281static void 282mem_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 296static void 297mem_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 313static void 314mem_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 320static u_int8_t 321mem_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 326static u_int16_t 327mem_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 339static u_int32_t 340mem_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 354static void 355mem_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 366void 367am79c930_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 380void 381am79c930_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 390u_int8_t 391am79c930_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 397void 398am79c930_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 416void 417am79c930_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