Line data Source code
1 : /* $OpenBSD: amdpm.c,v 1.33 2018/04/28 15:44:59 jasper Exp $ */
2 :
3 : /*
4 : * Copyright (c) 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 : * Copyright (c) 2002 The NetBSD Foundation, Inc.
21 : * All rights reserved.
22 : *
23 : * This code is derived from software contributed to The NetBSD Foundation
24 : * by Enami Tsugutomo.
25 : *
26 : * Redistribution and use in source and binary forms, with or without
27 : * modification, are permitted provided that the following conditions
28 : * are met:
29 : * 1. Redistributions of source code must retain the above copyright
30 : * notice, this list of conditions and the following disclaimer.
31 : * 2. Redistributions in binary form must reproduce the above copyright
32 : * notice, this list of conditions and the following disclaimer in the
33 : * documentation and/or other materials provided with the distribution.
34 : *
35 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
36 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
37 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
39 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45 : * POSSIBILITY OF SUCH DAMAGE.
46 : */
47 :
48 : #include <sys/param.h>
49 : #include <sys/systm.h>
50 : #include <sys/device.h>
51 : #include <sys/kernel.h>
52 : #include <sys/rwlock.h>
53 : #include <sys/timeout.h>
54 : #include <sys/timetc.h>
55 :
56 : #include <machine/bus.h>
57 :
58 : #include <dev/pci/pcivar.h>
59 : #include <dev/pci/pcireg.h>
60 : #include <dev/pci/pcidevs.h>
61 :
62 : #include <dev/rndvar.h>
63 : #include <dev/i2c/i2cvar.h>
64 :
65 : #ifdef AMDPM_DEBUG
66 : #define DPRINTF(x...) printf(x)
67 : #else
68 : #define DPRINTF(x...)
69 : #endif
70 :
71 : #define AMDPM_SMBUS_DELAY 100
72 : #define AMDPM_SMBUS_TIMEOUT 1
73 :
74 : u_int amdpm_get_timecount(struct timecounter *tc);
75 :
76 : #ifndef AMDPM_FREQUENCY
77 : #define AMDPM_FREQUENCY 3579545
78 : #endif
79 :
80 : static struct timecounter amdpm_timecounter = {
81 : amdpm_get_timecount, /* get_timecount */
82 : 0, /* no poll_pps */
83 : 0xffffff, /* counter_mask */
84 : AMDPM_FREQUENCY, /* frequency */
85 : "AMDPM", /* name */
86 : 1000 /* quality */
87 : };
88 :
89 : #define AMDPM_CONFREG 0x40
90 :
91 : /* 0x40: General Configuration 1 Register */
92 : #define AMDPM_RNGEN 0x00000080 /* random number generator enable */
93 : #define AMDPM_STOPTMR 0x00000040 /* stop free-running timer */
94 :
95 : /* 0x41: General Configuration 2 Register */
96 : #define AMDPM_PMIOEN 0x00008000 /* system management IO space enable */
97 : #define AMDPM_TMRRST 0x00004000 /* reset free-running timer */
98 : #define AMDPM_TMR32 0x00000800 /* extended (32 bit) timer enable */
99 :
100 : /* 0x42: SCI Interrupt Configuration Register */
101 : /* 0x43: Previous Power State Register */
102 :
103 : #define AMDPM_PMPTR 0x58 /* PMxx System Management IO space
104 : Pointer */
105 : #define NFPM_PMPTR 0x14 /* nForce System Management IO space
106 : POinter */
107 : #define AMDPM_PMBASE(x) ((x) & 0xff00) /* PMxx base address */
108 : #define AMDPM_PMSIZE 256 /* PMxx space size */
109 :
110 : /* Registers in PMxx space */
111 : #define AMDPM_TMR 0x08 /* 24/32 bit timer register */
112 :
113 : #define AMDPM_RNGDATA 0xf0 /* 32 bit random data register */
114 : #define AMDPM_RNGSTAT 0xf4 /* RNG status register */
115 : #define AMDPM_RNGDONE 0x00000001 /* Random number generation complete */
116 :
117 : #define AMDPM_SMB_REGS 0xe0 /* offset of SMB register space */
118 : #define AMDPM_SMB_SIZE 0xf /* size of SMB register space */
119 : #define AMDPM_SMBSTAT 0x0 /* SMBus status */
120 : #define AMDPM_SMBSTAT_ABRT (1 << 0) /* transfer abort */
121 : #define AMDPM_SMBSTAT_COL (1 << 1) /* collision */
122 : #define AMDPM_SMBSTAT_PRERR (1 << 2) /* protocol error */
123 : #define AMDPM_SMBSTAT_HBSY (1 << 3) /* host controller busy */
124 : #define AMDPM_SMBSTAT_CYC (1 << 4) /* cycle complete */
125 : #define AMDPM_SMBSTAT_TO (1 << 5) /* timeout */
126 : #define AMDPM_SMBSTAT_SNP (1 << 8) /* snoop address match */
127 : #define AMDPM_SMBSTAT_SLV (1 << 9) /* slave address match */
128 : #define AMDPM_SMBSTAT_SMBA (1 << 10) /* SMBALERT# asserted */
129 : #define AMDPM_SMBSTAT_BSY (1 << 11) /* bus busy */
130 : #define AMDPM_SMBSTAT_BITS "\020\001ABRT\002COL\003PRERR\004HBSY\005CYC\006TO\011SNP\012SLV\013SMBA\014BSY"
131 : #define AMDPM_SMBCTL 0x2 /* SMBus control */
132 : #define AMDPM_SMBCTL_CMD_QUICK 0 /* QUICK command */
133 : #define AMDPM_SMBCTL_CMD_BYTE 1 /* BYTE command */
134 : #define AMDPM_SMBCTL_CMD_BDATA 2 /* BYTE DATA command */
135 : #define AMDPM_SMBCTL_CMD_WDATA 3 /* WORD DATA command */
136 : #define AMDPM_SMBCTL_CMD_PCALL 4 /* PROCESS CALL command */
137 : #define AMDPM_SMBCTL_CMD_BLOCK 5 /* BLOCK command */
138 : #define AMDPM_SMBCTL_START (1 << 3) /* start transfer */
139 : #define AMDPM_SMBCTL_CYCEN (1 << 4) /* intr on cycle complete */
140 : #define AMDPM_SMBCTL_ABORT (1 << 5) /* abort transfer */
141 : #define AMDPM_SMBCTL_SNPEN (1 << 8) /* intr on snoop addr match */
142 : #define AMDPM_SMBCTL_SLVEN (1 << 9) /* intr on slave addr match */
143 : #define AMDPM_SMBCTL_SMBAEN (1 << 10) /* intr on SMBALERT# */
144 : #define AMDPM_SMBADDR 0x4 /* SMBus address */
145 : #define AMDPM_SMBADDR_READ (1 << 0) /* read direction */
146 : #define AMDPM_SMBADDR_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
147 : #define AMDPM_SMBDATA 0x6 /* SMBus data */
148 : #define AMDPM_SMBCMD 0x8 /* SMBus command */
149 :
150 :
151 : struct amdpm_softc {
152 : struct device sc_dev;
153 :
154 : pci_chipset_tag_t sc_pc;
155 : pcitag_t sc_tag;
156 :
157 : bus_space_tag_t sc_iot;
158 : bus_space_handle_t sc_ioh; /* PMxx space */
159 : bus_space_handle_t sc_i2c_ioh; /* I2C space */
160 : int sc_poll;
161 :
162 : struct timeout sc_rnd_ch;
163 :
164 : struct i2c_controller sc_i2c_tag;
165 : struct rwlock sc_i2c_lock;
166 : struct {
167 : i2c_op_t op;
168 : void *buf;
169 : size_t len;
170 : int flags;
171 : volatile int error;
172 : } sc_i2c_xfer;
173 : };
174 :
175 : int amdpm_match(struct device *, void *, void *);
176 : void amdpm_attach(struct device *, struct device *, void *);
177 : int amdpm_activate(struct device *, int);
178 : void amdpm_rnd_callout(void *);
179 :
180 : int amdpm_i2c_acquire_bus(void *, int);
181 : void amdpm_i2c_release_bus(void *, int);
182 : int amdpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
183 : void *, size_t, int);
184 :
185 : int amdpm_intr(void *);
186 :
187 : struct cfattach amdpm_ca = {
188 : sizeof(struct amdpm_softc), amdpm_match, amdpm_attach,
189 : NULL, amdpm_activate
190 : };
191 :
192 : struct cfdriver amdpm_cd = {
193 : NULL, "amdpm", DV_DULL
194 : };
195 :
196 : const struct pci_matchid amdpm_ids[] = {
197 : { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC756_PMC },
198 : { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_766_PMC },
199 : { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_PMC },
200 : { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_PMC },
201 : { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_SMB }
202 : };
203 :
204 : int
205 0 : amdpm_match(struct device *parent, void *match, void *aux)
206 : {
207 0 : return (pci_matchbyid(aux, amdpm_ids,
208 : sizeof(amdpm_ids) / sizeof(amdpm_ids[0])));
209 : }
210 :
211 : void
212 0 : amdpm_attach(struct device *parent, struct device *self, void *aux)
213 : {
214 0 : struct amdpm_softc *sc = (struct amdpm_softc *) self;
215 0 : struct pci_attach_args *pa = aux;
216 0 : struct i2cbus_attach_args iba;
217 : pcireg_t cfg_reg, reg;
218 : int i;
219 :
220 0 : sc->sc_pc = pa->pa_pc;
221 0 : sc->sc_tag = pa->pa_tag;
222 0 : sc->sc_iot = pa->pa_iot;
223 0 : sc->sc_poll = 1; /* XXX */
224 :
225 :
226 0 : if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD) {
227 0 : cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_CONFREG);
228 0 : if ((cfg_reg & AMDPM_PMIOEN) == 0) {
229 0 : printf(": PMxx space isn't enabled\n");
230 0 : return;
231 : }
232 :
233 0 : reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMDPM_PMPTR);
234 0 : if (AMDPM_PMBASE(reg) == 0 ||
235 0 : bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_PMSIZE,
236 0 : 0, &sc->sc_ioh)) {
237 0 : printf("\n");
238 0 : return;
239 : }
240 0 : if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, AMDPM_SMB_REGS,
241 0 : AMDPM_SMB_SIZE, &sc->sc_i2c_ioh)) {
242 0 : printf(": failed to map I2C subregion\n");
243 0 : return;
244 : }
245 :
246 0 : if ((cfg_reg & AMDPM_TMRRST) == 0 &&
247 0 : (cfg_reg & AMDPM_STOPTMR) == 0 &&
248 0 : (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
249 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC)) {
250 0 : printf(": %d-bit timer at %lluHz",
251 0 : (cfg_reg & AMDPM_TMR32) ? 32 : 24,
252 0 : amdpm_timecounter.tc_frequency);
253 :
254 0 : amdpm_timecounter.tc_priv = sc;
255 0 : if (cfg_reg & AMDPM_TMR32)
256 0 : amdpm_timecounter.tc_counter_mask = 0xffffffffu;
257 0 : tc_init(&amdpm_timecounter);
258 0 : }
259 0 : if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_PBC768_PMC ||
260 0 : PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_8111_PMC) {
261 0 : if ((cfg_reg & AMDPM_RNGEN) ==0) {
262 0 : pci_conf_write(pa->pa_pc, pa->pa_tag,
263 0 : AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
264 0 : cfg_reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
265 : AMDPM_CONFREG);
266 0 : }
267 0 : if (cfg_reg & AMDPM_RNGEN) {
268 : /* Check to see if we can read data from the RNG. */
269 0 : (void) bus_space_read_4(sc->sc_iot, sc->sc_ioh,
270 : AMDPM_RNGDATA);
271 0 : for (i = 1000; i--; ) {
272 0 : if (bus_space_read_1(sc->sc_iot,
273 0 : sc->sc_ioh, AMDPM_RNGSTAT) &
274 : AMDPM_RNGDONE)
275 : break;
276 0 : DELAY(10);
277 : }
278 0 : if (bus_space_read_1(sc->sc_iot, sc->sc_ioh,
279 0 : AMDPM_RNGSTAT) & AMDPM_RNGDONE) {
280 0 : printf(": rng active");
281 0 : timeout_set(&sc->sc_rnd_ch,
282 0 : amdpm_rnd_callout, sc);
283 0 : amdpm_rnd_callout(sc);
284 0 : }
285 : }
286 : }
287 0 : } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NVIDIA) {
288 0 : reg = pci_conf_read(pa->pa_pc, pa->pa_tag, NFPM_PMPTR);
289 0 : if (AMDPM_PMBASE(reg) == 0 ||
290 0 : bus_space_map(sc->sc_iot, AMDPM_PMBASE(reg), AMDPM_SMB_SIZE, 0,
291 0 : &sc->sc_i2c_ioh)) {
292 0 : printf(": failed to map I2C subregion\n");
293 0 : return;
294 : }
295 : }
296 0 : printf("\n");
297 :
298 : /* Attach I2C bus */
299 0 : rw_init(&sc->sc_i2c_lock, "iiclk");
300 0 : sc->sc_i2c_tag.ic_cookie = sc;
301 0 : sc->sc_i2c_tag.ic_acquire_bus = amdpm_i2c_acquire_bus;
302 0 : sc->sc_i2c_tag.ic_release_bus = amdpm_i2c_release_bus;
303 0 : sc->sc_i2c_tag.ic_exec = amdpm_i2c_exec;
304 :
305 0 : bzero(&iba, sizeof(iba));
306 0 : iba.iba_name = "iic";
307 0 : iba.iba_tag = &sc->sc_i2c_tag;
308 0 : config_found(self, &iba, iicbus_print);
309 0 : }
310 :
311 : int
312 0 : amdpm_activate(struct device *self, int act)
313 : {
314 0 : struct amdpm_softc *sc = (struct amdpm_softc *)self;
315 : int rv = 0;
316 :
317 0 : switch (act) {
318 : case DVACT_RESUME:
319 0 : if (timeout_initialized(&sc->sc_rnd_ch)) {
320 : pcireg_t cfg_reg;
321 :
322 : /* Restart the AMD PBC768_PMC/8111_PMC RNG */
323 0 : cfg_reg = pci_conf_read(sc->sc_pc, sc->sc_tag,
324 : AMDPM_CONFREG);
325 0 : pci_conf_write(sc->sc_pc, sc->sc_tag,
326 0 : AMDPM_CONFREG, cfg_reg | AMDPM_RNGEN);
327 :
328 0 : }
329 0 : rv = config_activate_children(self, act);
330 0 : break;
331 : default:
332 0 : rv = config_activate_children(self, act);
333 0 : break;
334 : }
335 0 : return (rv);
336 : }
337 :
338 : void
339 0 : amdpm_rnd_callout(void *v)
340 : {
341 0 : struct amdpm_softc *sc = v;
342 : u_int32_t reg;
343 :
344 0 : if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGSTAT) &
345 0 : AMDPM_RNGDONE) != 0) {
346 0 : reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_RNGDATA);
347 0 : enqueue_randomness(reg);
348 0 : }
349 0 : timeout_add(&sc->sc_rnd_ch, 1);
350 0 : }
351 :
352 : u_int
353 0 : amdpm_get_timecount(struct timecounter *tc)
354 : {
355 0 : struct amdpm_softc *sc = tc->tc_priv;
356 : u_int u2;
357 : #if 0
358 : u_int u1, u3;
359 : #endif
360 :
361 0 : u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
362 : #if 0
363 : u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
364 : do {
365 : u1 = u2;
366 : u2 = u3;
367 : u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, AMDPM_TMR);
368 : } while (u1 > u2 || u2 > u3);
369 : #endif
370 0 : return (u2);
371 : }
372 :
373 : int
374 0 : amdpm_i2c_acquire_bus(void *cookie, int flags)
375 : {
376 0 : struct amdpm_softc *sc = cookie;
377 :
378 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
379 0 : return (0);
380 :
381 0 : return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
382 0 : }
383 :
384 : void
385 0 : amdpm_i2c_release_bus(void *cookie, int flags)
386 : {
387 0 : struct amdpm_softc *sc = cookie;
388 :
389 0 : if (cold || sc->sc_poll || (flags & I2C_F_POLL))
390 0 : return;
391 :
392 0 : rw_exit(&sc->sc_i2c_lock);
393 0 : }
394 :
395 : int
396 0 : amdpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
397 : const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
398 : {
399 0 : struct amdpm_softc *sc = cookie;
400 : u_int8_t *b;
401 : u_int16_t st, ctl, data;
402 : int retries;
403 :
404 : DPRINTF("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
405 : "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr, cmdlen,
406 : len, flags);
407 :
408 : /* Wait for bus to be idle */
409 0 : for (retries = 100; retries > 0; retries--) {
410 0 : st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
411 0 : if (!(st & AMDPM_SMBSTAT_BSY))
412 : break;
413 0 : DELAY(AMDPM_SMBUS_DELAY);
414 : }
415 : DPRINTF("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
416 : AMDPM_SMBSTAT_BITS);
417 0 : if (st & AMDPM_SMBSTAT_BSY)
418 0 : return (1);
419 :
420 0 : if (cold || sc->sc_poll)
421 0 : flags |= I2C_F_POLL;
422 :
423 0 : if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
424 0 : return (1);
425 :
426 : /* Setup transfer */
427 0 : sc->sc_i2c_xfer.op = op;
428 0 : sc->sc_i2c_xfer.buf = buf;
429 0 : sc->sc_i2c_xfer.len = len;
430 0 : sc->sc_i2c_xfer.flags = flags;
431 0 : sc->sc_i2c_xfer.error = 0;
432 :
433 : /* Set slave address and transfer direction */
434 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBADDR,
435 : AMDPM_SMBADDR_ADDR(addr) |
436 : (I2C_OP_READ_P(op) ? AMDPM_SMBADDR_READ : 0));
437 :
438 : b = (void *)cmdbuf;
439 0 : if (cmdlen > 0)
440 : /* Set command byte */
441 0 : bus_space_write_1(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCMD, b[0]);
442 :
443 0 : if (I2C_OP_WRITE_P(op)) {
444 : /* Write data */
445 : data = 0;
446 : b = buf;
447 0 : if (len > 0)
448 0 : data = b[0];
449 0 : if (len > 1)
450 0 : data |= ((u_int16_t)b[1] << 8);
451 0 : if (len > 0)
452 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh,
453 : AMDPM_SMBDATA, data);
454 : }
455 :
456 : /* Set SMBus command */
457 0 : if (len == 0)
458 0 : ctl = AMDPM_SMBCTL_CMD_BYTE;
459 0 : else if (len == 1)
460 0 : ctl = AMDPM_SMBCTL_CMD_BDATA;
461 0 : else if (len == 2)
462 : ctl = AMDPM_SMBCTL_CMD_WDATA;
463 : else
464 0 : panic("%s: unexpected len %zd", __func__, len);
465 :
466 0 : if ((flags & I2C_F_POLL) == 0)
467 0 : ctl |= AMDPM_SMBCTL_CYCEN;
468 :
469 : /* Start transaction */
470 0 : ctl |= AMDPM_SMBCTL_START;
471 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL, ctl);
472 :
473 0 : if (flags & I2C_F_POLL) {
474 : /* Poll for completion */
475 0 : DELAY(AMDPM_SMBUS_DELAY);
476 0 : for (retries = 1000; retries > 0; retries--) {
477 0 : st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
478 : AMDPM_SMBSTAT);
479 0 : if ((st & AMDPM_SMBSTAT_HBSY) == 0)
480 : break;
481 0 : DELAY(AMDPM_SMBUS_DELAY);
482 : }
483 0 : if (st & AMDPM_SMBSTAT_HBSY)
484 : goto timeout;
485 0 : amdpm_intr(sc);
486 0 : } else {
487 : /* Wait for interrupt */
488 0 : if (tsleep(sc, PRIBIO, "amdpm", AMDPM_SMBUS_TIMEOUT * hz))
489 : goto timeout;
490 : }
491 :
492 0 : if (sc->sc_i2c_xfer.error)
493 0 : return (1);
494 :
495 0 : return (0);
496 :
497 : timeout:
498 : /*
499 : * Transfer timeout. Kill the transaction and clear status bits.
500 : */
501 0 : printf("%s: exec: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
502 : "flags 0x%02x: timeout, status 0x%b\n",
503 0 : sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags,
504 0 : st, AMDPM_SMBSTAT_BITS);
505 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBCTL,
506 : AMDPM_SMBCTL_ABORT);
507 0 : DELAY(AMDPM_SMBUS_DELAY);
508 0 : st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
509 0 : if ((st & AMDPM_SMBSTAT_ABRT) == 0)
510 0 : printf("%s: abort failed, status 0x%b\n",
511 : sc->sc_dev.dv_xname, st, AMDPM_SMBSTAT_BITS);
512 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
513 0 : return (1);
514 0 : }
515 :
516 : int
517 0 : amdpm_intr(void *arg)
518 : {
519 0 : struct amdpm_softc *sc = arg;
520 : u_int16_t st, data;
521 : u_int8_t *b;
522 : size_t len;
523 :
524 : /* Read status */
525 0 : st = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT);
526 0 : if ((st & AMDPM_SMBSTAT_HBSY) != 0 || (st & (AMDPM_SMBSTAT_ABRT |
527 : AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR | AMDPM_SMBSTAT_CYC |
528 : AMDPM_SMBSTAT_TO | AMDPM_SMBSTAT_SNP | AMDPM_SMBSTAT_SLV |
529 0 : AMDPM_SMBSTAT_SMBA)) == 0)
530 : /* Interrupt was not for us */
531 0 : return (0);
532 :
533 : DPRINTF("%s: intr: st 0x%b\n", sc->sc_dev.dv_xname, st,
534 : AMDPM_SMBSTAT_BITS);
535 :
536 : /* Clear status bits */
537 0 : bus_space_write_2(sc->sc_iot, sc->sc_i2c_ioh, AMDPM_SMBSTAT, st);
538 :
539 : /* Check for errors */
540 0 : if (st & (AMDPM_SMBSTAT_COL | AMDPM_SMBSTAT_PRERR |
541 : AMDPM_SMBSTAT_TO)) {
542 0 : sc->sc_i2c_xfer.error = 1;
543 0 : goto done;
544 : }
545 :
546 0 : if (st & AMDPM_SMBSTAT_CYC) {
547 0 : if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
548 : goto done;
549 :
550 : /* Read data */
551 0 : b = sc->sc_i2c_xfer.buf;
552 0 : len = sc->sc_i2c_xfer.len;
553 0 : if (len > 0) {
554 0 : data = bus_space_read_2(sc->sc_iot, sc->sc_i2c_ioh,
555 : AMDPM_SMBDATA);
556 0 : b[0] = data & 0xff;
557 0 : }
558 0 : if (len > 1)
559 0 : b[1] = (data >> 8) & 0xff;
560 : }
561 :
562 : done:
563 0 : if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
564 0 : wakeup(sc);
565 0 : return (1);
566 0 : }
|