diff options
Diffstat (limited to 'sys/arch/sparc64/dev')
-rw-r--r-- | sys/arch/sparc64/dev/mgiic.c | 224 |
1 files changed, 131 insertions, 93 deletions
diff --git a/sys/arch/sparc64/dev/mgiic.c b/sys/arch/sparc64/dev/mgiic.c index f122477923a..2187d2f01a6 100644 --- a/sys/arch/sparc64/dev/mgiic.c +++ b/sys/arch/sparc64/dev/mgiic.c @@ -1,6 +1,6 @@ -/* $OpenBSD: mgiic.c,v 1.1 2008/04/21 04:50:23 deraadt Exp $ */ +/* $OpenBSD: mgiic.c,v 1.2 2008/04/22 01:44:19 deraadt Exp $ */ /* - * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org> + * Copyright (c) 2008 Theo de Raadt <deraadt@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,7 +24,6 @@ #include <uvm/uvm_extern.h> -#define _SPARC_BUS_DMA_PRIVATE #include <machine/bus.h> #include <machine/autoconf.h> #include <machine/openfirm.h> @@ -32,36 +31,36 @@ #include <dev/i2c/i2cvar.h> #include <sparc64/dev/ofwi2cvar.h> -#define MGIIC_SLAVEADDR 0x00 -#define MGIIC_SLAVEXADDR 0x08 -#define MGIIC_DATA 0x10 -#define MGIIC_CONTROL 0x18 -#define MGIIC_CONTROL_IEN 0x80 -#define MGIIC_CONTROL_ENAB 0x40 -#define MGIIC_CONTROL_STA 0x20 -#define MGIIC_CONTROL_STP 0x10 -#define MGIIC_CONTROL_IFLG 0x08 -#define MGIIC_CONTROL_AAK 0x04 -#define MGIIC_STATUS 0x20 -#define MGIIC_STATUS_BUSERR 0x00 -#define MGIIC_STATUS_STARTSENT 0x08 -#define MGIIC_STATUS_REPEATSTART 0x10 -#define MGIIC_STATUS_ADDR_W_ACKR 0x18 -#define MGIIC_STATUS_ADDR_W_NOACKR 0x20 -#define MGIIC_STATUS_MDATA_ACKR 0x28 -#define MGIIC_STATUS_MDATA_NOACKR 0x30 -#define MGIIC_STATUS_ARBLOST 0x38 -#define MGIIC_STATUS_ADDR_R_ACKR 0x40 -#define MGIIC_STATUS_ADDR_R_NOACKR 0x48 -#define MGIIC_STATUS_MDATA_ACKT 0x50 -#define MGIIC_STATUS_MDATA_NOACKT 0x58 -#define MGIIC_STATUS_SADDR_W_ACKT 0x60 -#define MGIIC_STATUS_ARBLOST_SLW_ACKT 0x68 -#define MGIIC_STATUS_GC_TACK 0x70 -#define MGIIC_STATUS_ARBLOST_GC_ACKT 0x78 -#define MGIIC_STATUS_IDLE 0xf8 -#define MGIIC_CLOCKCONTROL 0x28 -#define MGIIC_SOFTRESET 0x30 +#define MGSLAVEADDR 0x00 +#define MGSLAVEXADDR 0x08 +#define MGDATA 0x10 +#define MGCONTROL 0x18 +#define MGCONTROL_IEN 0x80 +#define MGCONTROL_ENAB 0x40 +#define MGCONTROL_STA 0x20 +#define MGCONTROL_STP 0x10 +#define MGCONTROL_IFLG 0x08 +#define MGCONTROL_AAK 0x04 +#define MGSTATUS 0x20 +#define MGSTATUS_BUSERR 0x00 +#define MGSTATUS_STARTSENT 0x08 +#define MGSTATUS_REPEATSTART 0x10 +#define MGSTATUS_ADDR_W_ACKR 0x18 +#define MGSTATUS_ADDR_W_NOACKR 0x20 +#define MGSTATUS_MDATA_ACKR 0x28 +#define MGSTATUS_MDATA_NOACKR 0x30 +#define MGSTATUS_ARBLOST 0x38 +#define MGSTATUS_ADDR_R_ACKR 0x40 +#define MGSTATUS_ADDR_R_NOACKR 0x48 +#define MGSTATUS_MDATA_ACKT 0x50 +#define MGSTATUS_MDATA_NOACKT 0x58 +#define MGSTATUS_SADDR_W_ACKT 0x60 +#define MGSTATUS_ARBLOST_SLW_ACKT 0x68 +#define MGSTATUS_GC_TACK 0x70 +#define MGSTATUS_ARBLOST_GC_ACKT 0x78 +#define MGSTATUS_IDLE 0xf8 +#define MGCLOCKCONTROL 0x28 +#define MGSOFTRESET 0x30 struct mgiic_softc { struct device sc_dev; @@ -92,7 +91,8 @@ void mgiic_i2c_release_bus(void *, int); int mgiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); -int mgiic_xmit(struct mgiic_softc *, u_int8_t, const u_int8_t *, size_t); +int mgiic_xmit(struct mgiic_softc *, u_int8_t, const u_int8_t *, + size_t); int mgiic_recv(struct mgiic_softc *, u_int8_t, u_int8_t *, size_t); volatile u_int8_t mgiic_read(struct mgiic_softc *, bus_size_t); volatile void mgiic_write(struct mgiic_softc *, bus_size_t, u_int8_t); @@ -107,13 +107,10 @@ mgiic_match(struct device *parent, void *match, void *aux) if (strcmp(ma->ma_name, "i2c") != 0) return (0); - if (OF_getprop(ma->ma_node, "compatible", compat, sizeof(compat)) == -1) return (0); - if (strcmp(compat, "fire-i2c") == 0) return (1); - return (0); } @@ -123,7 +120,6 @@ mgiic_attach(struct device *parent, struct device *self, void *aux) struct mgiic_softc *sc = (struct mgiic_softc *)self; struct mainbus_attach_args *ma = aux; struct i2cbus_attach_args iba; - int i; sc->sc_bt = ma->ma_bustag; @@ -133,17 +129,14 @@ mgiic_attach(struct device *parent, struct device *self, void *aux) return; } - printf(": "); - for (i = 0; i < 7; i++) - printf("%04x ", mgiic_read(sc, i * 8)); - printf("\n"); - rw_init(&sc->sc_lock, "iiclk"); sc->sc_i2c.ic_cookie = sc; sc->sc_i2c.ic_acquire_bus = mgiic_i2c_acquire_bus; sc->sc_i2c.ic_release_bus = mgiic_i2c_release_bus; sc->sc_i2c.ic_exec = mgiic_i2c_exec; + printf("\n"); + bzero(&iba, sizeof(iba)); iba.iba_name = "iic"; iba.iba_tag = &sc->sc_i2c; @@ -179,7 +172,7 @@ mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) { struct mgiic_softc *sc = arg; - int ret = 0, i = 0; + int ret = 0; if (addr & ~0x7f) return (1); @@ -188,8 +181,9 @@ mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, flags |= I2C_F_POLL; if (cmdlen > 0) - if (mgiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0) - return (1); + ret = mgiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen); + if (ret != 0) + goto done; if (len > 0) { if (I2C_OP_WRITE_P(op)) @@ -197,10 +191,8 @@ mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, else ret = mgiic_recv(sc, addr & 0x7f, buf, len); } +done: printf("e%d\n", ret); - for (i = 0; i < 7; i++) - printf("%04x ", mgiic_read(sc, i * 8)); - printf("\n"); return (ret); } @@ -208,85 +200,134 @@ int mgiic_xmit(struct mgiic_softc *sc, u_int8_t addr, const u_int8_t *buf, size_t len) { - int err = 1; - int i; + int err = 1, i = 0; - mgiic_control(sc, MGIIC_CONTROL_STA, 0); +top: + printf("xmit s%02x STA ", mgiic_read(sc, MGSTATUS)); + mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); if (mgiic_poll(sc)) goto bail; - if (mgiic_read(sc, MGIIC_STATUS) != 0x08) + printf("s%02x ", mgiic_read(sc, MGSTATUS)); + if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT) goto bail; - mgiic_write(sc, MGIIC_DATA, addr << 1); - mgiic_control(sc, 0, MGIIC_CONTROL_IFLG); - - for (i = 0; i < len; i++) { + mgiic_write(sc, MGDATA, addr << 1); + printf("a%02x ", addr << 1); + mgiic_control(sc, 0, MGCONTROL_IFLG); + + while (i < len) { if (mgiic_poll(sc)) - goto bail; - switch (mgiic_read(sc, MGIIC_STATUS)) { - case 0x18: - case 0x20: - case 0x28: - case 0x30: - mgiic_write(sc, MGIIC_DATA, buf[i]); + goto bail; + printf("s%02x ", mgiic_read(sc, MGSTATUS)); + switch (mgiic_read(sc, MGSTATUS)) { + case MGSTATUS_ADDR_W_ACKR: + case MGSTATUS_MDATA_ACKR: + mgiic_write(sc, MGDATA, buf[i]); printf("w%02x ", buf[i]); - mgiic_control(sc, 0, MGIIC_CONTROL_IFLG); + i++; + mgiic_control(sc, 0, MGCONTROL_IFLG); break; + case MGSTATUS_ADDR_W_NOACKR: + case MGSTATUS_MDATA_NOACKR: + mgiic_write(sc, MGDATA, buf[i]); + printf("w%02x ", buf[i]); + mgiic_control(sc, 0, MGCONTROL_IFLG); + break; + case MGSTATUS_BUSERR: + mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG); + i = 0; + if (mgiic_poll(sc)) + goto bail; + goto top; + case MGSTATUS_IDLE: default: + err = 1; goto bail; } } + printf("OK "); err = 0; bail: - mgiic_control(sc, MGIIC_CONTROL_STP, MGIIC_CONTROL_IFLG); - while (mgiic_read(sc, MGIIC_STATUS) != 0xf8) + if (err) + printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)); + mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG); + while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE) ; + printf("s%02x\n", mgiic_read(sc, MGSTATUS)); return (err); } int mgiic_recv(struct mgiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len) { - int err = 1; - int i; - - mgiic_control(sc, MGIIC_CONTROL_STA, 0); + int err = 1, i = 0; + printf("recv s%02x ", mgiic_read(sc, MGSTATUS)); + mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); if (mgiic_poll(sc)) goto bail; - if (mgiic_read(sc, MGIIC_STATUS) != 0x08) + + printf("s%02x ", mgiic_read(sc, MGSTATUS)); + if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT) goto bail; - mgiic_write(sc, MGIIC_DATA, (addr << 1) | 0x01); - mgiic_control(sc, 0, MGIIC_CONTROL_IFLG); +re_address: + mgiic_write(sc, MGDATA, (addr << 1) | 0x01); + printf("a%02x ", (addr << 1) | 0x01); + mgiic_control(sc, 0, MGCONTROL_IFLG); - for (i = 0; i < len; ) { + while (i < len) { if (mgiic_poll(sc)) goto bail; - switch (mgiic_read(sc, MGIIC_STATUS)) { - case 0x40: - mgiic_control(sc, 0, MGIIC_CONTROL_IFLG); - break; - case 0x48: - mgiic_control(sc, MGIIC_CONTROL_STA, MGIIC_CONTROL_IFLG); + printf("s%02x ", mgiic_read(sc, MGSTATUS)); + switch (mgiic_read(sc, MGSTATUS)) { + case MGSTATUS_ADDR_R_ACKR: + if (len - i > 1) + mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG); + else + mgiic_control(sc, 0, MGCONTROL_IFLG); + break; + case MGSTATUS_ADDR_R_NOACKR: + mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); break; - case 0x50: - case 0x58: - buf[i] = mgiic_read(sc, MGIIC_DATA); + case MGSTATUS_REPEATSTART: + goto re_address; + case MGSTATUS_MDATA_ACKT: + buf[i] = mgiic_read(sc, MGDATA); printf("r%02x ", buf[i]); i++; - mgiic_control(sc, MGIIC_CONTROL_AAK, MGIIC_CONTROL_IFLG); + if (len - i > 1) + mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG); + else + mgiic_control(sc, 0, MGCONTROL_IFLG|MGCONTROL_AAK); + break; + case MGSTATUS_MDATA_NOACKT: + buf[i] = mgiic_read(sc, MGDATA); + printf("r%02x ", buf[i]); + i++; + if (len == i) { + printf("DONE "); + err = 0; + goto bail; + } + printf("SHORT "); + goto bail; break; default: + printf("BAD"); goto bail; } } + printf("OK "); err = 0; bail: - mgiic_control(sc, MGIIC_CONTROL_STP, MGIIC_CONTROL_IFLG); - while (mgiic_read(sc, MGIIC_STATUS) != 0xf8) + if (err) + printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)); + mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG | MGCONTROL_AAK); + while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE) ; + printf("s%02x\n", mgiic_read(sc, MGSTATUS)); return (err); } @@ -313,9 +354,8 @@ mgiic_control(struct mgiic_softc *sc, u_int8_t on, u_int8_t off) { u_int8_t val; - val = (mgiic_read(sc, MGIIC_CONTROL) | on) & ~off; - printf("s%02xc%02x ", mgiic_read(sc, MGIIC_STATUS), val); - return mgiic_write(sc, MGIIC_CONTROL, val); + val = (mgiic_read(sc, MGCONTROL) | on) & ~off; + mgiic_write(sc, MGCONTROL, val); } int @@ -324,10 +364,8 @@ mgiic_poll(struct mgiic_softc *sc) int i; for (i = 0; i < 1000; i++) { - if (mgiic_read(sc, MGIIC_CONTROL) & MGIIC_CONTROL_IFLG) { - printf("s%02x ", mgiic_read(sc, MGIIC_STATUS)); + if (mgiic_read(sc, MGCONTROL) & MGCONTROL_IFLG) return (0); - } delay(100); } return (1); |