viapm.c revision 153084
1164032Srwatson/*-
2164032Srwatson * Copyright (c) 2001 Alcove - Nicolas Souchu
3164032Srwatson * All rights reserved.
4164032Srwatson *
5164032Srwatson * Redistribution and use in source and binary forms, with or without
6164032Srwatson * modification, are permitted provided that the following conditions
7164032Srwatson * are met:
8164032Srwatson * 1. Redistributions of source code must retain the above copyright
9164032Srwatson *    notice, this list of conditions and the following disclaimer.
10164032Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11164032Srwatson *    notice, this list of conditions and the following disclaimer in the
12164032Srwatson *    documentation and/or other materials provided with the distribution.
13164032Srwatson *
14164032Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15164032Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16164032Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17164032Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18164032Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19164032Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20164032Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21164032Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22164032Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23164032Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24164032Srwatson * SUCH DAMAGE.
25164032Srwatson */
26164032Srwatson
27164032Srwatson#include <sys/cdefs.h>
28164032Srwatson__FBSDID("$FreeBSD: head/sys/pci/viapm.c 153084 2005-12-04 10:06:06Z ru $");
29164032Srwatson
30164032Srwatson#include "opt_isa.h"
31164032Srwatson
32164032Srwatson#include <sys/param.h>
33164032Srwatson#include <sys/kernel.h>
34164032Srwatson#include <sys/systm.h>
35164032Srwatson#include <sys/module.h>
36164032Srwatson#include <sys/bus.h>
37164032Srwatson#include <sys/uio.h>
38164032Srwatson
39164032Srwatson#include <machine/bus.h>
40164032Srwatson#include <machine/clock.h>		/* for DELAY */
41164032Srwatson#include <machine/resource.h>
42164032Srwatson#include <sys/rman.h>
43164032Srwatson
44164032Srwatson#ifdef DEV_ISA
45164032Srwatson#include <isa/isavar.h>
46164032Srwatson#include <isa/isa_common.h>
47164032Srwatson#endif
48164032Srwatson#include <dev/pci/pcivar.h>
49164032Srwatson#include <dev/pci/pcireg.h>
50164032Srwatson
51164032Srwatson#include <dev/iicbus/iiconf.h>
52164032Srwatson#include <dev/iicbus/iicbus.h>
53164032Srwatson
54164032Srwatson#include <dev/smbus/smbconf.h>
55164032Srwatson#include <dev/smbus/smbus.h>
56164032Srwatson
57164032Srwatson#include "iicbb_if.h"
58164032Srwatson#include "smbus_if.h"
59164032Srwatson
60164032Srwatson#define VIAPM_DEBUG(x)	if (viapm_debug) (x)
61164032Srwatson
62164032Srwatson#ifdef DEBUG
63164032Srwatsonstatic int viapm_debug = 1;
64164032Srwatson#else
65164032Srwatsonstatic int viapm_debug = 0;
66164032Srwatson#endif
67164032Srwatson
68164032Srwatson#define VIA_586B_PMU_ID		0x30401106
69164032Srwatson#define VIA_596A_PMU_ID		0x30501106
70164032Srwatson#define VIA_596B_PMU_ID		0x30511106
71164032Srwatson#define VIA_686A_PMU_ID		0x30571106
72164032Srwatson#define VIA_8233_PMU_ID		0x30741106
73164032Srwatson#define	VIA_8233A_PMU_ID	0x31471106
74164032Srwatson#define	VIA_8235_PMU_ID		0x31771106
75164032Srwatson
76164032Srwatson#define VIAPM_INB(port) \
77164032Srwatson	((u_char)bus_space_read_1(viapm->st, viapm->sh, port))
78164032Srwatson#define VIAPM_OUTB(port,val) \
79164032Srwatson	(bus_space_write_1(viapm->st, viapm->sh, port, (u_char)(val)))
80164032Srwatson
81164032Srwatson#define VIAPM_TYP_UNKNOWN	0
82164032Srwatson#define VIAPM_TYP_586B_3040E	1
83164032Srwatson#define VIAPM_TYP_586B_3040F	2
84164032Srwatson#define VIAPM_TYP_596B		3
85164032Srwatson#define VIAPM_TYP_686A		4
86164032Srwatson#define VIAPM_TYP_8233		5
87164032Srwatson
88164032Srwatsonstruct viapm_softc {
89164032Srwatson	int type;
90164032Srwatson	u_int32_t base;
91164032Srwatson        bus_space_tag_t st;
92164032Srwatson        bus_space_handle_t sh;
93164032Srwatson	int iorid;
94164032Srwatson	int irqrid;
95164032Srwatson	struct resource *iores;
96164032Srwatson	struct resource *irqres;
97164032Srwatson	void *irqih;
98164032Srwatson
99164032Srwatson	device_t iicbb;
100164032Srwatson	device_t smbus;
101164032Srwatson};
102164032Srwatson
103164032Srwatsonstatic devclass_t viapm_devclass;
104164032Srwatsonstatic devclass_t viapropm_devclass;
105164032Srwatson
106164032Srwatson/*
107164032Srwatson * VT82C586B definitions
108164032Srwatson */
109164032Srwatson
110164032Srwatson#define VIAPM_586B_REVID	0x08
111164032Srwatson
112164032Srwatson#define VIAPM_586B_3040E_BASE	0x20
113164032Srwatson#define VIAPM_586B_3040E_ACTIV	0x4		/* 16 bits */
114164032Srwatson
115164032Srwatson#define VIAPM_586B_3040F_BASE	0x48
116164032Srwatson#define VIAPM_586B_3040F_ACTIV	0x41		/* 8 bits */
117164032Srwatson
118164032Srwatson#define VIAPM_586B_OEM_REV_E	0x00
119164032Srwatson#define VIAPM_586B_OEM_REV_F	0x01
120164032Srwatson#define VIAPM_586B_PROD_REV_A	0x10
121164032Srwatson
122164032Srwatson#define VIAPM_586B_BA_MASK	0x0000ff00
123164032Srwatson
124164032Srwatson#define GPIO_DIR	0x40
125164032Srwatson#define GPIO_VAL	0x42
126164032Srwatson#define EXTSMI_VAL	0x44
127164032Srwatson
128164032Srwatson#define VIAPM_SCL	0x02			/* GPIO1_VAL */
129164032Srwatson#define VIAPM_SDA	0x04			/* GPIO2_VAL */
130164032Srwatson
131164032Srwatson/*
132164032Srwatson * VIAPRO common definitions
133164032Srwatson */
134164032Srwatson
135164032Srwatson#define VIAPM_PRO_BA_MASK	0x0000fff0
136164032Srwatson#define VIAPM_PRO_SMBCTRL	0xd2
137164032Srwatson#define VIAPM_PRO_REVID		0xd6
138164032Srwatson
139164032Srwatson/*
140164032Srwatson * VT82C686A definitions
141164032Srwatson */
142164032Srwatson
143164032Srwatson#define VIAPM_PRO_BASE		0x90
144164032Srwatson
145164032Srwatson#define SMBHST			0x0
146164032Srwatson#define SMBHSL			0x1
147164032Srwatson#define SMBHCTRL		0x2
148164032Srwatson#define SMBHCMD			0x3
149164032Srwatson#define SMBHADDR		0x4
150164032Srwatson#define SMBHDATA0		0x5
151164032Srwatson#define SMBHDATA1		0x6
152164032Srwatson#define SMBHBLOCK		0x7
153164032Srwatson
154164032Srwatson#define SMBSST			0x1
155164032Srwatson#define SMBSCTRL		0x8
156164032Srwatson#define SMBSSDWCMD		0x9
157164032Srwatson#define SMBSEVENT		0xa
158164032Srwatson#define SMBSDATA		0xc
159164032Srwatson
160164032Srwatson#define SMBHST_RESERVED		0xef	/* reserved bits */
161164032Srwatson#define SMBHST_FAILED		0x10	/* failed bus transaction */
162164032Srwatson#define SMBHST_COLLID		0x08	/* bus collision */
163164032Srwatson#define SMBHST_ERROR		0x04	/* device error */
164164032Srwatson#define SMBHST_INTR		0x02	/* command completed */
165164032Srwatson#define SMBHST_BUSY		0x01	/* host busy */
166164032Srwatson
167164032Srwatson#define SMBHCTRL_START		0x40	/* start command */
168164032Srwatson#define SMBHCTRL_PROTO		0x1c	/* command protocol mask */
169164032Srwatson#define SMBHCTRL_QUICK		0x00
170164032Srwatson#define SMBHCTRL_SENDRECV	0x04
171164032Srwatson#define SMBHCTRL_BYTE		0x08
172164032Srwatson#define SMBHCTRL_WORD		0x0c
173164032Srwatson#define SMBHCTRL_BLOCK		0x14
174164032Srwatson#define SMBHCTRL_KILL		0x02	/* stop the current transaction */
175164032Srwatson#define SMBHCTRL_ENABLE		0x01	/* enable interrupts */
176164032Srwatson
177164032Srwatson#define SMBSCTRL_ENABLE		0x01	/* enable slave */
178164032Srwatson
179164032Srwatson
180164032Srwatson/*
181164032Srwatson * VIA8233 definitions
182164032Srwatson */
183164032Srwatson
184164032Srwatson#define VIAPM_8233_BASE		0xD0
185164032Srwatson
186164032Srwatsonstatic int
187164032Srwatsonviapm_586b_probe(device_t dev)
188164032Srwatson{
189164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
190164032Srwatson	u_int32_t l;
191164032Srwatson	u_int16_t s;
192164032Srwatson	u_int8_t c;
193164032Srwatson
194164032Srwatson	switch (pci_get_devid(dev)) {
195164032Srwatson	case VIA_586B_PMU_ID:
196164032Srwatson
197164032Srwatson		bzero(viapm, sizeof(struct viapm_softc));
198164032Srwatson
199164032Srwatson		l = pci_read_config(dev, VIAPM_586B_REVID, 1);
200164032Srwatson		switch (l) {
201164032Srwatson		case VIAPM_586B_OEM_REV_E:
202164032Srwatson			viapm->type = VIAPM_TYP_586B_3040E;
203164032Srwatson			viapm->iorid = VIAPM_586B_3040E_BASE;
204164032Srwatson
205164032Srwatson			/* Activate IO block access */
206164032Srwatson			s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
207164032Srwatson			pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
208164032Srwatson			break;
209164032Srwatson
210164032Srwatson		case VIAPM_586B_OEM_REV_F:
211164032Srwatson		case VIAPM_586B_PROD_REV_A:
212164032Srwatson		default:
213164032Srwatson			viapm->type = VIAPM_TYP_586B_3040F;
214164032Srwatson			viapm->iorid = VIAPM_586B_3040F_BASE;
215164032Srwatson
216164032Srwatson			/* Activate IO block access */
217164032Srwatson			c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
218164032Srwatson			pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
219164032Srwatson			break;
220164032Srwatson		}
221164032Srwatson
222164032Srwatson		viapm->base = pci_read_config(dev, viapm->iorid, 4) &
223164032Srwatson				VIAPM_586B_BA_MASK;
224164032Srwatson
225164032Srwatson		/*
226164032Srwatson		 * We have to set the I/O resources by hand because it is
227164032Srwatson		 * described outside the viapmope of the traditional maps
228164032Srwatson		 */
229164032Srwatson		if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
230164032Srwatson							viapm->base, 256)) {
231164032Srwatson			device_printf(dev, "could not set bus resource\n");
232164032Srwatson			return ENXIO;
233164032Srwatson		}
234164032Srwatson		device_set_desc(dev, "VIA VT82C586B Power Management Unit");
235164032Srwatson		return (BUS_PROBE_DEFAULT);
236164032Srwatson
237164032Srwatson	default:
238164032Srwatson		break;
239164032Srwatson	}
240164032Srwatson
241164032Srwatson	return ENXIO;
242164032Srwatson}
243164032Srwatson
244164032Srwatson
245164032Srwatsonstatic int
246164032Srwatsonviapm_pro_probe(device_t dev)
247164032Srwatson{
248164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
249164032Srwatson#ifdef VIAPM_BASE_ADDR
250164032Srwatson	u_int32_t l;
251164032Srwatson#endif
252164032Srwatson	u_int32_t base_cfgreg;
253164032Srwatson	char *desc;
254164032Srwatson
255164032Srwatson	switch (pci_get_devid(dev)) {
256164032Srwatson	case VIA_596A_PMU_ID:
257164032Srwatson		desc = "VIA VT82C596A Power Management Unit";
258164032Srwatson		viapm->type = VIAPM_TYP_596B;
259164032Srwatson		base_cfgreg = VIAPM_PRO_BASE;
260164032Srwatson		goto viapro;
261164032Srwatson
262164032Srwatson	case VIA_596B_PMU_ID:
263164032Srwatson		desc = "VIA VT82C596B Power Management Unit";
264164032Srwatson		viapm->type = VIAPM_TYP_596B;
265164032Srwatson		base_cfgreg = VIAPM_PRO_BASE;
266164032Srwatson		goto viapro;
267164032Srwatson
268164032Srwatson	case VIA_686A_PMU_ID:
269164032Srwatson		desc = "VIA VT82C686A Power Management Unit";
270164032Srwatson		viapm->type = VIAPM_TYP_686A;
271164032Srwatson		base_cfgreg = VIAPM_PRO_BASE;
272164032Srwatson		goto viapro;
273164032Srwatson
274164032Srwatson	case VIA_8233_PMU_ID:
275164032Srwatson	case VIA_8233A_PMU_ID:
276164032Srwatson		desc = "VIA VT8233 Power Management Unit";
277164032Srwatson		viapm->type = VIAPM_TYP_UNKNOWN;
278164032Srwatson		base_cfgreg = VIAPM_8233_BASE;
279164032Srwatson		goto viapro;
280164032Srwatson
281164032Srwatson	case VIA_8235_PMU_ID:
282164032Srwatson		desc = "VIA VT8235 Power Management Unit";
283164032Srwatson		viapm->type = VIAPM_TYP_UNKNOWN;
284164032Srwatson		base_cfgreg = VIAPM_8233_BASE;
285164032Srwatson		goto viapro;
286164032Srwatson
287164032Srwatson	viapro:
288164032Srwatson
289164032Srwatson#ifdef VIAPM_BASE_ADDR
290164032Srwatson		/* force VIAPM I/O base address */
291164032Srwatson
292164032Srwatson		/* enable the SMBus controller function */
293164032Srwatson		l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
294164032Srwatson		pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
295164032Srwatson
296164032Srwatson		/* write the base address */
297164032Srwatson		pci_write_config(dev, base_cfgreg,
298164032Srwatson				 VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
299164032Srwatson#endif
300164032Srwatson
301164032Srwatson		viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
302164032Srwatson
303164032Srwatson		/*
304164032Srwatson		 * We have to set the I/O resources by hand because it is
305164032Srwatson		 * described outside the viapmope of the traditional maps
306164032Srwatson		 */
307164032Srwatson		viapm->iorid = base_cfgreg;
308164032Srwatson		if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
309164032Srwatson				     viapm->base, 16)) {
310164032Srwatson			device_printf(dev, "could not set bus resource 0x%x\n",
311164032Srwatson					viapm->base);
312164032Srwatson			return ENXIO;
313164032Srwatson		}
314164032Srwatson
315164032Srwatson		if (1 || bootverbose) {
316164032Srwatson			device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
317164032Srwatson		}
318164032Srwatson
319164032Srwatson		device_set_desc(dev, desc);
320164032Srwatson		return (BUS_PROBE_DEFAULT);
321164032Srwatson
322164032Srwatson	default:
323164032Srwatson		break;
324164032Srwatson	}
325164032Srwatson
326164032Srwatson	return ENXIO;
327164032Srwatson}
328164032Srwatson
329164032Srwatsonstatic int
330164032Srwatsonviapm_pro_attach(device_t dev)
331164032Srwatson{
332164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
333164032Srwatson	u_int32_t l;
334164032Srwatson
335164032Srwatson	if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
336164032Srwatson		&viapm->iorid, RF_ACTIVE))) {
337164032Srwatson		device_printf(dev, "could not allocate bus space\n");
338164032Srwatson		goto error;
339164032Srwatson	}
340164032Srwatson	viapm->st = rman_get_bustag(viapm->iores);
341164032Srwatson	viapm->sh = rman_get_bushandle(viapm->iores);
342164032Srwatson
343164032Srwatson#ifdef notyet
344164032Srwatson	/* force irq 9 */
345164032Srwatson	l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
346164032Srwatson	pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
347164032Srwatson
348164032Srwatson	viapm->irqrid = 0;
349164032Srwatson	if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
350164032Srwatson				&viapm->irqrid, 9, 9, 1,
351164032Srwatson				RF_SHAREABLE | RF_ACTIVE))) {
352164032Srwatson		device_printf(dev, "could not allocate irq\n");
353164032Srwatson		goto error;
354164032Srwatson	}
355164032Srwatson
356164032Srwatson	if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
357164032Srwatson			(driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
358164032Srwatson		device_printf(dev, "could not setup irq\n");
359164032Srwatson		goto error;
360164032Srwatson	}
361164032Srwatson#endif
362164032Srwatson
363164032Srwatson	if (1 | bootverbose) {
364164032Srwatson		l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
365164032Srwatson		device_printf(dev, "SMBus revision code 0x%x\n", l);
366164032Srwatson	}
367164032Srwatson
368164032Srwatson	viapm->smbus = device_add_child(dev, "smbus", -1);
369164032Srwatson
370164032Srwatson	/* probe and attach the smbus */
371164032Srwatson	bus_generic_attach(dev);
372164032Srwatson
373164032Srwatson	/* disable slave function */
374164032Srwatson	VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
375164032Srwatson
376164032Srwatson	/* enable the SMBus controller function */
377164032Srwatson	l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
378164032Srwatson	pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
379164032Srwatson
380164032Srwatson#ifdef notyet
381164032Srwatson	/* enable interrupts */
382164032Srwatson	VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
383164032Srwatson#endif
384164032Srwatson
385164032Srwatson#ifdef DEV_ISA
386164032Srwatson	/* If this device is a PCI-ISA bridge, then attach an ISA bus. */
387164032Srwatson	if ((pci_get_class(dev) == PCIC_BRIDGE) &&
388164032Srwatson	    (pci_get_subclass(dev) == PCIS_BRIDGE_ISA))
389164032Srwatson		isab_attach(dev);
390164032Srwatson#endif
391164032Srwatson	return 0;
392164032Srwatson
393164032Srwatsonerror:
394164032Srwatson	if (viapm->iores)
395164032Srwatson		bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
396164032Srwatson#ifdef notyet
397164032Srwatson	if (viapm->irqres)
398164032Srwatson		bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
399164032Srwatson#endif
400164032Srwatson
401164032Srwatson	return ENXIO;
402164032Srwatson}
403164032Srwatson
404164032Srwatsonstatic int
405164032Srwatsonviapm_586b_attach(device_t dev)
406164032Srwatson{
407164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
408164032Srwatson
409164032Srwatson	if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
410164032Srwatson		&viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) {
411164032Srwatson		device_printf(dev, "could not allocate bus resource\n");
412164032Srwatson		return ENXIO;
413164032Srwatson	}
414164032Srwatson	viapm->st = rman_get_bustag(viapm->iores);
415164032Srwatson	viapm->sh = rman_get_bushandle(viapm->iores);
416164032Srwatson
417164032Srwatson	VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
418164032Srwatson
419164032Srwatson	/* add generic bit-banging code */
420164032Srwatson	if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
421164032Srwatson		goto error;
422164032Srwatson
423164032Srwatson	bus_generic_attach(dev);
424164032Srwatson
425164032Srwatson	return 0;
426164032Srwatson
427164032Srwatsonerror:
428164032Srwatson	if (viapm->iores)
429164032Srwatson		bus_release_resource(dev, SYS_RES_IOPORT,
430164032Srwatson					viapm->iorid, viapm->iores);
431164032Srwatson	return ENXIO;
432164032Srwatson}
433164032Srwatson
434164032Srwatsonstatic int
435164032Srwatsonviapm_586b_detach(device_t dev)
436164032Srwatson{
437164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
438164032Srwatson	int error;
439164032Srwatson
440164032Srwatson	bus_generic_detach(dev);
441164032Srwatson	if (viapm->iicbb) {
442164032Srwatson		device_delete_child(dev, viapm->iicbb);
443164032Srwatson	}
444164032Srwatson
445164032Srwatson	if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
446164032Srwatson						viapm->iorid, viapm->iores)))
447164032Srwatson		return (error);
448164032Srwatson
449164032Srwatson	return 0;
450164032Srwatson}
451164032Srwatson
452164032Srwatsonstatic int
453164032Srwatsonviapm_pro_detach(device_t dev)
454164032Srwatson{
455164032Srwatson	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
456164032Srwatson	int error;
457164032Srwatson
458	bus_generic_detach(dev);
459	if (viapm->smbus) {
460		device_delete_child(dev, viapm->smbus);
461	}
462
463	if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
464				viapm->iorid, viapm->iores)))
465		return (error);
466
467#ifdef notyet
468	if ((error = bus_release_resource(dev, SYS_RES_IRQ,
469					viapm->irqrid, viapm->irqres))
470		return (error);
471#endif
472
473	return 0;
474}
475
476static int
477viabb_callback(device_t dev, int index, caddr_t *data)
478{
479	return 0;
480}
481
482static void
483viabb_setscl(device_t dev, int ctrl)
484{
485	struct viapm_softc *viapm = device_get_softc(dev);
486	u_char val;
487
488	val = VIAPM_INB(GPIO_VAL);
489
490	if (ctrl)
491		val |= VIAPM_SCL;
492	else
493		val &= ~VIAPM_SCL;
494
495	VIAPM_OUTB(GPIO_VAL, val);
496
497	return;
498}
499
500static void
501viabb_setsda(device_t dev, int data)
502{
503	struct viapm_softc *viapm = device_get_softc(dev);
504	u_char val;
505
506	val = VIAPM_INB(GPIO_VAL);
507
508	if (data)
509		val |= VIAPM_SDA;
510	else
511		val &= ~VIAPM_SDA;
512
513	VIAPM_OUTB(GPIO_VAL, val);
514
515	return;
516}
517
518static int
519viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
520{
521	/* reset bus */
522	viabb_setsda(dev, 1);
523	viabb_setscl(dev, 1);
524
525	return (IIC_ENOADDR);
526}
527
528static int
529viabb_getscl(device_t dev)
530{
531	struct viapm_softc *viapm = device_get_softc(dev);
532
533	return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
534}
535
536static int
537viabb_getsda(device_t dev)
538{
539	struct viapm_softc *viapm = device_get_softc(dev);
540
541	return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
542}
543
544static int
545viapm_abort(struct viapm_softc *viapm)
546{
547	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
548	DELAY(10);
549
550	return (0);
551}
552
553static int
554viapm_clear(struct viapm_softc *viapm)
555{
556	VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
557		SMBHST_ERROR | SMBHST_INTR);
558	DELAY(10);
559
560	return (0);
561}
562
563static int
564viapm_busy(struct viapm_softc *viapm)
565{
566	u_char sts;
567
568	sts = VIAPM_INB(SMBHST);
569
570	VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
571
572	return (sts & SMBHST_BUSY);
573}
574
575/*
576 * Poll the SMBus controller
577 */
578static int
579viapm_wait(struct viapm_softc *viapm)
580{
581	int count = 10000;
582	u_char sts = 0;
583	int error;
584
585	/* wait for command to complete and SMBus controller is idle */
586	while(count--) {
587		DELAY(10);
588		sts = VIAPM_INB(SMBHST);
589
590		/* check if the controller is processing a command */
591		if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
592			break;
593	}
594
595	VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
596
597	error = SMB_ENOERR;
598
599	if (!count)
600		error |= SMB_ETIMEOUT;
601
602	if (sts & SMBHST_FAILED)
603		error |= SMB_EABORT;
604
605	if (sts & SMBHST_COLLID)
606		error |= SMB_ENOACK;
607
608	if (sts & SMBHST_ERROR)
609		error |= SMB_EBUSERR;
610
611	if (error != SMB_ENOERR)
612		viapm_abort(viapm);
613
614	viapm_clear(viapm);
615
616	return (error);
617}
618
619static int
620viasmb_callback(device_t dev, int index, caddr_t *data)
621{
622	int error = 0;
623
624	switch (index) {
625	case SMB_REQUEST_BUS:
626	case SMB_RELEASE_BUS:
627		/* ok, bus allocation accepted */
628		break;
629	default:
630		error = EINVAL;
631	}
632
633	return (error);
634}
635
636static int
637viasmb_quick(device_t dev, u_char slave, int how)
638{
639	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
640	int error;
641
642	viapm_clear(viapm);
643	if (viapm_busy(viapm))
644		return (EBUSY);
645
646	switch (how) {
647	case SMB_QWRITE:
648		VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
649		VIAPM_OUTB(SMBHADDR, slave & ~LSB);
650		break;
651	case SMB_QREAD:
652		VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
653		VIAPM_OUTB(SMBHADDR, slave | LSB);
654		break;
655	default:
656		panic("%s: unknown QUICK command (%x)!", __func__, how);
657	}
658
659	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
660
661	error = viapm_wait(viapm);
662
663	return (error);
664}
665
666static int
667viasmb_sendb(device_t dev, u_char slave, char byte)
668{
669	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
670	int error;
671
672	viapm_clear(viapm);
673	if (viapm_busy(viapm))
674		return (EBUSY);
675
676	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
677	VIAPM_OUTB(SMBHCMD, byte);
678
679	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
680
681	error = viapm_wait(viapm);
682
683	VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
684
685	return (error);
686}
687
688static int
689viasmb_recvb(device_t dev, u_char slave, char *byte)
690{
691	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
692	int error;
693
694	viapm_clear(viapm);
695	if (viapm_busy(viapm))
696		return (EBUSY);
697
698	VIAPM_OUTB(SMBHADDR, slave | LSB);
699
700	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
701
702	if ((error = viapm_wait(viapm)) == SMB_ENOERR)
703		*byte = VIAPM_INB(SMBHDATA0);
704
705	VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
706
707	return (error);
708}
709
710static int
711viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
712{
713	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
714	int error;
715
716	viapm_clear(viapm);
717	if (viapm_busy(viapm))
718		return (EBUSY);
719
720	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
721	VIAPM_OUTB(SMBHCMD, cmd);
722	VIAPM_OUTB(SMBHDATA0, byte);
723
724	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
725
726	error = viapm_wait(viapm);
727
728	VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
729
730	return (error);
731}
732
733static int
734viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
735{
736	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
737	int error;
738
739	viapm_clear(viapm);
740	if (viapm_busy(viapm))
741		return (EBUSY);
742
743	VIAPM_OUTB(SMBHADDR, slave | LSB);
744	VIAPM_OUTB(SMBHCMD, cmd);
745
746	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
747
748	if ((error = viapm_wait(viapm)) == SMB_ENOERR)
749		*byte = VIAPM_INB(SMBHDATA0);
750
751	VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
752
753	return (error);
754}
755
756static int
757viasmb_writew(device_t dev, u_char slave, char cmd, short word)
758{
759	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
760	int error;
761
762	viapm_clear(viapm);
763	if (viapm_busy(viapm))
764		return (EBUSY);
765
766	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
767	VIAPM_OUTB(SMBHCMD, cmd);
768	VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
769	VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
770
771	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
772
773	error = viapm_wait(viapm);
774
775	VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
776
777	return (error);
778}
779
780static int
781viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
782{
783	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
784	int error;
785	u_char high, low;
786
787	viapm_clear(viapm);
788	if (viapm_busy(viapm))
789		return (EBUSY);
790
791	VIAPM_OUTB(SMBHADDR, slave | LSB);
792	VIAPM_OUTB(SMBHCMD, cmd);
793
794	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
795
796	if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
797		low = VIAPM_INB(SMBHDATA0);
798		high = VIAPM_INB(SMBHDATA1);
799
800		*word = ((high & 0xff) << 8) | (low & 0xff);
801	}
802
803	VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
804
805	return (error);
806}
807
808static int
809viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
810{
811	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
812	u_char remain, len, i;
813	int error = SMB_ENOERR;
814
815	viapm_clear(viapm);
816	if (viapm_busy(viapm))
817		return (EBUSY);
818
819	remain = count;
820	while (remain) {
821		len = min(remain, 32);
822
823		VIAPM_OUTB(SMBHADDR, slave & ~LSB);
824		VIAPM_OUTB(SMBHCMD, cmd);
825		VIAPM_OUTB(SMBHDATA0, len);
826		i = VIAPM_INB(SMBHCTRL);
827
828		/* fill the 32-byte internal buffer */
829		for (i=0; i<len; i++) {
830			VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]);
831			DELAY(2);
832		}
833		VIAPM_OUTB(SMBHCMD, cmd);
834		VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
835
836		if ((error = viapm_wait(viapm)) != SMB_ENOERR)
837			goto error;
838
839		remain -= len;
840	}
841
842error:
843	VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
844
845	return (error);
846
847}
848
849static int
850viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
851{
852	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
853	u_char remain, len, i;
854	int error = SMB_ENOERR;
855
856	viapm_clear(viapm);
857	if (viapm_busy(viapm))
858		return (EBUSY);
859
860	remain = count;
861	while (remain) {
862		VIAPM_OUTB(SMBHADDR, slave | LSB);
863		VIAPM_OUTB(SMBHCMD, cmd);
864		VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
865
866		if ((error = viapm_wait(viapm)) != SMB_ENOERR)
867			goto error;
868
869		len = VIAPM_INB(SMBHDATA0);
870		i = VIAPM_INB(SMBHCTRL); 		/* reset counter */
871
872		len = min(len, remain);
873
874		/* read the 32-byte internal buffer */
875		for (i=0; i<len; i++) {
876			buf[count-remain+i] = VIAPM_INB(SMBHBLOCK);
877			DELAY(2);
878		}
879
880		remain -= len;
881	}
882error:
883	VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
884
885	return (error);
886}
887
888static device_method_t viapm_methods[] = {
889	/* device interface */
890	DEVMETHOD(device_probe,		viapm_586b_probe),
891	DEVMETHOD(device_attach,	viapm_586b_attach),
892	DEVMETHOD(device_detach,	viapm_586b_detach),
893
894	/* iicbb interface */
895	DEVMETHOD(iicbb_callback,	viabb_callback),
896	DEVMETHOD(iicbb_setscl,		viabb_setscl),
897	DEVMETHOD(iicbb_setsda,		viabb_setsda),
898	DEVMETHOD(iicbb_getscl,		viabb_getscl),
899	DEVMETHOD(iicbb_getsda,		viabb_getsda),
900	DEVMETHOD(iicbb_reset,		viabb_reset),
901
902	/* Bus interface */
903	DEVMETHOD(bus_print_child,	bus_generic_print_child),
904	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
905	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
906	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
907	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
908	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
909	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
910
911	{ 0, 0 }
912};
913
914static driver_t viapm_driver = {
915	"viapm",
916	viapm_methods,
917	sizeof(struct viapm_softc),
918};
919
920static device_method_t viapropm_methods[] = {
921	/* device interface */
922	DEVMETHOD(device_probe,		viapm_pro_probe),
923	DEVMETHOD(device_attach,	viapm_pro_attach),
924	DEVMETHOD(device_detach,	viapm_pro_detach),
925
926	/* smbus interface */
927	DEVMETHOD(smbus_callback,	viasmb_callback),
928	DEVMETHOD(smbus_quick,		viasmb_quick),
929	DEVMETHOD(smbus_sendb,		viasmb_sendb),
930	DEVMETHOD(smbus_recvb,		viasmb_recvb),
931	DEVMETHOD(smbus_writeb,		viasmb_writeb),
932	DEVMETHOD(smbus_readb,		viasmb_readb),
933	DEVMETHOD(smbus_writew,		viasmb_writew),
934	DEVMETHOD(smbus_readw,		viasmb_readw),
935	DEVMETHOD(smbus_bwrite,		viasmb_bwrite),
936	DEVMETHOD(smbus_bread,		viasmb_bread),
937
938	/* Bus interface */
939	DEVMETHOD(bus_print_child,	bus_generic_print_child),
940	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
941	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
942	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
943	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
944	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
945	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
946
947	{ 0, 0 }
948};
949
950static driver_t viapropm_driver = {
951	"viapropm",
952	viapropm_methods,
953	sizeof(struct viapm_softc),
954};
955
956DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
957DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
958
959MODULE_DEPEND(viapm, pci, 1, 1, 1);
960MODULE_DEPEND(viapropm, pci, 1, 1, 1);
961MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
962MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
963MODULE_VERSION(viapm, 1);
964
965#ifdef DEV_ISA
966DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0);
967DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0);
968MODULE_DEPEND(viapm, isa, 1, 1, 1);
969MODULE_DEPEND(viapropm, isa, 1, 1, 1);
970#endif
971