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