1 /* $NetBSD: nfsmb.c,v 1.10 2007/12/04 15:58:11 xtraeme 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.10 2007/12/04 15:58:11 xtraeme 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/rwlock.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 struct device 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 struct device *sc_nfsmb[2]; 65 }; 66 67 struct nfsmb_softc { 68 struct device sc_dev; 69 int sc_num; 70 struct device *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 krwlock_t sc_rwlock; 77 }; 78 79 80 static int nfsmbc_match(struct device *, struct cfdata *, void *); 81 static void nfsmbc_attach(struct device *, struct device *, void *); 82 static int nfsmbc_print(void *, const char *); 83 84 static int nfsmb_match(struct device *, struct cfdata *, void *); 85 static void nfsmb_attach(struct device *, struct device *, void *); 86 static int nfsmb_acquire_bus(void *, int); 87 static void nfsmb_release_bus(void *, int); 88 static int nfsmb_exec( 89 void *, i2c_op_t, i2c_addr_t, const void *, size_t, void *, size_t, int); 90 static int nfsmb_check_done(struct nfsmb_softc *); 91 static int 92 nfsmb_send_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 93 static int nfsmb_write_1( 94 struct nfsmb_softc *, uint8_t, uint8_t, i2c_addr_t, i2c_op_t, int); 95 static int nfsmb_write_2( 96 struct nfsmb_softc *, uint8_t, uint16_t, i2c_addr_t, i2c_op_t, int); 97 static int nfsmb_receive_1(struct nfsmb_softc *, i2c_addr_t, i2c_op_t, int); 98 static int 99 nfsmb_read_1(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 100 static int 101 nfsmb_read_2(struct nfsmb_softc *, uint8_t, i2c_addr_t, i2c_op_t, int); 102 103 104 CFATTACH_DECL(nfsmbc, sizeof(struct nfsmbc_softc), 105 nfsmbc_match, nfsmbc_attach, NULL, NULL); 106 107 static int 108 nfsmbc_match(struct device *parent, struct cfdata *match, void *aux) 109 { 110 struct pci_attach_args *pa = aux; 111 112 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) { 113 switch (PCI_PRODUCT(pa->pa_id)) { 114 case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS: 115 case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS: 116 case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS: 117 case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS: 118 case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS: 119 case PCI_PRODUCT_NVIDIA_NFORCE430_SMBUS: 120 case PCI_PRODUCT_NVIDIA_MCP04_SMBUS: 121 case PCI_PRODUCT_NVIDIA_MCP55_SMB: 122 case PCI_PRODUCT_NVIDIA_MCP61_SMB: 123 case PCI_PRODUCT_NVIDIA_MCP65_SMB: 124 case PCI_PRODUCT_NVIDIA_MCP67_SMB: 125 case PCI_PRODUCT_NVIDIA_MCP73_SMB: 126 return 1; 127 } 128 } 129 130 return 0; 131 } 132 133 static void 134 nfsmbc_attach(struct device *parent, struct device *self, void *aux) 135 { 136 struct nfsmbc_softc *sc = (struct nfsmbc_softc *) self; 137 struct pci_attach_args *pa = aux; 138 struct nfsmbc_attach_args nfsmbca; 139 pcireg_t reg; 140 int baseregs[2]; 141 char devinfo[256]; 142 143 aprint_naive("\n"); 144 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 145 aprint_normal(": %s (rev. 0x%02x)\n", devinfo, 146 PCI_REVISION(pa->pa_class)); 147 148 sc->sc_pc = pa->pa_pc; 149 sc->sc_tag = pa->pa_tag; 150 sc->sc_pa = pa; 151 sc->sc_iot = pa->pa_iot; 152 153 nfsmbca.nfsmb_iot = sc->sc_iot; 154 155 switch (PCI_PRODUCT(pa->pa_id)) { 156 case PCI_PRODUCT_NVIDIA_NFORCE2_SMBUS: 157 case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMBUS: 158 case PCI_PRODUCT_NVIDIA_NFORCE3_SMBUS: 159 case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMBUS: 160 case PCI_PRODUCT_NVIDIA_NFORCE4_SMBUS: 161 case PCI_PRODUCT_NVIDIA_NFORCE430_SMBUS: 162 baseregs[0] = NFORCE_OLD_SMB1; 163 baseregs[1] = NFORCE_OLD_SMB2; 164 break; 165 default: 166 baseregs[0] = NFORCE_SMB1; 167 baseregs[1] = NFORCE_SMB2; 168 break; 169 } 170 171 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[0]); 172 nfsmbca.nfsmb_num = 1; 173 nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg); 174 sc->sc_nfsmb[0] = config_found(&sc->sc_dev, &nfsmbca, nfsmbc_print); 175 176 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[1]); 177 nfsmbca.nfsmb_num = 2; 178 nfsmbca.nfsmb_addr = NFORCE_SMBBASE(reg); 179 sc->sc_nfsmb[1] = config_found(&sc->sc_dev, &nfsmbca, nfsmbc_print); 180 } 181 182 static int 183 nfsmbc_print(void *aux, const char *pnp) 184 { 185 struct nfsmbc_attach_args *nfsmbcap = aux; 186 187 if (pnp) 188 aprint_normal("nfsmb SMBus %d at %s", 189 nfsmbcap->nfsmb_num, pnp); 190 else 191 aprint_normal(" SMBus %d", nfsmbcap->nfsmb_num); 192 return UNCONF; 193 } 194 195 196 CFATTACH_DECL(nfsmb, sizeof(struct nfsmb_softc), 197 nfsmb_match, nfsmb_attach, NULL, NULL); 198 199 static int 200 nfsmb_match(struct device *parent, struct cfdata *match, void *aux) 201 { 202 struct nfsmbc_attach_args *nfsmbcap = aux; 203 204 if (nfsmbcap->nfsmb_num == 1 || nfsmbcap->nfsmb_num == 2) 205 return 1; 206 return 0; 207 } 208 209 static void 210 nfsmb_attach(struct device *parent, struct device *self, void *aux) 211 { 212 struct nfsmb_softc *sc = (struct nfsmb_softc *) self; 213 struct nfsmbc_attach_args *nfsmbcap = aux; 214 struct i2cbus_attach_args iba; 215 216 aprint_naive("\n"); 217 aprint_normal("\n"); 218 219 sc->sc_nfsmbc = parent; 220 sc->sc_num = nfsmbcap->nfsmb_num; 221 sc->sc_iot = nfsmbcap->nfsmb_iot; 222 223 /* register with iic */ 224 sc->sc_i2c.ic_cookie = sc; 225 sc->sc_i2c.ic_acquire_bus = nfsmb_acquire_bus; 226 sc->sc_i2c.ic_release_bus = nfsmb_release_bus; 227 sc->sc_i2c.ic_send_start = NULL; 228 sc->sc_i2c.ic_send_stop = NULL; 229 sc->sc_i2c.ic_initiate_xfer = NULL; 230 sc->sc_i2c.ic_read_byte = NULL; 231 sc->sc_i2c.ic_write_byte = NULL; 232 sc->sc_i2c.ic_exec = nfsmb_exec; 233 234 rw_init(&sc->sc_rwlock); 235 236 if (bus_space_map(sc->sc_iot, nfsmbcap->nfsmb_addr, NFORCE_SMBSIZE, 0, 237 &sc->sc_ioh) != 0) { 238 aprint_error("%s: failed to map SMBus space\n", 239 sc->sc_dev.dv_xname); 240 return; 241 } 242 243 iba.iba_type = I2C_TYPE_SMBUS; 244 iba.iba_tag = &sc->sc_i2c; 245 (void) config_found_ia(&sc->sc_dev, "i2cbus", &iba, iicbus_print); 246 } 247 248 static int 249 nfsmb_acquire_bus(void *cookie, int flags) 250 { 251 struct nfsmb_softc *sc = cookie; 252 253 rw_enter(&sc->sc_rwlock, RW_WRITER); 254 return 0; 255 } 256 257 static void 258 nfsmb_release_bus(void *cookie, int flags) 259 { 260 struct nfsmb_softc *sc = cookie; 261 262 rw_exit(&sc->sc_rwlock); 263 } 264 265 static int 266 nfsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmd, 267 size_t cmdlen, void *vbuf, size_t buflen, int flags) 268 { 269 struct nfsmb_softc *sc = (struct nfsmb_softc *)cookie; 270 uint8_t *p = vbuf; 271 int rv; 272 273 if (I2C_OP_READ_P(op) && (cmdlen == 0) && (buflen == 1)) { 274 rv = nfsmb_receive_1(sc, addr, op, flags); 275 if (rv == -1) 276 return -1; 277 *p = (uint8_t)rv; 278 return 0; 279 } 280 281 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 1)) { 282 rv = nfsmb_read_1(sc, *(const uint8_t*)cmd, addr, op, flags); 283 if (rv == -1) 284 return -1; 285 *p = (uint8_t)rv; 286 return 0; 287 } 288 289 if ((I2C_OP_READ_P(op)) && (cmdlen == 1) && (buflen == 2)) { 290 rv = nfsmb_read_2(sc, *(const uint8_t*)cmd, addr, op, flags); 291 if (rv == -1) 292 return -1; 293 *p = (uint8_t)rv; 294 return 0; 295 } 296 297 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 0) && (buflen == 1)) 298 return nfsmb_send_1(sc, *(uint8_t*)vbuf, addr, op, flags); 299 300 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 1)) 301 return nfsmb_write_1(sc, *(const uint8_t*)cmd, *(uint8_t*)vbuf, 302 addr, op, flags); 303 304 if ((I2C_OP_WRITE_P(op)) && (cmdlen == 1) && (buflen == 2)) 305 return nfsmb_write_2(sc, 306 *(const uint8_t*)cmd, *((uint16_t *)vbuf), addr, op, flags); 307 308 return -1; 309 } 310 311 static int 312 nfsmb_check_done(struct nfsmb_softc *sc) 313 { 314 int us; 315 uint8_t stat; 316 317 us = 10 * 1000; /* XXXX: wait maximum 10 msec */ 318 do { 319 delay(10); 320 us -= 10; 321 if (us <= 0) 322 return -1; 323 } while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, 324 NFORCE_SMB_PROTOCOL) != 0); 325 326 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_STATUS); 327 if ((stat & NFORCE_SMB_STATUS_DONE) && 328 !(stat & NFORCE_SMB_STATUS_STATUS)) 329 return 0; 330 return -1; 331 } 332 333 /* ARGSUSED */ 334 static int 335 nfsmb_send_1(struct nfsmb_softc *sc, uint8_t val, i2c_addr_t addr, i2c_op_t op, 336 int flags) 337 { 338 uint8_t data; 339 340 /* store cmd */ 341 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, val); 342 343 /* write smbus slave address to register */ 344 data = addr << 1; 345 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 346 347 /* write smbus protocol to register */ 348 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; 349 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 350 351 return nfsmb_check_done(sc); 352 } 353 354 /* ARGSUSED */ 355 static int 356 nfsmb_write_1(struct nfsmb_softc *sc, uint8_t cmd, uint8_t val, i2c_addr_t addr, 357 i2c_op_t op, int flags) 358 { 359 uint8_t data; 360 361 /* store cmd */ 362 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 363 364 /* store data */ 365 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, val); 366 367 /* write smbus slave address to register */ 368 data = addr << 1; 369 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 370 371 /* write smbus protocol to register */ 372 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; 373 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 374 375 return nfsmb_check_done(sc); 376 } 377 378 static int 379 nfsmb_write_2(struct nfsmb_softc *sc, uint8_t cmd, uint16_t val, 380 i2c_addr_t addr, i2c_op_t op, int flags) 381 { 382 uint8_t data, low, high; 383 384 /* store cmd */ 385 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 386 387 /* store data */ 388 low = val; 389 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, low); 390 high = val >> 8; 391 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA, high); 392 393 /* write smbus slave address to register */ 394 data = addr << 1; 395 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 396 397 /* write smbus protocol to register */ 398 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_WORD_DATA; 399 if (flags & I2C_F_PEC) 400 data |= NFORCE_SMB_PROTOCOL_PEC; 401 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 402 403 return nfsmb_check_done(sc); 404 } 405 406 /* ARGSUSED */ 407 static int 408 nfsmb_receive_1(struct nfsmb_softc *sc, i2c_addr_t addr, i2c_op_t op, int flags) 409 { 410 uint8_t data; 411 412 /* write smbus slave address to register */ 413 data = addr << 1; 414 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 415 416 /* write smbus protocol to register */ 417 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE; 418 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 419 420 /* check for errors */ 421 if (nfsmb_check_done(sc) < 0) 422 return -1; 423 424 /* read data */ 425 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 426 } 427 428 /* ARGSUSED */ 429 static int 430 nfsmb_read_1(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op, 431 int flags) 432 { 433 uint8_t data; 434 435 /* store cmd */ 436 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 437 438 /* write smbus slave address to register */ 439 data = addr << 1; 440 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 441 442 /* write smbus protocol to register */ 443 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; 444 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 445 446 /* check for errors */ 447 if (nfsmb_check_done(sc) < 0) 448 return -1; 449 450 /* read data */ 451 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 452 } 453 454 static int 455 nfsmb_read_2(struct nfsmb_softc *sc, uint8_t cmd, i2c_addr_t addr, i2c_op_t op, 456 int flags) 457 { 458 uint8_t data, low, high; 459 460 /* store cmd */ 461 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_COMMAND, cmd); 462 463 /* write smbus slave address to register */ 464 data = addr << 1; 465 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_ADDRESS, data); 466 467 /* write smbus protocol to register */ 468 data = I2C_OP_READ_P(op) | NFORCE_SMB_PROTOCOL_BYTE_DATA; 469 if (flags & I2C_F_PEC) 470 data |= NFORCE_SMB_PROTOCOL_PEC; 471 bus_space_write_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_PROTOCOL, data); 472 473 /* check for errors */ 474 if (nfsmb_check_done(sc) < 0) 475 return -1; 476 477 /* read data */ 478 low = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 479 high = bus_space_read_1(sc->sc_iot, sc->sc_ioh, NFORCE_SMB_DATA); 480 return low | high << 8; 481 } 482