xref: /dflybsd-src/sys/dev/powermng/amdpm/amdpm.c (revision a9656fbcd49c376aba5e04370d8b0f1fa96e063c)
1 /*-
2  * Copyright (c) 2000 Matthew C. Forman
3  *
4  * Based (heavily) on alpm.c which is:
5  *
6  * Copyright (c) 1998, 1999 Nicolas Souchu
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/sys/pci/amdpm.c,v 1.10 2003/09/06 13:56:56 dfr Exp $
31  *
32  */
33 
34 /*
35  * Power management function/SMBus function support for the AMD 756 chip.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/module.h>
42 #include <sys/bus.h>
43 #include <sys/uio.h>
44 #include <sys/rman.h>
45 
46 #include <machine/clock.h>
47 
48 #include <bus/pci/pcivar.h>
49 #include <bus/pci/pcireg.h>
50 
51 #include <bus/iicbus/iiconf.h>
52 #include <bus/smbus/smbconf.h>
53 #include "smbus_if.h"
54 
55 #define AMDPM_DEBUG(x)	if (amdpm_debug) (x)
56 
57 #ifdef DEBUG
58 static int amdpm_debug = 1;
59 #else
60 static int amdpm_debug = 0;
61 #endif
62 
63 #define AMDPM_VENDORID_AMD 0x1022
64 #define AMDPM_DEVICEID_AMD756PM 0x740b
65 #define AMDPM_DEVICEID_AMD766PM 0x7413
66 #define AMDPM_DEVICEID_AMD768PM 0x7443
67 
68 /* nVidia nForce chipset */
69 #define AMDPM_VENDORID_NVIDIA 0x10de
70 #define AMDPM_DEVICEID_NF_SMB 0x01b4
71 
72 
73 /* PCI Configuration space registers */
74 #define AMDPCI_PMBASE 0x58
75 #define NFPCI_PMBASE  0x14
76 
77 #define AMDPCI_GEN_CONFIG_PM 0x41
78 #define AMDPCI_PMIOEN (1<<7)
79 
80 #define AMDPCI_SCIINT_CONFIG_PM 0x42
81 #define AMDPCI_SCISEL_IRQ11 11
82 
83 #define AMDPCI_REVID 0x08
84 
85 /*
86  * I/O registers.
87  * Base address programmed via AMDPCI_PMBASE.
88  */
89 
90 #define AMDSMB_GLOBAL_STATUS (0x00)
91 #define AMDSMB_GS_TO_STS (1<<5)
92 #define AMDSMB_GS_HCYC_STS (1<<4)
93 #define AMDSMB_GS_HST_STS (1<<3)
94 #define AMDSMB_GS_PRERR_STS (1<<2)
95 #define AMDSMB_GS_COL_STS (1<<1)
96 #define AMDSMB_GS_ABRT_STS (1<<0)
97 #define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS)
98 
99 #define AMDSMB_GLOBAL_ENABLE (0x02)
100 #define AMDSMB_GE_ABORT (1<<5)
101 #define AMDSMB_GE_HCYC_EN (1<<4)
102 #define AMDSMB_GE_HOST_STC (1<<3)
103 #define AMDSMB_GE_CYC_QUICK 0
104 #define AMDSMB_GE_CYC_BYTE 1
105 #define AMDSMB_GE_CYC_BDATA 2
106 #define AMDSMB_GE_CYC_WDATA 3
107 #define AMDSMB_GE_CYC_PROCCALL 4
108 #define AMDSMB_GE_CYC_BLOCK 5
109 
110 #define AMDSMB_HSTADDR  (0x04)
111 #define AMDSMB_HSTDATA  (0x06)
112 #define AMDSMB_HSTCMD   (0x08)
113 #define AMDSMB_HSTDFIFO (0x09)
114 #define AMDSMB_HSLVDATA (0x0A)
115 #define AMDSMB_HSLVDA   (0x0C)
116 #define AMDSMB_HSLVDDR  (0x0E)
117 #define AMDSMB_SNPADDR  (0x0F)
118 
119 struct amdpm_softc {
120 	int base;
121 	int rid;
122 	struct resource *res;
123 	bus_space_tag_t smbst;
124 	bus_space_handle_t smbsh;
125 
126 	device_t smbus;
127 };
128 
129 #define AMDPM_SMBINB(amdpm,register) \
130 	(bus_space_read_1(amdpm->smbst, amdpm->smbsh, register))
131 #define AMDPM_SMBOUTB(amdpm,register,value) \
132 	(bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value))
133 #define AMDPM_SMBINW(amdpm,register) \
134 	(bus_space_read_2(amdpm->smbst, amdpm->smbsh, register))
135 #define AMDPM_SMBOUTW(amdpm,register,value) \
136 	(bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value))
137 
138 static int
139 amdpm_probe(device_t dev)
140 {
141 	u_long base;
142 	u_int16_t vid;
143 	u_int16_t did;
144 
145 	vid = pci_get_vendor(dev);
146 	did = pci_get_device(dev);
147 	if ((vid == AMDPM_VENDORID_AMD) &&
148 	    ((did == AMDPM_DEVICEID_AMD756PM) ||
149 	     (did == AMDPM_DEVICEID_AMD766PM) ||
150 	     (did == AMDPM_DEVICEID_AMD768PM))) {
151 	      device_set_desc(dev, "AMD 756/766/768 Power Management Controller");
152 
153 	      /*
154 	       * We have to do this, since the BIOS won't give us the
155 	       * resource info (not mine, anyway).
156 	       */
157 	      base = pci_read_config(dev, AMDPCI_PMBASE, 4);
158 	      base &= 0xff00;
159 	      bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE,
160 			       base+0xe0, 32);
161 	      return (0);
162 	}
163 
164 	if ((vid == AMDPM_VENDORID_NVIDIA) &&
165 	    (did == AMDPM_DEVICEID_NF_SMB)) {
166 		device_set_desc(dev, "nForce SMBus Controller");
167 
168 		/*
169 		 * We have to do this, since the BIOS won't give us the
170 		 * resource info (not mine, anyway).
171 		 */
172 		base = pci_read_config(dev, NFPCI_PMBASE, 4);
173 		base &= 0xff00;
174 		bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE,
175 				 base, 32);
176 
177 		return (0);
178 	}
179 
180 	return ENXIO;
181 }
182 
183 static int
184 amdpm_attach(device_t dev)
185 {
186 	struct amdpm_softc *amdpm_sc = device_get_softc(dev);
187 	u_char val_b;
188 
189 	/* Enable I/O block access */
190 	val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1);
191 	pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1);
192 
193 	/* Allocate I/O space */
194 	if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD)
195 		amdpm_sc->rid = AMDPCI_PMBASE;
196 	else
197 		amdpm_sc->rid = NFPCI_PMBASE;
198 	amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE);
199 
200 	if (amdpm_sc->res == NULL) {
201 		device_printf(dev, "could not map i/o space\n");
202 		return (ENXIO);
203 	}
204 
205 	amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
206 	amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
207 
208 	/* Allocate a new smbus device */
209 	amdpm_sc->smbus = device_add_child(dev, "smbus", -1);
210 	if (!amdpm_sc->smbus)
211 	  return (EINVAL);
212 
213 	bus_generic_attach(dev);
214 
215 	return (0);
216 }
217 
218 static int
219 amdpm_detach(device_t dev)
220 {
221 	struct amdpm_softc *amdpm_sc = device_get_softc(dev);
222 
223 	if (amdpm_sc->smbus) {
224 	  device_delete_child(dev, amdpm_sc->smbus);
225 	  amdpm_sc->smbus = NULL;
226 	}
227 
228 	if (amdpm_sc->res)
229 	  bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid,
230 					amdpm_sc->res);
231 
232 	return (0);
233 }
234 
235 static int
236 amdpm_callback(device_t dev, int index, caddr_t *data)
237 {
238 	int error = 0;
239 
240 	switch (index) {
241 	case SMB_REQUEST_BUS:
242 	case SMB_RELEASE_BUS:
243 		break;
244 	default:
245 		error = EINVAL;
246 	}
247 
248 	return (error);
249 }
250 
251 static int
252 amdpm_clear(struct amdpm_softc *sc)
253 {
254 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
255 	DELAY(10);
256 
257 	return (0);
258 }
259 
260 #if 0
261 static int
262 amdpm_abort(struct amdpm_softc *sc)
263 {
264 	u_short l;
265 
266 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
267 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
268 
269 	return (0);
270 }
271 #endif
272 
273 static int
274 amdpm_idle(struct amdpm_softc *sc)
275 {
276 	u_short sts;
277 
278 	sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
279 
280 	AMDPM_DEBUG(kprintf("amdpm: busy? STS=0x%x\n", sts));
281 
282 	return (~(sts & AMDSMB_GS_HST_STS));
283 }
284 
285 /*
286  * Poll the SMBus controller
287  */
288 static int
289 amdpm_wait(struct amdpm_softc *sc)
290 {
291 	int count = 10000;
292 	u_short sts = 0;
293 	int error;
294 
295 	/* Wait for command to complete (SMBus controller is idle) */
296 	while(count--) {
297 		DELAY(10);
298 		sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
299 		if (!(sts & AMDSMB_GS_HST_STS))
300 			break;
301 	}
302 
303 	AMDPM_DEBUG(kprintf("amdpm: STS=0x%x (count=%d)\n", sts, count));
304 
305 	error = SMB_ENOERR;
306 
307 	if (!count)
308 		error |= SMB_ETIMEOUT;
309 
310 	if (sts & AMDSMB_GS_ABRT_STS)
311 		error |= SMB_EABORT;
312 
313 	if (sts & AMDSMB_GS_COL_STS)
314 		error |= SMB_ENOACK;
315 
316 	if (sts & AMDSMB_GS_PRERR_STS)
317 		error |= SMB_EBUSERR;
318 
319 	if (error != SMB_ENOERR)
320 		amdpm_clear(sc);
321 
322 	return (error);
323 }
324 
325 static int
326 amdpm_quick(device_t dev, u_char slave, int how)
327 {
328 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
329 	int error;
330 	u_short l;
331 
332 	amdpm_clear(sc);
333 	if (!amdpm_idle(sc))
334 		return (EBUSY);
335 
336 	switch (how) {
337 	case SMB_QWRITE:
338 		AMDPM_DEBUG(kprintf("amdpm: QWRITE to 0x%x", slave));
339 		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
340 		break;
341 	case SMB_QREAD:
342 		AMDPM_DEBUG(kprintf("amdpm: QREAD to 0x%x", slave));
343 		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
344 		break;
345 	default:
346 		panic("%s: unknown QUICK command (%x)!", __func__, how);
347 	}
348 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
349 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
350 
351 	error = amdpm_wait(sc);
352 
353 	AMDPM_DEBUG(kprintf(", error=0x%x\n", error));
354 
355 	return (error);
356 }
357 
358 static int
359 amdpm_sendb(device_t dev, u_char slave, char byte)
360 {
361 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
362 	int error;
363 	u_short l;
364 
365 	amdpm_clear(sc);
366 	if (!amdpm_idle(sc))
367 		return (SMB_EBUSY);
368 
369 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
370 	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
371 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
372 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
373 
374 	error = amdpm_wait(sc);
375 
376 	AMDPM_DEBUG(kprintf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
377 
378 	return (error);
379 }
380 
381 static int
382 amdpm_recvb(device_t dev, u_char slave, char *byte)
383 {
384 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
385 	int error;
386 	u_short l;
387 
388 	amdpm_clear(sc);
389 	if (!amdpm_idle(sc))
390 		return (SMB_EBUSY);
391 
392 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
393 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
394 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
395 
396 	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
397 		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
398 
399 	AMDPM_DEBUG(kprintf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
400 
401 	return (error);
402 }
403 
404 static int
405 amdpm_writeb(device_t dev, u_char slave, char cmd, char byte)
406 {
407 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
408 	int error;
409 	u_short l;
410 
411 	amdpm_clear(sc);
412 	if (!amdpm_idle(sc))
413 		return (SMB_EBUSY);
414 
415 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
416 	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
417 	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
418 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
419 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
420 
421 	error = amdpm_wait(sc);
422 
423 	AMDPM_DEBUG(kprintf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
424 
425 	return (error);
426 }
427 
428 static int
429 amdpm_readb(device_t dev, u_char slave, char cmd, char *byte)
430 {
431 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
432 	int error;
433 	u_short l;
434 
435 	amdpm_clear(sc);
436 	if (!amdpm_idle(sc))
437 		return (SMB_EBUSY);
438 
439 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
440 	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
441 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
442 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
443 
444 	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
445 		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
446 
447 	AMDPM_DEBUG(kprintf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
448 
449 	return (error);
450 }
451 
452 static int
453 amdpm_writew(device_t dev, u_char slave, char cmd, short word)
454 {
455 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
456 	int error;
457 	u_short l;
458 
459 	amdpm_clear(sc);
460 	if (!amdpm_idle(sc))
461 		return (SMB_EBUSY);
462 
463 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
464 	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
465 	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
466 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
467 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
468 
469 	error = amdpm_wait(sc);
470 
471 	AMDPM_DEBUG(kprintf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
472 
473 	return (error);
474 }
475 
476 static int
477 amdpm_readw(device_t dev, u_char slave, char cmd, short *word)
478 {
479 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
480 	int error;
481 	u_short l;
482 
483 	amdpm_clear(sc);
484 	if (!amdpm_idle(sc))
485 		return (SMB_EBUSY);
486 
487 	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
488 	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
489 	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
490 	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
491 
492 	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
493 		*word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
494 
495 	AMDPM_DEBUG(kprintf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
496 
497 	return (error);
498 }
499 
500 static int
501 amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
502 {
503 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
504 	u_char remain, len, i;
505 	int error = SMB_ENOERR;
506 	u_short l;
507 
508 	amdpm_clear(sc);
509 	if(!amdpm_idle(sc))
510 		return (SMB_EBUSY);
511 
512 	remain = count;
513 	while (remain) {
514 		len = min(remain, 32);
515 
516 		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
517 
518 		/*
519 		 * Do we have to reset the internal 32-byte buffer?
520 		 * Can't see how to do this from the data sheet.
521 		 */
522 
523 		AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len);
524 
525 		/* Fill the 32-byte internal buffer */
526 		for (i=0; i<len; i++) {
527 			AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]);
528 			DELAY(2);
529 		}
530 		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
531 		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
532 		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
533 
534 		if ((error = amdpm_wait(sc)) != SMB_ENOERR)
535 			goto error;
536 
537 		remain -= len;
538 	}
539 
540 error:
541 	AMDPM_DEBUG(kprintf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
542 
543 	return (error);
544 }
545 
546 static int
547 amdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
548 {
549 	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
550 	u_char remain, len, i;
551 	int error = SMB_ENOERR;
552 	u_short l;
553 
554 	amdpm_clear(sc);
555 	if (!amdpm_idle(sc))
556 		return (SMB_EBUSY);
557 
558 	remain = count;
559 	while (remain) {
560 		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
561 
562 		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
563 
564 		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
565 		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
566 
567 		if ((error = amdpm_wait(sc)) != SMB_ENOERR)
568 			goto error;
569 
570 		len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
571 
572 		/* Read the 32-byte internal buffer */
573 		for (i=0; i<len; i++) {
574 			buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
575 			DELAY(2);
576 		}
577 
578 		remain -= len;
579 	}
580 error:
581 	AMDPM_DEBUG(kprintf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
582 
583 	return (error);
584 }
585 
586 static devclass_t amdpm_devclass;
587 
588 static device_method_t amdpm_methods[] = {
589 	/* Device interface */
590 	DEVMETHOD(device_probe,		amdpm_probe),
591 	DEVMETHOD(device_attach,	amdpm_attach),
592 	DEVMETHOD(device_detach,	amdpm_detach),
593 
594 	/* SMBus interface */
595 	DEVMETHOD(smbus_callback,	amdpm_callback),
596 	DEVMETHOD(smbus_quick,		amdpm_quick),
597 	DEVMETHOD(smbus_sendb,		amdpm_sendb),
598 	DEVMETHOD(smbus_recvb,		amdpm_recvb),
599 	DEVMETHOD(smbus_writeb,		amdpm_writeb),
600 	DEVMETHOD(smbus_readb,		amdpm_readb),
601 	DEVMETHOD(smbus_writew,		amdpm_writew),
602 	DEVMETHOD(smbus_readw,		amdpm_readw),
603 	DEVMETHOD(smbus_bwrite,		amdpm_bwrite),
604 	DEVMETHOD(smbus_bread,		amdpm_bread),
605 
606 	{ 0, 0 }
607 };
608 
609 static driver_t amdpm_driver = {
610 	"amdpm",
611 	amdpm_methods,
612 	sizeof(struct amdpm_softc),
613 };
614 
615 DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
616 
617 MODULE_DEPEND(amdpm, pci, 1, 1, 1);
618 MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
619 MODULE_VERSION(amdpm, 1);
620