1 /* $NetBSD: nfsmb.c,v 1.29 2025/09/15 13:23:03 thorpej Exp $ */ 2 /* 3 * Copyright (c) 2007 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: nfsmb.c,v 1.29 2025/09/15 13:23:03 thorpej Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/device.h> 33 #include <sys/errno.h> 34 #include <sys/kernel.h> 35 #include <sys/mutex.h> 36 #include <sys/proc.h> 37 38 #include <sys/bus.h> 39 40 #include <dev/i2c/i2cvar.h> 41 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcidevs.h> 45 46 #include <dev/pci/nfsmbreg.h> 47 48 49 struct nfsmbc_attach_args { 50 int nfsmb_num; 51 bus_space_tag_t nfsmb_iot; 52 int nfsmb_addr; 53 }; 54 55 struct nfsmb_softc; 56 struct nfsmbc_softc { 57 device_t sc_dev; 58 59 pci_chipset_tag_t sc_pc; 60 pcitag_t sc_tag; 61 struct pci_attach_args *sc_pa; 62 63 bus_space_tag_t sc_iot; 64 device_t sc_nfsmb[2]; 65 }; 66 67 struct nfsmb_softc { 68 device_t sc_dev; 69 int sc_num; 70 device_t sc_nfsmbc; 71 72 bus_space_tag_t sc_iot; 73 bus_space_handle_t sc_ioh; 74 75 struct i2c_controller sc_i2c; /* i2c controller info */ 76 }; 77 78 79 static int nfsmbc_match(device_t, cfdata_t, void *); 80 static void nfsmbc_attach(device_t, device_t, void *); 81 static int nfsmbc_print(void *, const char *); 82 83 static int nfsmb_match(device_t, cfdata_t, void *); 84 static void nfsmb_attach(device_t, device_t, void *); 85 static int nfsmb_exec( 86 void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); 87 static int nfsmb_check_done(struct nfsmb_softc *); 88 static int 89 nfsmb_send_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 90 static int nfsmb_write_1( 91 struct nfsmb_softc *, uint8_t, uint8_t, i2c_addr_t, i2c_op_t, int); 92 static int nfsmb_write_2( 93 struct nfsmb_softc *, uint8_t, uint16_t, i2c_addr_t, i2c_op_t, int); 94 static int nfsmb_receive_1(struct nfsmb_softc *, i2c_addr_t, i2c_op_t, int); 95 static int 96 nfsmb_read_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 97 static int 98 nfsmb_read_2(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 99 static int 100 nfsmb_quick(struct nfsmb_softc *, i2c_addr_t, i2c_op_t, int); 101 102 CFATTACH_DECL_NEW(nfsmbc, sizeof(struct nfsmbc_softc), 103 nfsmbc_match, nfsmbc_attach, NULL, NULL); 104 105 static int 106 nfsmbc_match(device_t parent, cfdata_t match, void *aux) 107 { 108 struct pci_attach_args *pa = aux; 109 110 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) { 111 switch (PCI_PRODUCT(pa->pa_id)) { 112 case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS: 113 case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS: 114 case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS: 115 case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS: 116 case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS: 117 case PCI_PRODUCT_NVIDIA_NFORCE430_SMBUS: 118 case PCI_PRODUCT_NVIDIA_MCP04_SMBUS: 119 case PCI_PRODUCT_NVIDIA_MCP55_SMB: 120 case PCI_PRODUCT_NVIDIA_MCP61_SMB: 121 case PCI_PRODUCT_NVIDIA_MCP65_SMB: 122 case PCI_PRODUCT_NVIDIA_MCP67_SMB: 123 case PCI_PRODUCT_NVIDIA_MCP73_SMB: 124 case PCI_PRODUCT_NVIDIA_MCP78S_SMB: 125 case PCI_PRODUCT_NVIDIA_MCP79_SMB: 126 return 1; 127 } 128 } 129 130 return 0; 131 } 132 133 static void 134 nfsmbc_attach(device_t parent, device_t self, void *aux) 135 { 136 struct nfsmbc_softc *sc = device_private(self); 137 struct pci_attach_args *pa = aux; 138 struct nfsmbc_attach_args nfsmbca; 139 pcireg_t reg; 140 int baseregs[2]; 141 142 pci_aprint_devinfo(pa, NULL); 143 144 sc->sc_dev = self; 145 sc->sc_pc = pa->pa_pc; 146 sc->sc_tag = pa->pa_tag; 147 sc->sc_pa = pa; 148 sc->sc_iot = pa->pa_iot; 149 150 nfsmbca.nfsmb_iot = sc->sc_iot; 151 152 switch (PCI_PRODUCT(pa->pa_id)) { 153 case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS: 154 case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS: 155 case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS: 156 case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS: 157 case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS: 158 baseregs[0] = NFORCE_OLD_SMB1; 159 baseregs[1] = NFORCE_OLD_SMB2; 160 break; 161 default: 162 baseregs[0] = NFORCE_SMB1; 163 baseregs[1] = NFORCE_SMB2; 164 break; 165 } 166 167 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[0]); 168 nfsmbca.nfsmb_num = 1; 169 nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg); 170 sc->sc_nfsmb[0] = config_found(sc->sc_dev, &nfsmbca, nfsmbc_print, 171 CFARGS_NONE); 172 173 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[1]); 174 nfsmbca.nfsmb_num = 2; 175 nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg); 176 sc->sc_nfsmb[1] = config_found(sc->sc_dev, &nfsmbca, nfsmbc_print, 177 CFARGS_NONE); 178 179 /* This driver is similar to an ISA bridge that doesn't 180 * need any special handling. So registering NULL handlers 181 * are sufficient. */ 182 if (!pmf_device_register(self, NULL, NULL)) 183 aprint_error_dev(self, "couldn't establish power handler\n"); 184 } 185 186 static int 187 nfsmbc_print(void *aux, const char *pnp) 188 { 189 struct nfsmbc_attach_args *nfsmbcap = aux; 190 191 if (pnp) 192 aprint_normal("nfsmb SMBus %d at %s", 193 nfsmbcap->nfsmb_num, pnp); 194 else 195 aprint_normal(" SMBus %d", nfsmbcap->nfsmb_num); 196 return UNCONF; 197 } 198 199 200 CFATTACH_DECL_NEW(nfsmb, sizeof(struct nfsmb_softc), 201 nfsmb_match, nfsmb_attach, NULL, NULL); 202 203 static int 204 nfsmb_match(device_t parent, cfdata_t match, void *aux) 205 { 206 struct nfsmbc_attach_args *nfsmbcap = aux; 207 208 if (nfsmbcap->nfsmb_num == 1 || nfsmbcap->nfsmb_num == 2) 209 return 1; 210 return 0; 211 } 212 213 static void 214 nfsmb_attach(device_t parent, device_t self, void *aux) 215 { 216 struct nfsmb_softc *sc = device_private(self); 217 struct nfsmbc_attach_args *nfsmbcap = aux; 218 219 aprint_naive("\n"); 220 aprint_normal("\n"); 221 222 sc->sc_dev = self; 223 sc->sc_nfsmbc = parent; 224 sc->sc_num = nfsmbcap->nfsmb_num; 225 sc->sc_iot = nfsmbcap->nfsmb_iot; 226 227 /* register with iic */ 228 iic_tag_init(&sc->sc_i2c); 229 sc->sc_i2c.ic_cookie = sc; 230 sc->sc_i2c.ic_exec = nfsmb_exec; 231 232 if (bus_space_map(sc->sc_iot, nfsmbcap->nfsmb_addr, NFORCE_SMBSIZE, 0, 233 &sc->sc_ioh) != 0) { 234 aprint_error_dev(self, "failed to map SMBus space\n"); 235 return; 236 } 237 238 iicbus_attach(sc->sc_dev, &sc->sc_i2c); 239 240 /* This driver is similar to an ISA bridge that doesn't 241 * need any special handling. So registering NULL handlers 242 * are sufficient. */ 243 if (!pmf_device_register(self, NULL, NULL)) 244 aprint_error_dev(self, "couldn't establish power handler\n"); 245 } 246 247 static int 248 nfsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, 249 size_t cmdlen, void *vbuf, size_t buflen, int flags) 250 { 251 struct nfsmb_softc *sc = (struct nfsmb_softc *)cookie; 252 uint8_t *p = vbuf; 253 int rv; 254 255 if ((cmdlen == 0) && (buflen == 0)) { 256 return nfsmb_quick(sc, addr, op, flags); 257 } 258 259 if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) { 260 rv = nfsmb_receive_1(sc, addr, op, flags); 261 if (rv == -1) 262 return -1; 263 *p = (uint8_t)rv; 264 return 0; 265 } 266 267 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { 268 rv = nfsmb_read_1(sc, *(const uint8_t*)cmd, addr, op, flags); 269 if (rv == -1) 270 return -1; 271 *p = (uint8_t)rv; 272 return 0; 273 } 274 275 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { 276 rv = nfsmb_read_2(sc, *(const uint8_t*)cmd, addr, op, flags); 277 if (rv == -1) 278 return -1; 279 *(uint16_t *)p = (uint16_t)rv; 280 return 0; 281 } 282 283 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) 284 return nfsmb_send_1(sc, *(uint8_t*)vbuf, addr, op, flags); 285 286 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) 287 return nfsmb_write_1(sc, *(const uint8_t*)cmd, *(uint8_t*)vbuf, 288 addr, op, flags); 289 290 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) 291 return nfsmb_write_2(sc, 292 *(const uint8_t*)cmd, *((uint16_t *)vbuf), addr, op, flags); 293 294 return -1; 295 } 296 297 static int 298 nfsmb_check_done(struct nfsmb_softc *sc) 299 { 300 int us; 301 uint8_t stat; 302 303 us = 10 * 1000; /* XXXX: wait maximum 10 msec */ 304 do { 305 delay(10); 306 us -= 10; 307 if (us <= 0) 308 return -1; 309 } while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 310 NFORCE_SMB_PROTOCOL) != 0); 311 312 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_STATUS); 313 if ((stat & NFORCE_SMB_STATUS_DONE) && 314 !(stat & NFORCE_SMB_STATUS_STATUS)) 315 return 0; 316 return -1; 317 } 318 319 /* ARGSUSED */ 320 static int 321 nfsmb_quick(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags) 322 { 323 uint8_t data; 324 325 /* write smbus slave address to register */ 326 data = addr << 1; 327 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 328 329 /* write smbus protocol to register */ 330 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_QUICK; 331 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 332 333 return nfsmb_check_done(sc); 334 } 335 336 /* ARGSUSED */ 337 static int 338 nfsmb_send_1(struct nfsmb_softc *sc, uint8_t val, i2c_addr_t addr, i2c_op_t op, 339 int flags) 340 { 341 uint8_t data; 342 343 /* store cmd */ 344 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, val); 345 346 /* write smbus slave address to register */ 347 data = addr << 1; 348 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 349 350 /* write smbus protocol to register */ 351 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; 352 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 353 354 return nfsmb_check_done(sc); 355 } 356 357 /* ARGSUSED */ 358 static int 359 nfsmb_write_1(struct nfsmb_softc *sc, uint8_t cmd, uint8_t val, i2c_addr_t addr, 360 i2c_op_t op, int flags) 361 { 362 uint8_t data; 363 364 /* store cmd */ 365 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 366 367 /* store data */ 368 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, val); 369 370 /* write smbus slave address to register */ 371 data = addr << 1; 372 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 373 374 /* write smbus protocol to register */ 375 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; 376 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 377 378 return nfsmb_check_done(sc); 379 } 380 381 static int 382 nfsmb_write_2(struct nfsmb_softc *sc, uint8_t cmd, uint16_t val, 383 i2c_addr_t addr, i2c_op_t op, int flags) 384 { 385 uint8_t data, low, high; 386 387 /* store cmd */ 388 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 389 390 /* store data */ 391 low = val; 392 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, low); 393 high = val >> 8; 394 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA + 1, high); 395 396 /* write smbus slave address to register */ 397 data = addr << 1; 398 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 399 400 /* write smbus protocol to register */ 401 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA; 402 if (flags & I2C_F_PEC) 403 data |= NFORCE_SMB_PROTOCOL_PEC; 404 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 405 406 return nfsmb_check_done(sc); 407 } 408 409 /* ARGSUSED */ 410 static int 411 nfsmb_receive_1(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags) 412 { 413 uint8_t data; 414 415 /* write smbus slave address to register */ 416 data = addr << 1; 417 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 418 419 /* write smbus protocol to register */ 420 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; 421 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 422 423 /* check for errors */ 424 if (nfsmb_check_done(sc) < 0) 425 return -1; 426 427 /* read data */ 428 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 429 } 430 431 /* ARGSUSED */ 432 static int 433 nfsmb_read_1(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op, 434 int flags) 435 { 436 uint8_t data; 437 438 /* store cmd */ 439 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 440 441 /* write smbus slave address to register */ 442 data = addr << 1; 443 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 444 445 /* write smbus protocol to register */ 446 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; 447 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 448 449 /* check for errors */ 450 if (nfsmb_check_done(sc) < 0) 451 return -1; 452 453 /* read data */ 454 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 455 } 456 457 static int 458 nfsmb_read_2(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op, 459 int flags) 460 { 461 uint8_t data, low, high; 462 463 /* store cmd */ 464 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 465 466 /* write smbus slave address to register */ 467 data = addr << 1; 468 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 469 470 /* write smbus protocol to register */ 471 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA; 472 if (flags & I2C_F_PEC) 473 data |= NFORCE_SMB_PROTOCOL_PEC; 474 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 475 476 /* check for errors */ 477 if (nfsmb_check_done(sc) < 0) 478 return -1; 479 480 /* read data */ 481 low = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 482 high = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA + 1); 483 return low | high << 8; 484 } 485