viapm.c revision 153084
1164032Srwatson/*- 2164032Srwatson * Copyright (c) 2001 Alcove - Nicolas Souchu 3164032Srwatson * All rights reserved. 4164032Srwatson * 5164032Srwatson * Redistribution and use in source and binary forms, with or without 6164032Srwatson * modification, are permitted provided that the following conditions 7164032Srwatson * are met: 8164032Srwatson * 1. Redistributions of source code must retain the above copyright 9164032Srwatson * notice, this list of conditions and the following disclaimer. 10164032Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11164032Srwatson * notice, this list of conditions and the following disclaimer in the 12164032Srwatson * documentation and/or other materials provided with the distribution. 13164032Srwatson * 14164032Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15164032Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16164032Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17164032Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18164032Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19164032Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20164032Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21164032Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22164032Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23164032Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24164032Srwatson * SUCH DAMAGE. 25164032Srwatson */ 26164032Srwatson 27164032Srwatson#include <sys/cdefs.h> 28164032Srwatson__FBSDID("$FreeBSD: head/sys/pci/viapm.c 153084 2005-12-04 10:06:06Z ru $"); 29164032Srwatson 30164032Srwatson#include "opt_isa.h" 31164032Srwatson 32164032Srwatson#include <sys/param.h> 33164032Srwatson#include <sys/kernel.h> 34164032Srwatson#include <sys/systm.h> 35164032Srwatson#include <sys/module.h> 36164032Srwatson#include <sys/bus.h> 37164032Srwatson#include <sys/uio.h> 38164032Srwatson 39164032Srwatson#include <machine/bus.h> 40164032Srwatson#include <machine/clock.h> /* for DELAY */ 41164032Srwatson#include <machine/resource.h> 42164032Srwatson#include <sys/rman.h> 43164032Srwatson 44164032Srwatson#ifdef DEV_ISA 45164032Srwatson#include <isa/isavar.h> 46164032Srwatson#include <isa/isa_common.h> 47164032Srwatson#endif 48164032Srwatson#include <dev/pci/pcivar.h> 49164032Srwatson#include <dev/pci/pcireg.h> 50164032Srwatson 51164032Srwatson#include <dev/iicbus/iiconf.h> 52164032Srwatson#include <dev/iicbus/iicbus.h> 53164032Srwatson 54164032Srwatson#include <dev/smbus/smbconf.h> 55164032Srwatson#include <dev/smbus/smbus.h> 56164032Srwatson 57164032Srwatson#include "iicbb_if.h" 58164032Srwatson#include "smbus_if.h" 59164032Srwatson 60164032Srwatson#define VIAPM_DEBUG(x) if (viapm_debug) (x) 61164032Srwatson 62164032Srwatson#ifdef DEBUG 63164032Srwatsonstatic int viapm_debug = 1; 64164032Srwatson#else 65164032Srwatsonstatic int viapm_debug = 0; 66164032Srwatson#endif 67164032Srwatson 68164032Srwatson#define VIA_586B_PMU_ID 0x30401106 69164032Srwatson#define VIA_596A_PMU_ID 0x30501106 70164032Srwatson#define VIA_596B_PMU_ID 0x30511106 71164032Srwatson#define VIA_686A_PMU_ID 0x30571106 72164032Srwatson#define VIA_8233_PMU_ID 0x30741106 73164032Srwatson#define VIA_8233A_PMU_ID 0x31471106 74164032Srwatson#define VIA_8235_PMU_ID 0x31771106 75164032Srwatson 76164032Srwatson#define VIAPM_INB(port) \ 77164032Srwatson ((u_char)bus_space_read_1(viapm->st, viapm->sh, port)) 78164032Srwatson#define VIAPM_OUTB(port,val) \ 79164032Srwatson (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)(val))) 80164032Srwatson 81164032Srwatson#define VIAPM_TYP_UNKNOWN 0 82164032Srwatson#define VIAPM_TYP_586B_3040E 1 83164032Srwatson#define VIAPM_TYP_586B_3040F 2 84164032Srwatson#define VIAPM_TYP_596B 3 85164032Srwatson#define VIAPM_TYP_686A 4 86164032Srwatson#define VIAPM_TYP_8233 5 87164032Srwatson 88164032Srwatsonstruct viapm_softc { 89164032Srwatson int type; 90164032Srwatson u_int32_t base; 91164032Srwatson bus_space_tag_t st; 92164032Srwatson bus_space_handle_t sh; 93164032Srwatson int iorid; 94164032Srwatson int irqrid; 95164032Srwatson struct resource *iores; 96164032Srwatson struct resource *irqres; 97164032Srwatson void *irqih; 98164032Srwatson 99164032Srwatson device_t iicbb; 100164032Srwatson device_t smbus; 101164032Srwatson}; 102164032Srwatson 103164032Srwatsonstatic devclass_t viapm_devclass; 104164032Srwatsonstatic devclass_t viapropm_devclass; 105164032Srwatson 106164032Srwatson/* 107164032Srwatson * VT82C586B definitions 108164032Srwatson */ 109164032Srwatson 110164032Srwatson#define VIAPM_586B_REVID 0x08 111164032Srwatson 112164032Srwatson#define VIAPM_586B_3040E_BASE 0x20 113164032Srwatson#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ 114164032Srwatson 115164032Srwatson#define VIAPM_586B_3040F_BASE 0x48 116164032Srwatson#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ 117164032Srwatson 118164032Srwatson#define VIAPM_586B_OEM_REV_E 0x00 119164032Srwatson#define VIAPM_586B_OEM_REV_F 0x01 120164032Srwatson#define VIAPM_586B_PROD_REV_A 0x10 121164032Srwatson 122164032Srwatson#define VIAPM_586B_BA_MASK 0x0000ff00 123164032Srwatson 124164032Srwatson#define GPIO_DIR 0x40 125164032Srwatson#define GPIO_VAL 0x42 126164032Srwatson#define EXTSMI_VAL 0x44 127164032Srwatson 128164032Srwatson#define VIAPM_SCL 0x02 /* GPIO1_VAL */ 129164032Srwatson#define VIAPM_SDA 0x04 /* GPIO2_VAL */ 130164032Srwatson 131164032Srwatson/* 132164032Srwatson * VIAPRO common definitions 133164032Srwatson */ 134164032Srwatson 135164032Srwatson#define VIAPM_PRO_BA_MASK 0x0000fff0 136164032Srwatson#define VIAPM_PRO_SMBCTRL 0xd2 137164032Srwatson#define VIAPM_PRO_REVID 0xd6 138164032Srwatson 139164032Srwatson/* 140164032Srwatson * VT82C686A definitions 141164032Srwatson */ 142164032Srwatson 143164032Srwatson#define VIAPM_PRO_BASE 0x90 144164032Srwatson 145164032Srwatson#define SMBHST 0x0 146164032Srwatson#define SMBHSL 0x1 147164032Srwatson#define SMBHCTRL 0x2 148164032Srwatson#define SMBHCMD 0x3 149164032Srwatson#define SMBHADDR 0x4 150164032Srwatson#define SMBHDATA0 0x5 151164032Srwatson#define SMBHDATA1 0x6 152164032Srwatson#define SMBHBLOCK 0x7 153164032Srwatson 154164032Srwatson#define SMBSST 0x1 155164032Srwatson#define SMBSCTRL 0x8 156164032Srwatson#define SMBSSDWCMD 0x9 157164032Srwatson#define SMBSEVENT 0xa 158164032Srwatson#define SMBSDATA 0xc 159164032Srwatson 160164032Srwatson#define SMBHST_RESERVED 0xef /* reserved bits */ 161164032Srwatson#define SMBHST_FAILED 0x10 /* failed bus transaction */ 162164032Srwatson#define SMBHST_COLLID 0x08 /* bus collision */ 163164032Srwatson#define SMBHST_ERROR 0x04 /* device error */ 164164032Srwatson#define SMBHST_INTR 0x02 /* command completed */ 165164032Srwatson#define SMBHST_BUSY 0x01 /* host busy */ 166164032Srwatson 167164032Srwatson#define SMBHCTRL_START 0x40 /* start command */ 168164032Srwatson#define SMBHCTRL_PROTO 0x1c /* command protocol mask */ 169164032Srwatson#define SMBHCTRL_QUICK 0x00 170164032Srwatson#define SMBHCTRL_SENDRECV 0x04 171164032Srwatson#define SMBHCTRL_BYTE 0x08 172164032Srwatson#define SMBHCTRL_WORD 0x0c 173164032Srwatson#define SMBHCTRL_BLOCK 0x14 174164032Srwatson#define SMBHCTRL_KILL 0x02 /* stop the current transaction */ 175164032Srwatson#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ 176164032Srwatson 177164032Srwatson#define SMBSCTRL_ENABLE 0x01 /* enable slave */ 178164032Srwatson 179164032Srwatson 180164032Srwatson/* 181164032Srwatson * VIA8233 definitions 182164032Srwatson */ 183164032Srwatson 184164032Srwatson#define VIAPM_8233_BASE 0xD0 185164032Srwatson 186164032Srwatsonstatic int 187164032Srwatsonviapm_586b_probe(device_t dev) 188164032Srwatson{ 189164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 190164032Srwatson u_int32_t l; 191164032Srwatson u_int16_t s; 192164032Srwatson u_int8_t c; 193164032Srwatson 194164032Srwatson switch (pci_get_devid(dev)) { 195164032Srwatson case VIA_586B_PMU_ID: 196164032Srwatson 197164032Srwatson bzero(viapm, sizeof(struct viapm_softc)); 198164032Srwatson 199164032Srwatson l = pci_read_config(dev, VIAPM_586B_REVID, 1); 200164032Srwatson switch (l) { 201164032Srwatson case VIAPM_586B_OEM_REV_E: 202164032Srwatson viapm->type = VIAPM_TYP_586B_3040E; 203164032Srwatson viapm->iorid = VIAPM_586B_3040E_BASE; 204164032Srwatson 205164032Srwatson /* Activate IO block access */ 206164032Srwatson s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); 207164032Srwatson pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); 208164032Srwatson break; 209164032Srwatson 210164032Srwatson case VIAPM_586B_OEM_REV_F: 211164032Srwatson case VIAPM_586B_PROD_REV_A: 212164032Srwatson default: 213164032Srwatson viapm->type = VIAPM_TYP_586B_3040F; 214164032Srwatson viapm->iorid = VIAPM_586B_3040F_BASE; 215164032Srwatson 216164032Srwatson /* Activate IO block access */ 217164032Srwatson c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); 218164032Srwatson pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); 219164032Srwatson break; 220164032Srwatson } 221164032Srwatson 222164032Srwatson viapm->base = pci_read_config(dev, viapm->iorid, 4) & 223164032Srwatson VIAPM_586B_BA_MASK; 224164032Srwatson 225164032Srwatson /* 226164032Srwatson * We have to set the I/O resources by hand because it is 227164032Srwatson * described outside the viapmope of the traditional maps 228164032Srwatson */ 229164032Srwatson if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 230164032Srwatson viapm->base, 256)) { 231164032Srwatson device_printf(dev, "could not set bus resource\n"); 232164032Srwatson return ENXIO; 233164032Srwatson } 234164032Srwatson device_set_desc(dev, "VIA VT82C586B Power Management Unit"); 235164032Srwatson return (BUS_PROBE_DEFAULT); 236164032Srwatson 237164032Srwatson default: 238164032Srwatson break; 239164032Srwatson } 240164032Srwatson 241164032Srwatson return ENXIO; 242164032Srwatson} 243164032Srwatson 244164032Srwatson 245164032Srwatsonstatic int 246164032Srwatsonviapm_pro_probe(device_t dev) 247164032Srwatson{ 248164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 249164032Srwatson#ifdef VIAPM_BASE_ADDR 250164032Srwatson u_int32_t l; 251164032Srwatson#endif 252164032Srwatson u_int32_t base_cfgreg; 253164032Srwatson char *desc; 254164032Srwatson 255164032Srwatson switch (pci_get_devid(dev)) { 256164032Srwatson case VIA_596A_PMU_ID: 257164032Srwatson desc = "VIA VT82C596A Power Management Unit"; 258164032Srwatson viapm->type = VIAPM_TYP_596B; 259164032Srwatson base_cfgreg = VIAPM_PRO_BASE; 260164032Srwatson goto viapro; 261164032Srwatson 262164032Srwatson case VIA_596B_PMU_ID: 263164032Srwatson desc = "VIA VT82C596B Power Management Unit"; 264164032Srwatson viapm->type = VIAPM_TYP_596B; 265164032Srwatson base_cfgreg = VIAPM_PRO_BASE; 266164032Srwatson goto viapro; 267164032Srwatson 268164032Srwatson case VIA_686A_PMU_ID: 269164032Srwatson desc = "VIA VT82C686A Power Management Unit"; 270164032Srwatson viapm->type = VIAPM_TYP_686A; 271164032Srwatson base_cfgreg = VIAPM_PRO_BASE; 272164032Srwatson goto viapro; 273164032Srwatson 274164032Srwatson case VIA_8233_PMU_ID: 275164032Srwatson case VIA_8233A_PMU_ID: 276164032Srwatson desc = "VIA VT8233 Power Management Unit"; 277164032Srwatson viapm->type = VIAPM_TYP_UNKNOWN; 278164032Srwatson base_cfgreg = VIAPM_8233_BASE; 279164032Srwatson goto viapro; 280164032Srwatson 281164032Srwatson case VIA_8235_PMU_ID: 282164032Srwatson desc = "VIA VT8235 Power Management Unit"; 283164032Srwatson viapm->type = VIAPM_TYP_UNKNOWN; 284164032Srwatson base_cfgreg = VIAPM_8233_BASE; 285164032Srwatson goto viapro; 286164032Srwatson 287164032Srwatson viapro: 288164032Srwatson 289164032Srwatson#ifdef VIAPM_BASE_ADDR 290164032Srwatson /* force VIAPM I/O base address */ 291164032Srwatson 292164032Srwatson /* enable the SMBus controller function */ 293164032Srwatson l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 294164032Srwatson pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 295164032Srwatson 296164032Srwatson /* write the base address */ 297164032Srwatson pci_write_config(dev, base_cfgreg, 298164032Srwatson VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); 299164032Srwatson#endif 300164032Srwatson 301164032Srwatson viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; 302164032Srwatson 303164032Srwatson /* 304164032Srwatson * We have to set the I/O resources by hand because it is 305164032Srwatson * described outside the viapmope of the traditional maps 306164032Srwatson */ 307164032Srwatson viapm->iorid = base_cfgreg; 308164032Srwatson if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 309164032Srwatson viapm->base, 16)) { 310164032Srwatson device_printf(dev, "could not set bus resource 0x%x\n", 311164032Srwatson viapm->base); 312164032Srwatson return ENXIO; 313164032Srwatson } 314164032Srwatson 315164032Srwatson if (1 || bootverbose) { 316164032Srwatson device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); 317164032Srwatson } 318164032Srwatson 319164032Srwatson device_set_desc(dev, desc); 320164032Srwatson return (BUS_PROBE_DEFAULT); 321164032Srwatson 322164032Srwatson default: 323164032Srwatson break; 324164032Srwatson } 325164032Srwatson 326164032Srwatson return ENXIO; 327164032Srwatson} 328164032Srwatson 329164032Srwatsonstatic int 330164032Srwatsonviapm_pro_attach(device_t dev) 331164032Srwatson{ 332164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 333164032Srwatson u_int32_t l; 334164032Srwatson 335164032Srwatson if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 336164032Srwatson &viapm->iorid, RF_ACTIVE))) { 337164032Srwatson device_printf(dev, "could not allocate bus space\n"); 338164032Srwatson goto error; 339164032Srwatson } 340164032Srwatson viapm->st = rman_get_bustag(viapm->iores); 341164032Srwatson viapm->sh = rman_get_bushandle(viapm->iores); 342164032Srwatson 343164032Srwatson#ifdef notyet 344164032Srwatson /* force irq 9 */ 345164032Srwatson l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 346164032Srwatson pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); 347164032Srwatson 348164032Srwatson viapm->irqrid = 0; 349164032Srwatson if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, 350164032Srwatson &viapm->irqrid, 9, 9, 1, 351164032Srwatson RF_SHAREABLE | RF_ACTIVE))) { 352164032Srwatson device_printf(dev, "could not allocate irq\n"); 353164032Srwatson goto error; 354164032Srwatson } 355164032Srwatson 356164032Srwatson if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC, 357164032Srwatson (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { 358164032Srwatson device_printf(dev, "could not setup irq\n"); 359164032Srwatson goto error; 360164032Srwatson } 361164032Srwatson#endif 362164032Srwatson 363164032Srwatson if (1 | bootverbose) { 364164032Srwatson l = pci_read_config(dev, VIAPM_PRO_REVID, 1); 365164032Srwatson device_printf(dev, "SMBus revision code 0x%x\n", l); 366164032Srwatson } 367164032Srwatson 368164032Srwatson viapm->smbus = device_add_child(dev, "smbus", -1); 369164032Srwatson 370164032Srwatson /* probe and attach the smbus */ 371164032Srwatson bus_generic_attach(dev); 372164032Srwatson 373164032Srwatson /* disable slave function */ 374164032Srwatson VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); 375164032Srwatson 376164032Srwatson /* enable the SMBus controller function */ 377164032Srwatson l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 378164032Srwatson pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 379164032Srwatson 380164032Srwatson#ifdef notyet 381164032Srwatson /* enable interrupts */ 382164032Srwatson VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); 383164032Srwatson#endif 384164032Srwatson 385164032Srwatson#ifdef DEV_ISA 386164032Srwatson /* If this device is a PCI-ISA bridge, then attach an ISA bus. */ 387164032Srwatson if ((pci_get_class(dev) == PCIC_BRIDGE) && 388164032Srwatson (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) 389164032Srwatson isab_attach(dev); 390164032Srwatson#endif 391164032Srwatson return 0; 392164032Srwatson 393164032Srwatsonerror: 394164032Srwatson if (viapm->iores) 395164032Srwatson bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 396164032Srwatson#ifdef notyet 397164032Srwatson if (viapm->irqres) 398164032Srwatson bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 399164032Srwatson#endif 400164032Srwatson 401164032Srwatson return ENXIO; 402164032Srwatson} 403164032Srwatson 404164032Srwatsonstatic int 405164032Srwatsonviapm_586b_attach(device_t dev) 406164032Srwatson{ 407164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 408164032Srwatson 409164032Srwatson if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 410164032Srwatson &viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) { 411164032Srwatson device_printf(dev, "could not allocate bus resource\n"); 412164032Srwatson return ENXIO; 413164032Srwatson } 414164032Srwatson viapm->st = rman_get_bustag(viapm->iores); 415164032Srwatson viapm->sh = rman_get_bushandle(viapm->iores); 416164032Srwatson 417164032Srwatson VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); 418164032Srwatson 419164032Srwatson /* add generic bit-banging code */ 420164032Srwatson if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) 421164032Srwatson goto error; 422164032Srwatson 423164032Srwatson bus_generic_attach(dev); 424164032Srwatson 425164032Srwatson return 0; 426164032Srwatson 427164032Srwatsonerror: 428164032Srwatson if (viapm->iores) 429164032Srwatson bus_release_resource(dev, SYS_RES_IOPORT, 430164032Srwatson viapm->iorid, viapm->iores); 431164032Srwatson return ENXIO; 432164032Srwatson} 433164032Srwatson 434164032Srwatsonstatic int 435164032Srwatsonviapm_586b_detach(device_t dev) 436164032Srwatson{ 437164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 438164032Srwatson int error; 439164032Srwatson 440164032Srwatson bus_generic_detach(dev); 441164032Srwatson if (viapm->iicbb) { 442164032Srwatson device_delete_child(dev, viapm->iicbb); 443164032Srwatson } 444164032Srwatson 445164032Srwatson if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT, 446164032Srwatson viapm->iorid, viapm->iores))) 447164032Srwatson return (error); 448164032Srwatson 449164032Srwatson return 0; 450164032Srwatson} 451164032Srwatson 452164032Srwatsonstatic int 453164032Srwatsonviapm_pro_detach(device_t dev) 454164032Srwatson{ 455164032Srwatson struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 456164032Srwatson int error; 457164032Srwatson 458 bus_generic_detach(dev); 459 if (viapm->smbus) { 460 device_delete_child(dev, viapm->smbus); 461 } 462 463 if ((error = bus_release_resource(dev, SYS_RES_IOPORT, 464 viapm->iorid, viapm->iores))) 465 return (error); 466 467#ifdef notyet 468 if ((error = bus_release_resource(dev, SYS_RES_IRQ, 469 viapm->irqrid, viapm->irqres)) 470 return (error); 471#endif 472 473 return 0; 474} 475 476static int 477viabb_callback(device_t dev, int index, caddr_t *data) 478{ 479 return 0; 480} 481 482static void 483viabb_setscl(device_t dev, int ctrl) 484{ 485 struct viapm_softc *viapm = device_get_softc(dev); 486 u_char val; 487 488 val = VIAPM_INB(GPIO_VAL); 489 490 if (ctrl) 491 val |= VIAPM_SCL; 492 else 493 val &= ~VIAPM_SCL; 494 495 VIAPM_OUTB(GPIO_VAL, val); 496 497 return; 498} 499 500static void 501viabb_setsda(device_t dev, int data) 502{ 503 struct viapm_softc *viapm = device_get_softc(dev); 504 u_char val; 505 506 val = VIAPM_INB(GPIO_VAL); 507 508 if (data) 509 val |= VIAPM_SDA; 510 else 511 val &= ~VIAPM_SDA; 512 513 VIAPM_OUTB(GPIO_VAL, val); 514 515 return; 516} 517 518static int 519viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 520{ 521 /* reset bus */ 522 viabb_setsda(dev, 1); 523 viabb_setscl(dev, 1); 524 525 return (IIC_ENOADDR); 526} 527 528static int 529viabb_getscl(device_t dev) 530{ 531 struct viapm_softc *viapm = device_get_softc(dev); 532 533 return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0); 534} 535 536static int 537viabb_getsda(device_t dev) 538{ 539 struct viapm_softc *viapm = device_get_softc(dev); 540 541 return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0); 542} 543 544static int 545viapm_abort(struct viapm_softc *viapm) 546{ 547 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 548 DELAY(10); 549 550 return (0); 551} 552 553static int 554viapm_clear(struct viapm_softc *viapm) 555{ 556 VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | 557 SMBHST_ERROR | SMBHST_INTR); 558 DELAY(10); 559 560 return (0); 561} 562 563static int 564viapm_busy(struct viapm_softc *viapm) 565{ 566 u_char sts; 567 568 sts = VIAPM_INB(SMBHST); 569 570 VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); 571 572 return (sts & SMBHST_BUSY); 573} 574 575/* 576 * Poll the SMBus controller 577 */ 578static int 579viapm_wait(struct viapm_softc *viapm) 580{ 581 int count = 10000; 582 u_char sts = 0; 583 int error; 584 585 /* wait for command to complete and SMBus controller is idle */ 586 while(count--) { 587 DELAY(10); 588 sts = VIAPM_INB(SMBHST); 589 590 /* check if the controller is processing a command */ 591 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) 592 break; 593 } 594 595 VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); 596 597 error = SMB_ENOERR; 598 599 if (!count) 600 error |= SMB_ETIMEOUT; 601 602 if (sts & SMBHST_FAILED) 603 error |= SMB_EABORT; 604 605 if (sts & SMBHST_COLLID) 606 error |= SMB_ENOACK; 607 608 if (sts & SMBHST_ERROR) 609 error |= SMB_EBUSERR; 610 611 if (error != SMB_ENOERR) 612 viapm_abort(viapm); 613 614 viapm_clear(viapm); 615 616 return (error); 617} 618 619static int 620viasmb_callback(device_t dev, int index, caddr_t *data) 621{ 622 int error = 0; 623 624 switch (index) { 625 case SMB_REQUEST_BUS: 626 case SMB_RELEASE_BUS: 627 /* ok, bus allocation accepted */ 628 break; 629 default: 630 error = EINVAL; 631 } 632 633 return (error); 634} 635 636static int 637viasmb_quick(device_t dev, u_char slave, int how) 638{ 639 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 640 int error; 641 642 viapm_clear(viapm); 643 if (viapm_busy(viapm)) 644 return (EBUSY); 645 646 switch (how) { 647 case SMB_QWRITE: 648 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); 649 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 650 break; 651 case SMB_QREAD: 652 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); 653 VIAPM_OUTB(SMBHADDR, slave | LSB); 654 break; 655 default: 656 panic("%s: unknown QUICK command (%x)!", __func__, how); 657 } 658 659 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); 660 661 error = viapm_wait(viapm); 662 663 return (error); 664} 665 666static int 667viasmb_sendb(device_t dev, u_char slave, char byte) 668{ 669 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 670 int error; 671 672 viapm_clear(viapm); 673 if (viapm_busy(viapm)) 674 return (EBUSY); 675 676 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 677 VIAPM_OUTB(SMBHCMD, byte); 678 679 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 680 681 error = viapm_wait(viapm); 682 683 VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 684 685 return (error); 686} 687 688static int 689viasmb_recvb(device_t dev, u_char slave, char *byte) 690{ 691 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 692 int error; 693 694 viapm_clear(viapm); 695 if (viapm_busy(viapm)) 696 return (EBUSY); 697 698 VIAPM_OUTB(SMBHADDR, slave | LSB); 699 700 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 701 702 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 703 *byte = VIAPM_INB(SMBHDATA0); 704 705 VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 706 707 return (error); 708} 709 710static int 711viasmb_writeb(device_t dev, u_char slave, char cmd, char byte) 712{ 713 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 714 int error; 715 716 viapm_clear(viapm); 717 if (viapm_busy(viapm)) 718 return (EBUSY); 719 720 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 721 VIAPM_OUTB(SMBHCMD, cmd); 722 VIAPM_OUTB(SMBHDATA0, byte); 723 724 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 725 726 error = viapm_wait(viapm); 727 728 VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 729 730 return (error); 731} 732 733static int 734viasmb_readb(device_t dev, u_char slave, char cmd, char *byte) 735{ 736 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 737 int error; 738 739 viapm_clear(viapm); 740 if (viapm_busy(viapm)) 741 return (EBUSY); 742 743 VIAPM_OUTB(SMBHADDR, slave | LSB); 744 VIAPM_OUTB(SMBHCMD, cmd); 745 746 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 747 748 if ((error = viapm_wait(viapm)) == SMB_ENOERR) 749 *byte = VIAPM_INB(SMBHDATA0); 750 751 VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 752 753 return (error); 754} 755 756static int 757viasmb_writew(device_t dev, u_char slave, char cmd, short word) 758{ 759 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 760 int error; 761 762 viapm_clear(viapm); 763 if (viapm_busy(viapm)) 764 return (EBUSY); 765 766 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 767 VIAPM_OUTB(SMBHCMD, cmd); 768 VIAPM_OUTB(SMBHDATA0, word & 0x00ff); 769 VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); 770 771 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 772 773 error = viapm_wait(viapm); 774 775 VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 776 777 return (error); 778} 779 780static int 781viasmb_readw(device_t dev, u_char slave, char cmd, short *word) 782{ 783 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 784 int error; 785 u_char high, low; 786 787 viapm_clear(viapm); 788 if (viapm_busy(viapm)) 789 return (EBUSY); 790 791 VIAPM_OUTB(SMBHADDR, slave | LSB); 792 VIAPM_OUTB(SMBHCMD, cmd); 793 794 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 795 796 if ((error = viapm_wait(viapm)) == SMB_ENOERR) { 797 low = VIAPM_INB(SMBHDATA0); 798 high = VIAPM_INB(SMBHDATA1); 799 800 *word = ((high & 0xff) << 8) | (low & 0xff); 801 } 802 803 VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 804 805 return (error); 806} 807 808static int 809viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 810{ 811 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 812 u_char remain, len, i; 813 int error = SMB_ENOERR; 814 815 viapm_clear(viapm); 816 if (viapm_busy(viapm)) 817 return (EBUSY); 818 819 remain = count; 820 while (remain) { 821 len = min(remain, 32); 822 823 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 824 VIAPM_OUTB(SMBHCMD, cmd); 825 VIAPM_OUTB(SMBHDATA0, len); 826 i = VIAPM_INB(SMBHCTRL); 827 828 /* fill the 32-byte internal buffer */ 829 for (i=0; i<len; i++) { 830 VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]); 831 DELAY(2); 832 } 833 VIAPM_OUTB(SMBHCMD, cmd); 834 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 835 836 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 837 goto error; 838 839 remain -= len; 840 } 841 842error: 843 VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 844 845 return (error); 846 847} 848 849static int 850viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 851{ 852 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 853 u_char remain, len, i; 854 int error = SMB_ENOERR; 855 856 viapm_clear(viapm); 857 if (viapm_busy(viapm)) 858 return (EBUSY); 859 860 remain = count; 861 while (remain) { 862 VIAPM_OUTB(SMBHADDR, slave | LSB); 863 VIAPM_OUTB(SMBHCMD, cmd); 864 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 865 866 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 867 goto error; 868 869 len = VIAPM_INB(SMBHDATA0); 870 i = VIAPM_INB(SMBHCTRL); /* reset counter */ 871 872 len = min(len, remain); 873 874 /* read the 32-byte internal buffer */ 875 for (i=0; i<len; i++) { 876 buf[count-remain+i] = VIAPM_INB(SMBHBLOCK); 877 DELAY(2); 878 } 879 880 remain -= len; 881 } 882error: 883 VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 884 885 return (error); 886} 887 888static device_method_t viapm_methods[] = { 889 /* device interface */ 890 DEVMETHOD(device_probe, viapm_586b_probe), 891 DEVMETHOD(device_attach, viapm_586b_attach), 892 DEVMETHOD(device_detach, viapm_586b_detach), 893 894 /* iicbb interface */ 895 DEVMETHOD(iicbb_callback, viabb_callback), 896 DEVMETHOD(iicbb_setscl, viabb_setscl), 897 DEVMETHOD(iicbb_setsda, viabb_setsda), 898 DEVMETHOD(iicbb_getscl, viabb_getscl), 899 DEVMETHOD(iicbb_getsda, viabb_getsda), 900 DEVMETHOD(iicbb_reset, viabb_reset), 901 902 /* Bus interface */ 903 DEVMETHOD(bus_print_child, bus_generic_print_child), 904 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 905 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 906 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 907 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 908 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 909 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 910 911 { 0, 0 } 912}; 913 914static driver_t viapm_driver = { 915 "viapm", 916 viapm_methods, 917 sizeof(struct viapm_softc), 918}; 919 920static device_method_t viapropm_methods[] = { 921 /* device interface */ 922 DEVMETHOD(device_probe, viapm_pro_probe), 923 DEVMETHOD(device_attach, viapm_pro_attach), 924 DEVMETHOD(device_detach, viapm_pro_detach), 925 926 /* smbus interface */ 927 DEVMETHOD(smbus_callback, viasmb_callback), 928 DEVMETHOD(smbus_quick, viasmb_quick), 929 DEVMETHOD(smbus_sendb, viasmb_sendb), 930 DEVMETHOD(smbus_recvb, viasmb_recvb), 931 DEVMETHOD(smbus_writeb, viasmb_writeb), 932 DEVMETHOD(smbus_readb, viasmb_readb), 933 DEVMETHOD(smbus_writew, viasmb_writew), 934 DEVMETHOD(smbus_readw, viasmb_readw), 935 DEVMETHOD(smbus_bwrite, viasmb_bwrite), 936 DEVMETHOD(smbus_bread, viasmb_bread), 937 938 /* Bus interface */ 939 DEVMETHOD(bus_print_child, bus_generic_print_child), 940 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 941 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 942 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 943 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 944 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 945 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 946 947 { 0, 0 } 948}; 949 950static driver_t viapropm_driver = { 951 "viapropm", 952 viapropm_methods, 953 sizeof(struct viapm_softc), 954}; 955 956DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 957DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 958 959MODULE_DEPEND(viapm, pci, 1, 1, 1); 960MODULE_DEPEND(viapropm, pci, 1, 1, 1); 961MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 962MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 963MODULE_VERSION(viapm, 1); 964 965#ifdef DEV_ISA 966DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0); 967DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0); 968MODULE_DEPEND(viapm, isa, 1, 1, 1); 969MODULE_DEPEND(viapropm, isa, 1, 1, 1); 970#endif 971