1 /* $OpenBSD: nviic.c,v 1.13 2008/05/22 05:27:01 brad Exp $ */ 2 3 /* 4 * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/kernel.h> 23 #include <sys/rwlock.h> 24 #include <sys/proc.h> 25 26 #include <machine/bus.h> 27 28 #include <dev/pci/pcidevs.h> 29 #include <dev/pci/pcireg.h> 30 #include <dev/pci/pcivar.h> 31 32 #include <dev/i2c/i2cvar.h> 33 34 /* PCI Configuration space registers */ 35 #define NVI_PCI_SMBASE1 0x20 36 #define NVI_PCI_SMBASE2 0x24 37 38 #define NVI_OLD_PCI_SMBASE1 0x50 39 #define NVI_OLD_PCI_SMBASE2 0x54 40 41 #define NVI_SMBASE(x) ((x) & 0xfffc) 42 #define NVI_SMBASE_SIZE 8 43 44 /* SMBus 2.0 registers */ 45 #define NVI_SMB_PRTCL 0x00 /* protocol, PEC */ 46 #define NVI_SMB_STS 0x01 /* status */ 47 #define NVI_SMB_ADDR 0x02 /* address */ 48 #define NVI_SMB_CMD 0x03 /* command */ 49 #define NVI_SMB_DATA(o) (0x04 + (o)) /* 32 data registers */ 50 #define NVI_SMB_BCNT 0x24 /* number of data bytes */ 51 #define NVI_SMB_ALRM_A 0x25 /* alarm address */ 52 #define NVI_SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 53 54 #define NVI_SMB_STS_DONE 0x80 55 #define NVI_SMB_STS_ALRM 0x40 56 #define NVI_SMB_STS_RES 0x20 57 #define NVI_SMB_STS_STATUS 0x1f 58 59 #define NVI_SMB_PRTCL_WRITE 0x00 60 #define NVI_SMB_PRTCL_READ 0x01 61 #define NVI_SMB_PRTCL_QUICK 0x02 62 #define NVI_SMB_PRTCL_BYTE 0x04 63 #define NVI_SMB_PRTCL_BYTE_DATA 0x06 64 #define NVI_SMB_PRTCL_WORD_DATA 0x08 65 #define NVI_SMB_PRTCL_BLOCK_DATA 0x0a 66 #define NVI_SMB_PRTCL_PROC_CALL 0x0c 67 #define NVI_SMB_PRTCL_BLOCK_PROC_CALL 0x0d 68 #define NVI_SMB_PRTCL_PEC 0x80 69 70 #ifdef NVIIC_DEBUG 71 #define DPRINTF(x...) do { if (nviic_debug) printf(x); } while (0) 72 int nviic_debug = 1; 73 #else 74 #define DPRINTF(x...) /* x */ 75 #endif 76 77 /* there are two iic busses on this pci device */ 78 #define NVIIC_NBUS 2 79 80 int nviic_match(struct device *, void *, void *); 81 void nviic_attach(struct device *, struct device *, void *); 82 83 struct nviic_softc; 84 85 struct nviic_controller { 86 struct nviic_softc *nc_sc; 87 bus_space_handle_t nc_ioh; 88 struct rwlock nc_lock; 89 struct i2c_controller nc_i2c; 90 }; 91 92 struct nviic_softc { 93 struct device sc_dev; 94 bus_space_tag_t sc_iot; 95 struct nviic_controller sc_nc[NVIIC_NBUS]; 96 }; 97 98 struct cfattach nviic_ca = { 99 sizeof(struct nviic_softc), nviic_match, nviic_attach 100 }; 101 102 struct cfdriver nviic_cd = { 103 NULL, "nviic", DV_DULL 104 }; 105 106 int nviic_i2c_acquire_bus(void *, int); 107 void nviic_i2c_release_bus(void *, int); 108 int nviic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, 109 size_t, void *, size_t, int); 110 111 u_int8_t nviic_read(struct nviic_controller *, bus_size_t); 112 void nviic_write(struct nviic_controller *, bus_size_t, u_int8_t); 113 114 #define DEVNAME(s) ((sc)->sc_dev.dv_xname) 115 116 const struct pci_matchid nviic_ids[] = { 117 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_SMB }, 118 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_SMB }, 119 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_SMB }, 120 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_SMB }, 121 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_SMB }, 122 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_SMB }, 123 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP55_SMB }, 124 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP61_SMB }, 125 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP65_SMB }, 126 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP67_SMB }, 127 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP73_SMB }, 128 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP77_SMB }, 129 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP79_SMB }, 130 { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP7B_SMB } 131 }; 132 133 int 134 nviic_match(struct device *parent, void *match, void *aux) 135 { 136 return (pci_matchbyid(aux, nviic_ids, 137 sizeof(nviic_ids) / sizeof(nviic_ids[0]))); 138 } 139 140 void 141 nviic_attach(struct device *parent, struct device *self, void *aux) 142 { 143 struct nviic_softc *sc = (struct nviic_softc *)self; 144 struct pci_attach_args *pa = aux; 145 struct nviic_controller *nc; 146 struct i2cbus_attach_args iba; 147 int baseregs[NVIIC_NBUS]; 148 pcireg_t reg; 149 int i; 150 151 sc->sc_iot = pa->pa_iot; 152 153 printf("\n"); 154 155 /* Older chipsets used non-standard BARs */ 156 switch (PCI_PRODUCT(pa->pa_id)) { 157 case PCI_PRODUCT_NVIDIA_NFORCE2_SMB: 158 case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMB: 159 case PCI_PRODUCT_NVIDIA_NFORCE3_SMB: 160 case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMB: 161 case PCI_PRODUCT_NVIDIA_NFORCE4_SMB: 162 baseregs[0] = NVI_OLD_PCI_SMBASE1; 163 baseregs[1] = NVI_OLD_PCI_SMBASE2; 164 break; 165 default: 166 baseregs[0] = NVI_PCI_SMBASE1; 167 baseregs[1] = NVI_PCI_SMBASE2; 168 } 169 170 for (i = 0; i < NVIIC_NBUS; i++) { 171 nc = &sc->sc_nc[i]; 172 173 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[i]); 174 if (NVI_SMBASE(reg) == 0 || 175 bus_space_map(sc->sc_iot, NVI_SMBASE(reg), NVI_SMBASE_SIZE, 176 0, &nc->nc_ioh)) { 177 printf("%s: unable to map space for bus %d\n", 178 DEVNAME(sc), i); 179 continue; 180 } 181 182 nc->nc_sc = sc; 183 rw_init(&nc->nc_lock, "nviic"); 184 nc->nc_i2c.ic_cookie = nc; 185 nc->nc_i2c.ic_acquire_bus = nviic_i2c_acquire_bus; 186 nc->nc_i2c.ic_release_bus = nviic_i2c_release_bus; 187 nc->nc_i2c.ic_exec = nviic_i2c_exec; 188 189 bzero(&iba, sizeof(iba)); 190 iba.iba_name = "iic"; 191 iba.iba_tag = &nc->nc_i2c; 192 config_found(self, &iba, iicbus_print); 193 } 194 } 195 196 int 197 nviic_i2c_acquire_bus(void *arg, int flags) 198 { 199 struct nviic_controller *nc = arg; 200 201 if (cold || (flags & I2C_F_POLL)) 202 return (0); 203 204 return (rw_enter(&nc->nc_lock, RW_WRITE | RW_INTR)); 205 } 206 207 void 208 nviic_i2c_release_bus(void *arg, int flags) 209 { 210 struct nviic_controller *nc = arg; 211 212 if (cold || (flags & I2C_F_POLL)) 213 return; 214 215 rw_exit(&nc->nc_lock); 216 } 217 218 int 219 nviic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr, 220 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) 221 { 222 struct nviic_controller *nc = arg; 223 #ifdef NVIIC_DEBUG 224 struct nviic_softc *sc = nc->nc_sc; 225 #endif 226 u_int8_t protocol; 227 u_int8_t *b; 228 u_int8_t sts; 229 int i; 230 231 DPRINTF("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n", 232 DEVNAME(sc), op, addr, cmdlen, len, flags); 233 234 if (cold) 235 flags |= I2C_F_POLL; 236 237 if (I2C_OP_STOP_P(op) == 0 || cmdlen > 1 || len > 2) 238 return (1); 239 240 /* set slave address */ 241 nviic_write(nc, NVI_SMB_ADDR, addr << 1); 242 243 /* set command byte */ 244 if (cmdlen > 0) { 245 b = (u_int8_t *)cmdbuf; 246 nviic_write(nc, NVI_SMB_CMD, b[0]); 247 } 248 249 b = (u_int8_t *)buf; 250 251 /* write data */ 252 if (I2C_OP_WRITE_P(op)) { 253 for (i = 0; i < len; i++) 254 nviic_write(nc, NVI_SMB_DATA(i), b[i]); 255 } 256 257 switch (len) { 258 case 0: 259 protocol = NVI_SMB_PRTCL_BYTE; 260 break; 261 case 1: 262 protocol = NVI_SMB_PRTCL_BYTE_DATA; 263 break; 264 case 2: 265 protocol = NVI_SMB_PRTCL_WORD_DATA; 266 break; 267 } 268 269 /* set direction */ 270 if (I2C_OP_READ_P(op)) 271 protocol |= NVI_SMB_PRTCL_READ; 272 273 /* start transaction */ 274 nviic_write(nc, NVI_SMB_PRTCL, protocol); 275 276 for (i = 1000; i > 0; i--) { 277 delay(100); 278 if (nviic_read(nc, NVI_SMB_PRTCL) == 0) 279 break; 280 } 281 if (i == 0) { 282 DPRINTF("%s: timeout\n", DEVNAME(sc)); 283 return (1); 284 } 285 286 sts = nviic_read(nc, NVI_SMB_STS); 287 if (sts & NVI_SMB_STS_STATUS) 288 return (1); 289 290 /* read data */ 291 if (I2C_OP_READ_P(op)) { 292 for (i = 0; i < len; i++) 293 b[i] = nviic_read(nc, NVI_SMB_DATA(i)); 294 } 295 296 return (0); 297 } 298 299 u_int8_t 300 nviic_read(struct nviic_controller *nc, bus_size_t r) 301 { 302 struct nviic_softc *sc = nc->nc_sc; 303 304 bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1, 305 BUS_SPACE_BARRIER_READ); 306 return (bus_space_read_1(sc->sc_iot, nc->nc_ioh, r)); 307 } 308 309 void 310 nviic_write(struct nviic_controller *nc, bus_size_t r, u_int8_t v) 311 { 312 struct nviic_softc *sc = nc->nc_sc; 313 314 bus_space_write_1(sc->sc_iot, nc->nc_ioh, r, v); 315 bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1, 316 BUS_SPACE_BARRIER_WRITE); 317 } 318