Annotation of sys/dev/pci/nviic.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: nviic.c,v 1.11 2007/05/03 09:36:26 dlg 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: };
128:
129: int
130: nviic_match(struct device *parent, void *match, void *aux)
131: {
132: return (pci_matchbyid(aux, nviic_ids,
133: sizeof(nviic_ids) / sizeof(nviic_ids[0])));
134: }
135:
136: void
137: nviic_attach(struct device *parent, struct device *self, void *aux)
138: {
139: struct nviic_softc *sc = (struct nviic_softc *)self;
140: struct pci_attach_args *pa = aux;
141: struct nviic_controller *nc;
142: struct i2cbus_attach_args iba;
143: int baseregs[NVIIC_NBUS];
144: pcireg_t reg;
145: int i;
146:
147: sc->sc_iot = pa->pa_iot;
148:
149: printf("\n");
150:
151: /* Older chipsets used non-standard BARs */
152: switch (PCI_PRODUCT(pa->pa_id)) {
153: case PCI_PRODUCT_NVIDIA_NFORCE2_SMB:
154: case PCI_PRODUCT_NVIDIA_NFORCE2_400_SMB:
155: case PCI_PRODUCT_NVIDIA_NFORCE3_SMB:
156: case PCI_PRODUCT_NVIDIA_NFORCE3_250_SMB:
157: case PCI_PRODUCT_NVIDIA_NFORCE4_SMB:
158: baseregs[0] = NVI_OLD_PCI_SMBASE1;
159: baseregs[1] = NVI_OLD_PCI_SMBASE2;
160: break;
161: default:
162: baseregs[0] = NVI_PCI_SMBASE1;
163: baseregs[1] = NVI_PCI_SMBASE2;
164: }
165:
166: for (i = 0; i < NVIIC_NBUS; i++) {
167: nc = &sc->sc_nc[i];
168:
169: reg = pci_conf_read(pa->pa_pc, pa->pa_tag, baseregs[i]);
170: if (NVI_SMBASE(reg) == 0 ||
171: bus_space_map(sc->sc_iot, NVI_SMBASE(reg), NVI_SMBASE_SIZE,
172: 0, &nc->nc_ioh)) {
173: printf("%s: unable to map space for bus %d\n",
174: DEVNAME(sc), i);
175: continue;
176: }
177:
178: nc->nc_sc = sc;
179: rw_init(&nc->nc_lock, "nviic");
180: nc->nc_i2c.ic_cookie = nc;
181: nc->nc_i2c.ic_acquire_bus = nviic_i2c_acquire_bus;
182: nc->nc_i2c.ic_release_bus = nviic_i2c_release_bus;
183: nc->nc_i2c.ic_exec = nviic_i2c_exec;
184:
185: bzero(&iba, sizeof(iba));
186: iba.iba_name = "iic";
187: iba.iba_tag = &nc->nc_i2c;
188: config_found(self, &iba, iicbus_print);
189: }
190: }
191:
192: int
193: nviic_i2c_acquire_bus(void *arg, int flags)
194: {
195: struct nviic_controller *nc = arg;
196:
197: if (cold || (flags & I2C_F_POLL))
198: return (0);
199:
200: return (rw_enter(&nc->nc_lock, RW_WRITE | RW_INTR));
201: }
202:
203: void
204: nviic_i2c_release_bus(void *arg, int flags)
205: {
206: struct nviic_controller *nc = arg;
207:
208: if (cold || (flags & I2C_F_POLL))
209: return;
210:
211: rw_exit(&nc->nc_lock);
212: }
213:
214: int
215: nviic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
216: const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
217: {
218: struct nviic_controller *nc = arg;
219: #ifdef NVIIC_DEBUG
220: struct nviic_softc *sc = nc->nc_sc;
221: #endif
222: u_int8_t protocol;
223: u_int8_t *b;
224: u_int8_t sts;
225: int i;
226:
227: DPRINTF("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
228: DEVNAME(sc), op, addr, cmdlen, len, flags);
229:
230: if (cold)
231: flags |= I2C_F_POLL;
232:
233: if (I2C_OP_STOP_P(op) == 0 || cmdlen > 1 || len > 2)
234: return (1);
235:
236: /* set slave address */
237: nviic_write(nc, NVI_SMB_ADDR, addr << 1);
238:
239: /* set command byte */
240: if (cmdlen > 0) {
241: b = (u_int8_t *)cmdbuf;
242: nviic_write(nc, NVI_SMB_CMD, b[0]);
243: }
244:
245: b = (u_int8_t *)buf;
246:
247: /* write data */
248: if (I2C_OP_WRITE_P(op)) {
249: for (i = 0; i < len; i++)
250: nviic_write(nc, NVI_SMB_DATA(i), b[i]);
251: }
252:
253: switch (len) {
254: case 0:
255: protocol = NVI_SMB_PRTCL_BYTE;
256: break;
257: case 1:
258: protocol = NVI_SMB_PRTCL_BYTE_DATA;
259: break;
260: case 2:
261: protocol = NVI_SMB_PRTCL_WORD_DATA;
262: break;
263: }
264:
265: /* set direction */
266: if (I2C_OP_READ_P(op))
267: protocol |= NVI_SMB_PRTCL_READ;
268:
269: /* start transaction */
270: nviic_write(nc, NVI_SMB_PRTCL, protocol);
271:
272: for (i = 1000; i > 0; i--) {
273: delay(100);
274: if (nviic_read(nc, NVI_SMB_PRTCL) == 0)
275: break;
276: }
277: if (i == 0) {
278: DPRINTF("%s: timeout\n", DEVNAME(sc));
279: return (1);
280: }
281:
282: sts = nviic_read(nc, NVI_SMB_STS);
283: if (sts & NVI_SMB_STS_STATUS)
284: return (1);
285:
286: /* read data */
287: if (I2C_OP_READ_P(op)) {
288: for (i = 0; i < len; i++)
289: b[i] = nviic_read(nc, NVI_SMB_DATA(i));
290: }
291:
292: return (0);
293: }
294:
295: u_int8_t
296: nviic_read(struct nviic_controller *nc, bus_size_t r)
297: {
298: struct nviic_softc *sc = nc->nc_sc;
299:
300: bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1,
301: BUS_SPACE_BARRIER_READ);
302: return (bus_space_read_1(sc->sc_iot, nc->nc_ioh, r));
303: }
304:
305: void
306: nviic_write(struct nviic_controller *nc, bus_size_t r, u_int8_t v)
307: {
308: struct nviic_softc *sc = nc->nc_sc;
309:
310: bus_space_write_1(sc->sc_iot, nc->nc_ioh, r, v);
311: bus_space_barrier(sc->sc_iot, nc->nc_ioh, r, 1,
312: BUS_SPACE_BARRIER_WRITE);
313: }
CVSweb