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