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