amdpm.c revision 119798
183553Smurray/*-
283553Smurray * Copyright (c) 2000 Matthew C. Forman
383553Smurray *
483553Smurray * Based (heavily) on alpm.c which is:
583553Smurray *
683553Smurray * Copyright (c) 1998, 1999 Nicolas Souchu
783553Smurray * All rights reserved.
883553Smurray *
983553Smurray * Redistribution and use in source and binary forms, with or without
1083553Smurray * modification, are permitted provided that the following conditions
1183553Smurray * are met:
1283553Smurray * 1. Redistributions of source code must retain the above copyright
1383553Smurray *    notice, this list of conditions and the following disclaimer.
1483553Smurray * 2. Redistributions in binary form must reproduce the above copyright
1583553Smurray *    notice, this list of conditions and the following disclaimer in the
1683553Smurray *    documentation and/or other materials provided with the distribution.
1783553Smurray *
1883553Smurray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1983553Smurray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2083553Smurray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2183553Smurray * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2283553Smurray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2383553Smurray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2483553Smurray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2583553Smurray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2683553Smurray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2783553Smurray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2883553Smurray * SUCH DAMAGE.
2983553Smurray */
3083553Smurray
3183553Smurray/*
3283553Smurray * Power management function/SMBus function support for the AMD 756 chip.
3383553Smurray */
3483553Smurray
35116192Sobrien#include <sys/cdefs.h>
36116192Sobrien__FBSDID("$FreeBSD: head/sys/pci/amdpm.c 119798 2003-09-06 14:04:30Z dfr $");
37116192Sobrien
3883553Smurray#include <sys/param.h>
3983553Smurray#include <sys/kernel.h>
4083553Smurray#include <sys/systm.h>
4183553Smurray#include <sys/module.h>
4283553Smurray#include <sys/bus.h>
4383553Smurray#include <sys/uio.h>
4483553Smurray
4583553Smurray#include <machine/bus_pio.h>
4683553Smurray#include <machine/bus_memio.h>
4783553Smurray#include <machine/bus.h>
4883553Smurray#include <machine/clock.h>
4983553Smurray#include <machine/resource.h>
5083553Smurray#include <sys/rman.h>
5183553Smurray
52119288Simp#include <dev/pci/pcivar.h>
53119288Simp#include <dev/pci/pcireg.h>
5483553Smurray
5583553Smurray#include <dev/iicbus/iiconf.h>
5683553Smurray#include <dev/smbus/smbconf.h>
5783553Smurray#include "smbus_if.h"
5883553Smurray
5983553Smurray#define AMDPM_DEBUG(x)	if (amdpm_debug) (x)
6083553Smurray
6183553Smurray#ifdef DEBUG
6283553Smurraystatic int amdpm_debug = 1;
6383553Smurray#else
6483553Smurraystatic int amdpm_debug = 0;
6583553Smurray#endif
6683553Smurray
6783553Smurray#define AMDPM_VENDORID_AMD 0x1022
6883553Smurray#define AMDPM_DEVICEID_AMD756PM 0x740b
69119655Sdfr#define AMDPM_DEVICEID_AMD766PM 0x7413
70119655Sdfr#define AMDPM_DEVICEID_AMD768PM 0x7443
7183553Smurray
72103764Snsouch/* nVidia nForce chipset */
73103764Snsouch#define AMDPM_VENDORID_NVIDIA 0x10de
74103764Snsouch#define AMDPM_DEVICEID_NF_SMB 0x01b4
75103764Snsouch
7683553Smurray/* PCI Configuration space registers */
7783553Smurray#define AMDPCI_PMBASE 0x58
78103764Snsouch#define NFPCI_PMBASE  0x14
7983553Smurray
8083553Smurray#define AMDPCI_GEN_CONFIG_PM 0x41
8183553Smurray#define AMDPCI_PMIOEN (1<<7)
8283553Smurray
8383553Smurray#define AMDPCI_SCIINT_CONFIG_PM 0x42
8483553Smurray#define AMDPCI_SCISEL_IRQ11 11
8583553Smurray
8683553Smurray#define AMDPCI_REVID 0x08
8783553Smurray
8883553Smurray/*
8983553Smurray * I/O registers.
9083553Smurray * Base address programmed via AMDPCI_PMBASE.
9183553Smurray */
92103764Snsouch
93119796Sdfr#define AMDSMB_GLOBAL_STATUS (0x00)
9483553Smurray#define AMDSMB_GS_TO_STS (1<<5)
9583553Smurray#define AMDSMB_GS_HCYC_STS (1<<4)
9683553Smurray#define AMDSMB_GS_HST_STS (1<<3)
9783553Smurray#define AMDSMB_GS_PRERR_STS (1<<2)
9883553Smurray#define AMDSMB_GS_COL_STS (1<<1)
9983553Smurray#define AMDSMB_GS_ABRT_STS (1<<0)
10083553Smurray#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)
10183553Smurray
102119796Sdfr#define AMDSMB_GLOBAL_ENABLE (0x02)
10383553Smurray#define AMDSMB_GE_ABORT (1<<5)
10483553Smurray#define AMDSMB_GE_HCYC_EN (1<<4)
10583553Smurray#define AMDSMB_GE_HOST_STC (1<<3)
10683553Smurray#define AMDSMB_GE_CYC_QUICK 0
10783553Smurray#define AMDSMB_GE_CYC_BYTE 1
10883553Smurray#define AMDSMB_GE_CYC_BDATA 2
10983553Smurray#define AMDSMB_GE_CYC_WDATA 3
11083553Smurray#define AMDSMB_GE_CYC_PROCCALL 4
11183553Smurray#define AMDSMB_GE_CYC_BLOCK 5
11283553Smurray
113119796Sdfr#define AMDSMB_HSTADDR  (0x04)
114119796Sdfr#define AMDSMB_HSTDATA  (0x06)
115119796Sdfr#define AMDSMB_HSTCMD   (0x08)
116119796Sdfr#define AMDSMB_HSTDFIFO (0x09)
117119796Sdfr#define AMDSMB_HSLVDATA (0x0A)
118119796Sdfr#define AMDSMB_HSLVDA   (0x0C)
119119796Sdfr#define AMDSMB_HSLVDDR  (0x0E)
120119796Sdfr#define AMDSMB_SNPADDR  (0x0F)
12183553Smurray
12283553Smurraystruct amdpm_softc {
12383553Smurray	int base;
12483553Smurray	int rid;
12583553Smurray	struct resource *res;
126103764Snsouch	bus_space_tag_t smbst;
127103764Snsouch	bus_space_handle_t smbsh;
12883553Smurray
12983553Smurray	device_t smbus;
13083553Smurray};
13183553Smurray
132103764Snsouch#define AMDPM_SMBINB(amdpm,register) \
133103764Snsouch	(bus_space_read_1(amdpm->smbst, amdpm->smbsh, register))
134103764Snsouch#define AMDPM_SMBOUTB(amdpm,register,value) \
135103764Snsouch	(bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value))
136103764Snsouch#define AMDPM_SMBINW(amdpm,register) \
137103764Snsouch	(bus_space_read_2(amdpm->smbst, amdpm->smbsh, register))
138103764Snsouch#define AMDPM_SMBOUTW(amdpm,register,value) \
139103764Snsouch	(bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value))
14083553Smurray
14183553Smurraystatic int
14283553Smurrayamdpm_probe(device_t dev)
14383553Smurray{
14483553Smurray	u_long base;
145119796Sdfr	u_int16_t vid;
146119655Sdfr	u_int16_t did;
147119655Sdfr
148119796Sdfr	vid = pci_get_vendor(dev);
149119655Sdfr	did = pci_get_device(dev);
150119796Sdfr	if ((vid == AMDPM_VENDORID_AMD) &&
151119655Sdfr	    ((did == AMDPM_DEVICEID_AMD756PM) ||
152119655Sdfr	     (did == AMDPM_DEVICEID_AMD766PM) ||
153119655Sdfr	     (did == AMDPM_DEVICEID_AMD768PM))) {
154119798Sdfr		device_set_desc(dev, "AMD 756/766/768 Power Management Controller");
155119798Sdfr
156119798Sdfr		/*
157119798Sdfr		 * We have to do this, since the BIOS won't give us the
158119798Sdfr		 * resource info (not mine, anyway).
159119798Sdfr		 */
160119798Sdfr		base = pci_read_config(dev, AMDPCI_PMBASE, 4);
161119798Sdfr		base &= 0xff00;
162119798Sdfr		bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE,
163119798Sdfr				 base+0xe0, 32);
164119798Sdfr		return (0);
16583553Smurray	}
166119796Sdfr
167119796Sdfr	if ((vid == AMDPM_VENDORID_NVIDIA) &&
168119796Sdfr	    (did == AMDPM_DEVICEID_NF_SMB)) {
169119796Sdfr		device_set_desc(dev, "nForce SMBus Controller");
170119796Sdfr
171119796Sdfr		/*
172119796Sdfr		* We have to do this, since the BIOS won't give us the
173119796Sdfr		* resource info (not mine, anyway).
174119796Sdfr		*/
175119796Sdfr		base = pci_read_config(dev, NFPCI_PMBASE, 4);
176119796Sdfr		base &= 0xff00;
177119796Sdfr		bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE,
178119796Sdfr				 base, 32);
179119796Sdfr
180119796Sdfr		return (0);
181119796Sdfr	}
182119796Sdfr
18383553Smurray	return ENXIO;
18483553Smurray}
18583553Smurray
18683553Smurraystatic int
18783553Smurrayamdpm_attach(device_t dev)
18883553Smurray{
18983553Smurray	struct amdpm_softc *amdpm_sc = device_get_softc(dev);
19083553Smurray	u_char val_b;
19183553Smurray
19283553Smurray	/* Enable I/O block access */
19383553Smurray	val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1);
19483553Smurray	pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1);
19583553Smurray
19683553Smurray	/* Allocate I/O space */
197119796Sdfr	if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD)
198119796Sdfr		amdpm_sc->rid = AMDPCI_PMBASE;
199119796Sdfr	else
200119796Sdfr		amdpm_sc->rid = NFPCI_PMBASE;
20183553Smurray	amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE);
20283553Smurray
20383553Smurray	if (amdpm_sc->res == NULL) {
20483553Smurray		device_printf(dev, "could not map i/o space\n");
20583553Smurray		return (ENXIO);
20683553Smurray	}
20783553Smurray
20883553Smurray	amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
20983553Smurray	amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
21083553Smurray
211103764Snsouch	/* Allocate a new smbus device */
212103764Snsouch	amdpm_sc->smbus = device_add_child(dev, "smbus", -1);
213103764Snsouch	if (!amdpm_sc->smbus)
214119798Sdfr		return (EINVAL);
215103764Snsouch
216103764Snsouch	bus_generic_attach(dev);
217103764Snsouch
21883553Smurray	return (0);
21983553Smurray}
22083553Smurray
22183553Smurraystatic int
222103764Snsouchamdpm_detach(device_t dev)
22383553Smurray{
224103764Snsouch	struct amdpm_softc *amdpm_sc = device_get_softc(dev);
22583553Smurray
226103764Snsouch	if (amdpm_sc->smbus) {
227119798Sdfr		device_delete_child(dev, amdpm_sc->smbus);
228119798Sdfr		amdpm_sc->smbus = NULL;
229103764Snsouch	}
23093040Snsouch
231103764Snsouch	if (amdpm_sc->res)
232119798Sdfr		bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid,
233119798Sdfr				     amdpm_sc->res);
23483553Smurray
23583553Smurray	return (0);
23683553Smurray}
23783553Smurray
23883553Smurraystatic int
239103764Snsouchamdpm_callback(device_t dev, int index, caddr_t *data)
24083553Smurray{
24183553Smurray	int error = 0;
24283553Smurray
24383553Smurray	switch (index) {
24483553Smurray	case SMB_REQUEST_BUS:
24583553Smurray	case SMB_RELEASE_BUS:
24683553Smurray		break;
24783553Smurray	default:
24883553Smurray		error = EINVAL;
24983553Smurray	}
25083553Smurray
25183553Smurray	return (error);
25283553Smurray}
25383553Smurray
25483553Smurraystatic int
255103764Snsouchamdpm_clear(struct amdpm_softc *sc)
25683553Smurray{
25783553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
25883553Smurray	DELAY(10);
25983553Smurray
26083553Smurray	return (0);
26183553Smurray}
26283553Smurray
26391265Speter#if 0
26483553Smurraystatic int
265103764Snsouchamdpm_abort(struct amdpm_softc *sc)
26683553Smurray{
26783553Smurray	u_short l;
26883553Smurray
26983553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
27083553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
27183553Smurray
27283553Smurray	return (0);
27383553Smurray}
27491265Speter#endif
27583553Smurray
27683553Smurraystatic int
277103764Snsouchamdpm_idle(struct amdpm_softc *sc)
27883553Smurray{
27983553Smurray	u_short sts;
28083553Smurray
28183553Smurray	sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
28283553Smurray
28383553Smurray	AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
28483553Smurray
28583553Smurray	return (~(sts & AMDSMB_GS_HST_STS));
28683553Smurray}
28783553Smurray
28883553Smurray/*
28983553Smurray * Poll the SMBus controller
29083553Smurray */
29183553Smurraystatic int
292103764Snsouchamdpm_wait(struct amdpm_softc *sc)
29383553Smurray{
29483553Smurray	int count = 10000;
29583553Smurray	u_short sts = 0;
29683553Smurray	int error;
29783553Smurray
29883553Smurray	/* Wait for command to complete (SMBus controller is idle) */
29983553Smurray	while(count--) {
30083553Smurray		DELAY(10);
30183553Smurray		sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
30283553Smurray		if (!(sts & AMDSMB_GS_HST_STS))
30383553Smurray			break;
30483553Smurray	}
30583553Smurray
30683553Smurray	AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
30783553Smurray
30883553Smurray	error = SMB_ENOERR;
30983553Smurray
31083553Smurray	if (!count)
31183553Smurray		error |= SMB_ETIMEOUT;
31283553Smurray
31383553Smurray	if (sts & AMDSMB_GS_ABRT_STS)
31483553Smurray		error |= SMB_EABORT;
31583553Smurray
31683553Smurray	if (sts & AMDSMB_GS_COL_STS)
31783553Smurray		error |= SMB_ENOACK;
31883553Smurray
31983553Smurray	if (sts & AMDSMB_GS_PRERR_STS)
32083553Smurray		error |= SMB_EBUSERR;
32183553Smurray
32283553Smurray	if (error != SMB_ENOERR)
323103764Snsouch		amdpm_clear(sc);
32483553Smurray
32583553Smurray	return (error);
32683553Smurray}
32783553Smurray
32883553Smurraystatic int
329103764Snsouchamdpm_quick(device_t dev, u_char slave, int how)
33083553Smurray{
331103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
33283553Smurray	int error;
33383553Smurray	u_short l;
33483553Smurray
335103764Snsouch	amdpm_clear(sc);
336103764Snsouch	if (!amdpm_idle(sc))
33783553Smurray		return (EBUSY);
33883553Smurray
33983553Smurray	switch (how) {
34083553Smurray	case SMB_QWRITE:
34183553Smurray		AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
34283553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
34383553Smurray		break;
34483553Smurray	case SMB_QREAD:
34583553Smurray		AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
34683553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
34783553Smurray		break;
34883553Smurray	default:
34987599Sobrien		panic("%s: unknown QUICK command (%x)!", __func__, how);
35083553Smurray	}
35183553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
35283553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
35383553Smurray
354103764Snsouch	error = amdpm_wait(sc);
35583553Smurray
35683553Smurray	AMDPM_DEBUG(printf(", error=0x%x\n", error));
35783553Smurray
35883553Smurray	return (error);
35983553Smurray}
36083553Smurray
36183553Smurraystatic int
362103764Snsouchamdpm_sendb(device_t dev, u_char slave, char byte)
36383553Smurray{
364103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
36583553Smurray	int error;
36683553Smurray	u_short l;
36783553Smurray
368103764Snsouch	amdpm_clear(sc);
369103764Snsouch	if (!amdpm_idle(sc))
37083553Smurray		return (SMB_EBUSY);
37183553Smurray
37283553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
37383553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
37483553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
37583553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
37683553Smurray
377103764Snsouch	error = amdpm_wait(sc);
37883553Smurray
37983553Smurray	AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
38083553Smurray
38183553Smurray	return (error);
38283553Smurray}
38383553Smurray
38483553Smurraystatic int
385103764Snsouchamdpm_recvb(device_t dev, u_char slave, char *byte)
38683553Smurray{
387103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
38883553Smurray	int error;
38983553Smurray	u_short l;
39083553Smurray
391103764Snsouch	amdpm_clear(sc);
392103764Snsouch	if (!amdpm_idle(sc))
39383553Smurray		return (SMB_EBUSY);
39483553Smurray
39583553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
39683553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
39783553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
39883553Smurray
399103764Snsouch	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
40083553Smurray		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
40183553Smurray
40283553Smurray	AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
40383553Smurray
40483553Smurray	return (error);
40583553Smurray}
40683553Smurray
40783553Smurraystatic int
408103764Snsouchamdpm_writeb(device_t dev, u_char slave, char cmd, char byte)
40983553Smurray{
410103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
41183553Smurray	int error;
41283553Smurray	u_short l;
41383553Smurray
414103764Snsouch	amdpm_clear(sc);
415103764Snsouch	if (!amdpm_idle(sc))
41683553Smurray		return (SMB_EBUSY);
41783553Smurray
41883553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
41983553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
42083553Smurray	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
42183553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
42283553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
42383553Smurray
424103764Snsouch	error = amdpm_wait(sc);
42583553Smurray
42683553Smurray	AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
42783553Smurray
42883553Smurray	return (error);
42983553Smurray}
43083553Smurray
43183553Smurraystatic int
432103764Snsouchamdpm_readb(device_t dev, u_char slave, char cmd, char *byte)
43383553Smurray{
434103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
43583553Smurray	int error;
43683553Smurray	u_short l;
43783553Smurray
438103764Snsouch	amdpm_clear(sc);
439103764Snsouch	if (!amdpm_idle(sc))
44083553Smurray		return (SMB_EBUSY);
44183553Smurray
44283553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
44383553Smurray	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
44483553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
44583553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
44683553Smurray
447103764Snsouch	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
44883553Smurray		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
44983553Smurray
45083553Smurray	AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
45183553Smurray
45283553Smurray	return (error);
45383553Smurray}
45483553Smurray
45583553Smurraystatic int
456103764Snsouchamdpm_writew(device_t dev, u_char slave, char cmd, short word)
45783553Smurray{
458103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
45983553Smurray	int error;
46083553Smurray	u_short l;
46183553Smurray
462103764Snsouch	amdpm_clear(sc);
463103764Snsouch	if (!amdpm_idle(sc))
46483553Smurray		return (SMB_EBUSY);
46583553Smurray
46683553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
46783553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
46883553Smurray	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
46983553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
47083553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
47183553Smurray
472103764Snsouch	error = amdpm_wait(sc);
47383553Smurray
47483553Smurray	AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
47583553Smurray
47683553Smurray	return (error);
47783553Smurray}
47883553Smurray
47983553Smurraystatic int
480103764Snsouchamdpm_readw(device_t dev, u_char slave, char cmd, short *word)
48183553Smurray{
482103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
48383553Smurray	int error;
48483553Smurray	u_short l;
48583553Smurray
486103764Snsouch	amdpm_clear(sc);
487103764Snsouch	if (!amdpm_idle(sc))
48883553Smurray		return (SMB_EBUSY);
48983553Smurray
49083553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
49183553Smurray	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
49283553Smurray	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
49383553Smurray	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
49483553Smurray
495103764Snsouch	if ((error = amdpm_wait(sc)) == SMB_ENOERR)
49683553Smurray		*word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
49783553Smurray
49883553Smurray	AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
49983553Smurray
50083553Smurray	return (error);
50183553Smurray}
50283553Smurray
50383553Smurraystatic int
504103764Snsouchamdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
50583553Smurray{
506103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
50783553Smurray	u_char remain, len, i;
50883553Smurray	int error = SMB_ENOERR;
50983553Smurray	u_short l;
51083553Smurray
511103764Snsouch	amdpm_clear(sc);
512103764Snsouch	if(!amdpm_idle(sc))
51383553Smurray		return (SMB_EBUSY);
51483553Smurray
51583553Smurray	remain = count;
51683553Smurray	while (remain) {
51783553Smurray		len = min(remain, 32);
51883553Smurray
51983553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
52083553Smurray
52183553Smurray		/*
52283553Smurray		 * Do we have to reset the internal 32-byte buffer?
52383553Smurray		 * Can't see how to do this from the data sheet.
52483553Smurray		 */
52583553Smurray
52683553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len);
52783553Smurray
52883553Smurray		/* Fill the 32-byte internal buffer */
52983553Smurray		for (i=0; i<len; i++) {
53083553Smurray			AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]);
53183553Smurray			DELAY(2);
53283553Smurray		}
53383553Smurray		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
53483553Smurray		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
53583553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
53683553Smurray
537103764Snsouch		if ((error = amdpm_wait(sc)) != SMB_ENOERR)
53883553Smurray			goto error;
53983553Smurray
54083553Smurray		remain -= len;
54183553Smurray	}
54283553Smurray
54383553Smurrayerror:
54483553Smurray	AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
54583553Smurray
54683553Smurray	return (error);
54783553Smurray}
54883553Smurray
54983553Smurraystatic int
550103764Snsouchamdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
55183553Smurray{
552103764Snsouch	struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev);
55383553Smurray	u_char remain, len, i;
55483553Smurray	int error = SMB_ENOERR;
55583553Smurray	u_short l;
55683553Smurray
557103764Snsouch	amdpm_clear(sc);
558103764Snsouch	if (!amdpm_idle(sc))
55983553Smurray		return (SMB_EBUSY);
56083553Smurray
56183553Smurray	remain = count;
56283553Smurray	while (remain) {
56383553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
56483553Smurray
56583553Smurray		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
56683553Smurray
56783553Smurray		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
56883553Smurray		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
56983553Smurray
570103764Snsouch		if ((error = amdpm_wait(sc)) != SMB_ENOERR)
57183553Smurray			goto error;
57283553Smurray
57383553Smurray		len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
57483553Smurray
57583553Smurray		/* Read the 32-byte internal buffer */
57683553Smurray		for (i=0; i<len; i++) {
57783553Smurray			buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
57883553Smurray			DELAY(2);
57983553Smurray		}
58083553Smurray
58183553Smurray		remain -= len;
58283553Smurray	}
58383553Smurrayerror:
58483553Smurray	AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
58583553Smurray
58683553Smurray	return (error);
58783553Smurray}
58883553Smurray
58983553Smurraystatic devclass_t amdpm_devclass;
59083553Smurray
59183553Smurraystatic device_method_t amdpm_methods[] = {
59283553Smurray	/* Device interface */
59383553Smurray	DEVMETHOD(device_probe,		amdpm_probe),
59483553Smurray	DEVMETHOD(device_attach,	amdpm_attach),
595103764Snsouch	DEVMETHOD(device_detach,	amdpm_detach),
59683553Smurray
597103764Snsouch	/* SMBus interface */
598103764Snsouch	DEVMETHOD(smbus_callback,	amdpm_callback),
599103764Snsouch	DEVMETHOD(smbus_quick,		amdpm_quick),
600103764Snsouch	DEVMETHOD(smbus_sendb,		amdpm_sendb),
601103764Snsouch	DEVMETHOD(smbus_recvb,		amdpm_recvb),
602103764Snsouch	DEVMETHOD(smbus_writeb,		amdpm_writeb),
603103764Snsouch	DEVMETHOD(smbus_readb,		amdpm_readb),
604103764Snsouch	DEVMETHOD(smbus_writew,		amdpm_writew),
605103764Snsouch	DEVMETHOD(smbus_readw,		amdpm_readw),
606103764Snsouch	DEVMETHOD(smbus_bwrite,		amdpm_bwrite),
607103764Snsouch	DEVMETHOD(smbus_bread,		amdpm_bread),
608103764Snsouch
60983553Smurray	{ 0, 0 }
61083553Smurray};
61183553Smurray
61283553Smurraystatic driver_t amdpm_driver = {
61383553Smurray	"amdpm",
61483553Smurray	amdpm_methods,
61583553Smurray	sizeof(struct amdpm_softc),
61683553Smurray};
61783553Smurray
61883553SmurrayDRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
619103764Snsouch
620113506SmdoddMODULE_DEPEND(amdpm, pci, 1, 1, 1);
62193040SnsouchMODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
62293040SnsouchMODULE_VERSION(amdpm, 1);
623103764Snsouch
624