xref: /openbsd/sys/dev/pci/ichiic.c (revision 91f110e0)
1 /*	$OpenBSD: ichiic.c,v 1.33 2014/03/10 02:31:12 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@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 /*
20  * Intel ICH SMBus controller driver.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kernel.h>
27 #include <sys/rwlock.h>
28 
29 #include <machine/bus.h>
30 
31 #include <dev/pci/pcidevs.h>
32 #include <dev/pci/pcireg.h>
33 #include <dev/pci/pcivar.h>
34 
35 #include <dev/pci/ichreg.h>
36 
37 #include <dev/i2c/i2cvar.h>
38 
39 #ifdef ICHIIC_DEBUG
40 #define DPRINTF(x) printf x
41 #else
42 #define DPRINTF(x)
43 #endif
44 
45 #define ICHIIC_DELAY	100
46 #define ICHIIC_TIMEOUT	1
47 
48 struct ichiic_softc {
49 	struct device		sc_dev;
50 
51 	bus_space_tag_t		sc_iot;
52 	bus_space_handle_t	sc_ioh;
53 	void *			sc_ih;
54 	int			sc_poll;
55 
56 	struct i2c_controller	sc_i2c_tag;
57 	struct rwlock		sc_i2c_lock;
58 	struct {
59 		i2c_op_t     op;
60 		void *       buf;
61 		size_t       len;
62 		int          flags;
63 		volatile int error;
64 	}			sc_i2c_xfer;
65 };
66 
67 int	ichiic_match(struct device *, void *, void *);
68 void	ichiic_attach(struct device *, struct device *, void *);
69 
70 int	ichiic_i2c_acquire_bus(void *, int);
71 void	ichiic_i2c_release_bus(void *, int);
72 int	ichiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
73 	    void *, size_t, int);
74 
75 int	ichiic_intr(void *);
76 
77 struct cfattach ichiic_ca = {
78 	sizeof(struct ichiic_softc),
79 	ichiic_match,
80 	ichiic_attach
81 };
82 
83 struct cfdriver ichiic_cd = {
84 	NULL, "ichiic", DV_DULL
85 };
86 
87 const struct pci_matchid ichiic_ids[] = {
88 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_3400_SMB },
89 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6SERIES_SMB },
90 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_SMB },
91 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_SMB },
92 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_7SERIES_SMB },
93 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_SMB },
94 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_8SERIES_LP_SMB },
95 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
96 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
97 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
98 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
99 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
100 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
101 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
102 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
103 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
104 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB },
105 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_SMB },
106 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JD_SMB },
107 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SMB },
108 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ATOMC2000_PCU_SMB },
109 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB },
110 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_1 },
111 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_2 },
112 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_C600_SMB_IDF_3 },
113 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_DH8900_SMB },
114 	{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_SMBUS }
115 };
116 
117 int
118 ichiic_match(struct device *parent, void *match, void *aux)
119 {
120 	return (pci_matchbyid(aux, ichiic_ids,
121 	    sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
122 }
123 
124 void
125 ichiic_attach(struct device *parent, struct device *self, void *aux)
126 {
127 	struct ichiic_softc *sc = (struct ichiic_softc *)self;
128 	struct pci_attach_args *pa = aux;
129 	struct i2cbus_attach_args iba;
130 	pcireg_t conf;
131 	bus_size_t iosize;
132 	pci_intr_handle_t ih;
133 	const char *intrstr = NULL;
134 
135 	/* Read configuration */
136 	conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
137 	DPRINTF((": conf 0x%08x", conf));
138 
139 	if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
140 		printf(": SMBus disabled\n");
141 		return;
142 	}
143 
144 	/* Map I/O space */
145 	if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
146 	    &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
147 		printf(": can't map i/o space\n");
148 		return;
149 	}
150 
151 	sc->sc_poll = 1;
152 	if (conf & ICH_SMB_HOSTC_SMIEN) {
153 		/* No PCI IRQ */
154 		printf(": SMI");
155 	} else {
156 		/* Install interrupt handler */
157 		if (pci_intr_map(pa, &ih) == 0) {
158 			intrstr = pci_intr_string(pa->pa_pc, ih);
159 			sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
160 			    ichiic_intr, sc, sc->sc_dev.dv_xname);
161 			if (sc->sc_ih != NULL) {
162 				printf(": %s", intrstr);
163 				sc->sc_poll = 0;
164 			}
165 		}
166 		if (sc->sc_poll)
167 			printf(": polling");
168 	}
169 
170 	printf("\n");
171 
172 	/* Attach I2C bus */
173 	rw_init(&sc->sc_i2c_lock, "iiclk");
174 	sc->sc_i2c_tag.ic_cookie = sc;
175 	sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
176 	sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
177 	sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
178 
179 	bzero(&iba, sizeof(iba));
180 	iba.iba_name = "iic";
181 	iba.iba_tag = &sc->sc_i2c_tag;
182 	config_found(self, &iba, iicbus_print);
183 
184 	return;
185 }
186 
187 int
188 ichiic_i2c_acquire_bus(void *cookie, int flags)
189 {
190 	struct ichiic_softc *sc = cookie;
191 
192 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
193 		return (0);
194 
195 	return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
196 }
197 
198 void
199 ichiic_i2c_release_bus(void *cookie, int flags)
200 {
201 	struct ichiic_softc *sc = cookie;
202 
203 	if (cold || sc->sc_poll || (flags & I2C_F_POLL))
204 		return;
205 
206 	rw_exit(&sc->sc_i2c_lock);
207 }
208 
209 int
210 ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
211     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
212 {
213 	struct ichiic_softc *sc = cookie;
214 	u_int8_t *b;
215 	u_int8_t ctl, st;
216 	int retries;
217 
218 	DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
219 	    "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
220 	    len, flags));
221 
222 	/* Wait for bus to be idle */
223 	for (retries = 100; retries > 0; retries--) {
224 		st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
225 		if (!(st & ICH_SMB_HS_BUSY))
226 			break;
227 		DELAY(ICHIIC_DELAY);
228 	}
229 	DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
230 	    ICH_SMB_HS_BITS));
231 	if (st & ICH_SMB_HS_BUSY)
232 		return (1);
233 
234 	if (cold || sc->sc_poll)
235 		flags |= I2C_F_POLL;
236 
237 	if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
238 		return (1);
239 
240 	/* Setup transfer */
241 	sc->sc_i2c_xfer.op = op;
242 	sc->sc_i2c_xfer.buf = buf;
243 	sc->sc_i2c_xfer.len = len;
244 	sc->sc_i2c_xfer.flags = flags;
245 	sc->sc_i2c_xfer.error = 0;
246 
247 	/* Set slave address and transfer direction */
248 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
249 	    ICH_SMB_TXSLVA_ADDR(addr) |
250 	    (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
251 
252 	b = (void *)cmdbuf;
253 	if (cmdlen > 0)
254 		/* Set command byte */
255 		bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
256 
257 	if (I2C_OP_WRITE_P(op)) {
258 		/* Write data */
259 		b = buf;
260 		if (len > 0)
261 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
262 			    ICH_SMB_HD0, b[0]);
263 		if (len > 1)
264 			bus_space_write_1(sc->sc_iot, sc->sc_ioh,
265 			    ICH_SMB_HD1, b[1]);
266 	}
267 
268 	/* Set SMBus command */
269 	if (len == 0)
270 		ctl = ICH_SMB_HC_CMD_BYTE;
271 	else if (len == 1)
272 		ctl = ICH_SMB_HC_CMD_BDATA;
273 	else if (len == 2)
274 		ctl = ICH_SMB_HC_CMD_WDATA;
275 	else
276 		panic("%s: unexpected len %zd", __func__, len);
277 
278 	if ((flags & I2C_F_POLL) == 0)
279 		ctl |= ICH_SMB_HC_INTREN;
280 
281 	/* Start transaction */
282 	ctl |= ICH_SMB_HC_START;
283 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
284 
285 	if (flags & I2C_F_POLL) {
286 		/* Poll for completion */
287 		DELAY(ICHIIC_DELAY);
288 		for (retries = 1000; retries > 0; retries--) {
289 			st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
290 			    ICH_SMB_HS);
291 			if ((st & ICH_SMB_HS_BUSY) == 0)
292 				break;
293 			DELAY(ICHIIC_DELAY);
294 		}
295 		if (st & ICH_SMB_HS_BUSY)
296 			goto timeout;
297 		ichiic_intr(sc);
298 	} else {
299 		/* Wait for interrupt */
300 		if (tsleep(sc, PRIBIO, "ichiic", ICHIIC_TIMEOUT * hz))
301 			goto timeout;
302 	}
303 
304 	if (sc->sc_i2c_xfer.error)
305 		return (1);
306 
307 	return (0);
308 
309 timeout:
310 	/*
311 	 * Transfer timeout. Kill the transaction and clear status bits.
312 	 */
313 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
314 	    ICH_SMB_HC_KILL);
315 	DELAY(ICHIIC_DELAY);
316 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
317 	if ((st & ICH_SMB_HS_FAILED) == 0)
318 		printf("%s: abort failed, status 0x%b\n",
319 		    sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
320 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
321 	return (1);
322 }
323 
324 int
325 ichiic_intr(void *arg)
326 {
327 	struct ichiic_softc *sc = arg;
328 	u_int8_t st;
329 	u_int8_t *b;
330 	size_t len;
331 
332 	/* Read status */
333 	st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
334 	if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
335 	    ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
336 	    ICH_SMB_HS_SMBAL | ICH_SMB_HS_BDONE)) == 0)
337 		/* Interrupt was not for us */
338 		return (0);
339 
340 	DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
341 	    ICH_SMB_HS_BITS));
342 
343 	/* Clear status bits */
344 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
345 
346 	/* Check for errors */
347 	if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
348 		sc->sc_i2c_xfer.error = 1;
349 		goto done;
350 	}
351 
352 	if (st & ICH_SMB_HS_INTR) {
353 		if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
354 			goto done;
355 
356 		/* Read data */
357 		b = sc->sc_i2c_xfer.buf;
358 		len = sc->sc_i2c_xfer.len;
359 		if (len > 0)
360 			b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
361 			    ICH_SMB_HD0);
362 		if (len > 1)
363 			b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
364 			    ICH_SMB_HD1);
365 	}
366 
367 done:
368 	if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
369 		wakeup(sc);
370 	return (1);
371 }
372