xref: /openbsd-src/sys/dev/pci/nviic.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
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)
71 int 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 
79 int		nviic_match(struct device *, void *, void *);
80 void		nviic_attach(struct device *, struct device *, void *);
81 
82 struct nviic_softc;
83 
84 struct 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 
91 struct nviic_softc {
92 	struct device		sc_dev;
93 	bus_space_tag_t		sc_iot;
94 	struct nviic_controller	sc_nc[NVIIC_NBUS];
95 };
96 
97 struct cfattach nviic_ca = {
98 	sizeof(struct nviic_softc), nviic_match, nviic_attach
99 };
100 
101 struct cfdriver nviic_cd = {
102 	NULL, "nviic", DV_DULL
103 };
104 
105 int		nviic_i2c_acquire_bus(void *, int);
106 void		nviic_i2c_release_bus(void *, int);
107 int		nviic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
108 		    size_t, void *, size_t, int);
109 
110 u_int8_t	nviic_read(struct nviic_controller *, bus_size_t);
111 void		nviic_write(struct nviic_controller *, bus_size_t, u_int8_t);
112 
113 #define DEVNAME(s)		((sc)->sc_dev.dv_xname)
114 
115 const 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 
132 int
133 nviic_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 
139 void
140 nviic_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 
195 int
196 nviic_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 
206 void
207 nviic_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 
217 int
218 nviic_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 
298 u_int8_t
299 nviic_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 
308 void
309 nviic_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