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