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