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 #include "opt_isa.h"
29
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/lock.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/systm.h>
37
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 #include <sys/rman.h>
41
42 #ifdef DEV_ISA
43 #include <isa/isavar.h>
44 #include <isa/isa_common.h>
45 #endif
46 #include <dev/pci/pcivar.h>
47 #include <dev/pci/pcireg.h>
48
49 #include <dev/iicbus/iiconf.h>
50
51 #include <dev/smbus/smbconf.h>
52
53 #include "iicbb_if.h"
54 #include "smbus_if.h"
55
56 #define VIAPM_DEBUG(x) if (viapm_debug) (x)
57
58 #ifdef DEBUG
59 static int viapm_debug = 1;
60 #else
61 static int viapm_debug = 0;
62 #endif
63
64 #define VIA_586B_PMU_ID 0x30401106
65 #define VIA_596A_PMU_ID 0x30501106
66 #define VIA_596B_PMU_ID 0x30511106
67 #define VIA_686A_PMU_ID 0x30571106
68 #define VIA_8233_PMU_ID 0x30741106
69 #define VIA_8233A_PMU_ID 0x31471106
70 #define VIA_8235_PMU_ID 0x31771106
71 #define VIA_8237_PMU_ID 0x32271106
72 #define VIA_CX700_PMU_ID 0x83241106
73
74 #define VIAPM_INB(port) \
75 ((u_char)bus_read_1(viapm->iores, port))
76 #define VIAPM_OUTB(port,val) \
77 (bus_write_1(viapm->iores, port, (u_char)(val)))
78
79 #define VIAPM_TYP_UNKNOWN 0
80 #define VIAPM_TYP_586B_3040E 1
81 #define VIAPM_TYP_586B_3040F 2
82 #define VIAPM_TYP_596B 3
83 #define VIAPM_TYP_686A 4
84 #define VIAPM_TYP_8233 5
85
86 #define VIAPM_LOCK(sc) mtx_lock(&(sc)->lock)
87 #define VIAPM_UNLOCK(sc) mtx_unlock(&(sc)->lock)
88 #define VIAPM_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED)
89
90 struct viapm_softc {
91 int type;
92 u_int32_t base;
93 int iorid;
94 int irqrid;
95 struct resource *iores;
96 struct resource *irqres;
97 void *irqih;
98 device_t iicbb;
99 device_t smbus;
100 struct mtx lock;
101 };
102
103 /*
104 * VT82C586B definitions
105 */
106
107 #define VIAPM_586B_REVID 0x08
108
109 #define VIAPM_586B_3040E_BASE 0x20
110 #define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */
111
112 #define VIAPM_586B_3040F_BASE 0x48
113 #define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */
114
115 #define VIAPM_586B_OEM_REV_E 0x00
116 #define VIAPM_586B_OEM_REV_F 0x01
117 #define VIAPM_586B_PROD_REV_A 0x10
118
119 #define VIAPM_586B_BA_MASK 0x0000ff00
120
121 #define GPIO_DIR 0x40
122 #define GPIO_VAL 0x42
123 #define EXTSMI_VAL 0x44
124
125 #define VIAPM_SCL 0x02 /* GPIO1_VAL */
126 #define VIAPM_SDA 0x04 /* GPIO2_VAL */
127
128 /*
129 * VIAPRO common definitions
130 */
131
132 #define VIAPM_PRO_BA_MASK 0x0000fff0
133 #define VIAPM_PRO_SMBCTRL 0xd2
134 #define VIAPM_PRO_REVID 0xd6
135
136 /*
137 * VT82C686A definitions
138 */
139
140 #define VIAPM_PRO_BASE 0x90
141
142 #define SMBHST 0x0
143 #define SMBHSL 0x1
144 #define SMBHCTRL 0x2
145 #define SMBHCMD 0x3
146 #define SMBHADDR 0x4
147 #define SMBHDATA0 0x5
148 #define SMBHDATA1 0x6
149 #define SMBHBLOCK 0x7
150
151 #define SMBSST 0x1
152 #define SMBSCTRL 0x8
153 #define SMBSSDWCMD 0x9
154 #define SMBSEVENT 0xa
155 #define SMBSDATA 0xc
156
157 #define SMBHST_RESERVED 0xef /* reserved bits */
158 #define SMBHST_FAILED 0x10 /* failed bus transaction */
159 #define SMBHST_COLLID 0x08 /* bus collision */
160 #define SMBHST_ERROR 0x04 /* device error */
161 #define SMBHST_INTR 0x02 /* command completed */
162 #define SMBHST_BUSY 0x01 /* host busy */
163
164 #define SMBHCTRL_START 0x40 /* start command */
165 #define SMBHCTRL_PROTO 0x1c /* command protocol mask */
166 #define SMBHCTRL_QUICK 0x00
167 #define SMBHCTRL_SENDRECV 0x04
168 #define SMBHCTRL_BYTE 0x08
169 #define SMBHCTRL_WORD 0x0c
170 #define SMBHCTRL_BLOCK 0x14
171 #define SMBHCTRL_KILL 0x02 /* stop the current transaction */
172 #define SMBHCTRL_ENABLE 0x01 /* enable interrupts */
173
174 #define SMBSCTRL_ENABLE 0x01 /* enable slave */
175
176 /*
177 * VIA8233 definitions
178 */
179
180 #define VIAPM_8233_BASE 0xD0
181
182 static int
viapm_586b_probe(device_t dev)183 viapm_586b_probe(device_t dev)
184 {
185 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
186 u_int32_t l;
187 u_int16_t s;
188 u_int8_t c;
189
190 switch (pci_get_devid(dev)) {
191 case VIA_586B_PMU_ID:
192
193 bzero(viapm, sizeof(struct viapm_softc));
194
195 l = pci_read_config(dev, VIAPM_586B_REVID, 1);
196 switch (l) {
197 case VIAPM_586B_OEM_REV_E:
198 viapm->type = VIAPM_TYP_586B_3040E;
199 viapm->iorid = VIAPM_586B_3040E_BASE;
200
201 /* Activate IO block access */
202 s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
203 pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
204 break;
205
206 case VIAPM_586B_OEM_REV_F:
207 case VIAPM_586B_PROD_REV_A:
208 default:
209 viapm->type = VIAPM_TYP_586B_3040F;
210 viapm->iorid = VIAPM_586B_3040F_BASE;
211
212 /* Activate IO block access */
213 c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
214 pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
215 break;
216 }
217
218 viapm->base = pci_read_config(dev, viapm->iorid, 4) &
219 VIAPM_586B_BA_MASK;
220
221 /*
222 * We have to set the I/O resources by hand because it is
223 * described outside the viapmope of the traditional maps
224 */
225 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
226 viapm->base, 256)) {
227 device_printf(dev, "could not set bus resource\n");
228 return ENXIO;
229 }
230 device_set_desc(dev, "VIA VT82C586B Power Management Unit");
231 return (BUS_PROBE_DEFAULT);
232
233 default:
234 break;
235 }
236
237 return ENXIO;
238 }
239
240 static int
viapm_pro_probe(device_t dev)241 viapm_pro_probe(device_t dev)
242 {
243 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
244 #ifdef VIAPM_BASE_ADDR
245 u_int32_t l;
246 #endif
247 u_int32_t base_cfgreg;
248 char *desc;
249
250 switch (pci_get_devid(dev)) {
251 case VIA_596A_PMU_ID:
252 desc = "VIA VT82C596A Power Management Unit";
253 viapm->type = VIAPM_TYP_596B;
254 base_cfgreg = VIAPM_PRO_BASE;
255 goto viapro;
256
257 case VIA_596B_PMU_ID:
258 desc = "VIA VT82C596B Power Management Unit";
259 viapm->type = VIAPM_TYP_596B;
260 base_cfgreg = VIAPM_PRO_BASE;
261 goto viapro;
262
263 case VIA_686A_PMU_ID:
264 desc = "VIA VT82C686A Power Management Unit";
265 viapm->type = VIAPM_TYP_686A;
266 base_cfgreg = VIAPM_PRO_BASE;
267 goto viapro;
268
269 case VIA_8233_PMU_ID:
270 case VIA_8233A_PMU_ID:
271 desc = "VIA VT8233 Power Management Unit";
272 viapm->type = VIAPM_TYP_UNKNOWN;
273 base_cfgreg = VIAPM_8233_BASE;
274 goto viapro;
275
276 case VIA_8235_PMU_ID:
277 desc = "VIA VT8235 Power Management Unit";
278 viapm->type = VIAPM_TYP_UNKNOWN;
279 base_cfgreg = VIAPM_8233_BASE;
280 goto viapro;
281
282 case VIA_8237_PMU_ID:
283 desc = "VIA VT8237 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
336 static int
viapm_pro_attach(device_t dev)337 viapm_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
399 error:
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
411 static int
viapm_586b_attach(device_t dev)412 viapm_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
433 error:
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
441 static int
viapm_586b_detach(device_t dev)442 viapm_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
459 static int
viapm_pro_detach(device_t dev)460 viapm_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
479 static int
viabb_callback(device_t dev,int index,caddr_t data)480 viabb_callback(device_t dev, int index, caddr_t data)
481 {
482 return 0;
483 }
484
485 static void
viabb_setscl(device_t dev,int ctrl)486 viabb_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
505 static void
viabb_setsda(device_t dev,int data)506 viabb_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
525 static int
viabb_reset(device_t dev,u_char speed,u_char addr,u_char * oldaddr)526 viabb_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
535 static int
viabb_getscl(device_t dev)536 viabb_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
547 static int
viabb_getsda(device_t dev)548 viabb_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
559 static int
viapm_abort(struct viapm_softc * viapm)560 viapm_abort(struct viapm_softc *viapm)
561 {
562 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
563 DELAY(10);
564
565 return (0);
566 }
567
568 static int
viapm_clear(struct viapm_softc * viapm)569 viapm_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
578 static int
viapm_busy(struct viapm_softc * viapm)579 viapm_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 */
593 static int
viapm_wait(struct viapm_softc * viapm)594 viapm_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
636 static int
viasmb_callback(device_t dev,int index,void * data)637 viasmb_callback(device_t dev, int index, void *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
653 static int
viasmb_quick(device_t dev,u_char slave,int how)654 viasmb_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
687 static int
viasmb_sendb(device_t dev,u_char slave,char byte)688 viasmb_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
713 static int
viasmb_recvb(device_t dev,u_char slave,char * byte)714 viasmb_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
739 static int
viasmb_writeb(device_t dev,u_char slave,char cmd,char byte)740 viasmb_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
766 static int
viasmb_readb(device_t dev,u_char slave,char cmd,char * byte)767 viasmb_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
793 static int
viasmb_writew(device_t dev,u_char slave,char cmd,short word)794 viasmb_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
821 static int
viasmb_readw(device_t dev,u_char slave,char cmd,short * word)822 viasmb_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
853 static int
viasmb_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)854 viasmb_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
892 static int
viasmb_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)893 viasmb_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
928 error:
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
935 static 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_alloc_resource, bus_generic_alloc_resource),
951 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
952 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
953 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
954 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
955 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
956
957 DEVMETHOD_END
958 };
959
960 static driver_t viapm_driver = {
961 "viapm",
962 viapm_methods,
963 sizeof(struct viapm_softc),
964 };
965
966 static device_method_t viapropm_methods[] = {
967 /* device interface */
968 DEVMETHOD(device_probe, viapm_pro_probe),
969 DEVMETHOD(device_attach, viapm_pro_attach),
970 DEVMETHOD(device_detach, viapm_pro_detach),
971
972 /* smbus interface */
973 DEVMETHOD(smbus_callback, viasmb_callback),
974 DEVMETHOD(smbus_quick, viasmb_quick),
975 DEVMETHOD(smbus_sendb, viasmb_sendb),
976 DEVMETHOD(smbus_recvb, viasmb_recvb),
977 DEVMETHOD(smbus_writeb, viasmb_writeb),
978 DEVMETHOD(smbus_readb, viasmb_readb),
979 DEVMETHOD(smbus_writew, viasmb_writew),
980 DEVMETHOD(smbus_readw, viasmb_readw),
981 DEVMETHOD(smbus_bwrite, viasmb_bwrite),
982 DEVMETHOD(smbus_bread, viasmb_bread),
983
984 /* Bus interface */
985 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
986 DEVMETHOD(bus_release_resource, bus_generic_release_resource),
987 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
988 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
989 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
990 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
991
992 DEVMETHOD_END
993 };
994
995 static driver_t viapropm_driver = {
996 "viapropm",
997 viapropm_methods,
998 sizeof(struct viapm_softc),
999 };
1000
1001 DRIVER_MODULE(viapm, pci, viapm_driver, 0, 0);
1002 DRIVER_MODULE(viapropm, pci, viapropm_driver, 0, 0);
1003 DRIVER_MODULE(iicbb, viapm, iicbb_driver, 0, 0);
1004 DRIVER_MODULE(smbus, viapropm, smbus_driver, 0, 0);
1005
1006 MODULE_DEPEND(viapm, pci, 1, 1, 1);
1007 MODULE_DEPEND(viapropm, pci, 1, 1, 1);
1008 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
1009 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
1010 MODULE_VERSION(viapm, 1);
1011
1012 #ifdef DEV_ISA
1013 DRIVER_MODULE(isa, viapm, isa_driver, 0, 0);
1014 DRIVER_MODULE(isa, viapropm, isa_driver, 0, 0);
1015 MODULE_DEPEND(viapm, isa, 1, 1, 1);
1016 MODULE_DEPEND(viapropm, isa, 1, 1, 1);
1017 #endif
1018