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
ichiic_match(struct device * parent,void * match,void * aux)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
ichiic_attach(struct device * parent,struct device * self,void * aux)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
ichiic_i2c_acquire_bus(void * cookie,int flags)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
ichiic_i2c_release_bus(void * cookie,int flags)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
ichiic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)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
ichiic_intr(void * arg)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