viapm.c revision 272017
1259698Sdim/*- 2259698Sdim * Copyright (c) 2001 Alcove - Nicolas Souchu 3259698Sdim * All rights reserved. 4259698Sdim * 5259698Sdim * Redistribution and use in source and binary forms, with or without 6259698Sdim * modification, are permitted provided that the following conditions 7259698Sdim * are met: 8259698Sdim * 1. Redistributions of source code must retain the above copyright 9259698Sdim * notice, this list of conditions and the following disclaimer. 10259698Sdim * 2. Redistributions in binary form must reproduce the above copyright 11259698Sdim * notice, this list of conditions and the following disclaimer in the 12259698Sdim * documentation and/or other materials provided with the distribution. 13259698Sdim * 14259698Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15259698Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16259698Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17259698Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18259698Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19259698Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20259698Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21259698Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22259698Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23259698Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24259698Sdim * SUCH DAMAGE. 25259698Sdim */ 26259698Sdim 27259698Sdim#include <sys/cdefs.h> 28259698Sdim__FBSDID("$FreeBSD: head/sys/dev/viapm/viapm.c 272017 2014-09-23 06:31:15Z rpaulo $"); 29259698Sdim 30259698Sdim#include "opt_isa.h" 31259698Sdim 32259698Sdim#include <sys/param.h> 33259698Sdim#include <sys/bus.h> 34259698Sdim#include <sys/kernel.h> 35259698Sdim#include <sys/lock.h> 36259698Sdim#include <sys/module.h> 37259698Sdim#include <sys/mutex.h> 38259698Sdim#include <sys/systm.h> 39259698Sdim 40259698Sdim#include <machine/bus.h> 41259698Sdim#include <machine/resource.h> 42259698Sdim#include <sys/rman.h> 43259698Sdim 44259698Sdim#ifdef DEV_ISA 45259698Sdim#include <isa/isavar.h> 46259698Sdim#include <isa/isa_common.h> 47259698Sdim#endif 48259698Sdim#include <dev/pci/pcivar.h> 49259698Sdim#include <dev/pci/pcireg.h> 50259698Sdim 51259698Sdim#include <dev/iicbus/iiconf.h> 52259698Sdim 53259698Sdim#include <dev/smbus/smbconf.h> 54259698Sdim 55259698Sdim#include "iicbb_if.h" 56259698Sdim#include "smbus_if.h" 57259698Sdim 58259698Sdim#define VIAPM_DEBUG(x) if (viapm_debug) (x) 59259698Sdim 60259698Sdim#ifdef DEBUG 61259698Sdimstatic int viapm_debug = 1; 62259698Sdim#else 63259698Sdimstatic int viapm_debug = 0; 64259698Sdim#endif 65259698Sdim 66259698Sdim#define VIA_586B_PMU_ID 0x30401106 67259698Sdim#define VIA_596A_PMU_ID 0x30501106 68259698Sdim#define VIA_596B_PMU_ID 0x30511106 69259698Sdim#define VIA_686A_PMU_ID 0x30571106 70259698Sdim#define VIA_8233_PMU_ID 0x30741106 71259698Sdim#define VIA_8233A_PMU_ID 0x31471106 72259698Sdim#define VIA_8235_PMU_ID 0x31771106 73259698Sdim#define VIA_8237_PMU_ID 0x32271106 74259698Sdim#define VIA_CX700_PMU_ID 0x83241106 75259698Sdim 76259698Sdim#define VIAPM_INB(port) \ 77259698Sdim ((u_char)bus_read_1(viapm->iores, port)) 78259698Sdim#define VIAPM_OUTB(port,val) \ 79259698Sdim (bus_write_1(viapm->iores, port, (u_char)(val))) 80259698Sdim 81259698Sdim#define VIAPM_TYP_UNKNOWN 0 82259698Sdim#define VIAPM_TYP_586B_3040E 1 83259698Sdim#define VIAPM_TYP_586B_3040F 2 84259698Sdim#define VIAPM_TYP_596B 3 85259698Sdim#define VIAPM_TYP_686A 4 86259698Sdim#define VIAPM_TYP_8233 5 87259698Sdim 88259698Sdim#define VIAPM_LOCK(sc) mtx_lock(&(sc)->lock) 89259698Sdim#define VIAPM_UNLOCK(sc) mtx_unlock(&(sc)->lock) 90259698Sdim#define VIAPM_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED) 91259698Sdim 92259698Sdimstruct viapm_softc { 93259698Sdim int type; 94259698Sdim u_int32_t base; 95259698Sdim int iorid; 96259698Sdim int irqrid; 97259698Sdim struct resource *iores; 98259698Sdim struct resource *irqres; 99259698Sdim void *irqih; 100259698Sdim device_t iicbb; 101259698Sdim device_t smbus; 102259698Sdim struct mtx lock; 103259698Sdim}; 104259698Sdim 105259698Sdimstatic devclass_t viapm_devclass; 106259698Sdimstatic devclass_t viapropm_devclass; 107259698Sdim 108259698Sdim/* 109259698Sdim * VT82C586B definitions 110259698Sdim */ 111259698Sdim 112259698Sdim#define VIAPM_586B_REVID 0x08 113259698Sdim 114259698Sdim#define VIAPM_586B_3040E_BASE 0x20 115259698Sdim#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ 116259698Sdim 117259698Sdim#define VIAPM_586B_3040F_BASE 0x48 118259698Sdim#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ 119259698Sdim 120259698Sdim#define VIAPM_586B_OEM_REV_E 0x00 121259698Sdim#define VIAPM_586B_OEM_REV_F 0x01 122259698Sdim#define VIAPM_586B_PROD_REV_A 0x10 123259698Sdim 124259698Sdim#define VIAPM_586B_BA_MASK 0x0000ff00 125259698Sdim 126259698Sdim#define GPIO_DIR 0x40 127259698Sdim#define GPIO_VAL 0x42 128259698Sdim#define EXTSMI_VAL 0x44 129259698Sdim 130259698Sdim#define VIAPM_SCL 0x02 /* GPIO1_VAL */ 131259698Sdim#define VIAPM_SDA 0x04 /* GPIO2_VAL */ 132259698Sdim 133259698Sdim/* 134259698Sdim * VIAPRO common definitions 135259698Sdim */ 136259698Sdim 137259698Sdim#define VIAPM_PRO_BA_MASK 0x0000fff0 138259698Sdim#define VIAPM_PRO_SMBCTRL 0xd2 139259698Sdim#define VIAPM_PRO_REVID 0xd6 140259698Sdim 141259698Sdim/* 142259698Sdim * VT82C686A definitions 143259698Sdim */ 144259698Sdim 145259698Sdim#define VIAPM_PRO_BASE 0x90 146259698Sdim 147259698Sdim#define SMBHST 0x0 148259698Sdim#define SMBHSL 0x1 149259698Sdim#define SMBHCTRL 0x2 150259698Sdim#define SMBHCMD 0x3 151259698Sdim#define SMBHADDR 0x4 152259698Sdim#define SMBHDATA0 0x5 153259698Sdim#define SMBHDATA1 0x6 154259698Sdim#define SMBHBLOCK 0x7 155259698Sdim 156259698Sdim#define SMBSST 0x1 157259698Sdim#define SMBSCTRL 0x8 158259698Sdim#define SMBSSDWCMD 0x9 159259698Sdim#define SMBSEVENT 0xa 160259698Sdim#define SMBSDATA 0xc 161259698Sdim 162259698Sdim#define SMBHST_RESERVED 0xef /* reserved bits */ 163259698Sdim#define SMBHST_FAILED 0x10 /* failed bus transaction */ 164259698Sdim#define SMBHST_COLLID 0x08 /* bus collision */ 165259698Sdim#define SMBHST_ERROR 0x04 /* device error */ 166259698Sdim#define SMBHST_INTR 0x02 /* command completed */ 167259698Sdim#define SMBHST_BUSY 0x01 /* host busy */ 168259698Sdim 169259698Sdim#define SMBHCTRL_START 0x40 /* start command */ 170259698Sdim#define SMBHCTRL_PROTO 0x1c /* command protocol mask */ 171259698Sdim#define SMBHCTRL_QUICK 0x00 172259698Sdim#define SMBHCTRL_SENDRECV 0x04 173259698Sdim#define SMBHCTRL_BYTE 0x08 174259698Sdim#define SMBHCTRL_WORD 0x0c 175259698Sdim#define SMBHCTRL_BLOCK 0x14 176259698Sdim#define SMBHCTRL_KILL 0x02 /* stop the current transaction */ 177259698Sdim#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ 178259698Sdim 179259698Sdim#define SMBSCTRL_ENABLE 0x01 /* enable slave */ 180259698Sdim 181259698Sdim 182259698Sdim/* 183259698Sdim * VIA8233 definitions 184259698Sdim */ 185259698Sdim 186259698Sdim#define VIAPM_8233_BASE 0xD0 187259698Sdim 188259698Sdimstatic int 189259698Sdimviapm_586b_probe(device_t dev) 190259698Sdim{ 191259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 192259698Sdim u_int32_t l; 193259698Sdim u_int16_t s; 194259698Sdim u_int8_t c; 195259698Sdim 196259698Sdim switch (pci_get_devid(dev)) { 197259698Sdim case VIA_586B_PMU_ID: 198259698Sdim 199259698Sdim bzero(viapm, sizeof(struct viapm_softc)); 200259698Sdim 201259698Sdim l = pci_read_config(dev, VIAPM_586B_REVID, 1); 202259698Sdim switch (l) { 203259698Sdim case VIAPM_586B_OEM_REV_E: 204259698Sdim viapm->type = VIAPM_TYP_586B_3040E; 205259698Sdim viapm->iorid = VIAPM_586B_3040E_BASE; 206259698Sdim 207259698Sdim /* Activate IO block access */ 208259698Sdim s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); 209259698Sdim pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); 210259698Sdim break; 211259698Sdim 212259698Sdim case VIAPM_586B_OEM_REV_F: 213259698Sdim case VIAPM_586B_PROD_REV_A: 214259698Sdim default: 215259698Sdim viapm->type = VIAPM_TYP_586B_3040F; 216259698Sdim viapm->iorid = VIAPM_586B_3040F_BASE; 217259698Sdim 218259698Sdim /* Activate IO block access */ 219259698Sdim c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); 220259698Sdim pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); 221259698Sdim break; 222259698Sdim } 223259698Sdim 224259698Sdim viapm->base = pci_read_config(dev, viapm->iorid, 4) & 225259698Sdim VIAPM_586B_BA_MASK; 226259698Sdim 227259698Sdim /* 228259698Sdim * We have to set the I/O resources by hand because it is 229259698Sdim * described outside the viapmope of the traditional maps 230259698Sdim */ 231259698Sdim if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 232259698Sdim viapm->base, 256)) { 233259698Sdim device_printf(dev, "could not set bus resource\n"); 234259698Sdim return ENXIO; 235259698Sdim } 236259698Sdim device_set_desc(dev, "VIA VT82C586B Power Management Unit"); 237259698Sdim return (BUS_PROBE_DEFAULT); 238259698Sdim 239259698Sdim default: 240259698Sdim break; 241259698Sdim } 242259698Sdim 243259698Sdim return ENXIO; 244259698Sdim} 245259698Sdim 246259698Sdim 247259698Sdimstatic int 248259698Sdimviapm_pro_probe(device_t dev) 249259698Sdim{ 250259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 251259698Sdim#ifdef VIAPM_BASE_ADDR 252259698Sdim u_int32_t l; 253259698Sdim#endif 254259698Sdim u_int32_t base_cfgreg; 255259698Sdim char *desc; 256259698Sdim 257259698Sdim switch (pci_get_devid(dev)) { 258259698Sdim case VIA_596A_PMU_ID: 259259698Sdim desc = "VIA VT82C596A Power Management Unit"; 260259698Sdim viapm->type = VIAPM_TYP_596B; 261259698Sdim base_cfgreg = VIAPM_PRO_BASE; 262259698Sdim goto viapro; 263259698Sdim 264259698Sdim case VIA_596B_PMU_ID: 265259698Sdim desc = "VIA VT82C596B Power Management Unit"; 266259698Sdim viapm->type = VIAPM_TYP_596B; 267259698Sdim base_cfgreg = VIAPM_PRO_BASE; 268259698Sdim goto viapro; 269259698Sdim 270259698Sdim case VIA_686A_PMU_ID: 271259698Sdim desc = "VIA VT82C686A Power Management Unit"; 272259698Sdim viapm->type = VIAPM_TYP_686A; 273259698Sdim base_cfgreg = VIAPM_PRO_BASE; 274259698Sdim goto viapro; 275259698Sdim 276259698Sdim case VIA_8233_PMU_ID: 277259698Sdim case VIA_8233A_PMU_ID: 278259698Sdim desc = "VIA VT8233 Power Management Unit"; 279259698Sdim viapm->type = VIAPM_TYP_UNKNOWN; 280259698Sdim base_cfgreg = VIAPM_8233_BASE; 281259698Sdim goto viapro; 282259698Sdim 283259698Sdim case VIA_8235_PMU_ID: 284259698Sdim desc = "VIA VT8235 Power Management Unit"; 285259698Sdim viapm->type = VIAPM_TYP_UNKNOWN; 286259698Sdim base_cfgreg = VIAPM_8233_BASE; 287259698Sdim goto viapro; 288259698Sdim 289259698Sdim case VIA_8237_PMU_ID: 290259698Sdim desc = "VIA VT8237 Power Management Unit"; 291259698Sdim viapm->type = VIAPM_TYP_UNKNOWN; 292259698Sdim base_cfgreg = VIAPM_8233_BASE; 293259698Sdim goto viapro; 294259698Sdim 295259698Sdim case VIA_CX700_PMU_ID: 296259698Sdim desc = "VIA CX700 Power Management Unit"; 297259698Sdim viapm->type = VIAPM_TYP_UNKNOWN; 298259698Sdim base_cfgreg = VIAPM_8233_BASE; 299259698Sdim goto viapro; 300259698Sdim 301259698Sdim viapro: 302259698Sdim 303259698Sdim#ifdef VIAPM_BASE_ADDR 304259698Sdim /* force VIAPM I/O base address */ 305259698Sdim 306259698Sdim /* enable the SMBus controller function */ 307259698Sdim l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 308259698Sdim pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 309259698Sdim 310259698Sdim /* write the base address */ 311259698Sdim pci_write_config(dev, base_cfgreg, 312259698Sdim VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); 313259698Sdim#endif 314259698Sdim 315259698Sdim viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; 316259698Sdim 317259698Sdim /* 318259698Sdim * We have to set the I/O resources by hand because it is 319259698Sdim * described outside the viapmope of the traditional maps 320259698Sdim */ 321259698Sdim viapm->iorid = base_cfgreg; 322259698Sdim if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, 323259698Sdim viapm->base, 16)) { 324259698Sdim device_printf(dev, "could not set bus resource 0x%x\n", 325259698Sdim viapm->base); 326259698Sdim return ENXIO; 327259698Sdim } 328259698Sdim 329259698Sdim if (bootverbose) { 330259698Sdim device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); 331259698Sdim } 332259698Sdim 333259698Sdim device_set_desc(dev, desc); 334259698Sdim return (BUS_PROBE_DEFAULT); 335259698Sdim 336259698Sdim default: 337259698Sdim break; 338259698Sdim } 339259698Sdim 340259698Sdim return ENXIO; 341259698Sdim} 342259698Sdim 343259698Sdimstatic int 344259698Sdimviapm_pro_attach(device_t dev) 345259698Sdim{ 346259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 347259698Sdim u_int32_t l; 348259698Sdim 349259698Sdim mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 350259698Sdim if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 351259698Sdim &viapm->iorid, RF_ACTIVE))) { 352259698Sdim device_printf(dev, "could not allocate bus space\n"); 353259698Sdim goto error; 354259698Sdim } 355259698Sdim 356259698Sdim#ifdef notyet 357259698Sdim /* force irq 9 */ 358259698Sdim l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 359259698Sdim pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); 360259698Sdim 361259698Sdim viapm->irqrid = 0; 362259698Sdim if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, 363259698Sdim &viapm->irqrid, 9, 9, 1, 364259698Sdim RF_SHAREABLE | RF_ACTIVE))) { 365259698Sdim device_printf(dev, "could not allocate irq\n"); 366259698Sdim goto error; 367259698Sdim } 368259698Sdim 369259698Sdim if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC | INTR_MPSAFE, 370259698Sdim (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { 371259698Sdim device_printf(dev, "could not setup irq\n"); 372259698Sdim goto error; 373259698Sdim } 374259698Sdim#endif 375259698Sdim 376259698Sdim if (bootverbose) { 377259698Sdim l = pci_read_config(dev, VIAPM_PRO_REVID, 1); 378259698Sdim device_printf(dev, "SMBus revision code 0x%x\n", l); 379259698Sdim } 380259698Sdim 381259698Sdim viapm->smbus = device_add_child(dev, "smbus", -1); 382259698Sdim 383259698Sdim /* probe and attach the smbus */ 384259698Sdim bus_generic_attach(dev); 385259698Sdim 386259698Sdim /* disable slave function */ 387259698Sdim VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); 388259698Sdim 389259698Sdim /* enable the SMBus controller function */ 390259698Sdim l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); 391259698Sdim pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); 392259698Sdim 393259698Sdim#ifdef notyet 394259698Sdim /* enable interrupts */ 395259698Sdim VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); 396259698Sdim#endif 397259698Sdim 398259698Sdim#ifdef DEV_ISA 399259698Sdim /* If this device is a PCI-ISA bridge, then attach an ISA bus. */ 400259698Sdim if ((pci_get_class(dev) == PCIC_BRIDGE) && 401259698Sdim (pci_get_subclass(dev) == PCIS_BRIDGE_ISA)) 402259698Sdim isab_attach(dev); 403259698Sdim#endif 404259698Sdim return 0; 405259698Sdim 406259698Sdimerror: 407259698Sdim if (viapm->iores) 408259698Sdim bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 409259698Sdim#ifdef notyet 410259698Sdim if (viapm->irqres) 411259698Sdim bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 412259698Sdim#endif 413259698Sdim mtx_destroy(&viapm->lock); 414259698Sdim 415259698Sdim return ENXIO; 416259698Sdim} 417259698Sdim 418259698Sdimstatic int 419259698Sdimviapm_586b_attach(device_t dev) 420259698Sdim{ 421259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 422259698Sdim 423259698Sdim mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF); 424259698Sdim if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 425259698Sdim &viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) { 426259698Sdim device_printf(dev, "could not allocate bus resource\n"); 427259698Sdim goto error; 428259698Sdim } 429259698Sdim 430259698Sdim VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); 431259698Sdim 432259698Sdim /* add generic bit-banging code */ 433259698Sdim if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) 434259698Sdim goto error; 435259698Sdim 436259698Sdim bus_generic_attach(dev); 437259698Sdim 438259698Sdim return 0; 439259698Sdim 440259698Sdimerror: 441259698Sdim if (viapm->iores) 442259698Sdim bus_release_resource(dev, SYS_RES_IOPORT, 443259698Sdim viapm->iorid, viapm->iores); 444259698Sdim mtx_destroy(&viapm->lock); 445259698Sdim return ENXIO; 446259698Sdim} 447259698Sdim 448259698Sdimstatic int 449259698Sdimviapm_586b_detach(device_t dev) 450259698Sdim{ 451259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 452259698Sdim 453259698Sdim bus_generic_detach(dev); 454259698Sdim if (viapm->iicbb) { 455259698Sdim device_delete_child(dev, viapm->iicbb); 456259698Sdim } 457259698Sdim 458259698Sdim if (viapm->iores) 459259698Sdim bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, 460259698Sdim viapm->iores); 461259698Sdim mtx_destroy(&viapm->lock); 462259698Sdim 463259698Sdim return 0; 464259698Sdim} 465259698Sdim 466259698Sdimstatic int 467259698Sdimviapm_pro_detach(device_t dev) 468259698Sdim{ 469259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 470259698Sdim 471259698Sdim bus_generic_detach(dev); 472259698Sdim if (viapm->smbus) { 473259698Sdim device_delete_child(dev, viapm->smbus); 474259698Sdim } 475259698Sdim 476259698Sdim bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); 477259698Sdim 478259698Sdim#ifdef notyet 479259698Sdim bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); 480259698Sdim#endif 481259698Sdim mtx_destroy(&viapm->lock); 482259698Sdim 483259698Sdim return 0; 484259698Sdim} 485259698Sdim 486259698Sdimstatic int 487259698Sdimviabb_callback(device_t dev, int index, caddr_t data) 488259698Sdim{ 489259698Sdim return 0; 490259698Sdim} 491259698Sdim 492259698Sdimstatic void 493259698Sdimviabb_setscl(device_t dev, int ctrl) 494259698Sdim{ 495259698Sdim struct viapm_softc *viapm = device_get_softc(dev); 496259698Sdim u_char val; 497259698Sdim 498259698Sdim VIAPM_LOCK(viapm); 499259698Sdim val = VIAPM_INB(GPIO_VAL); 500259698Sdim 501259698Sdim if (ctrl) 502259698Sdim val |= VIAPM_SCL; 503259698Sdim else 504259698Sdim val &= ~VIAPM_SCL; 505259698Sdim 506259698Sdim VIAPM_OUTB(GPIO_VAL, val); 507259698Sdim VIAPM_UNLOCK(viapm); 508259698Sdim 509259698Sdim return; 510259698Sdim} 511259698Sdim 512259698Sdimstatic void 513259698Sdimviabb_setsda(device_t dev, int data) 514259698Sdim{ 515259698Sdim struct viapm_softc *viapm = device_get_softc(dev); 516259698Sdim u_char val; 517259698Sdim 518259698Sdim VIAPM_LOCK(viapm); 519259698Sdim val = VIAPM_INB(GPIO_VAL); 520259698Sdim 521259698Sdim if (data) 522259698Sdim val |= VIAPM_SDA; 523259698Sdim else 524259698Sdim val &= ~VIAPM_SDA; 525259698Sdim 526259698Sdim VIAPM_OUTB(GPIO_VAL, val); 527259698Sdim VIAPM_UNLOCK(viapm); 528259698Sdim 529259698Sdim return; 530259698Sdim} 531259698Sdim 532259698Sdimstatic int 533259698Sdimviabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 534259698Sdim{ 535259698Sdim /* reset bus */ 536259698Sdim viabb_setsda(dev, 1); 537259698Sdim viabb_setscl(dev, 1); 538259698Sdim 539259698Sdim return (IIC_ENOADDR); 540259698Sdim} 541259698Sdim 542259698Sdimstatic int 543259698Sdimviabb_getscl(device_t dev) 544259698Sdim{ 545259698Sdim struct viapm_softc *viapm = device_get_softc(dev); 546259698Sdim u_char val; 547259698Sdim 548259698Sdim VIAPM_LOCK(viapm); 549259698Sdim val = VIAPM_INB(EXTSMI_VAL); 550259698Sdim VIAPM_UNLOCK(viapm); 551259698Sdim return ((val & VIAPM_SCL) != 0); 552259698Sdim} 553259698Sdim 554259698Sdimstatic int 555259698Sdimviabb_getsda(device_t dev) 556259698Sdim{ 557259698Sdim struct viapm_softc *viapm = device_get_softc(dev); 558259698Sdim u_char val; 559259698Sdim 560259698Sdim VIAPM_LOCK(viapm); 561259698Sdim val = VIAPM_INB(EXTSMI_VAL); 562259698Sdim VIAPM_UNLOCK(viapm); 563259698Sdim return ((val & VIAPM_SDA) != 0); 564259698Sdim} 565259698Sdim 566259698Sdimstatic int 567259698Sdimviapm_abort(struct viapm_softc *viapm) 568259698Sdim{ 569259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); 570259698Sdim DELAY(10); 571259698Sdim 572259698Sdim return (0); 573259698Sdim} 574259698Sdim 575259698Sdimstatic int 576259698Sdimviapm_clear(struct viapm_softc *viapm) 577259698Sdim{ 578259698Sdim VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | 579259698Sdim SMBHST_ERROR | SMBHST_INTR); 580259698Sdim DELAY(10); 581259698Sdim 582259698Sdim return (0); 583259698Sdim} 584259698Sdim 585259698Sdimstatic int 586259698Sdimviapm_busy(struct viapm_softc *viapm) 587259698Sdim{ 588259698Sdim u_char sts; 589259698Sdim 590259698Sdim sts = VIAPM_INB(SMBHST); 591259698Sdim 592259698Sdim VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); 593259698Sdim 594259698Sdim return (sts & SMBHST_BUSY); 595259698Sdim} 596259698Sdim 597259698Sdim/* 598259698Sdim * Poll the SMBus controller 599259698Sdim */ 600259698Sdimstatic int 601259698Sdimviapm_wait(struct viapm_softc *viapm) 602259698Sdim{ 603259698Sdim int count = 10000; 604259698Sdim u_char sts = 0; 605259698Sdim int error; 606259698Sdim 607259698Sdim VIAPM_LOCK_ASSERT(viapm); 608259698Sdim 609259698Sdim /* wait for command to complete and SMBus controller is idle */ 610259698Sdim while(count--) { 611259698Sdim DELAY(10); 612259698Sdim sts = VIAPM_INB(SMBHST); 613259698Sdim 614259698Sdim /* check if the controller is processing a command */ 615259698Sdim if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) 616259698Sdim break; 617259698Sdim } 618259698Sdim 619259698Sdim VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); 620259698Sdim 621259698Sdim error = SMB_ENOERR; 622259698Sdim 623259698Sdim if (!count) 624259698Sdim error |= SMB_ETIMEOUT; 625259698Sdim 626259698Sdim if (sts & SMBHST_FAILED) 627259698Sdim error |= SMB_EABORT; 628259698Sdim 629259698Sdim if (sts & SMBHST_COLLID) 630259698Sdim error |= SMB_ENOACK; 631259698Sdim 632259698Sdim if (sts & SMBHST_ERROR) 633259698Sdim error |= SMB_EBUSERR; 634259698Sdim 635259698Sdim if (error != SMB_ENOERR) 636259698Sdim viapm_abort(viapm); 637259698Sdim 638259698Sdim viapm_clear(viapm); 639259698Sdim 640259698Sdim return (error); 641259698Sdim} 642259698Sdim 643259698Sdimstatic int 644259698Sdimviasmb_callback(device_t dev, int index, void *data) 645259698Sdim{ 646259698Sdim int error = 0; 647259698Sdim 648259698Sdim switch (index) { 649259698Sdim case SMB_REQUEST_BUS: 650259698Sdim case SMB_RELEASE_BUS: 651259698Sdim /* ok, bus allocation accepted */ 652259698Sdim break; 653259698Sdim default: 654259698Sdim error = EINVAL; 655259698Sdim } 656259698Sdim 657259698Sdim return (error); 658259698Sdim} 659259698Sdim 660259698Sdimstatic int 661259698Sdimviasmb_quick(device_t dev, u_char slave, int how) 662259698Sdim{ 663259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 664259698Sdim int error; 665259698Sdim 666259698Sdim VIAPM_LOCK(viapm); 667259698Sdim viapm_clear(viapm); 668259698Sdim if (viapm_busy(viapm)) { 669259698Sdim VIAPM_UNLOCK(viapm); 670259698Sdim return (SMB_EBUSY); 671259698Sdim } 672259698Sdim 673259698Sdim switch (how) { 674259698Sdim case SMB_QWRITE: 675259698Sdim VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); 676259698Sdim VIAPM_OUTB(SMBHADDR, slave & ~LSB); 677259698Sdim break; 678259698Sdim case SMB_QREAD: 679259698Sdim VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); 680259698Sdim VIAPM_OUTB(SMBHADDR, slave | LSB); 681259698Sdim break; 682259698Sdim default: 683259698Sdim panic("%s: unknown QUICK command (%x)!", __func__, how); 684259698Sdim } 685259698Sdim 686259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); 687259698Sdim 688259698Sdim error = viapm_wait(viapm); 689259698Sdim VIAPM_UNLOCK(viapm); 690259698Sdim 691259698Sdim return (error); 692259698Sdim} 693259698Sdim 694259698Sdimstatic int 695259698Sdimviasmb_sendb(device_t dev, u_char slave, char byte) 696259698Sdim{ 697259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 698259698Sdim int error; 699259698Sdim 700259698Sdim VIAPM_LOCK(viapm); 701259698Sdim viapm_clear(viapm); 702259698Sdim if (viapm_busy(viapm)) { 703259698Sdim VIAPM_UNLOCK(viapm); 704259698Sdim return (SMB_EBUSY); 705259698Sdim } 706259698Sdim 707259698Sdim VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 708259698Sdim VIAPM_OUTB(SMBHCMD, byte); 709259698Sdim 710259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 711259698Sdim 712259698Sdim error = viapm_wait(viapm); 713259698Sdim 714259698Sdim VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 715259698Sdim VIAPM_UNLOCK(viapm); 716259698Sdim 717259698Sdim return (error); 718259698Sdim} 719259698Sdim 720259698Sdimstatic int 721259698Sdimviasmb_recvb(device_t dev, u_char slave, char *byte) 722259698Sdim{ 723259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 724259698Sdim int error; 725259698Sdim 726259698Sdim VIAPM_LOCK(viapm); 727259698Sdim viapm_clear(viapm); 728259698Sdim if (viapm_busy(viapm)) { 729259698Sdim VIAPM_UNLOCK(viapm); 730259698Sdim return (SMB_EBUSY); 731259698Sdim } 732259698Sdim 733259698Sdim VIAPM_OUTB(SMBHADDR, slave | LSB); 734259698Sdim 735259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); 736259698Sdim 737259698Sdim if ((error = viapm_wait(viapm)) == SMB_ENOERR) 738259698Sdim *byte = VIAPM_INB(SMBHDATA0); 739259698Sdim 740259698Sdim VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 741259698Sdim VIAPM_UNLOCK(viapm); 742259698Sdim 743259698Sdim return (error); 744259698Sdim} 745259698Sdim 746259698Sdimstatic int 747259698Sdimviasmb_writeb(device_t dev, u_char slave, char cmd, char byte) 748259698Sdim{ 749259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 750259698Sdim int error; 751259698Sdim 752259698Sdim VIAPM_LOCK(viapm); 753259698Sdim viapm_clear(viapm); 754259698Sdim if (viapm_busy(viapm)) { 755259698Sdim VIAPM_UNLOCK(viapm); 756259698Sdim return (SMB_EBUSY); 757259698Sdim } 758259698Sdim 759259698Sdim VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 760259698Sdim VIAPM_OUTB(SMBHCMD, cmd); 761259698Sdim VIAPM_OUTB(SMBHDATA0, byte); 762259698Sdim 763259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 764259698Sdim 765259698Sdim error = viapm_wait(viapm); 766259698Sdim 767259698Sdim VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 768259698Sdim VIAPM_UNLOCK(viapm); 769259698Sdim 770259698Sdim return (error); 771259698Sdim} 772259698Sdim 773259698Sdimstatic int 774259698Sdimviasmb_readb(device_t dev, u_char slave, char cmd, char *byte) 775259698Sdim{ 776259698Sdim struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 777259698Sdim int error; 778259698Sdim 779259698Sdim VIAPM_LOCK(viapm); 780259698Sdim viapm_clear(viapm); 781259698Sdim if (viapm_busy(viapm)) { 782259698Sdim VIAPM_UNLOCK(viapm); 783259698Sdim return (SMB_EBUSY); 784259698Sdim } 785259698Sdim 786259698Sdim VIAPM_OUTB(SMBHADDR, slave | LSB); 787259698Sdim VIAPM_OUTB(SMBHCMD, cmd); 788259698Sdim 789259698Sdim VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); 790259698Sdim 791259698Sdim if ((error = viapm_wait(viapm)) == SMB_ENOERR) 792259698Sdim *byte = VIAPM_INB(SMBHDATA0); 793259698Sdim 794259698Sdim VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 795 VIAPM_UNLOCK(viapm); 796 797 return (error); 798} 799 800static int 801viasmb_writew(device_t dev, u_char slave, char cmd, short word) 802{ 803 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 804 int error; 805 806 VIAPM_LOCK(viapm); 807 viapm_clear(viapm); 808 if (viapm_busy(viapm)) { 809 VIAPM_UNLOCK(viapm); 810 return (SMB_EBUSY); 811 } 812 813 VIAPM_OUTB(SMBHADDR, slave & ~ LSB); 814 VIAPM_OUTB(SMBHCMD, cmd); 815 VIAPM_OUTB(SMBHDATA0, word & 0x00ff); 816 VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); 817 818 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 819 820 error = viapm_wait(viapm); 821 822 VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 823 VIAPM_UNLOCK(viapm); 824 825 return (error); 826} 827 828static int 829viasmb_readw(device_t dev, u_char slave, char cmd, short *word) 830{ 831 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 832 int error; 833 u_char high, low; 834 835 VIAPM_LOCK(viapm); 836 viapm_clear(viapm); 837 if (viapm_busy(viapm)) { 838 VIAPM_UNLOCK(viapm); 839 return (SMB_EBUSY); 840 } 841 842 VIAPM_OUTB(SMBHADDR, slave | LSB); 843 VIAPM_OUTB(SMBHCMD, cmd); 844 845 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); 846 847 if ((error = viapm_wait(viapm)) == SMB_ENOERR) { 848 low = VIAPM_INB(SMBHDATA0); 849 high = VIAPM_INB(SMBHDATA1); 850 851 *word = ((high & 0xff) << 8) | (low & 0xff); 852 } 853 854 VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 855 VIAPM_UNLOCK(viapm); 856 857 return (error); 858} 859 860static int 861viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 862{ 863 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 864 u_char i; 865 int error; 866 867 if (count < 1 || count > 32) 868 return (SMB_EINVAL); 869 870 VIAPM_LOCK(viapm); 871 viapm_clear(viapm); 872 if (viapm_busy(viapm)) { 873 VIAPM_UNLOCK(viapm); 874 return (SMB_EBUSY); 875 } 876 877 VIAPM_OUTB(SMBHADDR, slave & ~LSB); 878 VIAPM_OUTB(SMBHCMD, cmd); 879 VIAPM_OUTB(SMBHDATA0, count); 880 i = VIAPM_INB(SMBHCTRL); 881 882 /* fill the 32-byte internal buffer */ 883 for (i = 0; i < count; i++) { 884 VIAPM_OUTB(SMBHBLOCK, buf[i]); 885 DELAY(2); 886 } 887 VIAPM_OUTB(SMBHCMD, cmd); 888 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 889 890 error = viapm_wait(viapm); 891 892 VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 893 VIAPM_UNLOCK(viapm); 894 895 return (error); 896 897} 898 899static int 900viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 901{ 902 struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); 903 u_char data, len, i; 904 int error; 905 906 if (*count < 1 || *count > 32) 907 return (SMB_EINVAL); 908 909 VIAPM_LOCK(viapm); 910 viapm_clear(viapm); 911 if (viapm_busy(viapm)) { 912 VIAPM_UNLOCK(viapm); 913 return (SMB_EBUSY); 914 } 915 916 VIAPM_OUTB(SMBHADDR, slave | LSB); 917 VIAPM_OUTB(SMBHCMD, cmd); 918 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); 919 920 if ((error = viapm_wait(viapm)) != SMB_ENOERR) 921 goto error; 922 923 len = VIAPM_INB(SMBHDATA0); 924 i = VIAPM_INB(SMBHCTRL); /* reset counter */ 925 926 /* read the 32-byte internal buffer */ 927 for (i = 0; i < len; i++) { 928 data = VIAPM_INB(SMBHBLOCK); 929 if (i < *count) 930 buf[i] = data; 931 DELAY(2); 932 } 933 *count = len; 934 935error: 936 VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 937 VIAPM_UNLOCK(viapm); 938 939 return (error); 940} 941 942static device_method_t viapm_methods[] = { 943 /* device interface */ 944 DEVMETHOD(device_probe, viapm_586b_probe), 945 DEVMETHOD(device_attach, viapm_586b_attach), 946 DEVMETHOD(device_detach, viapm_586b_detach), 947 948 /* iicbb interface */ 949 DEVMETHOD(iicbb_callback, viabb_callback), 950 DEVMETHOD(iicbb_setscl, viabb_setscl), 951 DEVMETHOD(iicbb_setsda, viabb_setsda), 952 DEVMETHOD(iicbb_getscl, viabb_getscl), 953 DEVMETHOD(iicbb_getsda, viabb_getsda), 954 DEVMETHOD(iicbb_reset, viabb_reset), 955 956 /* Bus interface */ 957 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 958 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 959 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 960 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 961 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 962 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 963 964 DEVMETHOD_END 965}; 966 967static driver_t viapm_driver = { 968 "viapm", 969 viapm_methods, 970 sizeof(struct viapm_softc), 971}; 972 973static device_method_t viapropm_methods[] = { 974 /* device interface */ 975 DEVMETHOD(device_probe, viapm_pro_probe), 976 DEVMETHOD(device_attach, viapm_pro_attach), 977 DEVMETHOD(device_detach, viapm_pro_detach), 978 979 /* smbus interface */ 980 DEVMETHOD(smbus_callback, viasmb_callback), 981 DEVMETHOD(smbus_quick, viasmb_quick), 982 DEVMETHOD(smbus_sendb, viasmb_sendb), 983 DEVMETHOD(smbus_recvb, viasmb_recvb), 984 DEVMETHOD(smbus_writeb, viasmb_writeb), 985 DEVMETHOD(smbus_readb, viasmb_readb), 986 DEVMETHOD(smbus_writew, viasmb_writew), 987 DEVMETHOD(smbus_readw, viasmb_readw), 988 DEVMETHOD(smbus_bwrite, viasmb_bwrite), 989 DEVMETHOD(smbus_bread, viasmb_bread), 990 991 /* Bus interface */ 992 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 993 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 994 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 995 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 996 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 997 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 998 999 DEVMETHOD_END 1000}; 1001 1002static driver_t viapropm_driver = { 1003 "viapropm", 1004 viapropm_methods, 1005 sizeof(struct viapm_softc), 1006}; 1007 1008DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); 1009DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); 1010DRIVER_MODULE(iicbb, viapm, iicbb_driver, iicbb_devclass, 0, 0); 1011DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0); 1012 1013MODULE_DEPEND(viapm, pci, 1, 1, 1); 1014MODULE_DEPEND(viapropm, pci, 1, 1, 1); 1015MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); 1016MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 1017MODULE_VERSION(viapm, 1); 1018 1019#ifdef DEV_ISA 1020DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0); 1021DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0); 1022MODULE_DEPEND(viapm, isa, 1, 1, 1); 1023MODULE_DEPEND(viapropm, isa, 1, 1, 1); 1024#endif 1025