1 /* $OpenBSD: mgiic.c,v 1.4 2021/10/24 17:05:03 mpi Exp $ */ 2 /* 3 * Copyright (c) 2008 Theo de Raadt <deraadt@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/device.h> 20 #include <sys/errno.h> 21 #include <sys/malloc.h> 22 #include <sys/systm.h> 23 #include <sys/rwlock.h> 24 25 #include <uvm/uvm_extern.h> 26 27 #include <machine/bus.h> 28 #include <machine/autoconf.h> 29 #include <machine/openfirm.h> 30 31 #include <dev/i2c/i2cvar.h> 32 #include <sparc64/dev/ofwi2cvar.h> 33 34 #define MGSLAVEADDR 0x00 35 #define MGSLAVEXADDR 0x08 36 #define MGDATA 0x10 37 #define MGCONTROL 0x18 38 #define MGCONTROL_IEN 0x80 39 #define MGCONTROL_ENAB 0x40 40 #define MGCONTROL_STA 0x20 41 #define MGCONTROL_STP 0x10 42 #define MGCONTROL_IFLG 0x08 43 #define MGCONTROL_AAK 0x04 44 #define MGSTATUS 0x20 45 #define MGSTATUS_BUSERR 0x00 46 #define MGSTATUS_STARTSENT 0x08 47 #define MGSTATUS_REPEATSTART 0x10 48 #define MGSTATUS_ADDR_W_ACKR 0x18 49 #define MGSTATUS_ADDR_W_NOACKR 0x20 50 #define MGSTATUS_MDATA_ACKR 0x28 51 #define MGSTATUS_MDATA_NOACKR 0x30 52 #define MGSTATUS_ARBLOST 0x38 53 #define MGSTATUS_ADDR_R_ACKR 0x40 54 #define MGSTATUS_ADDR_R_NOACKR 0x48 55 #define MGSTATUS_MDATA_ACKT 0x50 56 #define MGSTATUS_MDATA_NOACKT 0x58 57 #define MGSTATUS_SADDR_W_ACKT 0x60 58 #define MGSTATUS_ARBLOST_SLW_ACKT 0x68 59 #define MGSTATUS_GC_TACK 0x70 60 #define MGSTATUS_ARBLOST_GC_ACKT 0x78 61 #define MGSTATUS_IDLE 0xf8 62 #define MGCLOCKCONTROL 0x28 63 #define MGSOFTRESET 0x30 64 65 struct mgiic_softc { 66 struct device sc_dev; 67 68 bus_space_tag_t sc_bt; 69 bus_space_handle_t sc_regh; 70 71 72 int sc_poll; 73 74 struct i2c_controller sc_i2c; 75 struct rwlock sc_lock; 76 }; 77 78 int mgiic_match(struct device *, void *, void *); 79 void mgiic_attach(struct device *, struct device *, void *); 80 81 struct cfdriver mgiic_cd = { 82 NULL, "mgiic", DV_DULL 83 }; 84 85 const struct cfattach mgiic_ca = { 86 sizeof(struct mgiic_softc), mgiic_match, mgiic_attach 87 }; 88 89 int mgiic_i2c_acquire_bus(void *, int); 90 void mgiic_i2c_release_bus(void *, int); 91 int mgiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 92 size_t, void *, size_t, int); 93 94 int mgiic_xmit(struct mgiic_softc *, u_int8_t, const u_int8_t *, 95 size_t); 96 int mgiic_recv(struct mgiic_softc *, u_int8_t, u_int8_t *, size_t); 97 volatile u_int8_t mgiic_read(struct mgiic_softc *, bus_size_t); 98 volatile void mgiic_write(struct mgiic_softc *, bus_size_t, u_int8_t); 99 volatile void mgiic_control(struct mgiic_softc *, u_int8_t, u_int8_t); 100 int mgiic_poll(struct mgiic_softc *); 101 102 int 103 mgiic_match(struct device *parent, void *match, void *aux) 104 { 105 struct mainbus_attach_args *ma = aux; 106 char compat[32]; 107 108 if (strcmp(ma->ma_name, "i2c") != 0) 109 return (0); 110 if (OF_getprop(ma->ma_node, "compatible", compat, sizeof(compat)) == -1) 111 return (0); 112 if (strcmp(compat, "fire-i2c") == 0) 113 return (1); 114 return (0); 115 } 116 117 void 118 mgiic_attach(struct device *parent, struct device *self, void *aux) 119 { 120 struct mgiic_softc *sc = (struct mgiic_softc *)self; 121 struct mainbus_attach_args *ma = aux; 122 struct i2cbus_attach_args iba; 123 124 sc->sc_bt = ma->ma_bustag; 125 126 if (bus_space_map(sc->sc_bt, ma->ma_reg[0].ur_paddr, 127 ma->ma_reg[0].ur_len, 0, &sc->sc_regh)) { 128 printf(": failed to map preg\n"); 129 return; 130 } 131 132 rw_init(&sc->sc_lock, "iiclk"); 133 sc->sc_i2c.ic_cookie = sc; 134 sc->sc_i2c.ic_acquire_bus = mgiic_i2c_acquire_bus; 135 sc->sc_i2c.ic_release_bus = mgiic_i2c_release_bus; 136 sc->sc_i2c.ic_exec = mgiic_i2c_exec; 137 138 printf("\n"); 139 140 bzero(&iba, sizeof(iba)); 141 iba.iba_name = "iic"; 142 iba.iba_tag = &sc->sc_i2c; 143 iba.iba_bus_scan = ofwiic_scan; 144 iba.iba_bus_scan_arg = &ma->ma_node; 145 config_found(&sc->sc_dev, &iba, iicbus_print); 146 } 147 148 int 149 mgiic_i2c_acquire_bus(void *arg, int flags) 150 { 151 struct mgiic_softc *sc = arg; 152 153 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 154 return (0); 155 156 return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR)); 157 } 158 159 void 160 mgiic_i2c_release_bus(void *arg, int flags) 161 { 162 struct mgiic_softc *sc = arg; 163 164 if (cold || sc->sc_poll || (flags & I2C_F_POLL)) 165 return; 166 167 rw_exit(&sc->sc_lock); 168 } 169 170 int 171 mgiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, 172 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 173 { 174 struct mgiic_softc *sc = arg; 175 int ret = 0; 176 177 if (addr & ~0x7f) 178 return (1); 179 180 if (cold || sc->sc_poll) 181 flags |= I2C_F_POLL; 182 183 if (cmdlen > 0) { 184 ret = mgiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen); 185 if (ret != 0) 186 goto done; 187 } 188 189 if (len > 0) { 190 if (I2C_OP_WRITE_P(op)) 191 ret = mgiic_xmit(sc, addr & 0x7f, buf, len); 192 else 193 ret = mgiic_recv(sc, addr & 0x7f, buf, len); 194 } 195 done: 196 printf("e%d\n", ret); 197 return (ret); 198 } 199 200 int 201 mgiic_xmit(struct mgiic_softc *sc, u_int8_t addr, const u_int8_t *buf, 202 size_t len) 203 { 204 int err = 1, i = 0; 205 206 top: 207 printf("xmit s%02x STA ", mgiic_read(sc, MGSTATUS)); 208 mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); 209 210 if (mgiic_poll(sc)) 211 goto bail; 212 printf("s%02x ", mgiic_read(sc, MGSTATUS)); 213 if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT) 214 goto bail; 215 216 mgiic_write(sc, MGDATA, addr << 1); 217 printf("a%02x ", addr << 1); 218 mgiic_control(sc, 0, MGCONTROL_IFLG); 219 220 while (i < len) { 221 if (mgiic_poll(sc)) 222 goto bail; 223 printf("s%02x ", mgiic_read(sc, MGSTATUS)); 224 switch (mgiic_read(sc, MGSTATUS)) { 225 case MGSTATUS_ADDR_W_ACKR: 226 case MGSTATUS_MDATA_ACKR: 227 mgiic_write(sc, MGDATA, buf[i]); 228 printf("w%02x ", buf[i]); 229 i++; 230 mgiic_control(sc, 0, MGCONTROL_IFLG); 231 break; 232 case MGSTATUS_ADDR_W_NOACKR: 233 case MGSTATUS_MDATA_NOACKR: 234 mgiic_write(sc, MGDATA, buf[i]); 235 printf("w%02x ", buf[i]); 236 mgiic_control(sc, 0, MGCONTROL_IFLG); 237 break; 238 case MGSTATUS_BUSERR: 239 mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG); 240 i = 0; 241 if (mgiic_poll(sc)) 242 goto bail; 243 goto top; 244 case MGSTATUS_IDLE: 245 default: 246 err = 1; 247 goto bail; 248 } 249 } 250 printf("OK "); 251 err = 0; 252 bail: 253 if (err) 254 printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)); 255 mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG); 256 while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE) 257 ; 258 printf("s%02x\n", mgiic_read(sc, MGSTATUS)); 259 return (err); 260 } 261 262 int 263 mgiic_recv(struct mgiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len) 264 { 265 int err = 1, i = 0; 266 267 printf("recv s%02x ", mgiic_read(sc, MGSTATUS)); 268 mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); 269 if (mgiic_poll(sc)) 270 goto bail; 271 272 printf("s%02x ", mgiic_read(sc, MGSTATUS)); 273 if (mgiic_read(sc, MGSTATUS) != MGSTATUS_STARTSENT) 274 goto bail; 275 276 re_address: 277 mgiic_write(sc, MGDATA, (addr << 1) | 0x01); 278 printf("a%02x ", (addr << 1) | 0x01); 279 mgiic_control(sc, 0, MGCONTROL_IFLG); 280 281 while (i < len) { 282 if (mgiic_poll(sc)) 283 goto bail; 284 printf("s%02x ", mgiic_read(sc, MGSTATUS)); 285 switch (mgiic_read(sc, MGSTATUS)) { 286 case MGSTATUS_ADDR_R_ACKR: 287 if (len - i > 1) 288 mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG); 289 else 290 mgiic_control(sc, 0, MGCONTROL_IFLG); 291 break; 292 case MGSTATUS_ADDR_R_NOACKR: 293 mgiic_control(sc, MGCONTROL_STA, MGCONTROL_IFLG); 294 break; 295 case MGSTATUS_REPEATSTART: 296 goto re_address; 297 case MGSTATUS_MDATA_ACKT: 298 buf[i] = mgiic_read(sc, MGDATA); 299 printf("r%02x ", buf[i]); 300 i++; 301 if (len - i > 1) 302 mgiic_control(sc, MGCONTROL_AAK, MGCONTROL_IFLG); 303 else 304 mgiic_control(sc, 0, MGCONTROL_IFLG|MGCONTROL_AAK); 305 break; 306 case MGSTATUS_MDATA_NOACKT: 307 buf[i] = mgiic_read(sc, MGDATA); 308 printf("r%02x ", buf[i]); 309 i++; 310 if (len == i) { 311 printf("DONE "); 312 err = 0; 313 goto bail; 314 } 315 printf("SHORT "); 316 goto bail; 317 break; 318 default: 319 printf("BAD"); 320 goto bail; 321 } 322 } 323 printf("OK "); 324 err = 0; 325 bail: 326 if (err) 327 printf("BAIL STP s%02x\n", mgiic_read(sc, MGSTATUS)); 328 mgiic_control(sc, MGCONTROL_STP, MGCONTROL_IFLG | MGCONTROL_AAK); 329 while (mgiic_read(sc, MGSTATUS) != MGSTATUS_IDLE) 330 ; 331 printf("s%02x\n", mgiic_read(sc, MGSTATUS)); 332 return (err); 333 } 334 335 volatile u_int8_t 336 mgiic_read(struct mgiic_softc *sc, bus_size_t r) 337 { 338 bus_space_barrier(sc->sc_bt, sc->sc_regh, r, 8, 339 BUS_SPACE_BARRIER_READ); 340 return (bus_space_read_8(sc->sc_bt, sc->sc_regh, r)) & 0xff; 341 } 342 343 volatile void 344 mgiic_write(struct mgiic_softc *sc, bus_size_t r, u_int8_t v) 345 { 346 u_int64_t val = v; 347 348 bus_space_write_8(sc->sc_bt, sc->sc_regh, r, val); 349 bus_space_barrier(sc->sc_bt, sc->sc_regh, r, 8, 350 BUS_SPACE_BARRIER_WRITE); 351 } 352 353 volatile void 354 mgiic_control(struct mgiic_softc *sc, u_int8_t on, u_int8_t off) 355 { 356 u_int8_t val; 357 358 val = (mgiic_read(sc, MGCONTROL) | on) & ~off; 359 mgiic_write(sc, MGCONTROL, val); 360 } 361 362 int 363 mgiic_poll(struct mgiic_softc *sc) 364 { 365 int i; 366 367 for (i = 0; i < 1000; i++) { 368 if (mgiic_read(sc, MGCONTROL) & MGCONTROL_IFLG) 369 return (0); 370 delay(100); 371 } 372 return (1); 373 } 374