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