1 /* $NetBSD: ausmbus_psc.c,v 1.15 2021/08/07 16:18:58 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Shigeyuki Fukushima. 5 * All rights reserved. 6 * 7 * Written by Shigeyuki Fukushima. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 3. The name of the author may not be used to endorse or promote 19 * products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 23 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: ausmbus_psc.c,v 1.15 2021/08/07 16:18:58 thorpej Exp $"); 37 38 #include "locators.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 #include <sys/errno.h> 44 45 #include <sys/bus.h> 46 #include <machine/cpu.h> 47 48 #include <mips/alchemy/dev/aupscreg.h> 49 #include <mips/alchemy/dev/aupscvar.h> 50 #include <mips/alchemy/dev/ausmbus_pscreg.h> 51 52 #include <dev/i2c/i2cvar.h> 53 #include <dev/i2c/i2c_bitbang.h> 54 55 struct ausmbus_softc { 56 device_t sc_dev; 57 58 /* protocol comoon fields */ 59 struct aupsc_controller sc_ctrl; 60 61 /* protocol specific fields */ 62 struct i2c_controller sc_i2c; 63 i2c_addr_t sc_smbus_slave_addr; 64 int sc_smbus_timeout; 65 }; 66 67 #define ausmbus_reg_read(sc, reg) \ 68 bus_space_read_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg) 69 #define ausmbus_reg_write(sc, reg, val) \ 70 bus_space_write_4(sc->sc_ctrl.psc_bust, sc->sc_ctrl.psc_bush, reg, \ 71 val); \ 72 delay(100); 73 74 static int ausmbus_match(device_t, struct cfdata *, void *); 75 static void ausmbus_attach(device_t, device_t, void *); 76 77 CFATTACH_DECL_NEW(ausmbus, sizeof(struct ausmbus_softc), 78 ausmbus_match, ausmbus_attach, NULL, NULL); 79 80 /* fuctions for i2c_controller */ 81 static int ausmbus_acquire_bus(void *, int); 82 static void ausmbus_release_bus(void *, int); 83 static int ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, 84 const void *cmd, size_t cmdlen, void *vbuf, 85 size_t buflen, int flags); 86 87 /* subroutine functions for i2c_controller */ 88 static int ausmbus_quick_write(struct ausmbus_softc *); 89 static int ausmbus_quick_read(struct ausmbus_softc *); 90 static int ausmbus_receive_1(struct ausmbus_softc *, uint8_t *); 91 static int ausmbus_read_1(struct ausmbus_softc *, uint8_t, uint8_t *); 92 static int ausmbus_read_2(struct ausmbus_softc *, uint8_t, uint16_t *); 93 static int ausmbus_send_1(struct ausmbus_softc *, uint8_t); 94 static int ausmbus_write_1(struct ausmbus_softc *, uint8_t, uint8_t); 95 static int ausmbus_write_2(struct ausmbus_softc *, uint8_t, uint16_t); 96 static int ausmbus_wait_mastertx(struct ausmbus_softc *sc); 97 static int ausmbus_wait_masterrx(struct ausmbus_softc *sc); 98 static int ausmbus_initiate_xfer(void *, i2c_addr_t, int); 99 static int ausmbus_read_byte(void *arg, uint8_t *vp, int flags); 100 static int ausmbus_write_byte(void *arg, uint8_t v, int flags); 101 102 103 static int 104 ausmbus_match(device_t parent, struct cfdata *cf, void *aux) 105 { 106 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux; 107 108 if (strcmp(aa->aupsc_name, cf->cf_name) != 0) 109 return 0; 110 111 return 1; 112 } 113 114 static void 115 ausmbus_attach(device_t parent, device_t self, void *aux) 116 { 117 struct ausmbus_softc *sc = device_private(self); 118 struct aupsc_attach_args *aa = (struct aupsc_attach_args *)aux; 119 struct i2cbus_attach_args iba; 120 121 aprint_normal(": Alchemy PSC SMBus protocol\n"); 122 123 sc->sc_dev = self; 124 125 /* Initialize PSC */ 126 sc->sc_ctrl = aa->aupsc_ctrl; 127 128 /* Initialize i2c_controller for SMBus */ 129 iic_tag_init(&sc->sc_i2c); 130 sc->sc_i2c.ic_cookie = sc; 131 sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus; 132 sc->sc_i2c.ic_release_bus = ausmbus_release_bus; 133 sc->sc_i2c.ic_exec = ausmbus_exec; 134 sc->sc_smbus_timeout = 10; 135 136 memset(&iba, 0, sizeof(iba)); 137 iba.iba_tag = &sc->sc_i2c; 138 config_found(self, &iba, iicbus_print, CFARGS_NONE); 139 } 140 141 static int 142 ausmbus_acquire_bus(void *arg, int flags) 143 { 144 struct ausmbus_softc *sc = arg; 145 uint32_t v; 146 147 /* Select SMBus Protocol & Enable PSC */ 148 sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS); 149 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 150 if ((v & SMBUS_STAT_SR) == 0) { 151 /* PSC is not ready */ 152 return -1; 153 } 154 155 /* Setup SMBus Configuration register */ 156 v = SMBUS_CFG_DD; /* Disable DMA */ 157 v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8); /* Rx FIFO 8data */ 158 v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8); /* Tx FIFO 8data */ 159 v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8); /* pscn_mainclk/8 */ 160 v &= ~SMBUS_CFG_SFM; /* Standard Mode */ 161 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 162 163 /* Setup SMBus Protocol Timing register */ 164 v = SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH) 165 | SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS) 166 | SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU) 167 | SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH) 168 | SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU) 169 | SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL) 170 | SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH); 171 ausmbus_reg_write(sc, AUPSC_SMBTMR, v); 172 173 /* Setup SMBus Mask register */ 174 v = SMBUS_MSK_ALLMASK; 175 ausmbus_reg_write(sc, AUPSC_SMBMSK, v); 176 177 /* SMBus Enable */ 178 v = ausmbus_reg_read(sc, AUPSC_SMBCFG); 179 v |= SMBUS_CFG_DE; 180 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 181 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 182 if ((v & SMBUS_STAT_SR) == 0) { 183 /* SMBus is not ready */ 184 return -1; 185 } 186 187 #ifdef AUSMBUS_PSC_DEBUG 188 aprint_normal("AuSMBus enabled.\n"); 189 aprint_normal("AuSMBus smbconfig: 0x%08x\n", 190 ausmbus_reg_read(sc, AUPSC_SMBCFG)); 191 aprint_normal("AuSMBus smbstatus: 0x%08x\n", 192 ausmbus_reg_read(sc, AUPSC_SMBSTAT)); 193 aprint_normal("AuSMBus smbtmr : 0x%08x\n", 194 ausmbus_reg_read(sc, AUPSC_SMBTMR)); 195 aprint_normal("AuSMBus smbmask : 0x%08x\n", 196 ausmbus_reg_read(sc, AUPSC_SMBMSK)); 197 #endif 198 199 return 0; 200 } 201 202 static void 203 ausmbus_release_bus(void *arg, int flags) 204 { 205 struct ausmbus_softc *sc = arg; 206 207 ausmbus_reg_write(sc, AUPSC_SMBCFG, 0); 208 sc->sc_ctrl.psc_disable(sc); 209 210 return; 211 } 212 213 static int 214 ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 215 size_t cmdlen, void *vbuf, size_t buflen, int flags) 216 { 217 struct ausmbus_softc *sc = (struct ausmbus_softc *)cookie; 218 const uint8_t *cmd = vcmd; 219 220 sc->sc_smbus_slave_addr = addr; 221 222 /* Receive byte */ 223 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 1)) { 224 return ausmbus_receive_1(sc, (uint8_t *)vbuf); 225 } 226 227 /* Read byte */ 228 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { 229 return ausmbus_read_1(sc, *cmd, (uint8_t *)vbuf); 230 } 231 232 /* Read word */ 233 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { 234 return ausmbus_read_2(sc, *cmd, (uint16_t *)vbuf); 235 } 236 237 /* Read quick */ 238 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 0)) { 239 return ausmbus_quick_read(sc); 240 } 241 242 /* Send byte */ 243 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) { 244 return ausmbus_send_1(sc, *((uint8_t *)vbuf)); 245 } 246 247 /* Write byte */ 248 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) { 249 return ausmbus_write_1(sc, *cmd, *((uint8_t *)vbuf)); 250 } 251 252 /* Write word */ 253 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) { 254 return ausmbus_write_2(sc, *cmd, *((uint16_t *)vbuf)); 255 } 256 257 /* Write quick */ 258 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 0)) { 259 return ausmbus_quick_write(sc); 260 } 261 262 /* 263 * XXX: TODO Please Support other protocols defined in SMBus 2.0 264 * - Process call 265 * - Block write/read 266 * - Clock write-block read process cal 267 * - SMBus host notify protocol 268 * 269 * - Read quick and write quick have not been tested! 270 */ 271 272 return -1; 273 } 274 275 static int 276 ausmbus_receive_1(struct ausmbus_softc *sc, uint8_t *vp) 277 { 278 int error; 279 280 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 281 if (error != 0) { 282 return error; 283 } 284 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 285 if (error != 0) { 286 return error; 287 } 288 289 return 0; 290 } 291 292 static int 293 ausmbus_read_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t *vp) 294 { 295 int error; 296 297 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 298 if (error != 0) { 299 return error; 300 } 301 302 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 303 if (error != 0) { 304 return error; 305 } 306 307 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 308 if (error != 0) { 309 return error; 310 } 311 312 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 313 if (error != 0) { 314 return error; 315 } 316 317 return 0; 318 } 319 320 static int 321 ausmbus_read_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t *vp) 322 { 323 int error; 324 uint8_t high, low; 325 326 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 327 if (error != 0) { 328 return error; 329 } 330 331 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 332 if (error != 0) { 333 return error; 334 } 335 336 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 337 if (error != 0) { 338 return error; 339 } 340 341 error = ausmbus_read_byte(sc, &low, 0); 342 if (error != 0) { 343 return error; 344 } 345 346 error = ausmbus_read_byte(sc, &high, I2C_F_STOP); 347 if (error != 0) { 348 return error; 349 } 350 351 *vp = (high << 8) | low; 352 353 return 0; 354 } 355 356 static int 357 ausmbus_send_1(struct ausmbus_softc *sc, uint8_t val) 358 { 359 int error; 360 361 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 362 if (error != 0) { 363 return error; 364 } 365 366 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 367 if (error != 0) { 368 return error; 369 } 370 371 return 0; 372 } 373 374 static int 375 ausmbus_write_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t val) 376 { 377 int error; 378 379 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 380 if (error != 0) { 381 return error; 382 } 383 384 error = ausmbus_write_byte(sc, cmd, 0); 385 if (error != 0) { 386 return error; 387 } 388 389 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 390 if (error != 0) { 391 return error; 392 } 393 394 return 0; 395 } 396 397 static int 398 ausmbus_write_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t val) 399 { 400 int error; 401 uint8_t high, low; 402 403 high = (val >> 8) & 0xff; 404 low = val & 0xff; 405 406 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 407 if (error != 0) { 408 return error; 409 } 410 411 error = ausmbus_write_byte(sc, cmd, 0); 412 if (error != 0) { 413 return error; 414 } 415 416 error = ausmbus_write_byte(sc, low, 0); 417 if (error != 0) { 418 return error; 419 } 420 421 error = ausmbus_write_byte(sc, high, I2C_F_STOP); 422 if (error != 0) { 423 return error; 424 } 425 426 return 0; 427 } 428 429 /* 430 * XXX The quick_write() and quick_read() routines have not been tested! 431 */ 432 static int 433 ausmbus_quick_write(struct ausmbus_softc *sc) 434 { 435 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, 436 I2C_F_STOP | I2C_F_WRITE); 437 } 438 439 static int 440 ausmbus_quick_read(struct ausmbus_softc *sc) 441 { 442 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, 443 I2C_F_STOP | I2C_F_READ); 444 } 445 446 static int 447 ausmbus_wait_mastertx(struct ausmbus_softc *sc) 448 { 449 uint32_t v; 450 int timeout; 451 int txerr = 0; 452 453 timeout = sc->sc_smbus_timeout; 454 455 do { 456 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 457 #ifdef AUSMBUS_PSC_DEBUG 458 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v); 459 #endif 460 if ((v & SMBUS_EVNT_TU) != 0) 461 break; 462 if ((v & SMBUS_EVNT_MD) != 0) 463 break; 464 if ((v & (SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL)) 465 != 0) { 466 txerr = 1; 467 break; 468 } 469 timeout--; 470 delay(1); 471 } while (timeout > 0); 472 473 if (txerr != 0) { 474 ausmbus_reg_write(sc, AUPSC_SMBEVNT, 475 SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL); 476 #ifdef AUSMBUS_PSC_DEBUG 477 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n"); 478 #endif 479 return -1; 480 } 481 482 /* Reset Event TU (Tx Underflow) */ 483 ausmbus_reg_write(sc, AUPSC_SMBEVNT, SMBUS_EVNT_TU | SMBUS_EVNT_MD); 484 485 #ifdef AUSMBUS_PSC_DEBUG 486 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 487 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v); 488 #endif 489 return 0; 490 } 491 492 static int 493 ausmbus_wait_masterrx(struct ausmbus_softc *sc) 494 { 495 uint32_t v; 496 int timeout; 497 timeout = sc->sc_smbus_timeout; 498 499 if (ausmbus_wait_mastertx(sc) != 0) 500 return -1; 501 502 do { 503 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 504 #ifdef AUSMBUS_PSC_DEBUG 505 aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v); 506 #endif 507 if ((v & SMBUS_STAT_RE) == 0) 508 break; 509 timeout--; 510 delay(1); 511 } while (timeout > 0); 512 513 return 0; 514 } 515 516 static int 517 ausmbus_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 518 { 519 struct ausmbus_softc *sc = arg; 520 uint32_t v; 521 522 /* Tx/Rx Slave Address */ 523 v = (addr << 1) & SMBUS_TXRX_ADDRDATA; 524 if ((flags & I2C_F_READ) != 0) 525 v |= 1; 526 if ((flags & I2C_F_STOP) != 0) 527 v |= SMBUS_TXRX_STP; 528 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 529 530 /* Master Start */ 531 ausmbus_reg_write(sc, AUPSC_SMBPCR, SMBUS_PCR_MS); 532 533 if (ausmbus_wait_mastertx(sc) != 0) 534 return -1; 535 536 return 0; 537 } 538 539 static int 540 ausmbus_read_byte(void *arg, uint8_t *vp, int flags) 541 { 542 struct ausmbus_softc *sc = arg; 543 uint32_t v; 544 545 if ((flags & I2C_F_STOP) != 0) { 546 ausmbus_reg_write(sc, AUPSC_SMBTXRX, SMBUS_TXRX_STP); 547 } else { 548 ausmbus_reg_write(sc, AUPSC_SMBTXRX, 0); 549 } 550 551 if (ausmbus_wait_masterrx(sc) != 0) 552 return -1; 553 554 v = ausmbus_reg_read(sc, AUPSC_SMBTXRX); 555 *vp = v & SMBUS_TXRX_ADDRDATA; 556 557 return 0; 558 } 559 560 static int 561 ausmbus_write_byte(void *arg, uint8_t v, int flags) 562 { 563 struct ausmbus_softc *sc = arg; 564 565 if ((flags & I2C_F_STOP) != 0) { 566 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_STP)); 567 } else if ((flags & I2C_F_READ) != 0) { 568 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_RSR)); 569 } else { 570 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 571 } 572 573 if (ausmbus_wait_mastertx(sc) != 0) 574 return -1; 575 576 return 0; 577 } 578