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