ichsmb.c revision 1.1.4.2 1 /* $NetBSD: ichsmb.c,v 1.1.4.2 2007/08/16 11:03:09 jmcneill Exp $ */
2 /* $OpenBSD: ichiic.c,v 1.18 2007/05/03 09:36:26 dlg Exp $ */
3
4 /*
5 * Copyright (c) 2005, 2006 Alexander Yurchenko <grange (at) openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * Intel ICH SMBus controller driver.
22 */
23
24 #include <sys/param.h>
25 #include <sys/device.h>
26 #include <sys/errno.h>
27 #include <sys/kernel.h>
28 #include <sys/lock.h>
29 #include <sys/proc.h>
30
31 #include <machine/bus.h>
32
33 #include <dev/pci/pcidevs.h>
34 #include <dev/pci/pcireg.h>
35 #include <dev/pci/pcivar.h>
36
37 #include <dev/pci/ichreg.h>
38
39 #include <dev/i2c/i2cvar.h>
40
41 #ifdef ICHIIC_DEBUG
42 #define DPRINTF(x) printf x
43 #else
44 #define DPRINTF(x)
45 #endif
46
47 #define ICHIIC_DELAY 100
48 #define ICHIIC_TIMEOUT 1
49
50 struct ichsmb_softc {
51 struct device sc_dev;
52
53 bus_space_tag_t sc_iot;
54 bus_space_handle_t sc_ioh;
55 void * sc_ih;
56 int sc_poll;
57
58 struct i2c_controller sc_i2c_tag;
59 struct lock sc_i2c_lock;
60 struct {
61 i2c_op_t op;
62 void * buf;
63 size_t len;
64 int flags;
65 volatile int error;
66 } sc_i2c_xfer;
67 };
68
69 static int ichsmb_match(struct device *, struct cfdata *, void *);
70 static void ichsmb_attach(struct device *, struct device *, void *);
71
72 static int ichsmb_i2c_acquire_bus(void *, int);
73 static void ichsmb_i2c_release_bus(void *, int);
74 static int ichsmb_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
75 size_t, void *, size_t, int);
76
77 static int ichsmb_intr(void *);
78
79
80 CFATTACH_DECL(ichsmb, sizeof(struct ichsmb_softc),
81 ichsmb_match, ichsmb_attach, NULL, NULL);
82
83
84 static int
85 ichsmb_match(struct device *parent, struct cfdata *match, void *aux)
86 {
87 struct pci_attach_args *pa = aux;
88
89 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL) {
90 switch (PCI_PRODUCT(pa->pa_id)) {
91 case PCI_PRODUCT_INTEL_6300ESB_SMB:
92 case PCI_PRODUCT_INTEL_63XXESB_SMB:
93 case PCI_PRODUCT_INTEL_82801AA_SMB:
94 case PCI_PRODUCT_INTEL_82801AB_SMB:
95 case PCI_PRODUCT_INTEL_82801BA_SMB:
96 case PCI_PRODUCT_INTEL_82801CA_SMB:
97 case PCI_PRODUCT_INTEL_82801DB_SMB:
98 case PCI_PRODUCT_INTEL_82801E_SMB:
99 case PCI_PRODUCT_INTEL_82801EB_SMB:
100 case PCI_PRODUCT_INTEL_82801FB_SMB:
101 case PCI_PRODUCT_INTEL_82801G_SMB:
102 case PCI_PRODUCT_INTEL_82801H_SMB:
103 return 1;
104 }
105 }
106 return 0;
107 }
108
109 static void
110 ichsmb_attach(struct device *parent, struct device *self, void *aux)
111 {
112 struct ichsmb_softc *sc = (struct ichsmb_softc *)self;
113 struct pci_attach_args *pa = aux;
114 struct i2cbus_attach_args iba;
115 pcireg_t conf;
116 bus_size_t iosize;
117 pci_intr_handle_t ih;
118 const char *intrstr = NULL;
119 char devinfo[256];
120
121 aprint_naive("\n");
122 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
123 aprint_normal(": %s (rev. 0x%02x)\n", devinfo,
124 PCI_REVISION(pa->pa_class));
125
126 /* Read configuration */
127 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_SMB_HOSTC);
128 DPRINTF(("%s: conf 0x%08x", sc->sc_dev.dv_xname, conf));
129
130 if ((conf & ICH_SMB_HOSTC_HSTEN) == 0) {
131 aprint_error("%s: SMBus disabled\n", sc->sc_dev.dv_xname);
132 return;
133 }
134
135 /* Map I/O space */
136 if (pci_mapreg_map(pa, ICH_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
137 &sc->sc_iot, &sc->sc_ioh, NULL, &iosize)) {
138 aprint_error("%s: can't map I/O space\n", sc->sc_dev.dv_xname);
139 return;
140 }
141
142 sc->sc_poll = 1;
143 if (conf & ICH_SMB_HOSTC_SMIEN) {
144 /* No PCI IRQ */
145 aprint_normal("%s: SMI\n", sc->sc_dev.dv_xname);
146 } else {
147 /* Install interrupt handler */
148 if (pci_intr_map(pa, &ih) == 0) {
149 intrstr = pci_intr_string(pa->pa_pc, ih);
150 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
151 ichsmb_intr, sc);
152 if (sc->sc_ih != NULL) {
153 aprint_normal("%s: interrupting at %s\n",
154 sc->sc_dev.dv_xname, intrstr);
155 sc->sc_poll = 0;
156 }
157 }
158 if (sc->sc_poll)
159 aprint_normal("%s: polling\n", sc->sc_dev.dv_xname);
160 }
161
162 /* Attach I2C bus */
163 lockinit(&sc->sc_i2c_lock, PZERO, "smblk", 0, 0);
164 sc->sc_i2c_tag.ic_cookie = sc;
165 sc->sc_i2c_tag.ic_acquire_bus = ichsmb_i2c_acquire_bus;
166 sc->sc_i2c_tag.ic_release_bus = ichsmb_i2c_release_bus;
167 sc->sc_i2c_tag.ic_exec = ichsmb_i2c_exec;
168
169 bzero(&iba, sizeof(iba));
170 iba.iba_tag = &sc->sc_i2c_tag;
171 config_found(self, &iba, iicbus_print);
172
173 return;
174 }
175
176 static int
177 ichsmb_i2c_acquire_bus(void *cookie, int flags)
178 {
179 struct ichsmb_softc *sc = cookie;
180
181 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
182 return (0);
183
184 return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL));
185 }
186
187 static void
188 ichsmb_i2c_release_bus(void *cookie, int flags)
189 {
190 struct ichsmb_softc *sc = cookie;
191
192 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
193 return;
194
195 lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL);
196 }
197
198 static int
199 ichsmb_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
200 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
201 {
202 struct ichsmb_softc *sc = cookie;
203 const uint8_t *b;
204 uint8_t ctl = 0, st;
205 int retries;
206 char fbuf[64];
207
208 DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %d, "
209 "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
210 len, flags));
211
212 /* Wait for bus to be idle */
213 for (retries = 100; retries > 0; retries--) {
214 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
215 if (!(st & ICH_SMB_HS_BUSY))
216 break;
217 DELAY(ICHIIC_DELAY);
218 }
219 #ifdef ICHIIC_DEBUG
220 bitmask_snprintf(st, ICH_SMB_HS_BITS, fbuf, sizeof(fbuf));
221 printf("%s: exec: st 0x%s\n", sc->sc_dev.dv_xname, fbuf);
222 #endif
223 if (st & ICH_SMB_HS_BUSY)
224 return (1);
225
226 if (cold || sc->sc_poll)
227 flags |= I2C_F_POLL;
228
229 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
230 return (1);
231
232 /* Setup transfer */
233 sc->sc_i2c_xfer.op = op;
234 sc->sc_i2c_xfer.buf = buf;
235 sc->sc_i2c_xfer.len = len;
236 sc->sc_i2c_xfer.flags = flags;
237 sc->sc_i2c_xfer.error = 0;
238
239 /* Set slave address and transfer direction */
240 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_TXSLVA,
241 ICH_SMB_TXSLVA_ADDR(addr) |
242 (I2C_OP_READ_P(op) ? ICH_SMB_TXSLVA_READ : 0));
243
244 b = (const uint8_t *)cmdbuf;
245 if (cmdlen > 0)
246 /* Set command byte */
247 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HCMD, b[0]);
248
249 if (I2C_OP_WRITE_P(op)) {
250 /* Write data */
251 b = buf;
252 if (len > 0)
253 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
254 ICH_SMB_HD0, b[0]);
255 if (len > 1)
256 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
257 ICH_SMB_HD1, b[1]);
258 }
259
260 /* Set SMBus command */
261 if (len == 0)
262 ctl = ICH_SMB_HC_CMD_BYTE;
263 else if (len == 1)
264 ctl = ICH_SMB_HC_CMD_BDATA;
265 else if (len == 2)
266 ctl = ICH_SMB_HC_CMD_WDATA;
267
268 if ((flags & I2C_F_POLL) == 0)
269 ctl |= ICH_SMB_HC_INTREN;
270
271 /* Start transaction */
272 ctl |= ICH_SMB_HC_START;
273 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC, ctl);
274
275 if (flags & I2C_F_POLL) {
276 /* Poll for completion */
277 DELAY(ICHIIC_DELAY);
278 for (retries = 1000; retries > 0; retries--) {
279 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
280 ICH_SMB_HS);
281 if ((st & ICH_SMB_HS_BUSY) == 0)
282 break;
283 DELAY(ICHIIC_DELAY);
284 }
285 if (st & ICH_SMB_HS_BUSY)
286 goto timeout;
287 ichsmb_intr(sc);
288 } else {
289 /* Wait for interrupt */
290 if (tsleep(sc, PRIBIO, "iicexec", ICHIIC_TIMEOUT * hz))
291 goto timeout;
292 }
293
294 if (sc->sc_i2c_xfer.error)
295 return (1);
296
297 return (0);
298
299 timeout:
300 /*
301 * Transfer timeout. Kill the transaction and clear status bits.
302 */
303 bitmask_snprintf(st, ICH_SMB_HS_BITS, fbuf, sizeof(fbuf));
304 printf("%s: exec: op %d, addr 0x%02x, cmdlen %zd, len %zd, "
305 "flags 0x%02x: timeout, status 0x%s\n",
306 sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags, fbuf);
307 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HC,
308 ICH_SMB_HC_KILL);
309 DELAY(ICHIIC_DELAY);
310 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
311 if ((st & ICH_SMB_HS_FAILED) == 0) {
312 bitmask_snprintf(st, ICH_SMB_HS_BITS, fbuf, sizeof(fbuf));
313 printf("%s: abort failed, status 0x%s\n",
314 sc->sc_dev.dv_xname, fbuf);
315 }
316 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
317 return (1);
318 }
319
320 static int
321 ichsmb_intr(void *arg)
322 {
323 struct ichsmb_softc *sc = arg;
324 uint8_t st;
325 uint8_t *b;
326 size_t len;
327 #ifdef ICHIIC_DEBUG
328 char fbuf[64];
329 #endif
330
331 /* Read status */
332 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS);
333 if ((st & ICH_SMB_HS_BUSY) != 0 || (st & (ICH_SMB_HS_INTR |
334 ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED |
335 ICH_SMB_HS_SMBAL | ICH_SMB_HS_BDONE)) == 0)
336 /* Interrupt was not for us */
337 return (0);
338
339 #ifdef ICHIIC_DEBUG
340 bitmask_snprintf(st, ICH_SMB_HS_BITS, fbuf, sizeof(fbuf));
341 printf("%s: intr st 0x%s\n", sc->sc_dev.dv_xname, fbuf);
342 #endif
343
344 /* Clear status bits */
345 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ICH_SMB_HS, st);
346
347 /* Check for errors */
348 if (st & (ICH_SMB_HS_DEVERR | ICH_SMB_HS_BUSERR | ICH_SMB_HS_FAILED)) {
349 sc->sc_i2c_xfer.error = 1;
350 goto done;
351 }
352
353 if (st & ICH_SMB_HS_INTR) {
354 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
355 goto done;
356
357 /* Read data */
358 b = sc->sc_i2c_xfer.buf;
359 len = sc->sc_i2c_xfer.len;
360 if (len > 0)
361 b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
362 ICH_SMB_HD0);
363 if (len > 1)
364 b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
365 ICH_SMB_HD1);
366 }
367
368 done:
369 if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
370 wakeup(sc);
371 return (1);
372 }
373