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