viapm.c revision 179622
1181834Sroberto/*-
2181834Sroberto * Copyright (c) 2001 Alcove - Nicolas Souchu
3181834Sroberto * All rights reserved.
4181834Sroberto *
5181834Sroberto * Redistribution and use in source and binary forms, with or without
6181834Sroberto * modification, are permitted provided that the following conditions
7181834Sroberto * are met:
8181834Sroberto * 1. Redistributions of source code must retain the above copyright
9181834Sroberto *    notice, this list of conditions and the following disclaimer.
10181834Sroberto * 2. Redistributions in binary form must reproduce the above copyright
11181834Sroberto *    notice, this list of conditions and the following disclaimer in the
12181834Sroberto *    documentation and/or other materials provided with the distribution.
13181834Sroberto *
14181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15181834Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17181834Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18181834Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19181834Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20181834Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22181834Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23181834Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24181834Sroberto * SUCH DAMAGE.
25181834Sroberto */
26181834Sroberto
27181834Sroberto#include <sys/cdefs.h>
28181834Sroberto__FBSDID("$FreeBSD: head/sys/pci/viapm.c 179622 2008-06-06 18:29:56Z jhb $");
29181834Sroberto
30181834Sroberto#include "opt_isa.h"
31181834Sroberto
32181834Sroberto#include <sys/param.h>
33181834Sroberto#include <sys/bus.h>
34181834Sroberto#include <sys/kernel.h>
35181834Sroberto#include <sys/lock.h>
36181834Sroberto#include <sys/module.h>
37181834Sroberto#include <sys/mutex.h>
38181834Sroberto#include <sys/systm.h>
39181834Sroberto
40181834Sroberto#include <machine/bus.h>
41181834Sroberto#include <machine/resource.h>
42181834Sroberto#include <sys/rman.h>
43181834Sroberto
44181834Sroberto#ifdef DEV_ISA
45181834Sroberto#include <isa/isavar.h>
46181834Sroberto#include <isa/isa_common.h>
47181834Sroberto#endif
48181834Sroberto#include <dev/pci/pcivar.h>
49181834Sroberto#include <dev/pci/pcireg.h>
50181834Sroberto
51181834Sroberto#include <dev/iicbus/iiconf.h>
52181834Sroberto
53181834Sroberto#include <dev/smbus/smbconf.h>
54181834Sroberto
55181834Sroberto#include "iicbb_if.h"
56181834Sroberto#include "smbus_if.h"
57181834Sroberto
58181834Sroberto#define VIAPM_DEBUG(x)	if (viapm_debug) (x)
59181834Sroberto
60181834Sroberto#ifdef DEBUG
61181834Srobertostatic int viapm_debug = 1;
62181834Sroberto#else
63181834Srobertostatic int viapm_debug = 0;
64181834Sroberto#endif
65181834Sroberto
66181834Sroberto#define VIA_586B_PMU_ID		0x30401106
67181834Sroberto#define VIA_596A_PMU_ID		0x30501106
68181834Sroberto#define VIA_596B_PMU_ID		0x30511106
69181834Sroberto#define VIA_686A_PMU_ID		0x30571106
70181834Sroberto#define VIA_8233_PMU_ID		0x30741106
71181834Sroberto#define	VIA_8233A_PMU_ID	0x31471106
72181834Sroberto#define	VIA_8235_PMU_ID		0x31771106
73181834Sroberto#define	VIA_CX700_PMU_ID	0x83241106
74181834Sroberto
75181834Sroberto#define VIAPM_INB(port) \
76181834Sroberto	((u_char)bus_read_1(viapm->iores, port))
77181834Sroberto#define VIAPM_OUTB(port,val) \
78181834Sroberto	(bus_write_1(viapm->iores, port, (u_char)(val)))
79181834Sroberto
80181834Sroberto#define VIAPM_TYP_UNKNOWN	0
81181834Sroberto#define VIAPM_TYP_586B_3040E	1
82181834Sroberto#define VIAPM_TYP_586B_3040F	2
83181834Sroberto#define VIAPM_TYP_596B		3
84181834Sroberto#define VIAPM_TYP_686A		4
85181834Sroberto#define VIAPM_TYP_8233		5
86181834Sroberto
87181834Sroberto#define	VIAPM_LOCK(sc)		mtx_lock(&(sc)->lock)
88181834Sroberto#define	VIAPM_UNLOCK(sc)	mtx_unlock(&(sc)->lock)
89181834Sroberto#define	VIAPM_LOCK_ASSERT(sc)	mtx_assert(&(sc)->lock, MA_OWNED)
90181834Sroberto
91181834Srobertostruct viapm_softc {
92181834Sroberto	int type;
93181834Sroberto	u_int32_t base;
94181834Sroberto	int iorid;
95181834Sroberto	int irqrid;
96181834Sroberto	struct resource *iores;
97181834Sroberto	struct resource *irqres;
98181834Sroberto	void *irqih;
99181834Sroberto	device_t iicbb;
100181834Sroberto	device_t smbus;
101181834Sroberto	struct mtx lock;
102181834Sroberto};
103181834Sroberto
104181834Srobertostatic devclass_t viapm_devclass;
105181834Srobertostatic devclass_t viapropm_devclass;
106181834Sroberto
107181834Sroberto/*
108181834Sroberto * VT82C586B definitions
109181834Sroberto */
110181834Sroberto
111181834Sroberto#define VIAPM_586B_REVID	0x08
112181834Sroberto
113181834Sroberto#define VIAPM_586B_3040E_BASE	0x20
114181834Sroberto#define VIAPM_586B_3040E_ACTIV	0x4		/* 16 bits */
115181834Sroberto
116181834Sroberto#define VIAPM_586B_3040F_BASE	0x48
117181834Sroberto#define VIAPM_586B_3040F_ACTIV	0x41		/* 8 bits */
118181834Sroberto
119181834Sroberto#define VIAPM_586B_OEM_REV_E	0x00
120181834Sroberto#define VIAPM_586B_OEM_REV_F	0x01
121181834Sroberto#define VIAPM_586B_PROD_REV_A	0x10
122181834Sroberto
123181834Sroberto#define VIAPM_586B_BA_MASK	0x0000ff00
124181834Sroberto
125181834Sroberto#define GPIO_DIR	0x40
126181834Sroberto#define GPIO_VAL	0x42
127181834Sroberto#define EXTSMI_VAL	0x44
128181834Sroberto
129181834Sroberto#define VIAPM_SCL	0x02			/* GPIO1_VAL */
130181834Sroberto#define VIAPM_SDA	0x04			/* GPIO2_VAL */
131181834Sroberto
132181834Sroberto/*
133181834Sroberto * VIAPRO common definitions
134181834Sroberto */
135181834Sroberto
136181834Sroberto#define VIAPM_PRO_BA_MASK	0x0000fff0
137181834Sroberto#define VIAPM_PRO_SMBCTRL	0xd2
138181834Sroberto#define VIAPM_PRO_REVID		0xd6
139181834Sroberto
140181834Sroberto/*
141181834Sroberto * VT82C686A definitions
142181834Sroberto */
143
144#define VIAPM_PRO_BASE		0x90
145
146#define SMBHST			0x0
147#define SMBHSL			0x1
148#define SMBHCTRL		0x2
149#define SMBHCMD			0x3
150#define SMBHADDR		0x4
151#define SMBHDATA0		0x5
152#define SMBHDATA1		0x6
153#define SMBHBLOCK		0x7
154
155#define SMBSST			0x1
156#define SMBSCTRL		0x8
157#define SMBSSDWCMD		0x9
158#define SMBSEVENT		0xa
159#define SMBSDATA		0xc
160
161#define SMBHST_RESERVED		0xef	/* reserved bits */
162#define SMBHST_FAILED		0x10	/* failed bus transaction */
163#define SMBHST_COLLID		0x08	/* bus collision */
164#define SMBHST_ERROR		0x04	/* device error */
165#define SMBHST_INTR		0x02	/* command completed */
166#define SMBHST_BUSY		0x01	/* host busy */
167
168#define SMBHCTRL_START		0x40	/* start command */
169#define SMBHCTRL_PROTO		0x1c	/* command protocol mask */
170#define SMBHCTRL_QUICK		0x00
171#define SMBHCTRL_SENDRECV	0x04
172#define SMBHCTRL_BYTE		0x08
173#define SMBHCTRL_WORD		0x0c
174#define SMBHCTRL_BLOCK		0x14
175#define SMBHCTRL_KILL		0x02	/* stop the current transaction */
176#define SMBHCTRL_ENABLE		0x01	/* enable interrupts */
177
178#define SMBSCTRL_ENABLE		0x01	/* enable slave */
179
180
181/*
182 * VIA8233 definitions
183 */
184
185#define VIAPM_8233_BASE		0xD0
186
187static int
188viapm_586b_probe(device_t dev)
189{
190	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
191	u_int32_t l;
192	u_int16_t s;
193	u_int8_t c;
194
195	switch (pci_get_devid(dev)) {
196	case VIA_586B_PMU_ID:
197
198		bzero(viapm, sizeof(struct viapm_softc));
199
200		l = pci_read_config(dev, VIAPM_586B_REVID, 1);
201		switch (l) {
202		case VIAPM_586B_OEM_REV_E:
203			viapm->type = VIAPM_TYP_586B_3040E;
204			viapm->iorid = VIAPM_586B_3040E_BASE;
205
206			/* Activate IO block access */
207			s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
208			pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
209			break;
210
211		case VIAPM_586B_OEM_REV_F:
212		case VIAPM_586B_PROD_REV_A:
213		default:
214			viapm->type = VIAPM_TYP_586B_3040F;
215			viapm->iorid = VIAPM_586B_3040F_BASE;
216
217			/* Activate IO block access */
218			c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
219			pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
220			break;
221		}
222
223		viapm->base = pci_read_config(dev, viapm->iorid, 4) &
224				VIAPM_586B_BA_MASK;
225
226		/*
227		 * We have to set the I/O resources by hand because it is
228		 * described outside the viapmope of the traditional maps
229		 */
230		if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
231							viapm->base, 256)) {
232			device_printf(dev, "could not set bus resource\n");
233			return ENXIO;
234		}
235		device_set_desc(dev, "VIA VT82C586B Power Management Unit");
236		return (BUS_PROBE_DEFAULT);
237
238	default:
239		break;
240	}
241
242	return ENXIO;
243}
244
245
246static int
247viapm_pro_probe(device_t dev)
248{
249	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
250#ifdef VIAPM_BASE_ADDR
251	u_int32_t l;
252#endif
253	u_int32_t base_cfgreg;
254	char *desc;
255
256	switch (pci_get_devid(dev)) {
257	case VIA_596A_PMU_ID:
258		desc = "VIA VT82C596A Power Management Unit";
259		viapm->type = VIAPM_TYP_596B;
260		base_cfgreg = VIAPM_PRO_BASE;
261		goto viapro;
262
263	case VIA_596B_PMU_ID:
264		desc = "VIA VT82C596B Power Management Unit";
265		viapm->type = VIAPM_TYP_596B;
266		base_cfgreg = VIAPM_PRO_BASE;
267		goto viapro;
268
269	case VIA_686A_PMU_ID:
270		desc = "VIA VT82C686A Power Management Unit";
271		viapm->type = VIAPM_TYP_686A;
272		base_cfgreg = VIAPM_PRO_BASE;
273		goto viapro;
274
275	case VIA_8233_PMU_ID:
276	case VIA_8233A_PMU_ID:
277		desc = "VIA VT8233 Power Management Unit";
278		viapm->type = VIAPM_TYP_UNKNOWN;
279		base_cfgreg = VIAPM_8233_BASE;
280		goto viapro;
281
282	case VIA_8235_PMU_ID:
283		desc = "VIA VT8235 Power Management Unit";
284		viapm->type = VIAPM_TYP_UNKNOWN;
285		base_cfgreg = VIAPM_8233_BASE;
286		goto viapro;
287
288	case VIA_CX700_PMU_ID:
289		desc = "VIA CX700 Power Management Unit";
290		viapm->type = VIAPM_TYP_UNKNOWN;
291		base_cfgreg = VIAPM_8233_BASE;
292		goto viapro;
293
294	viapro:
295
296#ifdef VIAPM_BASE_ADDR
297		/* force VIAPM I/O base address */
298
299		/* enable the SMBus controller function */
300		l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
301		pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
302
303		/* write the base address */
304		pci_write_config(dev, base_cfgreg,
305				 VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
306#endif
307
308		viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
309
310		/*
311		 * We have to set the I/O resources by hand because it is
312		 * described outside the viapmope of the traditional maps
313		 */
314		viapm->iorid = base_cfgreg;
315		if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
316				     viapm->base, 16)) {
317			device_printf(dev, "could not set bus resource 0x%x\n",
318					viapm->base);
319			return ENXIO;
320		}
321
322		if (bootverbose) {
323			device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
324		}
325
326		device_set_desc(dev, desc);
327		return (BUS_PROBE_DEFAULT);
328
329	default:
330		break;
331	}
332
333	return ENXIO;
334}
335
336static int
337viapm_pro_attach(device_t dev)
338{
339	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
340	u_int32_t l;
341
342	mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF);
343	if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
344		&viapm->iorid, RF_ACTIVE))) {
345		device_printf(dev, "could not allocate bus space\n");
346		goto error;
347	}
348
349#ifdef notyet
350	/* force irq 9 */
351	l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
352	pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
353
354	viapm->irqrid = 0;
355	if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
356				&viapm->irqrid, 9, 9, 1,
357				RF_SHAREABLE | RF_ACTIVE))) {
358		device_printf(dev, "could not allocate irq\n");
359		goto error;
360	}
361
362	if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC | INTR_MPSAFE,
363			(driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
364		device_printf(dev, "could not setup irq\n");
365		goto error;
366	}
367#endif
368
369	if (bootverbose) {
370		l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
371		device_printf(dev, "SMBus revision code 0x%x\n", l);
372	}
373
374	viapm->smbus = device_add_child(dev, "smbus", -1);
375
376	/* probe and attach the smbus */
377	bus_generic_attach(dev);
378
379	/* disable slave function */
380	VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
381
382	/* enable the SMBus controller function */
383	l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
384	pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
385
386#ifdef notyet
387	/* enable interrupts */
388	VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
389#endif
390
391#ifdef DEV_ISA
392	/* If this device is a PCI-ISA bridge, then attach an ISA bus. */
393	if ((pci_get_class(dev) == PCIC_BRIDGE) &&
394	    (pci_get_subclass(dev) == PCIS_BRIDGE_ISA))
395		isab_attach(dev);
396#endif
397	return 0;
398
399error:
400	if (viapm->iores)
401		bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
402#ifdef notyet
403	if (viapm->irqres)
404		bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
405#endif
406	mtx_destroy(&viapm->lock);
407
408	return ENXIO;
409}
410
411static int
412viapm_586b_attach(device_t dev)
413{
414	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
415
416	mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF);
417	if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
418		&viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) {
419		device_printf(dev, "could not allocate bus resource\n");
420		goto error;
421	}
422
423	VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
424
425	/* add generic bit-banging code */
426	if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
427		goto error;
428
429	bus_generic_attach(dev);
430
431	return 0;
432
433error:
434	if (viapm->iores)
435		bus_release_resource(dev, SYS_RES_IOPORT,
436					viapm->iorid, viapm->iores);
437	mtx_destroy(&viapm->lock);
438	return ENXIO;
439}
440
441static int
442viapm_586b_detach(device_t dev)
443{
444	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
445
446	bus_generic_detach(dev);
447	if (viapm->iicbb) {
448		device_delete_child(dev, viapm->iicbb);
449	}
450
451	if (viapm->iores)
452		bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid,
453		    viapm->iores);
454	mtx_destroy(&viapm->lock);
455
456	return 0;
457}
458
459static int
460viapm_pro_detach(device_t dev)
461{
462	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
463
464	bus_generic_detach(dev);
465	if (viapm->smbus) {
466		device_delete_child(dev, viapm->smbus);
467	}
468
469	bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
470
471#ifdef notyet
472	bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
473#endif
474	mtx_destroy(&viapm->lock);
475
476	return 0;
477}
478
479static int
480viabb_callback(device_t dev, int index, caddr_t *data)
481{
482	return 0;
483}
484
485static void
486viabb_setscl(device_t dev, int ctrl)
487{
488	struct viapm_softc *viapm = device_get_softc(dev);
489	u_char val;
490
491	VIAPM_LOCK(viapm);
492	val = VIAPM_INB(GPIO_VAL);
493
494	if (ctrl)
495		val |= VIAPM_SCL;
496	else
497		val &= ~VIAPM_SCL;
498
499	VIAPM_OUTB(GPIO_VAL, val);
500	VIAPM_UNLOCK(viapm);
501
502	return;
503}
504
505static void
506viabb_setsda(device_t dev, int data)
507{
508	struct viapm_softc *viapm = device_get_softc(dev);
509	u_char val;
510
511	VIAPM_LOCK(viapm);
512	val = VIAPM_INB(GPIO_VAL);
513
514	if (data)
515		val |= VIAPM_SDA;
516	else
517		val &= ~VIAPM_SDA;
518
519	VIAPM_OUTB(GPIO_VAL, val);
520	VIAPM_UNLOCK(viapm);
521
522	return;
523}
524
525static int
526viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
527{
528	/* reset bus */
529	viabb_setsda(dev, 1);
530	viabb_setscl(dev, 1);
531
532	return (IIC_ENOADDR);
533}
534
535static int
536viabb_getscl(device_t dev)
537{
538	struct viapm_softc *viapm = device_get_softc(dev);
539	u_char val;
540
541	VIAPM_LOCK(viapm);
542	val = VIAPM_INB(EXTSMI_VAL);
543	VIAPM_UNLOCK(viapm);
544	return ((val & VIAPM_SCL) != 0);
545}
546
547static int
548viabb_getsda(device_t dev)
549{
550	struct viapm_softc *viapm = device_get_softc(dev);
551	u_char val;
552
553	VIAPM_LOCK(viapm);
554	val = VIAPM_INB(EXTSMI_VAL);
555	VIAPM_UNLOCK(viapm);
556	return ((val & VIAPM_SDA) != 0);
557}
558
559static int
560viapm_abort(struct viapm_softc *viapm)
561{
562	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
563	DELAY(10);
564
565	return (0);
566}
567
568static int
569viapm_clear(struct viapm_softc *viapm)
570{
571	VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
572		SMBHST_ERROR | SMBHST_INTR);
573	DELAY(10);
574
575	return (0);
576}
577
578static int
579viapm_busy(struct viapm_softc *viapm)
580{
581	u_char sts;
582
583	sts = VIAPM_INB(SMBHST);
584
585	VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
586
587	return (sts & SMBHST_BUSY);
588}
589
590/*
591 * Poll the SMBus controller
592 */
593static int
594viapm_wait(struct viapm_softc *viapm)
595{
596	int count = 10000;
597	u_char sts = 0;
598	int error;
599
600	VIAPM_LOCK_ASSERT(viapm);
601
602	/* wait for command to complete and SMBus controller is idle */
603	while(count--) {
604		DELAY(10);
605		sts = VIAPM_INB(SMBHST);
606
607		/* check if the controller is processing a command */
608		if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
609			break;
610	}
611
612	VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
613
614	error = SMB_ENOERR;
615
616	if (!count)
617		error |= SMB_ETIMEOUT;
618
619	if (sts & SMBHST_FAILED)
620		error |= SMB_EABORT;
621
622	if (sts & SMBHST_COLLID)
623		error |= SMB_ENOACK;
624
625	if (sts & SMBHST_ERROR)
626		error |= SMB_EBUSERR;
627
628	if (error != SMB_ENOERR)
629		viapm_abort(viapm);
630
631	viapm_clear(viapm);
632
633	return (error);
634}
635
636static int
637viasmb_callback(device_t dev, int index, caddr_t *data)
638{
639	int error = 0;
640
641	switch (index) {
642	case SMB_REQUEST_BUS:
643	case SMB_RELEASE_BUS:
644		/* ok, bus allocation accepted */
645		break;
646	default:
647		error = EINVAL;
648	}
649
650	return (error);
651}
652
653static int
654viasmb_quick(device_t dev, u_char slave, int how)
655{
656	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
657	int error;
658
659	VIAPM_LOCK(viapm);
660	viapm_clear(viapm);
661	if (viapm_busy(viapm)) {
662		VIAPM_UNLOCK(viapm);
663		return (SMB_EBUSY);
664	}
665
666	switch (how) {
667	case SMB_QWRITE:
668		VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
669		VIAPM_OUTB(SMBHADDR, slave & ~LSB);
670		break;
671	case SMB_QREAD:
672		VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
673		VIAPM_OUTB(SMBHADDR, slave | LSB);
674		break;
675	default:
676		panic("%s: unknown QUICK command (%x)!", __func__, how);
677	}
678
679	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
680
681	error = viapm_wait(viapm);
682	VIAPM_UNLOCK(viapm);
683
684	return (error);
685}
686
687static int
688viasmb_sendb(device_t dev, u_char slave, char byte)
689{
690	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
691	int error;
692
693	VIAPM_LOCK(viapm);
694	viapm_clear(viapm);
695	if (viapm_busy(viapm)) {
696		VIAPM_UNLOCK(viapm);
697		return (SMB_EBUSY);
698	}
699
700	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
701	VIAPM_OUTB(SMBHCMD, byte);
702
703	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
704
705	error = viapm_wait(viapm);
706
707	VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
708	VIAPM_UNLOCK(viapm);
709
710	return (error);
711}
712
713static int
714viasmb_recvb(device_t dev, u_char slave, char *byte)
715{
716	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
717	int error;
718
719	VIAPM_LOCK(viapm);
720	viapm_clear(viapm);
721	if (viapm_busy(viapm)) {
722		VIAPM_UNLOCK(viapm);
723		return (SMB_EBUSY);
724	}
725
726	VIAPM_OUTB(SMBHADDR, slave | LSB);
727
728	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
729
730	if ((error = viapm_wait(viapm)) == SMB_ENOERR)
731		*byte = VIAPM_INB(SMBHDATA0);
732
733	VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
734	VIAPM_UNLOCK(viapm);
735
736	return (error);
737}
738
739static int
740viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
741{
742	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
743	int error;
744
745	VIAPM_LOCK(viapm);
746	viapm_clear(viapm);
747	if (viapm_busy(viapm)) {
748		VIAPM_UNLOCK(viapm);
749		return (SMB_EBUSY);
750	}
751
752	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
753	VIAPM_OUTB(SMBHCMD, cmd);
754	VIAPM_OUTB(SMBHDATA0, byte);
755
756	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
757
758	error = viapm_wait(viapm);
759
760	VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
761	VIAPM_UNLOCK(viapm);
762
763	return (error);
764}
765
766static int
767viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
768{
769	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
770	int error;
771
772	VIAPM_LOCK(viapm);
773	viapm_clear(viapm);
774	if (viapm_busy(viapm)) {
775		VIAPM_UNLOCK(viapm);
776		return (SMB_EBUSY);
777	}
778
779	VIAPM_OUTB(SMBHADDR, slave | LSB);
780	VIAPM_OUTB(SMBHCMD, cmd);
781
782	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
783
784	if ((error = viapm_wait(viapm)) == SMB_ENOERR)
785		*byte = VIAPM_INB(SMBHDATA0);
786
787	VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
788	VIAPM_UNLOCK(viapm);
789
790	return (error);
791}
792
793static int
794viasmb_writew(device_t dev, u_char slave, char cmd, short word)
795{
796	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
797	int error;
798
799	VIAPM_LOCK(viapm);
800	viapm_clear(viapm);
801	if (viapm_busy(viapm)) {
802		VIAPM_UNLOCK(viapm);
803		return (SMB_EBUSY);
804	}
805
806	VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
807	VIAPM_OUTB(SMBHCMD, cmd);
808	VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
809	VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
810
811	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
812
813	error = viapm_wait(viapm);
814
815	VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
816	VIAPM_UNLOCK(viapm);
817
818	return (error);
819}
820
821static int
822viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
823{
824	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
825	int error;
826	u_char high, low;
827
828	VIAPM_LOCK(viapm);
829	viapm_clear(viapm);
830	if (viapm_busy(viapm)) {
831		VIAPM_UNLOCK(viapm);
832		return (SMB_EBUSY);
833	}
834
835	VIAPM_OUTB(SMBHADDR, slave | LSB);
836	VIAPM_OUTB(SMBHCMD, cmd);
837
838	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
839
840	if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
841		low = VIAPM_INB(SMBHDATA0);
842		high = VIAPM_INB(SMBHDATA1);
843
844		*word = ((high & 0xff) << 8) | (low & 0xff);
845	}
846
847	VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
848	VIAPM_UNLOCK(viapm);
849
850	return (error);
851}
852
853static int
854viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
855{
856	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
857	u_char i;
858	int error;
859
860	if (count < 1 || count > 32)
861		return (SMB_EINVAL);
862
863	VIAPM_LOCK(viapm);
864	viapm_clear(viapm);
865	if (viapm_busy(viapm)) {
866		VIAPM_UNLOCK(viapm);
867		return (SMB_EBUSY);
868	}
869
870	VIAPM_OUTB(SMBHADDR, slave & ~LSB);
871	VIAPM_OUTB(SMBHCMD, cmd);
872	VIAPM_OUTB(SMBHDATA0, count);
873	i = VIAPM_INB(SMBHCTRL);
874
875	/* fill the 32-byte internal buffer */
876	for (i = 0; i < count; i++) {
877		VIAPM_OUTB(SMBHBLOCK, buf[i]);
878		DELAY(2);
879	}
880	VIAPM_OUTB(SMBHCMD, cmd);
881	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
882
883	error = viapm_wait(viapm);
884
885	VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
886	VIAPM_UNLOCK(viapm);
887
888	return (error);
889
890}
891
892static int
893viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
894{
895	struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
896	u_char data, len, i;
897	int error;
898
899	if (*count < 1 || *count > 32)
900		return (SMB_EINVAL);
901
902	VIAPM_LOCK(viapm);
903	viapm_clear(viapm);
904	if (viapm_busy(viapm)) {
905		VIAPM_UNLOCK(viapm);
906		return (SMB_EBUSY);
907	}
908
909	VIAPM_OUTB(SMBHADDR, slave | LSB);
910	VIAPM_OUTB(SMBHCMD, cmd);
911	VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
912
913	if ((error = viapm_wait(viapm)) != SMB_ENOERR)
914		goto error;
915
916	len = VIAPM_INB(SMBHDATA0);
917	i = VIAPM_INB(SMBHCTRL); 		/* reset counter */
918
919	/* read the 32-byte internal buffer */
920	for (i = 0; i < len; i++) {
921		data = VIAPM_INB(SMBHBLOCK);
922		if (i < *count)
923			buf[i] = data;
924		DELAY(2);
925	}
926	*count = len;
927
928error:
929	VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
930	VIAPM_UNLOCK(viapm);
931
932	return (error);
933}
934
935static device_method_t viapm_methods[] = {
936	/* device interface */
937	DEVMETHOD(device_probe,		viapm_586b_probe),
938	DEVMETHOD(device_attach,	viapm_586b_attach),
939	DEVMETHOD(device_detach,	viapm_586b_detach),
940
941	/* iicbb interface */
942	DEVMETHOD(iicbb_callback,	viabb_callback),
943	DEVMETHOD(iicbb_setscl,		viabb_setscl),
944	DEVMETHOD(iicbb_setsda,		viabb_setsda),
945	DEVMETHOD(iicbb_getscl,		viabb_getscl),
946	DEVMETHOD(iicbb_getsda,		viabb_getsda),
947	DEVMETHOD(iicbb_reset,		viabb_reset),
948
949	/* Bus interface */
950	DEVMETHOD(bus_print_child,	bus_generic_print_child),
951	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
952	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
953	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
954	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
955	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
956	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
957
958	{ 0, 0 }
959};
960
961static driver_t viapm_driver = {
962	"viapm",
963	viapm_methods,
964	sizeof(struct viapm_softc),
965};
966
967static device_method_t viapropm_methods[] = {
968	/* device interface */
969	DEVMETHOD(device_probe,		viapm_pro_probe),
970	DEVMETHOD(device_attach,	viapm_pro_attach),
971	DEVMETHOD(device_detach,	viapm_pro_detach),
972
973	/* smbus interface */
974	DEVMETHOD(smbus_callback,	viasmb_callback),
975	DEVMETHOD(smbus_quick,		viasmb_quick),
976	DEVMETHOD(smbus_sendb,		viasmb_sendb),
977	DEVMETHOD(smbus_recvb,		viasmb_recvb),
978	DEVMETHOD(smbus_writeb,		viasmb_writeb),
979	DEVMETHOD(smbus_readb,		viasmb_readb),
980	DEVMETHOD(smbus_writew,		viasmb_writew),
981	DEVMETHOD(smbus_readw,		viasmb_readw),
982	DEVMETHOD(smbus_bwrite,		viasmb_bwrite),
983	DEVMETHOD(smbus_bread,		viasmb_bread),
984
985	/* Bus interface */
986	DEVMETHOD(bus_print_child,	bus_generic_print_child),
987	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
988	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
989	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
990	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
991	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
992	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
993
994	{ 0, 0 }
995};
996
997static driver_t viapropm_driver = {
998	"viapropm",
999	viapropm_methods,
1000	sizeof(struct viapm_softc),
1001};
1002
1003DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
1004DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
1005DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0);
1006
1007MODULE_DEPEND(viapm, pci, 1, 1, 1);
1008MODULE_DEPEND(viapropm, pci, 1, 1, 1);
1009MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
1010MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
1011MODULE_VERSION(viapm, 1);
1012
1013#ifdef DEV_ISA
1014DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0);
1015DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0);
1016MODULE_DEPEND(viapm, isa, 1, 1, 1);
1017MODULE_DEPEND(viapropm, isa, 1, 1, 1);
1018#endif
1019