1 /* $NetBSD: ausmbus_psc.c,v 1.17 2025/09/15 13:23:02 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.17 2025/09/15 13:23:02 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 /* functions 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 120 aprint_normal(": Alchemy PSC SMBus protocol\n"); 121 122 sc->sc_dev = self; 123 124 /* Initialize PSC */ 125 sc->sc_ctrl = aa->aupsc_ctrl; 126 127 /* Initialize i2c_controller for SMBus */ 128 iic_tag_init(&sc->sc_i2c); 129 sc->sc_i2c.ic_cookie = sc; 130 sc->sc_i2c.ic_acquire_bus = ausmbus_acquire_bus; 131 sc->sc_i2c.ic_release_bus = ausmbus_release_bus; 132 sc->sc_i2c.ic_exec = ausmbus_exec; 133 sc->sc_smbus_timeout = 10; 134 135 iicbus_attach(self, &sc->sc_i2c); 136 } 137 138 static int 139 ausmbus_acquire_bus(void *arg, int flags) 140 { 141 struct ausmbus_softc *sc = arg; 142 uint32_t v; 143 144 /* Select SMBus Protocol & Enable PSC */ 145 sc->sc_ctrl.psc_enable(sc, AUPSC_SEL_SMBUS); 146 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 147 if ((v & SMBUS_STAT_SR) == 0) { 148 /* PSC is not ready */ 149 return -1; 150 } 151 152 /* Setup SMBus Configuration register */ 153 v = SMBUS_CFG_DD; /* Disable DMA */ 154 v |= SMBUS_CFG_RT_SET(SMBUS_CFG_RT_FIFO8); /* Rx FIFO 8data */ 155 v |= SMBUS_CFG_TT_SET(SMBUS_CFG_TT_FIFO8); /* Tx FIFO 8data */ 156 v |= SMBUS_CFG_DIV_SET(SMBUS_CFG_DIV8); /* pscn_mainclk/8 */ 157 v &= ~SMBUS_CFG_SFM; /* Standard Mode */ 158 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 159 160 /* Setup SMBus Protocol Timing register */ 161 v = SMBUS_TMR_TH_SET(SMBUS_TMR_STD_TH) 162 | SMBUS_TMR_PS_SET(SMBUS_TMR_STD_PS) 163 | SMBUS_TMR_PU_SET(SMBUS_TMR_STD_PU) 164 | SMBUS_TMR_SH_SET(SMBUS_TMR_STD_SH) 165 | SMBUS_TMR_SU_SET(SMBUS_TMR_STD_SU) 166 | SMBUS_TMR_CL_SET(SMBUS_TMR_STD_CL) 167 | SMBUS_TMR_CH_SET(SMBUS_TMR_STD_CH); 168 ausmbus_reg_write(sc, AUPSC_SMBTMR, v); 169 170 /* Setup SMBus Mask register */ 171 v = SMBUS_MSK_ALLMASK; 172 ausmbus_reg_write(sc, AUPSC_SMBMSK, v); 173 174 /* SMBus Enable */ 175 v = ausmbus_reg_read(sc, AUPSC_SMBCFG); 176 v |= SMBUS_CFG_DE; 177 ausmbus_reg_write(sc, AUPSC_SMBCFG, v); 178 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 179 if ((v & SMBUS_STAT_SR) == 0) { 180 /* SMBus is not ready */ 181 return -1; 182 } 183 184 #ifdef AUSMBUS_PSC_DEBUG 185 aprint_normal("AuSMBus enabled.\n"); 186 aprint_normal("AuSMBus smbconfig: 0x%08x\n", 187 ausmbus_reg_read(sc, AUPSC_SMBCFG)); 188 aprint_normal("AuSMBus smbstatus: 0x%08x\n", 189 ausmbus_reg_read(sc, AUPSC_SMBSTAT)); 190 aprint_normal("AuSMBus smbtmr : 0x%08x\n", 191 ausmbus_reg_read(sc, AUPSC_SMBTMR)); 192 aprint_normal("AuSMBus smbmask : 0x%08x\n", 193 ausmbus_reg_read(sc, AUPSC_SMBMSK)); 194 #endif 195 196 return 0; 197 } 198 199 static void 200 ausmbus_release_bus(void *arg, int flags) 201 { 202 struct ausmbus_softc *sc = arg; 203 204 ausmbus_reg_write(sc, AUPSC_SMBCFG, 0); 205 sc->sc_ctrl.psc_disable(sc); 206 207 return; 208 } 209 210 static int 211 ausmbus_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 212 size_t cmdlen, void *vbuf, size_t buflen, int flags) 213 { 214 struct ausmbus_softc *sc = (struct ausmbus_softc *)cookie; 215 const uint8_t *cmd = vcmd; 216 217 sc->sc_smbus_slave_addr = addr; 218 219 /* Receive byte */ 220 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 1)) { 221 return ausmbus_receive_1(sc, (uint8_t *)vbuf); 222 } 223 224 /* Read byte */ 225 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { 226 return ausmbus_read_1(sc, *cmd, (uint8_t *)vbuf); 227 } 228 229 /* Read word */ 230 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { 231 return ausmbus_read_2(sc, *cmd, (uint16_t *)vbuf); 232 } 233 234 /* Read quick */ 235 if ((I2C_OP_READ_P(op)) && (cmdlen == 0) && (buflen == 0)) { 236 return ausmbus_quick_read(sc); 237 } 238 239 /* Send byte */ 240 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) { 241 return ausmbus_send_1(sc, *((uint8_t *)vbuf)); 242 } 243 244 /* Write byte */ 245 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) { 246 return ausmbus_write_1(sc, *cmd, *((uint8_t *)vbuf)); 247 } 248 249 /* Write word */ 250 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) { 251 return ausmbus_write_2(sc, *cmd, *((uint16_t *)vbuf)); 252 } 253 254 /* Write quick */ 255 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 0)) { 256 return ausmbus_quick_write(sc); 257 } 258 259 /* 260 * XXX: TODO Please Support other protocols defined in SMBus 2.0 261 * - Process call 262 * - Block write/read 263 * - Clock write-block read process cal 264 * - SMBus host notify protocol 265 * 266 * - Read quick and write quick have not been tested! 267 */ 268 269 return -1; 270 } 271 272 static int 273 ausmbus_receive_1(struct ausmbus_softc *sc, uint8_t *vp) 274 { 275 int error; 276 277 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 278 if (error != 0) { 279 return error; 280 } 281 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 282 if (error != 0) { 283 return error; 284 } 285 286 return 0; 287 } 288 289 static int 290 ausmbus_read_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t *vp) 291 { 292 int error; 293 294 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 295 if (error != 0) { 296 return error; 297 } 298 299 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 300 if (error != 0) { 301 return error; 302 } 303 304 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 305 if (error != 0) { 306 return error; 307 } 308 309 error = ausmbus_read_byte(sc, vp, I2C_F_STOP); 310 if (error != 0) { 311 return error; 312 } 313 314 return 0; 315 } 316 317 static int 318 ausmbus_read_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t *vp) 319 { 320 int error; 321 uint8_t high, low; 322 323 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 324 if (error != 0) { 325 return error; 326 } 327 328 error = ausmbus_write_byte(sc, cmd, I2C_F_READ); 329 if (error != 0) { 330 return error; 331 } 332 333 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_READ); 334 if (error != 0) { 335 return error; 336 } 337 338 error = ausmbus_read_byte(sc, &low, 0); 339 if (error != 0) { 340 return error; 341 } 342 343 error = ausmbus_read_byte(sc, &high, I2C_F_STOP); 344 if (error != 0) { 345 return error; 346 } 347 348 *vp = (high << 8) | low; 349 350 return 0; 351 } 352 353 static int 354 ausmbus_send_1(struct ausmbus_softc *sc, uint8_t val) 355 { 356 int error; 357 358 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 359 if (error != 0) { 360 return error; 361 } 362 363 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 364 if (error != 0) { 365 return error; 366 } 367 368 return 0; 369 } 370 371 static int 372 ausmbus_write_1(struct ausmbus_softc *sc, uint8_t cmd, uint8_t val) 373 { 374 int error; 375 376 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 377 if (error != 0) { 378 return error; 379 } 380 381 error = ausmbus_write_byte(sc, cmd, 0); 382 if (error != 0) { 383 return error; 384 } 385 386 error = ausmbus_write_byte(sc, val, I2C_F_STOP); 387 if (error != 0) { 388 return error; 389 } 390 391 return 0; 392 } 393 394 static int 395 ausmbus_write_2(struct ausmbus_softc *sc, uint8_t cmd, uint16_t val) 396 { 397 int error; 398 uint8_t high, low; 399 400 high = (val >> 8) & 0xff; 401 low = val & 0xff; 402 403 error = ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, I2C_F_WRITE); 404 if (error != 0) { 405 return error; 406 } 407 408 error = ausmbus_write_byte(sc, cmd, 0); 409 if (error != 0) { 410 return error; 411 } 412 413 error = ausmbus_write_byte(sc, low, 0); 414 if (error != 0) { 415 return error; 416 } 417 418 error = ausmbus_write_byte(sc, high, I2C_F_STOP); 419 if (error != 0) { 420 return error; 421 } 422 423 return 0; 424 } 425 426 /* 427 * XXX The quick_write() and quick_read() routines have not been tested! 428 */ 429 static int 430 ausmbus_quick_write(struct ausmbus_softc *sc) 431 { 432 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, 433 I2C_F_STOP | I2C_F_WRITE); 434 } 435 436 static int 437 ausmbus_quick_read(struct ausmbus_softc *sc) 438 { 439 return ausmbus_initiate_xfer(sc, sc->sc_smbus_slave_addr, 440 I2C_F_STOP | I2C_F_READ); 441 } 442 443 static int 444 ausmbus_wait_mastertx(struct ausmbus_softc *sc) 445 { 446 uint32_t v; 447 int timeout; 448 int txerr = 0; 449 450 timeout = sc->sc_smbus_timeout; 451 452 do { 453 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 454 #ifdef AUSMBUS_PSC_DEBUG 455 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x\n", v); 456 #endif 457 if ((v & SMBUS_EVNT_TU) != 0) 458 break; 459 if ((v & SMBUS_EVNT_MD) != 0) 460 break; 461 if ((v & (SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL)) 462 != 0) { 463 txerr = 1; 464 break; 465 } 466 timeout--; 467 delay(1); 468 } while (timeout > 0); 469 470 if (txerr != 0) { 471 ausmbus_reg_write(sc, AUPSC_SMBEVNT, 472 SMBUS_EVNT_DN | SMBUS_EVNT_AN | SMBUS_EVNT_AL); 473 #ifdef AUSMBUS_PSC_DEBUG 474 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): Tx error\n"); 475 #endif 476 return -1; 477 } 478 479 /* Reset Event TU (Tx Underflow) */ 480 ausmbus_reg_write(sc, AUPSC_SMBEVNT, SMBUS_EVNT_TU | SMBUS_EVNT_MD); 481 482 #ifdef AUSMBUS_PSC_DEBUG 483 v = ausmbus_reg_read(sc, AUPSC_SMBEVNT); 484 aprint_normal("AuSMBus: ausmbus_wait_mastertx(): psc_smbevnt=0x%08x (reset)\n", v); 485 #endif 486 return 0; 487 } 488 489 static int 490 ausmbus_wait_masterrx(struct ausmbus_softc *sc) 491 { 492 uint32_t v; 493 int timeout; 494 timeout = sc->sc_smbus_timeout; 495 496 if (ausmbus_wait_mastertx(sc) != 0) 497 return -1; 498 499 do { 500 v = ausmbus_reg_read(sc, AUPSC_SMBSTAT); 501 #ifdef AUSMBUS_PSC_DEBUG 502 aprint_normal("AuSMBus: ausmbus_wait_masterrx(): psc_smbstat=0x%08x\n", v); 503 #endif 504 if ((v & SMBUS_STAT_RE) == 0) 505 break; 506 timeout--; 507 delay(1); 508 } while (timeout > 0); 509 510 return 0; 511 } 512 513 static int 514 ausmbus_initiate_xfer(void *arg, i2c_addr_t addr, int flags) 515 { 516 struct ausmbus_softc *sc = arg; 517 uint32_t v; 518 519 /* Tx/Rx Slave Address */ 520 v = (addr << 1) & SMBUS_TXRX_ADDRDATA; 521 if ((flags & I2C_F_READ) != 0) 522 v |= 1; 523 if ((flags & I2C_F_STOP) != 0) 524 v |= SMBUS_TXRX_STP; 525 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 526 527 /* Master Start */ 528 ausmbus_reg_write(sc, AUPSC_SMBPCR, SMBUS_PCR_MS); 529 530 if (ausmbus_wait_mastertx(sc) != 0) 531 return -1; 532 533 return 0; 534 } 535 536 static int 537 ausmbus_read_byte(void *arg, uint8_t *vp, int flags) 538 { 539 struct ausmbus_softc *sc = arg; 540 uint32_t v; 541 542 if ((flags & I2C_F_STOP) != 0) { 543 ausmbus_reg_write(sc, AUPSC_SMBTXRX, SMBUS_TXRX_STP); 544 } else { 545 ausmbus_reg_write(sc, AUPSC_SMBTXRX, 0); 546 } 547 548 if (ausmbus_wait_masterrx(sc) != 0) 549 return -1; 550 551 v = ausmbus_reg_read(sc, AUPSC_SMBTXRX); 552 *vp = v & SMBUS_TXRX_ADDRDATA; 553 554 return 0; 555 } 556 557 static int 558 ausmbus_write_byte(void *arg, uint8_t v, int flags) 559 { 560 struct ausmbus_softc *sc = arg; 561 562 if ((flags & I2C_F_STOP) != 0) { 563 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_STP)); 564 } else if ((flags & I2C_F_READ) != 0) { 565 ausmbus_reg_write(sc, AUPSC_SMBTXRX, (v | SMBUS_TXRX_RSR)); 566 } else { 567 ausmbus_reg_write(sc, AUPSC_SMBTXRX, v); 568 } 569 570 if (ausmbus_wait_mastertx(sc) != 0) 571 return -1; 572 573 return 0; 574 } 575