piixpm.c revision 1.2.8.2 1 /* $NetBSD: piixpm.c,v 1.2.8.2 2006/05/24 15:50:28 tron Exp $ */
2 /* $OpenBSD: piixpm.c,v 1.20 2006/02/27 08:25:02 grange 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 PIIX and compatible Power Management controller driver.
22 */
23
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.2.8.2 2006/05/24 15:50:28 tron Exp $");
26
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/kernel.h>
31 #include <sys/lock.h>
32 #include <sys/proc.h>
33
34 #include <machine/bus.h>
35
36 #include <dev/pci/pcidevs.h>
37 #include <dev/pci/pcireg.h>
38 #include <dev/pci/pcivar.h>
39
40 #include <dev/pci/piixpmreg.h>
41
42 #include <dev/i2c/i2cvar.h>
43
44 #ifdef PIIXPM_DEBUG
45 #define DPRINTF(x) printf x
46 #else
47 #define DPRINTF(x)
48 #endif
49
50 #define PIIXPM_DELAY 200
51 #define PIIXPM_TIMEOUT 1
52
53 struct piixpm_softc {
54 struct device sc_dev;
55
56 bus_space_tag_t sc_iot;
57 bus_space_handle_t sc_ioh;
58 void * sc_ih;
59 int sc_poll;
60
61 struct i2c_controller sc_i2c_tag;
62 struct lock sc_i2c_lock;
63 struct {
64 i2c_op_t op;
65 void * buf;
66 size_t len;
67 int flags;
68 volatile int error;
69 } sc_i2c_xfer;
70 };
71
72 int piixpm_match(struct device *, struct cfdata *, void *);
73 void piixpm_attach(struct device *, struct device *, void *);
74
75 int piixpm_i2c_acquire_bus(void *, int);
76 void piixpm_i2c_release_bus(void *, int);
77 int piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
78 void *, size_t, int);
79
80 int piixpm_intr(void *);
81
82 CFATTACH_DECL(piixpm, sizeof(struct piixpm_softc),
83 piixpm_match, piixpm_attach, NULL, NULL);
84
85 int
86 piixpm_match(struct device *parent, struct cfdata *match, void *aux)
87 {
88 struct pci_attach_args *pa;
89
90 pa = (struct pci_attach_args *)aux;
91 switch (PCI_VENDOR(pa->pa_id)) {
92 case PCI_VENDOR_INTEL:
93 switch (PCI_PRODUCT(pa->pa_id)) {
94 case PCI_PRODUCT_INTEL_82371AB_PMC:
95 case PCI_PRODUCT_INTEL_82440MX_PMC:
96 return 1;
97 }
98 break;
99 case PCI_VENDOR_ATI:
100 switch (PCI_PRODUCT(pa->pa_id)) {
101 case PCI_PRODUCT_ATI_SB200_SMB:
102 return 1;
103 }
104 break;
105 }
106
107 return 0;
108 }
109
110 void
111 piixpm_attach(struct device *parent, struct device *self, void *aux)
112 {
113 struct piixpm_softc *sc = (struct piixpm_softc *)self;
114 struct pci_attach_args *pa = aux;
115 struct i2cbus_attach_args iba;
116 pcireg_t base, conf;
117 pci_intr_handle_t ih;
118 const char *intrstr = NULL;
119
120 /* Read configuration */
121 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC);
122 DPRINTF((": conf 0x%x", conf));
123
124 if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) {
125 printf(": SMBus disabled\n");
126 return;
127 }
128
129 /* Map I/O space */
130 sc->sc_iot = pa->pa_iot;
131 base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff;
132 if (bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base),
133 PIIX_SMB_SIZE, 0, &sc->sc_ioh)) {
134 printf(": can't map I/O space\n");
135 return;
136 }
137
138 sc->sc_poll = 1;
139 if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) {
140 /* No PCI IRQ */
141 printf(": SMI");
142 } else if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) {
143 /* Install interrupt handler */
144 if (pci_intr_map(pa, &ih) == 0) {
145 intrstr = pci_intr_string(pa->pa_pc, ih);
146 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
147 piixpm_intr, sc);
148 if (sc->sc_ih != NULL) {
149 printf(": %s", intrstr);
150 sc->sc_poll = 0;
151 }
152 }
153 if (sc->sc_poll)
154 printf(": polling");
155 }
156
157 printf("\n");
158
159 /* Attach I2C bus */
160 lockinit(&sc->sc_i2c_lock, PRIBIO | PCATCH, "iiclk", 0, 0);
161 sc->sc_i2c_tag.ic_cookie = sc;
162 sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus;
163 sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus;
164 sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec;
165
166 bzero(&iba, sizeof(iba));
167 iba.iba_name = "iic";
168 iba.iba_tag = &sc->sc_i2c_tag;
169 config_found(self, &iba, iicbus_print);
170
171 return;
172 }
173
174 int
175 piixpm_i2c_acquire_bus(void *cookie, int flags)
176 {
177 struct piixpm_softc *sc = cookie;
178
179 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
180 return (0);
181
182 return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL));
183 }
184
185 void
186 piixpm_i2c_release_bus(void *cookie, int flags)
187 {
188 struct piixpm_softc *sc = cookie;
189
190 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
191 return;
192
193 lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL);
194 }
195
196 int
197 piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
198 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
199 {
200 struct piixpm_softc *sc = cookie;
201 const u_int8_t *b;
202 u_int8_t ctl = 0, st;
203 int retries;
204
205 DPRINTF(("%s: exec: op %d, addr 0x%x, cmdlen %d, len %d, flags 0x%x\n",
206 sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags));
207
208 /* Wait for bus to be idle */
209 for (retries = 100; retries > 0; retries--) {
210 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
211 if (!(st & PIIX_SMB_HS_BUSY))
212 break;
213 DELAY(PIIXPM_DELAY);
214 }
215 DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
216 PIIX_SMB_HS_BITS));
217 if (st & PIIX_SMB_HS_BUSY)
218 return (1);
219
220 if (cold || sc->sc_poll)
221 flags |= I2C_F_POLL;
222
223 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
224 return (1);
225
226 /* Setup transfer */
227 sc->sc_i2c_xfer.op = op;
228 sc->sc_i2c_xfer.buf = buf;
229 sc->sc_i2c_xfer.len = len;
230 sc->sc_i2c_xfer.flags = flags;
231 sc->sc_i2c_xfer.error = 0;
232
233 /* Set slave address and transfer direction */
234 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_TXSLVA,
235 PIIX_SMB_TXSLVA_ADDR(addr) |
236 (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0));
237
238 b = cmdbuf;
239 if (cmdlen > 0)
240 /* Set command byte */
241 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HCMD, b[0]);
242
243 if (I2C_OP_WRITE_P(op)) {
244 /* Write data */
245 b = buf;
246 if (len > 0)
247 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
248 PIIX_SMB_HD0, b[0]);
249 if (len > 1)
250 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
251 PIIX_SMB_HD1, b[1]);
252 }
253
254 /* Set SMBus command */
255 if (len == 0)
256 ctl = PIIX_SMB_HC_CMD_BYTE;
257 else if (len == 1)
258 ctl = PIIX_SMB_HC_CMD_BDATA;
259 else if (len == 2)
260 ctl = PIIX_SMB_HC_CMD_WDATA;
261
262 if ((flags & I2C_F_POLL) == 0)
263 ctl |= PIIX_SMB_HC_INTREN;
264
265 /* Start transaction */
266 ctl |= PIIX_SMB_HC_START;
267 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC, ctl);
268
269 if (flags & I2C_F_POLL) {
270 /* Poll for completion */
271 DELAY(PIIXPM_DELAY);
272 for (retries = 1000; retries > 0; retries--) {
273 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
274 PIIX_SMB_HS);
275 if ((st & PIIX_SMB_HS_BUSY) == 0)
276 break;
277 DELAY(PIIXPM_DELAY);
278 }
279 if (st & PIIX_SMB_HS_BUSY)
280 goto timeout;
281 piixpm_intr(sc);
282 } else {
283 /* Wait for interrupt */
284 if (tsleep(sc, PRIBIO, "iicexec", PIIXPM_TIMEOUT * hz))
285 goto timeout;
286 }
287
288 if (sc->sc_i2c_xfer.error)
289 return (1);
290
291 return (0);
292
293 timeout:
294 /*
295 * Transfer timeout. Kill the transaction and clear status bits.
296 */
297 printf("%s: timeout, status 0x%x\n", sc->sc_dev.dv_xname, st);
298 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC,
299 PIIX_SMB_HC_KILL);
300 DELAY(PIIXPM_DELAY);
301 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
302 if ((st & PIIX_SMB_HS_FAILED) == 0)
303 printf("%s: transaction abort failed, status 0x%x\n",
304 sc->sc_dev.dv_xname, st);
305 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);
306 return (1);
307 }
308
309 int
310 piixpm_intr(void *arg)
311 {
312 struct piixpm_softc *sc = arg;
313 u_int8_t st;
314 u_int8_t *b;
315 size_t len;
316
317 /* Read status */
318 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);
319 if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR |
320 PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
321 PIIX_SMB_HS_FAILED)) == 0)
322 /* Interrupt was not for us */
323 return (0);
324
325 DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
326 PIIX_SMB_HS_BITS));
327
328 /* Clear status bits */
329 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);
330
331 /* Check for errors */
332 if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
333 PIIX_SMB_HS_FAILED)) {
334 sc->sc_i2c_xfer.error = 1;
335 goto done;
336 }
337
338 if (st & PIIX_SMB_HS_INTR) {
339 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
340 goto done;
341
342 /* Read data */
343 b = sc->sc_i2c_xfer.buf;
344 len = sc->sc_i2c_xfer.len;
345 if (len > 0)
346 b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
347 PIIX_SMB_HD0);
348 if (len > 1)
349 b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
350 PIIX_SMB_HD1);
351 }
352
353 done:
354 if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
355 wakeup(sc);
356 return (1);
357 }
358