xref: /openbsd-src/sys/dev/pci/nviic.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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