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