viapm.c revision 116192
155682Smarkm/*- 2233294Sstas * Copyright (c) 2001 Alcove - Nicolas Souchu 355682Smarkm * All rights reserved. 455682Smarkm * 5233294Sstas * Redistribution and use in source and binary forms, with or without 655682Smarkm * modification, are permitted provided that the following conditions 755682Smarkm * are met: 855682Smarkm * 1. Redistributions of source code must retain the above copyright 9233294Sstas * notice, this list of conditions and the following disclaimer. 1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer in the 12233294Sstas * documentation and/or other materials provided with the distribution. 1355682Smarkm * 1455682Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1555682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1755682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1855682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1955682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2155682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2255682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2355682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2455682Smarkm * SUCH DAMAGE. 2555682Smarkm */ 2655682Smarkm 2755682Smarkm#include <sys/cdefs.h> 2855682Smarkm__FBSDID("$FreeBSD: head/sys/pci/viapm.c 116192 2003-06-11 06:34:30Z obrien $"); 2955682Smarkm 3055682Smarkm#include <sys/param.h> 3155682Smarkm#include <sys/kernel.h> 3255682Smarkm#include <sys/systm.h> 3355682Smarkm#include <sys/module.h> 3455682Smarkm#include <sys/bus.h> 3555682Smarkm#include <sys/uio.h> 3655682Smarkm 3755682Smarkm#include <machine/bus_pio.h> 3855682Smarkm#include <machine/bus_memio.h> 3955682Smarkm#include <machine/bus.h> 40178825Sdfr#include <machine/clock.h> /* for DELAY */ 41178825Sdfr#include <machine/resource.h> 4255682Smarkm#include <sys/rman.h> 4355682Smarkm 4455682Smarkm#include <pci/pcivar.h> 4555682Smarkm#include <pci/pcireg.h> 4655682Smarkm 4755682Smarkm#include <dev/iicbus/iiconf.h> 4855682Smarkm#include <dev/iicbus/iicbus.h> 4955682Smarkm 5055682Smarkm#include <dev/smbus/smbconf.h> 5155682Smarkm#include <dev/smbus/smbus.h> 5255682Smarkm 5355682Smarkm#include "iicbb_if.h" 5455682Smarkm#include "smbus_if.h" 5590926Snectar 56178825Sdfr#define VIAPM_DEBUG(x) if (viapm_debug) (x) 57178825Sdfr 58178825Sdfr#ifdef DEBUG 59178825Sdfrstatic int viapm_debug = 1; 60178825Sdfr#else 61178825Sdfrstatic int viapm_debug = 0; 62178825Sdfr#endif 6355682Smarkm 6455682Smarkm#define VIA_586B_PMU_ID 0x30401106 6590926Snectar#define VIA_596A_PMU_ID 0x30501106 6655682Smarkm#define VIA_596B_PMU_ID 0x30511106 6790926Snectar#define VIA_686A_PMU_ID 0x30571106 6855682Smarkm#define VIA_8233_PMU_ID 0x30741106 69178825Sdfr 7055682Smarkm#define VIAPM_INB(port) \ 7155682Smarkm ((u_char)bus_space_read_1(viapm->st, viapm->sh, port)) 7290926Snectar#define VIAPM_OUTB(port,val) \ 7390926Snectar (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)(val))) 7455682Smarkm 75178825Sdfr#define VIAPM_TYP_UNKNOWN 0 76178825Sdfr#define VIAPM_TYP_586B_3040E 1 7755682Smarkm#define VIAPM_TYP_586B_3040F 2 7855682Smarkm#define VIAPM_TYP_596B 3 7955682Smarkm#define VIAPM_TYP_686A 4 8055682Smarkm#define VIAPM_TYP_8233 5 8190926Snectar 8255682Smarkmstruct viapm_softc { 83178825Sdfr int type; 84178825Sdfr u_int32_t base; 85178825Sdfr bus_space_tag_t st; 8655682Smarkm bus_space_handle_t sh; 87178825Sdfr int iorid; 88178825Sdfr int irqrid; 8955682Smarkm struct resource *iores; 90178825Sdfr struct resource *irqres; 91178825Sdfr void *irqih; 92178825Sdfr 93178825Sdfr device_t iicbb; 94178825Sdfr device_t smbus; 95178825Sdfr}; 96178825Sdfr 97178825Sdfrstatic devclass_t viapm_devclass; 98178825Sdfrstatic devclass_t viapropm_devclass; 99178825Sdfr 100178825Sdfr/* 10155682Smarkm * VT82C586B definitions 10255682Smarkm */ 10390926Snectar 10490926Snectar#define VIAPM_586B_REVID 0x08 10555682Smarkm 106178825Sdfr#define VIAPM_586B_3040E_BASE 0x20 107178825Sdfr#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ 10855682Smarkm 10955682Smarkm#define VIAPM_586B_3040F_BASE 0x48 11090926Snectar#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ 11190926Snectar 11290926Snectar#define VIAPM_586B_OEM_REV_E 0x00 11390926Snectar#define VIAPM_586B_OEM_REV_F 0x01 11490926Snectar#define VIAPM_586B_PROD_REV_A 0x10 11590926Snectar 11690926Snectar#define VIAPM_586B_BA_MASK 0x0000ff00 11790926Snectar 11890926Snectar#define GPIO_DIR 0x40 11990926Snectar#define GPIO_VAL 0x42 12090926Snectar#define EXTSMI_VAL 0x44 121178825Sdfr 122233294Sstas#define VIAPM_SCL 0x02 /* GPIO1_VAL */ 123178825Sdfr#define VIAPM_SDA 0x04 /* GPIO2_VAL */ 124178825Sdfr 125233294Sstas/* 126178825Sdfr * VIAPRO common definitions 127178825Sdfr */ 128178825Sdfr 129178825Sdfr#define VIAPM_PRO_BA_MASK 0x0000fff0 130178825Sdfr#define VIAPM_PRO_SMBCTRL 0xd2 131178825Sdfr#define VIAPM_PRO_REVID 0xd6 132178825Sdfr 133178825Sdfr/* 134178825Sdfr * VT82C686A definitions 13590926Snectar */ 13690926Snectar 137178825Sdfr#define VIAPM_PRO_BASE 0x90 13890926Snectar 13990926Snectar#define SMBHST 0x0 14090926Snectar#define SMBHSL 0x1 14190926Snectar#define SMBHCTRL 0x2 142102644Snectar#define SMBHCMD 0x3 14355682Smarkm#define SMBHADDR 0x4 14455682Smarkm#define SMBHDATA0 0x5 145178825Sdfr#define SMBHDATA1 0x6 146178825Sdfr#define SMBHBLOCK 0x7 147178825Sdfr 148178825Sdfr#define SMBSST 0x1 149178825Sdfr#define SMBSCTRL 0x8 15055682Smarkm#define SMBSSDWCMD 0x9 151178825Sdfr#define SMBSEVENT 0xa 152178825Sdfr#define SMBSDATA 0xc 153178825Sdfr 154178825Sdfr#define SMBHST_RESERVED 0xef /* reserved bits */ 155178825Sdfr#define SMBHST_FAILED 0x10 /* failed bus transaction */ 156178825Sdfr#define SMBHST_COLLID 0x08 /* bus collision */ 157178825Sdfr#define SMBHST_ERROR 0x04 /* device error */ 158178825Sdfr#define SMBHST_INTR 0x02 /* command completed */ 159178825Sdfr#define SMBHST_BUSY 0x01 /* host busy */ 160178825Sdfr 161178825Sdfr#define SMBHCTRL_START 0x40 /* start command */ 162178825Sdfr#define SMBHCTRL_PROTO 0x1c /* command protocol mask */ 163178825Sdfr#define SMBHCTRL_QUICK 0x00 164178825Sdfr#define SMBHCTRL_SENDRECV 0x04 165178825Sdfr#define SMBHCTRL_BYTE 0x08 166178825Sdfr#define SMBHCTRL_WORD 0x0c 167178825Sdfr#define SMBHCTRL_BLOCK 0x14 168178825Sdfr#define SMBHCTRL_KILL 0x02 /* stop the current transaction */ 169178825Sdfr#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ 170178825Sdfr 171178825Sdfr#define SMBSCTRL_ENABLE 0x01 /* enable slave */ 17255682Smarkm 173178825Sdfr 174178825Sdfr/* 175178825Sdfr * VIA8233 definitions 176178825Sdfr */ 177178825Sdfr 178178825Sdfr#define VIAPM_8233_BASE 0xD0 179178825Sdfr 180178825Sdfrstatic int 181178825Sdfrviapm_586b_probe(device_t dev) 182178825Sdfr{ 183233294Sstas struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 184178825Sdfr u_int32_t l; 185233294Sstas u_int16_t s; 186178825Sdfr u_int8_t c; 187178825Sdfr 188178825Sdfr switch (pci_get_devid(dev)) { 189178825Sdfr case VIA_586B_PMU_ID: 190178825Sdfr 191178825Sdfr bzero(viapm, sizeof(struct viapm_softc)); 192178825Sdfr 193233294Sstas l = pci_read_config(dev, VIAPM_586B_REVID, 1); 194178825Sdfr switch (l) { 195178825Sdfr case VIAPM_586B_OEM_REV_E: 19655682Smarkm viapm->type = VIAPM_TYP_586B_3040E; 197178825Sdfr viapm->iorid = VIAPM_586B_3040E_BASE; 198178825Sdfr 199178825Sdfr /* Activate IO block access */ 200178825Sdfr s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); 201178825Sdfr pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); 202178825Sdfr break; 203178825Sdfr 204178825Sdfr case VIAPM_586B_OEM_REV_F: 205178825Sdfr case VIAPM_586B_PROD_REV_A: 206178825Sdfr default: 207178825Sdfr viapm->type = VIAPM_TYP_586B_3040F; 208178825Sdfr viapm->iorid = VIAPM_586B_3040F_BASE; 209178825Sdfr 210178825Sdfr /* Activate IO block access */ 211233294Sstas c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); 212178825Sdfr pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); 213178825Sdfr break; 214233294Sstas } 215178825Sdfr 216178825Sdfr viapm->base = pci_read_config(dev, viapm->iorid, 4) & 217233294Sstas VIAPM_586B_BA_MASK; 218178825Sdfr 219178825Sdfr /* 22055682Smarkm * We have to set the I/O resources by hand because it is 221178825Sdfr * described outside the viapmope of the traditional maps 222178825Sdfr */ 223178825Sdfr if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 224178825Sdfr viapm->base, 256)) { 225178825Sdfr device_printf(dev, "could not set bus resource\n"); 226178825Sdfr return ENXIO; 227178825Sdfr } 228178825Sdfr device_set_desc(dev, "VIA VT82C586B Power Management Unit"); 229178825Sdfr return 0; 230178825Sdfr 231178825Sdfr default: 232178825Sdfr break; 233178825Sdfr } 234178825Sdfr 235178825Sdfr return ENXIO; 236178825Sdfr} 237178825Sdfr 238178825Sdfr 239233294Sstasstatic int 240178825Sdfrviapm_pro_probe(device_t dev) 241178825Sdfr{ 242178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 243178825Sdfr#ifdef VIAPM_BASE_ADDR 244233294Sstas u_int32_t l; 245178825Sdfr#endif 246178825Sdfr u_int32_t base_cfgreg; 247178825Sdfr char *desc; 248178825Sdfr 24955682Smarkm switch (pci_get_devid(dev)) { 25055682Smarkm case VIA_596A_PMU_ID: 25190926Snectar desc = "VIA VT82C596A Power Management Unit"; 25290926Snectar viapm->type = VIAPM_TYP_596B; 25390926Snectar base_cfgreg = VIAPM_PRO_BASE; 25490926Snectar goto viapro; 255233294Sstas 25690926Snectar case VIA_596B_PMU_ID: 25790926Snectar desc = "VIA VT82C596B Power Management Unit"; 25855682Smarkm viapm->type = VIAPM_TYP_596B; 25955682Smarkm base_cfgreg = VIAPM_PRO_BASE; 26055682Smarkm goto viapro; 26155682Smarkm 262233294Sstas case VIA_686A_PMU_ID: 26390926Snectar desc = "VIA VT82C686A Power Management Unit"; 26472445Sassar viapm->type = VIAPM_TYP_686A; 26590926Snectar base_cfgreg = VIAPM_PRO_BASE; 26672445Sassar goto viapro; 26772445Sassar 26872445Sassar case VIA_8233_PMU_ID: 26972445Sassar desc = "VIA VT8233 Power Management Unit"; 27090926Snectar viapm->type = VIAPM_TYP_UNKNOWN; 27172445Sassar base_cfgreg = VIAPM_8233_BASE; 272178825Sdfr goto viapro; 273178825Sdfr 27472445Sassar viapro: 27590926Snectar 27690926Snectar#ifdef VIAPM_BASE_ADDR 27790926Snectar /* force VIAPM I/O base address */ 27890926Snectar 27972445Sassar /* enable the SMBus controller function */ 28090926Snectar l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 28190926Snectar pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 28290926Snectar 28390926Snectar /* write the base address */ 28472445Sassar pci_write_config(dev, base_cfgreg, 28572445Sassar VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); 286178825Sdfr#endif 28790926Snectar 28855682Smarkm viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; 28955682Smarkm 29055682Smarkm /* 29190926Snectar * We have to set the I/O resources by hand because it is 29255682Smarkm * described outside the viapmope of the traditional maps 29355682Smarkm */ 29455682Smarkm viapm->iorid = base_cfgreg; 29555682Smarkm if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 296178825Sdfr viapm->base, 16)) { 29790926Snectar device_printf(dev, "could not set bus resource 0x%x\n", 298178825Sdfr viapm->base); 299178825Sdfr return ENXIO; 300178825Sdfr } 301178825Sdfr 302178825Sdfr if (1 || bootverbose) { 30390926Snectar device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); 304178825Sdfr } 305178825Sdfr 306178825Sdfr device_set_desc(dev, desc); 307178825Sdfr return 0; 308178825Sdfr 30955682Smarkm default: 31055682Smarkm break; 31155682Smarkm } 31255682Smarkm 31355682Smarkm return ENXIO; 31455682Smarkm} 31590926Snectar 31690926Snectarstatic int 31755682Smarkmviapm_pro_attach(device_t dev) 31890926Snectar{ 31990926Snectar struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 32090926Snectar u_int32_t l; 32190926Snectar 322178825Sdfr if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, 323178825Sdfr &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) { 32490926Snectar device_printf(dev, "could not allocate bus space\n"); 32590926Snectar goto error; 32690926Snectar } 32790926Snectar viapm->st = rman_get_bustag(viapm->iores); 32890926Snectar viapm->sh = rman_get_bushandle(viapm->iores); 32990926Snectar 33090926Snectar#if notyet 33190926Snectar /* force irq 9 */ 33255682Smarkm l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 33355682Smarkm pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); 334178825Sdfr 335178825Sdfr viapm->irqrid = 0; 33655682Smarkm if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, 33757422Smarkm &viapm->irqrid, 9, 9, 1, 33855682Smarkm RF_SHAREABLE | RF_ACTIVE))) { 33955682Smarkm device_printf(dev, "could not allocate irq\n"); 34055682Smarkm goto error; 34190926Snectar } 34290926Snectar 34355682Smarkm if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC, 34490926Snectar (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { 34555682Smarkm device_printf(dev, "could not setup irq\n"); 34655682Smarkm goto error; 347233294Sstas } 34890926Snectar#endif 34955682Smarkm 350178825Sdfr if (1 | bootverbose) { 351178825Sdfr l = pci_read_config(dev, VIAPM_PRO_REVID, 1); 352233294Sstas device_printf(dev, "SMBus revision code 0x%x\n", l); 35355682Smarkm } 354178825Sdfr 355178825Sdfr viapm->smbus = device_add_child(dev, "smbus", -1); 356178825Sdfr 357178825Sdfr /* probe and attach the smbus */ 358178825Sdfr bus_generic_attach(dev); 359178825Sdfr 360178825Sdfr /* disable slave function */ 361178825Sdfr VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); 362178825Sdfr 36355682Smarkm /* enable the SMBus controller function */ 364178825Sdfr l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 365178825Sdfr pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 366178825Sdfr 367178825Sdfr#if notyet 368178825Sdfr /* enable interrupts */ 369178825Sdfr VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); 370178825Sdfr#endif 371178825Sdfr 372178825Sdfr return 0; 373178825Sdfr 374178825Sdfrerror: 375178825Sdfr if (viapm->iores) 376178825Sdfr bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 377178825Sdfr#if notyet 378178825Sdfr if (viapm->irqres) 379178825Sdfr bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 380178825Sdfr#endif 381233294Sstas 382178825Sdfr return ENXIO; 383178825Sdfr} 38455682Smarkm 385178825Sdfrstatic int 386178825Sdfrviapm_586b_attach(device_t dev) 38755682Smarkm{ 388178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 389178825Sdfr 390178825Sdfr if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, 391178825Sdfr &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) { 392178825Sdfr device_printf(dev, "could not allocate bus resource\n"); 393178825Sdfr return ENXIO; 394178825Sdfr } 395178825Sdfr viapm->st = rman_get_bustag(viapm->iores); 396178825Sdfr viapm->sh = rman_get_bushandle(viapm->iores); 397178825Sdfr 39855682Smarkm VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); 399178825Sdfr 400178825Sdfr /* add generic bit-banging code */ 401178825Sdfr if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) 402178825Sdfr goto error; 403178825Sdfr 404178825Sdfr bus_generic_attach(dev); 405178825Sdfr 406178825Sdfr return 0; 407178825Sdfr 408178825Sdfrerror: 409178825Sdfr if (viapm->iores) 410178825Sdfr bus_release_resource(dev, SYS_RES_IOPORT, 411178825Sdfr viapm->iorid, viapm->iores); 412178825Sdfr return ENXIO; 41355682Smarkm} 414178825Sdfr 41555682Smarkmstatic int 416178825Sdfrviapm_586b_detach(device_t dev) 417178825Sdfr{ 418178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 419178825Sdfr int error; 420178825Sdfr 421178825Sdfr bus_generic_detach(dev); 422178825Sdfr if (viapm->iicbb) { 423178825Sdfr device_delete_child(dev, viapm->iicbb); 424178825Sdfr } 425178825Sdfr 426178825Sdfr if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT, 427178825Sdfr viapm->iorid, viapm->iores))) 428178825Sdfr return (error); 429178825Sdfr 43055682Smarkm return 0; 431178825Sdfr} 432178825Sdfr 43355682Smarkmstatic int 434178825Sdfrviapm_pro_detach(device_t dev) 435178825Sdfr{ 436178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 437178825Sdfr int error; 438178825Sdfr 439178825Sdfr bus_generic_detach(dev); 440178825Sdfr if (viapm->smbus) { 441178825Sdfr device_delete_child(dev, viapm->smbus); 442178825Sdfr } 443233294Sstas 444178825Sdfr if ((error = bus_release_resource(dev, SYS_RES_IOPORT, 445178825Sdfr viapm->iorid, viapm->iores))) 446178825Sdfr return (error); 447178825Sdfr 448178825Sdfr#if notyet 449178825Sdfr if ((error = bus_release_resource(dev, SYS_RES_IRQ, 450178825Sdfr viapm->irqrid, viapm->irqres)) 45155682Smarkm return (error); 452178825Sdfr#endif 45355682Smarkm 454178825Sdfr return 0; 455178825Sdfr} 456178825Sdfr 457178825Sdfrstatic int 458178825Sdfrviabb_callback(device_t dev, int index, caddr_t *data) 45955682Smarkm{ 460178825Sdfr return 0; 461178825Sdfr} 462178825Sdfr 463178825Sdfrstatic void 464178825Sdfrviabb_setscl(device_t dev, int ctrl) 465178825Sdfr{ 46655682Smarkm struct viapm_softc *viapm = device_get_softc(dev); 467178825Sdfr u_char val; 46855682Smarkm 469178825Sdfr val = VIAPM_INB(GPIO_VAL); 470178825Sdfr 471178825Sdfr if (ctrl) 472178825Sdfr val |= VIAPM_SCL; 473178825Sdfr else 474178825Sdfr val &= ~VIAPM_SCL; 47555682Smarkm 476178825Sdfr VIAPM_OUTB(GPIO_VAL, val); 47755682Smarkm 478178825Sdfr return; 479178825Sdfr} 480178825Sdfr 481178825Sdfrstatic void 482178825Sdfrviabb_setsda(device_t dev, int data) 483178825Sdfr{ 48455682Smarkm struct viapm_softc *viapm = device_get_softc(dev); 485178825Sdfr u_char val; 48655682Smarkm 487178825Sdfr val = VIAPM_INB(GPIO_VAL); 488178825Sdfr 489178825Sdfr if (data) 490178825Sdfr val |= VIAPM_SDA; 491178825Sdfr else 492178825Sdfr val &= ~VIAPM_SDA; 49355682Smarkm 494178825Sdfr VIAPM_OUTB(GPIO_VAL, val); 49555682Smarkm 496178825Sdfr return; 497178825Sdfr} 498178825Sdfr 499178825Sdfrstatic int 500178825Sdfrviabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 501233294Sstas{ 502178825Sdfr /* reset bus */ 503178825Sdfr viabb_setsda(dev, 1); 504178825Sdfr viabb_setscl(dev, 1); 505178825Sdfr 506178825Sdfr return (IIC_ENOADDR); 507178825Sdfr} 508178825Sdfr 509178825Sdfrstatic int 510178825Sdfrviabb_getscl(device_t dev) 511178825Sdfr{ 512178825Sdfr struct viapm_softc *viapm = device_get_softc(dev); 513178825Sdfr 514178825Sdfr return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0); 515178825Sdfr} 516178825Sdfr 517178825Sdfrstatic int 518178825Sdfrviabb_getsda(device_t dev) 519178825Sdfr{ 520178825Sdfr struct viapm_softc *viapm = device_get_softc(dev); 521178825Sdfr 522178825Sdfr return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0); 523178825Sdfr} 524178825Sdfr 525178825Sdfrstatic int 526178825Sdfrviapm_abort(struct viapm_softc *viapm) 527178825Sdfr{ 528178825Sdfr VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 52990926Snectar DELAY(10); 530178825Sdfr 53155682Smarkm return (0); 53255682Smarkm} 53390926Snectar 534233294Sstasstatic int 535233294Sstasviapm_clear(struct viapm_softc *viapm) 53655682Smarkm{ 537178825Sdfr VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | 538178825Sdfr SMBHST_ERROR | SMBHST_INTR); 53955682Smarkm DELAY(10); 540178825Sdfr 541178825Sdfr return (0); 542178825Sdfr} 54355682Smarkm 54455682Smarkmstatic int 545178825Sdfrviapm_busy(struct viapm_softc *viapm) 546178825Sdfr{ 547178825Sdfr u_char sts; 54855682Smarkm 549178825Sdfr sts = VIAPM_INB(SMBHST); 550178825Sdfr 551178825Sdfr VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); 55255682Smarkm 553178825Sdfr return (sts & SMBHST_BUSY); 554178825Sdfr} 555178825Sdfr 556178825Sdfr/* 557178825Sdfr * Poll the SMBus controller 558178825Sdfr */ 559178825Sdfrstatic int 56055682Smarkmviapm_wait(struct viapm_softc *viapm) 56155682Smarkm{ 562178825Sdfr int count = 10000; 56355682Smarkm u_char sts = 0; 56455682Smarkm int error; 56555682Smarkm 56690926Snectar /* wait for command to complete and SMBus controller is idle */ 567233294Sstas while(count--) { 568233294Sstas DELAY(10); 56955682Smarkm sts = VIAPM_INB(SMBHST); 570178825Sdfr 571178825Sdfr /* check if the controller is processing a command */ 57255682Smarkm if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) 573178825Sdfr break; 574178825Sdfr } 575178825Sdfr 57655682Smarkm VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); 57755682Smarkm 578178825Sdfr error = SMB_ENOERR; 579178825Sdfr 580178825Sdfr if (!count) 581178825Sdfr error |= SMB_ETIMEOUT; 582178825Sdfr 583178825Sdfr if (sts & SMBHST_FAILED) 58455682Smarkm error |= SMB_EABORT; 585178825Sdfr 586178825Sdfr if (sts & SMBHST_COLLID) 587178825Sdfr error |= SMB_ENOACK; 588178825Sdfr 589178825Sdfr if (sts & SMBHST_ERROR) 590178825Sdfr error |= SMB_EBUSERR; 591178825Sdfr 59255682Smarkm if (error != SMB_ENOERR) 59355682Smarkm viapm_abort(viapm); 594178825Sdfr 59555682Smarkm viapm_clear(viapm); 59655682Smarkm 59755682Smarkm return (error); 59890926Snectar} 599233294Sstas 600233294Sstasstatic int 60155682Smarkmviasmb_callback(device_t dev, int index, caddr_t *data) 602178825Sdfr{ 603178825Sdfr int error = 0; 60455682Smarkm 605178825Sdfr switch (index) { 606178825Sdfr case SMB_REQUEST_BUS: 60755682Smarkm case SMB_RELEASE_BUS: 60855682Smarkm /* ok, bus allocation accepted */ 609178825Sdfr break; 610178825Sdfr default: 611178825Sdfr error = EINVAL; 612178825Sdfr } 613178825Sdfr 614178825Sdfr return (error); 61555682Smarkm} 616178825Sdfr 617178825Sdfrstatic int 618178825Sdfrviasmb_quick(device_t dev, u_char slave, int how) 619178825Sdfr{ 620178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 62155682Smarkm int error; 62255682Smarkm 623178825Sdfr viapm_clear(viapm); 624178825Sdfr if (viapm_busy(viapm)) 62555682Smarkm return (EBUSY); 62655682Smarkm 62755682Smarkm switch (how) { 62890926Snectar case SMB_QWRITE: 629233294Sstas VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); 630233294Sstas VIAPM_OUTB(SMBHADDR, slave & ~LSB); 63155682Smarkm break; 632178825Sdfr case SMB_QREAD: 63355682Smarkm VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); 63455682Smarkm VIAPM_OUTB(SMBHADDR, slave | LSB); 63555682Smarkm break; 63655682Smarkm default: 63790926Snectar panic("%s: unknown QUICK command (%x)!", __FUNCTION__, 638233294Sstas how); 639233294Sstas } 64055682Smarkm 641233294Sstas VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); 642178825Sdfr 64355682Smarkm error = viapm_wait(viapm); 644178825Sdfr 645178825Sdfr return (error); 646178825Sdfr} 647178825Sdfr 648178825Sdfrstatic int 649178825Sdfrviasmb_sendb(device_t dev, u_char slave, char byte) 650178825Sdfr{ 651178825Sdfr struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 652178825Sdfr int error; 653178825Sdfr 65455682Smarkm viapm_clear(viapm); 655178825Sdfr if (viapm_busy(viapm)) 656178825Sdfr return (EBUSY); 657178825Sdfr 658178825Sdfr VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 659178825Sdfr VIAPM_OUTB(SMBHCMD, byte); 660178825Sdfr 661178825Sdfr VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 66255682Smarkm 663178825Sdfr error = viapm_wait(viapm); 664178825Sdfr 665178825Sdfr VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 666178825Sdfr 667178825Sdfr return (error); 668178825Sdfr} 669178825Sdfr 670178825Sdfrstatic int 671178825Sdfrviasmb_recvb(device_t dev, u_char slave, char *byte) 67255682Smarkm{ 67355682Smarkm struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 67455682Smarkm int error; 67555682Smarkm 67690926Snectar viapm_clear(viapm); 677233294Sstas if (viapm_busy(viapm)) 678233294Sstas return (EBUSY); 67955682Smarkm 680178825Sdfr VIAPM_OUTB(SMBHADDR, slave | LSB); 681178825Sdfr 682178825Sdfr VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 68355682Smarkm 684178825Sdfr if ((error = viapm_wait(viapm)) == SMB_ENOERR) 685178825Sdfr *byte = VIAPM_INB(SMBHDATA0); 686178825Sdfr 687178825Sdfr VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 688178825Sdfr 689178825Sdfr return (error); 69055682Smarkm} 691178825Sdfr 692178825Sdfrstatic int 693178825Sdfrviasmb_writeb(device_t dev, u_char slave, char cmd, char byte) 694178825Sdfr{ 69555682Smarkm struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 69655682Smarkm int error; 697 698 viapm_clear(viapm); 699 if (viapm_busy(viapm)) 700 return (EBUSY); 701 702 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 703 VIAPM_OUTB(SMBHCMD, cmd); 704 VIAPM_OUTB(SMBHDATA0, byte); 705 706 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 707 708 error = viapm_wait(viapm); 709 710 VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 711 712 return (error); 713} 714 715static int 716viasmb_readb(device_t dev, u_char slave, char cmd, char *byte) 717{ 718 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 719 int error; 720 721 viapm_clear(viapm); 722 if (viapm_busy(viapm)) 723 return (EBUSY); 724 725 VIAPM_OUTB(SMBHADDR, slave | LSB); 726 VIAPM_OUTB(SMBHCMD, cmd); 727 728 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 729 730 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 731 *byte = VIAPM_INB(SMBHDATA0); 732 733 VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 734 735 return (error); 736} 737 738static int 739viasmb_writew(device_t dev, u_char slave, char cmd, short word) 740{ 741 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 742 int error; 743 744 viapm_clear(viapm); 745 if (viapm_busy(viapm)) 746 return (EBUSY); 747 748 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 749 VIAPM_OUTB(SMBHCMD, cmd); 750 VIAPM_OUTB(SMBHDATA0, word & 0x00ff); 751 VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); 752 753 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 754 755 error = viapm_wait(viapm); 756 757 VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 758 759 return (error); 760} 761 762static int 763viasmb_readw(device_t dev, u_char slave, char cmd, short *word) 764{ 765 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 766 int error; 767 u_char high, low; 768 769 viapm_clear(viapm); 770 if (viapm_busy(viapm)) 771 return (EBUSY); 772 773 VIAPM_OUTB(SMBHADDR, slave | LSB); 774 VIAPM_OUTB(SMBHCMD, cmd); 775 776 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 777 778 if ((error = viapm_wait(viapm)) == SMB_ENOERR) { 779 low = VIAPM_INB(SMBHDATA0); 780 high = VIAPM_INB(SMBHDATA1); 781 782 *word = ((high & 0xff) << 8) | (low & 0xff); 783 } 784 785 VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 786 787 return (error); 788} 789 790static int 791viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 792{ 793 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 794 u_char remain, len, i; 795 int error = SMB_ENOERR; 796 797 viapm_clear(viapm); 798 if (viapm_busy(viapm)) 799 return (EBUSY); 800 801 remain = count; 802 while (remain) { 803 len = min(remain, 32); 804 805 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 806 VIAPM_OUTB(SMBHCMD, cmd); 807 VIAPM_OUTB(SMBHDATA0, len); 808 i = VIAPM_INB(SMBHCTRL); 809 810 /* fill the 32-byte internal buffer */ 811 for (i=0; i<len; i++) { 812 VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]); 813 DELAY(2); 814 } 815 VIAPM_OUTB(SMBHCMD, cmd); 816 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 817 818 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 819 goto error; 820 821 remain -= len; 822 } 823 824error: 825 VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 826 827 return (error); 828 829} 830 831static int 832viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 833{ 834 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 835 u_char remain, len, i; 836 int error = SMB_ENOERR; 837 838 viapm_clear(viapm); 839 if (viapm_busy(viapm)) 840 return (EBUSY); 841 842 remain = count; 843 while (remain) { 844 VIAPM_OUTB(SMBHADDR, slave | LSB); 845 VIAPM_OUTB(SMBHCMD, cmd); 846 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 847 848 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 849 goto error; 850 851 len = VIAPM_INB(SMBHDATA0); 852 i = VIAPM_INB(SMBHCTRL); /* reset counter */ 853 854 len = min(len, remain); 855 856 /* read the 32-byte internal buffer */ 857 for (i=0; i<len; i++) { 858 buf[count-remain+i] = VIAPM_INB(SMBHBLOCK); 859 DELAY(2); 860 } 861 862 remain -= len; 863 } 864error: 865 VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 866 867 return (error); 868} 869 870static device_method_t viapm_methods[] = { 871 /* device interface */ 872 DEVMETHOD(device_probe, viapm_586b_probe), 873 DEVMETHOD(device_attach, viapm_586b_attach), 874 DEVMETHOD(device_detach, viapm_586b_detach), 875 876 /* iicbb interface */ 877 DEVMETHOD(iicbb_callback, viabb_callback), 878 DEVMETHOD(iicbb_setscl, viabb_setscl), 879 DEVMETHOD(iicbb_setsda, viabb_setsda), 880 DEVMETHOD(iicbb_getscl, viabb_getscl), 881 DEVMETHOD(iicbb_getsda, viabb_getsda), 882 DEVMETHOD(iicbb_reset, viabb_reset), 883 884 { 0, 0 } 885}; 886 887static driver_t viapm_driver = { 888 "viapm", 889 viapm_methods, 890 sizeof(struct viapm_softc), 891}; 892 893static device_method_t viapropm_methods[] = { 894 /* device interface */ 895 DEVMETHOD(device_probe, viapm_pro_probe), 896 DEVMETHOD(device_attach, viapm_pro_attach), 897 DEVMETHOD(device_detach, viapm_pro_detach), 898 899 /* smbus interface */ 900 DEVMETHOD(smbus_callback, viasmb_callback), 901 DEVMETHOD(smbus_quick, viasmb_quick), 902 DEVMETHOD(smbus_sendb, viasmb_sendb), 903 DEVMETHOD(smbus_recvb, viasmb_recvb), 904 DEVMETHOD(smbus_writeb, viasmb_writeb), 905 DEVMETHOD(smbus_readb, viasmb_readb), 906 DEVMETHOD(smbus_writew, viasmb_writew), 907 DEVMETHOD(smbus_readw, viasmb_readw), 908 DEVMETHOD(smbus_bwrite, viasmb_bwrite), 909 DEVMETHOD(smbus_bread, viasmb_bread), 910 911 { 0, 0 } 912}; 913 914static driver_t viapropm_driver = { 915 "viapropm", 916 viapropm_methods, 917 sizeof(struct viapm_softc), 918}; 919 920DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 921DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 922 923MODULE_DEPEND(viapm, pci, 1, 1, 1); 924MODULE_DEPEND(viaprom, pci, 1, 1, 1); 925MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 926MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 927MODULE_VERSION(viapm, 1); 928