Line data Source code
1 : /* $OpenBSD: ichiic.c,v 1.41 2018/04/02 08:39:24 henning 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_9SERIES_SMB },
96 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_9SERIES_LP_SMB },
97 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_SMB },
98 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_SMB },
99 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_SMB },
100 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_SMB },
101 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_SMB },
102 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801E_SMB },
103 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_SMB },
104 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_SMB },
105 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_SMB },
106 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801H_SMB },
107 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801I_SMB },
108 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JD_SMB },
109 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801JI_SMB },
110 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_APOLLOLAKE_SMB },
111 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ATOMC2000_PCU_SMB },
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_DH8900_SMB },
123 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_SMBUS },
124 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_SMB },
125 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_SMB },
126 : { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_200SERIES_SMB }
127 : };
128 :
129 : int
130 0 : ichiic_match(struct device *parent, void *match, void *aux)
131 : {
132 0 : return (pci_matchbyid(aux, ichiic_ids,
133 : sizeof(ichiic_ids) / sizeof(ichiic_ids[0])));
134 : }
135 :
136 : void
137 0 : ichiic_attach(struct device *parent, struct device *self, void *aux)
138 : {
139 0 : struct ichiic_softc *sc = (struct ichiic_softc *)self;
140 0 : struct pci_attach_args *pa = aux;
141 0 : struct i2cbus_attach_args iba;
142 : pcireg_t conf;
143 0 : bus_size_t iosize;
144 0 : pci_intr_handle_t ih;
145 : const char *intrstr = NULL;
146 :
147 : /* Read configuration */
148 0 : conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
149 : DPRINTF((": conf 0x%08x", conf));
150 :
151 0 : if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
152 0 : printf(": SMBus disabled\n");
153 0 : return;
154 : }
155 :
156 : /* Map I/O space */
157 0 : if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
158 0 : &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
159 0 : printf(": can't map i/o space\n");
160 0 : return;
161 : }
162 :
163 0 : sc->sc_poll = 1;
164 0 : if (conf & ICH_SMB_HOSTC_SMIEN) {
165 : /* No PCI IRQ */
166 0 : printf(": SMI");
167 0 : } else {
168 : /* Install interrupt handler */
169 0 : if (pci_intr_map(pa, &ih) == 0) {
170 0 : intrstr = pci_intr_string(pa->pa_pc, ih);
171 0 : sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
172 0 : ichiic_intr, sc, sc->sc_dev.dv_xname);
173 0 : if (sc->sc_ih != NULL) {
174 0 : printf(": %s", intrstr);
175 0 : sc->sc_poll = 0;
176 0 : }
177 : }
178 0 : if (sc->sc_poll)
179 0 : printf(": polling");
180 : }
181 :
182 0 : printf("\n");
183 :
184 : /* Attach I2C bus */
185 0 : rw_init(&sc->sc_i2c_lock, "iiclk");
186 0 : sc->sc_i2c_tag.ic_cookie = sc;
187 0 : sc->sc_i2c_tag.ic_acquire_bus = ichiic_i2c_acquire_bus;
188 0 : sc->sc_i2c_tag.ic_release_bus = ichiic_i2c_release_bus;
189 0 : sc->sc_i2c_tag.ic_exec = ichiic_i2c_exec;
190 :
191 0 : bzero(&iba, sizeof(iba));
192 0 : iba.iba_name = "iic";
193 0 : iba.iba_tag = &sc->sc_i2c_tag;
194 0 : config_found(self, &iba, iicbus_print);
195 :
196 0 : return;
197 0 : }
198 :
199 : int
200 0 : ichiic_i2c_acquire_bus(void *cookie, int flags)
201 : {
202 0 : struct ichiic_softc *sc = cookie;
203 :
204 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
205 0 : return (0);
206 :
207 0 : return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
208 0 : }
209 :
210 : void
211 0 : ichiic_i2c_release_bus(void *cookie, int flags)
212 : {
213 0 : struct ichiic_softc *sc = cookie;
214 :
215 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
216 0 : return;
217 :
218 0 : rw_exit(&sc->sc_i2c_lock);
219 0 : }
220 :
221 : int
222 0 : ichiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
223 : const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
224 : {
225 0 : struct ichiic_softc *sc = cookie;
226 : u_int8_t *b;
227 : u_int8_t ctl, st;
228 : int retries;
229 :
230 : DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
231 : "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
232 : len, flags));
233 :
234 : /* Wait for bus to be idle */
235 0 : for (retries = 100; retries > 0; retries--) {
236 0 : st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
237 0 : if (!(st & ICH_SMB_HS_BUSY))
238 : break;
239 0 : DELAY(ICHIIC_DELAY);
240 : }
241 : DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
242 : ICH_SMB_HS_BITS));
243 0 : if (st & ICH_SMB_HS_BUSY)
244 0 : return (1);
245 :
246 0 : if (cold || sc->sc_poll)
247 0 : flags |= I2C_F_POLL;
248 :
249 0 : if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
250 0 : return (1);
251 :
252 : /* Setup transfer */
253 0 : sc->sc_i2c_xfer.op = op;
254 0 : sc->sc_i2c_xfer.buf = buf;
255 0 : sc->sc_i2c_xfer.len = len;
256 0 : sc->sc_i2c_xfer.flags = flags;
257 0 : sc->sc_i2c_xfer.error = 0;
258 :
259 : /* Set slave address and transfer direction */
260 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
261 : ICH_SMB_TXSLVA_ADDR(addr) |
262 : (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
263 :
264 : b = (void *)cmdbuf;
265 0 : if (cmdlen > 0)
266 : /* Set command byte */
267 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
268 :
269 0 : if (I2C_OP_WRITE_P(op)) {
270 : /* Write data */
271 : b = buf;
272 0 : if (len > 0)
273 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh,
274 : ICH_SMB_HD0, b[0]);
275 0 : if (len > 1)
276 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh,
277 : ICH_SMB_HD1, b[1]);
278 : }
279 :
280 : /* Set SMBus command */
281 0 : if (len == 0)
282 0 : ctl = ICH_SMB_HC_CMD_BYTE;
283 0 : else if (len == 1)
284 0 : ctl = ICH_SMB_HC_CMD_BDATA;
285 0 : else if (len == 2)
286 : ctl = ICH_SMB_HC_CMD_WDATA;
287 : else
288 0 : panic("%s: unexpected len %zd", __func__, len);
289 :
290 0 : if ((flags & I2C_F_POLL) == 0)
291 0 : ctl |= ICH_SMB_HC_INTREN;
292 :
293 : /* Start transaction */
294 0 : ctl |= ICH_SMB_HC_START;
295 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
296 :
297 0 : if (flags & I2C_F_POLL) {
298 : /* Poll for completion */
299 0 : DELAY(ICHIIC_DELAY);
300 0 : for (retries = 1000; retries > 0; retries--) {
301 0 : st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
302 : ICH_SMB_HS);
303 0 : if ((st & ICH_SMB_HS_BUSY) == 0)
304 : break;
305 0 : DELAY(ICHIIC_DELAY);
306 : }
307 0 : if (st & ICH_SMB_HS_BUSY)
308 : goto timeout;
309 0 : ichiic_intr(sc);
310 0 : } else {
311 : /* Wait for interrupt */
312 0 : if (tsleep(sc, PRIBIO, "ichiic", ICHIIC_TIMEOUT * hz))
313 : goto timeout;
314 : }
315 :
316 0 : if (sc->sc_i2c_xfer.error)
317 0 : return (1);
318 :
319 0 : return (0);
320 :
321 : timeout:
322 : /*
323 : * Transfer timeout. Kill the transaction and clear status bits.
324 : */
325 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
326 : ICH_SMB_HC_KILL);
327 0 : DELAY(ICHIIC_DELAY);
328 0 : st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
329 0 : if ((st & ICH_SMB_HS_FAILED) == 0)
330 0 : printf("%s: abort failed, status 0x%b\n",
331 0 : sc->sc_dev.dv_xname, st, ICH_SMB_HS_BITS);
332 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
333 0 : return (1);
334 0 : }
335 :
336 : int
337 0 : ichiic_intr(void *arg)
338 : {
339 0 : struct ichiic_softc *sc = arg;
340 : u_int8_t st;
341 : u_int8_t *b;
342 : size_t len;
343 :
344 : /* Read status */
345 0 : st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
346 :
347 : /* Clear status bits */
348 0 : bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
349 :
350 : /* XXX Ignore SMBALERT# for now */
351 0 : if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
352 : ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
353 0 : ICH_SMB_HS_BDONE)) == 0)
354 : /* Interrupt was not for us */
355 0 : return (0);
356 :
357 : DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
358 : ICH_SMB_HS_BITS));
359 :
360 : /* Check for errors */
361 0 : if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
362 0 : sc->sc_i2c_xfer.error = 1;
363 0 : goto done;
364 : }
365 :
366 0 : if (st & ICH_SMB_HS_INTR) {
367 0 : if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
368 : goto done;
369 :
370 : /* Read data */
371 0 : b = sc->sc_i2c_xfer.buf;
372 0 : len = sc->sc_i2c_xfer.len;
373 0 : if (len > 0)
374 0 : b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
375 : ICH_SMB_HD0);
376 0 : if (len > 1)
377 0 : b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
378 : ICH_SMB_HD1);
379 : }
380 :
381 : done:
382 0 : if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
383 0 : wakeup(sc);
384 0 : return (1);
385 0 : }
|