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