2701 lines
79 KiB
C
2701 lines
79 KiB
C
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* ACPI emulation.
|
|
*
|
|
*
|
|
*
|
|
* Authors: Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2020 Miran Grca.
|
|
*/
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <stdbool.h>
|
|
#define HAVE_STDARG_H
|
|
#include <86box/86box.h>
|
|
#include "cpu.h"
|
|
#include <86box/device.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/io.h>
|
|
#include <86box/pci.h>
|
|
#include <86box/pic.h>
|
|
#include <86box/plat.h>
|
|
#include <86box/timer.h>
|
|
#include <86box/keyboard.h>
|
|
#include <86box/nvr.h>
|
|
#include <86box/pit.h>
|
|
#include <86box/apm.h>
|
|
#include <86box/acpi.h>
|
|
#include <86box/dma.h>
|
|
#include <86box/machine.h>
|
|
#include <86box/i2c.h>
|
|
#include <86box/video.h>
|
|
#include <86box/smbus.h>
|
|
#include <86box/hdc_ide.h>
|
|
#include <86box/hdc_ide_sff8038i.h>
|
|
#include <86box/sis_55xx.h>
|
|
|
|
int acpi_rtc_status = 0;
|
|
atomic_int acpi_pwrbut_pressed = 0;
|
|
int acpi_enabled = 0;
|
|
|
|
static double cpu_to_acpi;
|
|
|
|
static int acpi_power_on = 0;
|
|
static uint64_t acpi_last_clock = 0ULL;
|
|
static int acpi_count = 0;
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
int acpi_do_log = ENABLE_ACPI_LOG;
|
|
|
|
static void
|
|
acpi_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (acpi_do_log) {
|
|
va_start(ap, fmt);
|
|
pclog_ex(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#else
|
|
# define acpi_log(fmt, ...)
|
|
#endif
|
|
|
|
static uint64_t
|
|
acpi_clock_get(void)
|
|
{
|
|
return tsc * cpu_to_acpi;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_timer_get(acpi_t *dev)
|
|
{
|
|
uint64_t clock = acpi_clock_get();
|
|
if (dev->regs.timer32)
|
|
return clock & 0xffffffff;
|
|
else
|
|
return clock & 0xffffff;
|
|
}
|
|
|
|
static uint8_t
|
|
acpi_gp_timer_get(UNUSED(acpi_t *dev))
|
|
{
|
|
uint64_t clock = acpi_clock_get();
|
|
clock -= acpi_last_clock;
|
|
if (clock >= acpi_count)
|
|
clock = 0x00;
|
|
else
|
|
clock &= 0xff;
|
|
return clock;
|
|
}
|
|
|
|
static double
|
|
acpi_get_overflow_period(acpi_t *dev)
|
|
{
|
|
uint64_t timer = acpi_clock_get();
|
|
uint64_t overflow_time;
|
|
|
|
if (dev->regs.timer32)
|
|
overflow_time = (timer + 0x80000000LL) & ~0x7fffffffLL;
|
|
else
|
|
overflow_time = (timer + 0x800000LL) & ~0x7fffffLL;
|
|
|
|
uint64_t time_to_overflow = overflow_time - timer;
|
|
|
|
return ((double) time_to_overflow / (double) ACPI_TIMER_FREQ) * 1000000.0;
|
|
}
|
|
|
|
static void
|
|
acpi_timer_update(acpi_t *dev, bool enable)
|
|
{
|
|
if (enable)
|
|
timer_on_auto(&dev->timer, acpi_get_overflow_period(dev));
|
|
else
|
|
timer_stop(&dev->timer);
|
|
}
|
|
|
|
static void
|
|
acpi_timer_overflow(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
dev->regs.pmsts |= TMROF_STS;
|
|
acpi_update_irq(dev);
|
|
acpi_timer_update(dev, (dev->regs.pmen & TMROF_EN) && !(dev->regs.pmsts & TMROF_STS));
|
|
}
|
|
|
|
static void
|
|
acpi_gp_timer_update(acpi_t *dev, bool enable, int count)
|
|
{
|
|
if (enable) {
|
|
acpi_last_clock = acpi_clock_get();
|
|
acpi_count = count;
|
|
timer_on_auto(&dev->gp_timer, (1000000.0 / (double) ACPI_TIMER_FREQ) * ((double) count));
|
|
} else
|
|
timer_stop(&dev->timer);
|
|
}
|
|
|
|
void
|
|
acpi_sis5595_smi_raise(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
if (dev->regs.leg_en & 0x20) {
|
|
dev->regs.leg_sts |= 0x20;
|
|
smi_raise();
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_gp_timer(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
if (dev->vendor == VEN_SIS_5595_1997) {
|
|
dev->regs.gpe_sts |= 0x20000000;
|
|
dev->regs.leg_sts |= 0x20;
|
|
acpi_gp_timer_update(dev, (dev->regs.gpe_en & 0x20000000), acpi_count);
|
|
acpi_sis5595_smi_raise(dev);
|
|
} else if (dev->vendor == VEN_SIS_5595) {
|
|
dev->regs.gpe_sts |= 0x00000400;
|
|
dev->regs.leg_sts |= 0x20;
|
|
acpi_gp_timer_update(dev, (dev->regs.gpe_en & 0x00000400), acpi_count);
|
|
acpi_sis5595_smi_raise(dev);
|
|
} else {
|
|
dev->regs.reg_14 |= 0x2000;
|
|
acpi_gp_timer_update(dev, (dev->regs.reg_16 & 0x2000), acpi_count);
|
|
smi_raise();
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_per_timer(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
if (dev->vendor >= VEN_SIS_5595_1997) {
|
|
dev->regs.leg_sts |= 0x04;
|
|
acpi_sis5595_smi_raise(dev);
|
|
} else {
|
|
dev->regs.reg_25 |= 0x04;
|
|
smi_raise();
|
|
}
|
|
timer_on_auto(&dev->per_timer, 16000000.0);
|
|
}
|
|
|
|
void
|
|
acpi_update_irq(acpi_t *dev)
|
|
{
|
|
int sci_level = (dev->regs.pmsts & dev->regs.pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN);
|
|
sis_55xx_common_t *sis = (sis_55xx_common_t *) dev->priv;
|
|
|
|
switch (dev->vendor) {
|
|
case VEN_SMC:
|
|
sci_level |= (dev->regs.pmsts & BM_STS);
|
|
break;
|
|
case VEN_SIS_5595_1997:
|
|
case VEN_SIS_5595:
|
|
if ((sis != NULL) && (sis->pmu_regs != NULL)) {
|
|
sci_level |= (sis->pmu_regs[0x80] | sis->pmu_regs[0x81] |
|
|
sis->pmu_regs[0x82] | sis->pmu_regs[0x83]);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ((dev->regs.pmcntrl & 0x01) && sci_level) switch (dev->irq_mode) {
|
|
default:
|
|
if (dev->irq_line != 0)
|
|
picintlevel(1 << dev->irq_line, &dev->irq_state);
|
|
else
|
|
dev->irq_state = 1;
|
|
break;
|
|
case 1:
|
|
pci_set_irq(dev->slot, dev->irq_pin, &dev->irq_state);
|
|
break;
|
|
case 2:
|
|
pci_set_mirq(5, dev->mirq_is_level, &dev->irq_state);
|
|
break;
|
|
case -1:
|
|
break;
|
|
} else switch (dev->irq_mode) {
|
|
default:
|
|
if (dev->irq_line != 0)
|
|
picintclevel(1 << dev->irq_line, &dev->irq_state);
|
|
else
|
|
dev->irq_state = 0;
|
|
break;
|
|
case 1:
|
|
pci_clear_irq(dev->slot, dev->irq_pin, &dev->irq_state);
|
|
break;
|
|
case 2:
|
|
pci_clear_mirq(5, dev->mirq_is_level, &dev->irq_state);
|
|
break;
|
|
case -1:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_raise_smi(void *priv, int do_smi)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->regs.glbctl & 0x01) {
|
|
if ((dev->vendor == VEN_VIA) || (dev->vendor == VEN_VIA_596B)) {
|
|
if (!dev->regs.smi_lock || !dev->regs.smi_active) {
|
|
if (do_smi)
|
|
smi_raise();
|
|
dev->regs.smi_active = 1;
|
|
}
|
|
} else if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) {
|
|
if (do_smi)
|
|
smi_raise();
|
|
/* Clear bit 16 of GLBCTL. */
|
|
if (dev->vendor == VEN_INTEL)
|
|
dev->regs.glbctl &= ~0x00010000;
|
|
else
|
|
dev->regs.ali_soft_smi = 1;
|
|
} else if (dev->vendor == VEN_SMC) {
|
|
if (do_smi)
|
|
smi_raise();
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_common_regs(UNUSED(int size), uint16_t addr, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x00:
|
|
case 0x01:
|
|
/* PMSTS - Power Management Status Register (IO) */
|
|
ret = (dev->regs.pmsts >> shift16) & 0xff;
|
|
if (addr == 0x01)
|
|
ret |= (acpi_rtc_status << 2);
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
/* PMEN - Power Management Resume Enable Register (IO) */
|
|
ret = (dev->regs.pmen >> shift16) & 0xff;
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
/* PMCNTRL - Power Management Control Register (IO) */
|
|
ret = (dev->regs.pmcntrl >> shift16) & 0xff;
|
|
if (addr == 0x05)
|
|
ret = (ret & 0xdf); /* Bit 5 is write-only. */
|
|
break;
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
/* PMTMR - Power Management Timer Register (IO) */
|
|
ret = (acpi_timer_get(dev) >> shift32) & 0xff;
|
|
#ifdef USE_DYNAREC
|
|
if (cpu_use_dynarec)
|
|
update_tsc();
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_ali(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
ret = (dev->regs.pcntrl >> shift16) & 0xff;
|
|
break;
|
|
case 0x14:
|
|
/* LVL2 - Processor Level 2 Register */
|
|
ret = dev->regs.plvl2;
|
|
break;
|
|
case 0x15:
|
|
/* LVL3 - Processor Level 3 Register */
|
|
ret = dev->regs.plvl3;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
/* GPE0_STS - General Purpose Event0 Status Register */
|
|
ret = (dev->regs.gpsts >> shift16) & 0xff;
|
|
break;
|
|
case 0x1a:
|
|
case 0x1b:
|
|
/* GPE0_EN - General Purpose Event0 Enable Register */
|
|
ret = (dev->regs.gpen >> shift16) & 0xff;
|
|
break;
|
|
case 0x1d:
|
|
case 0x1c:
|
|
/* GPE1_STS - General Purpose Event1 Status Register */
|
|
ret = (dev->regs.gpsts1 >> shift16) & 0xff;
|
|
break;
|
|
case 0x1f:
|
|
case 0x1e:
|
|
/* GPE1_EN - General Purpose Event1 Enable Register */
|
|
ret = (dev->regs.gpen1 >> shift16) & 0xff;
|
|
break;
|
|
case 0x20 ... 0x27:
|
|
/* GPE1_CTL - General Purpose Event1 Control Register */
|
|
ret = (dev->regs.gpcntrl >> shift32) & 0xff;
|
|
break;
|
|
case 0x30:
|
|
/* PM2_CNTRL - Power Management 2 Control Register( */
|
|
ret = dev->regs.pmcntrl;
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_intel(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
/* GPSTS - General Purpose Status Register (IO) */
|
|
ret = (dev->regs.gpsts >> shift16) & 0xff;
|
|
break;
|
|
case 0x0e:
|
|
case 0x0f:
|
|
/* GPEN - General Purpose Enable Register (IO) */
|
|
ret = (dev->regs.gpen >> shift16) & 0xff;
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
ret = (dev->regs.pcntrl >> shift32) & 0xff;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
/* GLBSTS - Global Status Register (IO) */
|
|
ret = (dev->regs.glbsts >> shift16) & 0xff;
|
|
if (addr == 0x18) {
|
|
ret &= 0x27;
|
|
if (dev->regs.gpsts != 0x0000)
|
|
ret |= 0x80;
|
|
if (dev->regs.pmsts != 0x0000)
|
|
ret |= 0x40;
|
|
if (dev->regs.devsts != 0x00000000)
|
|
ret |= 0x10;
|
|
}
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
/* DEVSTS - Device Status Register (IO) */
|
|
ret = (dev->regs.devsts >> shift32) & 0xff;
|
|
break;
|
|
case 0x20:
|
|
case 0x21:
|
|
/* GLBEN - Global Enable Register (IO) */
|
|
ret = (dev->regs.glben >> shift16) & 0xff;
|
|
break;
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
/* GLBCTL - Global Control Register (IO) */
|
|
ret = (dev->regs.glbctl >> shift32) & 0xff;
|
|
break;
|
|
case 0x2c:
|
|
case 0x2d:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
/* DEVCTL - Device Control Register (IO) */
|
|
ret = (dev->regs.devctl >> shift32) & 0xff;
|
|
break;
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
/* GPIREG - General Purpose Input Register (IO) */
|
|
if (size == 1)
|
|
ret = dev->regs.gpireg[addr & 3];
|
|
break;
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
/* GPOREG - General Purpose Output Register (IO) */
|
|
if (size == 1)
|
|
ret = dev->regs.gporeg[addr & 3];
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
// if (size != 1)
|
|
// acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_via_common(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0xff;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
ret = (dev->regs.pcntrl >> shift32) & 0xff;
|
|
break;
|
|
case 0x20:
|
|
case 0x21:
|
|
/* GPSTS - General Purpose Status Register (IO) */
|
|
ret = (dev->regs.gpsts >> shift16) & 0xff;
|
|
break;
|
|
case 0x22:
|
|
case 0x23:
|
|
/* General Purpose SCI Enable */
|
|
ret = (dev->regs.gpscien >> shift16) & 0xff;
|
|
break;
|
|
case 0x24:
|
|
case 0x25:
|
|
/* General Purpose SMI Enable */
|
|
ret = (dev->regs.gpsmien >> shift16) & 0xff;
|
|
break;
|
|
case 0x26:
|
|
case 0x27:
|
|
/* Power Supply Control */
|
|
ret = (dev->regs.pscntrl >> shift16) & 0xff;
|
|
break;
|
|
case 0x28:
|
|
case 0x29:
|
|
/* GLBSTS - Global Status Register (IO) */
|
|
ret = (dev->regs.glbsts >> shift16) & 0xff;
|
|
break;
|
|
case 0x2a:
|
|
case 0x2b:
|
|
/* GLBEN - Global Enable Register (IO) */
|
|
ret = (dev->regs.glben >> shift16) & 0xff;
|
|
break;
|
|
case 0x2c:
|
|
case 0x2d:
|
|
/* GLBCTL - Global Control Register (IO) */
|
|
ret = (dev->regs.glbctl >> shift16) & 0xff;
|
|
ret &= ~0x0110;
|
|
ret |= (dev->regs.smi_lock ? 0x10 : 0x00);
|
|
ret |= (dev->regs.smi_active ? 0x01 : 0x00);
|
|
break;
|
|
case 0x2f:
|
|
/* SMI Command */
|
|
if (size == 1)
|
|
ret = dev->regs.smicmd & 0xff;
|
|
break;
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
/* Primary Activity Detect Status */
|
|
ret = (dev->regs.padsts >> shift32) & 0xff;
|
|
break;
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
/* Primary Activity Detect Enable */
|
|
ret = (dev->regs.paden >> shift32) & 0xff;
|
|
break;
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3a:
|
|
case 0x3b:
|
|
/* GP Timer Reload Enable */
|
|
ret = (dev->regs.gptren >> shift32) & 0xff;
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_via(int size, uint16_t addr, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
|
|
addr &= 0xff;
|
|
shift16 = (addr & 1) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x40:
|
|
/* GPIO Direction Control */
|
|
if (size == 1)
|
|
ret = dev->regs.gpio_dir & 0xff;
|
|
break;
|
|
case 0x42:
|
|
/* GPIO port Output Value */
|
|
if (size == 1)
|
|
ret = dev->regs.gpio_val & 0x13;
|
|
break;
|
|
case 0x44:
|
|
/* GPIO port Input Value */
|
|
if (size == 1) {
|
|
ret = dev->regs.extsmi_val & 0xff;
|
|
|
|
if (dev->i2c) {
|
|
ret &= 0xf9;
|
|
if (!(dev->regs.gpio_dir & 0x02) && i2c_gpio_get_scl(dev->i2c))
|
|
ret |= 0x02;
|
|
if (!(dev->regs.gpio_dir & 0x04) && i2c_gpio_get_sda(dev->i2c))
|
|
ret |= 0x04;
|
|
}
|
|
}
|
|
break;
|
|
case 0x46:
|
|
case 0x47:
|
|
/* GPO Port Output Value */
|
|
ret = (dev->regs.gpo_val >> shift16) & 0xff;
|
|
break;
|
|
case 0x48:
|
|
case 0x49:
|
|
/* GPO Port Input Value */
|
|
ret = (dev->regs.gpi_val >> shift16) & 0xff;
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_via_common(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_via_596b(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x7f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x40: /* Extended I/O Trap Status (686A/B) */
|
|
ret = dev->regs.extiotrapsts;
|
|
break;
|
|
case 0x42: /* Extended I/O Trap Enable (686A/B) */
|
|
ret = dev->regs.extiotrapen;
|
|
break;
|
|
case 0x44:
|
|
case 0x45:
|
|
/* External SMI Input Value */
|
|
ret = (dev->regs.extsmi_val >> shift16) & 0xff;
|
|
break;
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4a:
|
|
case 0x4b:
|
|
/* GPI Port Input Value */
|
|
ret = (dev->regs.gpi_val >> shift32) & 0xff;
|
|
break;
|
|
case 0x4c:
|
|
case 0x4d:
|
|
case 0x4e:
|
|
case 0x4f:
|
|
/* GPO Port Output Value */
|
|
ret = (dev->regs.gpo_val >> shift32) & 0xff;
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_via_common(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_smc(int size, uint16_t addr, void *priv)
|
|
{
|
|
uint32_t ret = 0x00000000;
|
|
|
|
addr &= 0x0f;
|
|
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_aux_reg_read_smc(UNUSED(int size), uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
|
|
addr &= 0x07;
|
|
shift16 = (addr & 1) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x00:
|
|
case 0x01:
|
|
/* SCI Status Register */
|
|
ret = (dev->regs.pcntrl >> shift16) & 0xff;
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
/* SCI Enable Register */
|
|
ret = (dev->regs.gpscien >> shift16) & 0xff;
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
/* Miscellaneous Status Register */
|
|
ret = (dev->regs.glbsts >> shift16) & 0xff;
|
|
break;
|
|
case 0x06:
|
|
/* Miscellaneous Enable Register */
|
|
ret = dev->regs.glben & 0xff;
|
|
break;
|
|
case 0x07:
|
|
/* Miscellaneous Control Register */
|
|
ret = dev->regs.glbctl & 0xff;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_sis_5582(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
ret = (dev->regs.reg_0c >> shift32) & 0xff;
|
|
break;
|
|
case 0x10:
|
|
ret = dev->regs.enter_c2_ps;
|
|
break;
|
|
case 0x11:
|
|
ret = dev->regs.enter_c3_ps;
|
|
break;
|
|
case 0x12:
|
|
ret = dev->regs.reg_12;
|
|
break;
|
|
case 0x13:
|
|
ret = acpi_gp_timer_get((acpi_t *) dev) & 0xff;
|
|
#ifdef USE_DYNAREC
|
|
if (cpu_use_dynarec)
|
|
update_tsc();
|
|
#endif
|
|
break;
|
|
case 0x14:
|
|
case 0x15:
|
|
ret = (dev->regs.reg_14 >> shift16) & 0xff;
|
|
break;
|
|
case 0x16:
|
|
case 0x17:
|
|
ret = (dev->regs.reg_16 >> shift16) & 0xff;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
ret = (dev->regs.reg_18 >> shift16) & 0xff;
|
|
break;
|
|
case 0x1a:
|
|
case 0x1b:
|
|
ret = (dev->regs.reg_18 >> shift16) & 0xff;
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
ret = (dev->regs.reg_1c >> shift16) & 0xff;
|
|
break;
|
|
case 0x20:
|
|
ret = dev->regs.smi_cmd;
|
|
break;
|
|
case 0x24:
|
|
ret = dev->regs.reg_24;
|
|
break;
|
|
case 0x25:
|
|
ret = dev->regs.reg_25;
|
|
break;
|
|
case 0x26:
|
|
ret = dev->regs.reg_26;
|
|
break;
|
|
case 0x28:
|
|
ret = dev->regs.smi_en_val;
|
|
break;
|
|
case 0x29:
|
|
ret = dev->regs.smi_dis_val;
|
|
break;
|
|
case 0x2a:
|
|
ret = dev->regs.mail_box;
|
|
break;
|
|
case 0x2b:
|
|
ret = dev->regs.reg_2b;
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
// if (size != 1)
|
|
// acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_sis_5595(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint32_t ret = 0x00000000;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
ret = (dev->regs.reg_0c >> shift32) & 0xff;
|
|
break;
|
|
case 0x10:
|
|
ret = dev->regs.enter_c2_ps;
|
|
break;
|
|
case 0x11:
|
|
ret = dev->regs.enter_c3_ps;
|
|
break;
|
|
case 0x12:
|
|
ret = dev->regs.reg_12;
|
|
break;
|
|
case 0x13:
|
|
ret = dev->regs.reg_13;
|
|
break;
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
ret = (dev->regs.gpe_sts >> shift32) & 0xff;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
ret = (dev->regs.gpe_en >> shift32) & 0xff;
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
ret = (dev->regs.gpe_pin >> shift32) & 0xff;
|
|
break;
|
|
case 0x1f:
|
|
ret = acpi_gp_timer_get((acpi_t *) dev) & 0xff;
|
|
#ifdef USE_DYNAREC
|
|
if (cpu_use_dynarec)
|
|
update_tsc();
|
|
#endif
|
|
break;
|
|
case 0x20:
|
|
case 0x21:
|
|
case 0x22:
|
|
case 0x23:
|
|
ret = (dev->regs.gpe_io >> shift32) & 0xff;
|
|
break;
|
|
case 0x24:
|
|
case 0x25:
|
|
case 0x26:
|
|
case 0x27:
|
|
ret = (dev->regs.gpe_pol >> shift32) & 0xff;
|
|
break;
|
|
case 0x28:
|
|
case 0x29:
|
|
ret = (dev->regs.gpe_mul >> shift16) & 0xff;
|
|
break;
|
|
case 0x2a:
|
|
case 0x2b:
|
|
ret = (dev->regs.gpe_ctl >> shift16) & 0xff;
|
|
break;
|
|
case 0x2c:
|
|
case 0x2d:
|
|
ret = (dev->regs.gpe_smi >> shift16) & 0xff;
|
|
break;
|
|
case 0x2e:
|
|
case 0x2f:
|
|
ret = (dev->regs.gpe_rl >> shift16) & 0xff;
|
|
break;
|
|
case 0x30:
|
|
ret = dev->regs.leg_sts;
|
|
break;
|
|
case 0x31:
|
|
ret = dev->regs.leg_en;
|
|
break;
|
|
case 0x32:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
ret = dev->regs.smi_cmd;
|
|
else
|
|
ret = 0x00;
|
|
break;
|
|
case 0x33:
|
|
ret = dev->regs.tst_ctl;
|
|
break;
|
|
case 0x34:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
ret = dev->regs.smi_en_val;
|
|
else
|
|
ret = dev->regs.reg_34;
|
|
break;
|
|
case 0x35:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
ret = dev->regs.smi_dis_val;
|
|
else
|
|
ret = dev->regs.smi_cmd;
|
|
break;
|
|
case 0x36:
|
|
ret = dev->regs.mail_box;
|
|
break;
|
|
case 0x38:
|
|
if (dev->vendor == VEN_SIS_5595)
|
|
ret = smbus_sis5595_read_index(dev->smbus);
|
|
break;
|
|
case 0x39:
|
|
if (dev->vendor == VEN_SIS_5595)
|
|
ret = smbus_sis5595_read_data(dev->smbus);
|
|
break;
|
|
default:
|
|
ret = acpi_reg_read_common_regs(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
#ifdef ENABLE_ACPI_LOG
|
|
// if (size != 1)
|
|
// acpi_log("(%i) ACPI Read (%i) %02X: %02X\n", in_smm, size, addr, ret);
|
|
#endif
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_common_regs(UNUSED(int size), uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int sus_typ;
|
|
uint8_t old;
|
|
|
|
addr &= 0x3f;
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
#endif
|
|
shift16 = (addr & 1) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x00:
|
|
case 0x01:
|
|
/* PMSTS - Power Management Status Register (IO) */
|
|
dev->regs.pmsts &= ~((val << shift16) & 0x8d31);
|
|
if ((addr == 0x01) && (val & 0x04))
|
|
acpi_rtc_status = 0;
|
|
acpi_update_irq(dev);
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
/* PMEN - Power Management Resume Enable Register (IO) */
|
|
dev->regs.pmen = ((dev->regs.pmen & ~(0xff << shift16)) | (val << shift16)) & 0x0521;
|
|
acpi_update_irq(dev);
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
/* PMCNTRL - Power Management Control Register (IO) */
|
|
old = dev->regs.pmcntrl & 0xff;
|
|
if ((addr == 0x05) && (val & 0x20)) {
|
|
sus_typ = dev->suspend_types[(val >> 2) & 7];
|
|
acpi_log("ACPI suspend type %d flags %02X\n", (val >> 2) & 7, sus_typ);
|
|
|
|
if (sus_typ & SUS_POWER_OFF) {
|
|
/* Soft power off. */
|
|
plat_power_off();
|
|
return;
|
|
}
|
|
|
|
if (sus_typ & SUS_SUSPEND) {
|
|
if (sus_typ & SUS_NVR) {
|
|
/* Suspend to RAM. */
|
|
nvr_reg_write(0x000f, 0xff, dev->nvr);
|
|
}
|
|
|
|
if (sus_typ & SUS_RESET_PCI) {
|
|
/* DMA is part of the southbridge so it responds to PCI reset. */
|
|
dma_reset();
|
|
dma_set_at(1);
|
|
|
|
device_reset_all(DEVICE_PCI);
|
|
}
|
|
|
|
if (sus_typ & SUS_RESET_CPU)
|
|
cpu_alt_reset = 0;
|
|
|
|
if (sus_typ & SUS_RESET_PCI) {
|
|
pci_reset();
|
|
|
|
mem_a20_alt = 0;
|
|
mem_a20_recalc();
|
|
}
|
|
|
|
if (sus_typ & (SUS_RESET_CPU | SUS_RESET_CACHE))
|
|
flushmmucache();
|
|
|
|
if (sus_typ & SUS_RESET_CPU)
|
|
resetx86();
|
|
|
|
/* Since the UI doesn't have a power button at the moment, pause emulation,
|
|
then trigger a resume event so that the system resumes after unpausing. */
|
|
plat_pause(2); /* 2 means do not wait for pause as
|
|
we're already in the CPU thread. */
|
|
timer_set_delay_u64(&dev->resume_timer, 50 * TIMER_USEC);
|
|
}
|
|
}
|
|
dev->regs.pmcntrl = ((dev->regs.pmcntrl & ~(0xff << shift16)) | (val << shift16)) & 0x3f07 /* 0x3c07 */;
|
|
if ((addr == 0x04) && ((old ^ val) & 0x01))
|
|
acpi_update_irq(dev);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_ali(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
#endif
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00023e1e;
|
|
break;
|
|
case 0x14:
|
|
/* LVL2 - Processor Level 2 Register */
|
|
dev->regs.plvl2 = val;
|
|
break;
|
|
case 0x15:
|
|
/* LVL3 - Processor Level 3 Register */
|
|
dev->regs.plvl3 = val;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
/* GPE0_STS - General Purpose Event0 Status Register */
|
|
dev->regs.gpsts &= ~((val << shift16) & 0x0d07);
|
|
break;
|
|
case 0x1a:
|
|
case 0x1b:
|
|
/* GPE0_EN - General Purpose Event0 Enable Register */
|
|
dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0d07;
|
|
break;
|
|
case 0x1d:
|
|
case 0x1c:
|
|
/* GPE1_STS - General Purpose Event1 Status Register */
|
|
dev->regs.gpsts1 &= ~((val << shift16) & 0x0c01);
|
|
break;
|
|
case 0x1f:
|
|
case 0x1e:
|
|
/* GPE1_EN - General Purpose Event1 Enable Register */
|
|
dev->regs.gpen1 = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0c01;
|
|
break;
|
|
case 0x20 ... 0x27:
|
|
/* GPE1_CTL - General Purpose Event1 Control Register */
|
|
dev->regs.gpcntrl = ((dev->regs.gpcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00000001;
|
|
break;
|
|
case 0x30:
|
|
/* PM2_CNTRL - Power Management 2 Control Register */
|
|
dev->regs.pmcntrl = val & 1;
|
|
break;
|
|
default:
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.gpcntrl &= ~0x0002;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.gpsts1 |= 0x01;
|
|
if (dev->regs.gpen1 & 0x01)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x3f;
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
#endif
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
/* GPSTS - General Purpose Status Register (IO) */
|
|
dev->regs.gpsts &= ~((val << shift16) & 0x0f81);
|
|
break;
|
|
case 0x0e:
|
|
case 0x0f:
|
|
/* GPEN - General Purpose Enable Register (IO) */
|
|
dev->regs.gpen = ((dev->regs.gpen & ~(0xff << shift16)) | (val << shift16)) & 0x0f01;
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x00023e1e;
|
|
break;
|
|
case 0x12:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xfd << shift32)) | (val << shift32)) & 0x00023e1e;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
/* GLBSTS - Global Status Register (IO) */
|
|
dev->regs.glbsts &= ~((val << shift16) & 0x0d27);
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f:
|
|
/* DEVSTS - Device Status Register (IO) */
|
|
dev->regs.devsts &= ~((val << shift32) & 0x3fff0fff);
|
|
break;
|
|
case 0x20:
|
|
case 0x21:
|
|
/* GLBEN - Global Enable Register (IO) */
|
|
dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x8d1f;
|
|
break;
|
|
case 0x28:
|
|
case 0x29:
|
|
case 0x2a:
|
|
case 0x2b:
|
|
/* GLBCTL - Global Control Register (IO) */
|
|
dev->regs.glbctl = ((dev->regs.glbctl & ~(0xff << shift32)) | (val << shift32)) & 0x0701ff07;
|
|
/* Setting BIOS_RLS also sets GBL_STS and generates SMI. */
|
|
if (dev->regs.glbctl & 0x00000002) {
|
|
dev->regs.pmsts |= 0x20;
|
|
if (dev->regs.pmen & 0x20)
|
|
acpi_update_irq(dev);
|
|
}
|
|
break;
|
|
case 0x2c:
|
|
case 0x2d:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
/* DEVCTL - Device Control Register (IO) */
|
|
dev->regs.devctl = ((dev->regs.devctl & ~(0xff << shift32)) | (val << shift32)) & 0x0fffffff;
|
|
if (dev->trap_update)
|
|
dev->trap_update(dev->trap_priv);
|
|
break;
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
/* GPOREG - General Purpose Output Register (IO) */
|
|
if (size == 1)
|
|
dev->regs.gporeg[addr & 3] = val;
|
|
break;
|
|
default:
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.glbctl &= ~0x0002;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.glbsts |= 0x01;
|
|
if (dev->regs.glben & 0x02)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0xff;
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
/* PCNTRL - Processor Control Register (IO) */
|
|
dev->regs.pcntrl = ((dev->regs.pcntrl & ~(0xff << shift32)) | (val << shift32)) & 0x0000001e;
|
|
break;
|
|
case 0x20:
|
|
case 0x21:
|
|
/* GPSTS - General Purpose Status Register (IO) */
|
|
dev->regs.gpsts &= ~((val << shift16) & 0x03ff);
|
|
break;
|
|
case 0x22:
|
|
case 0x23:
|
|
/* General Purpose SCI Enable */
|
|
dev->regs.gpscien = ((dev->regs.gpscien & ~(0xff << shift16)) | (val << shift16)) & 0x03ff;
|
|
break;
|
|
case 0x24:
|
|
case 0x25:
|
|
/* General Purpose SMI Enable */
|
|
dev->regs.gpsmien = ((dev->regs.gpsmien & ~(0xff << shift16)) | (val << shift16)) & 0x03ff;
|
|
break;
|
|
case 0x26:
|
|
case 0x27:
|
|
/* Power Supply Control */
|
|
dev->regs.pscntrl = ((dev->regs.pscntrl & ~(0xff << shift16)) | (val << shift16)) & 0x0701;
|
|
break;
|
|
case 0x2c:
|
|
/* GLBCTL - Global Control Register (IO) */
|
|
dev->regs.glbctl = (dev->regs.glbctl & ~0xff) | (val & 0xff);
|
|
dev->regs.smi_lock = !!(dev->regs.glbctl & 0x0010);
|
|
/* Setting BIOS_RLS also sets GBL_STS and generates SMI. */
|
|
if (dev->regs.glbctl & 0x0002) {
|
|
dev->regs.pmsts |= 0x20;
|
|
if (dev->regs.pmen & 0x20)
|
|
acpi_update_irq(dev);
|
|
}
|
|
break;
|
|
case 0x2d:
|
|
/* GLBCTL - Global Control Register (IO) */
|
|
dev->regs.glbctl &= ~((val << 8) & 0x0100);
|
|
if (val & 0x01)
|
|
dev->regs.smi_active = 0;
|
|
break;
|
|
case 0x2f:
|
|
/* SMI Command */
|
|
if (size == 1) {
|
|
dev->regs.smicmd = val & 0xff;
|
|
dev->regs.glbsts |= 0x40;
|
|
if (dev->regs.glben & 0x40)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
break;
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3a:
|
|
case 0x3b:
|
|
/* GP Timer Reload Enable */
|
|
dev->regs.gptren = ((dev->regs.gptren & ~(0xff << shift32)) | (val << shift32)) & 0x000000d9;
|
|
break;
|
|
default:
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.glbctl &= ~0x0002;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.glbsts |= 0x20;
|
|
if (dev->regs.glben & 0x20)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_i2c_set(acpi_t *dev)
|
|
{
|
|
if (dev->i2c)
|
|
i2c_gpio_set(dev->i2c, !(dev->regs.gpio_dir & 0x02) || (dev->regs.gpio_val & 0x02), !(dev->regs.gpio_dir & 0x04) || (dev->regs.gpio_val & 0x04));
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0xff;
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x28:
|
|
case 0x29:
|
|
/* GLBSTS - Global Status Register (IO) */
|
|
dev->regs.glbsts &= ~((val << shift16) & 0x007f);
|
|
break;
|
|
case 0x2a:
|
|
case 0x2b:
|
|
/* GLBEN - Global Enable Register (IO) */
|
|
dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x007f;
|
|
break;
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
/* Primary Activity Detect Status */
|
|
dev->regs.padsts &= ~((val << shift32) & 0x000000fd);
|
|
break;
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
/* Primary Activity Detect Enable */
|
|
dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000000fd;
|
|
if (dev->trap_update)
|
|
dev->trap_update(dev->trap_priv);
|
|
break;
|
|
case 0x40:
|
|
/* GPIO Direction Control */
|
|
if (size == 1) {
|
|
dev->regs.gpio_dir = val & 0x7f;
|
|
acpi_i2c_set(dev);
|
|
}
|
|
break;
|
|
case 0x42:
|
|
/* GPIO port Output Value */
|
|
if (size == 1) {
|
|
dev->regs.gpio_val = val & 0x13;
|
|
acpi_i2c_set(dev);
|
|
}
|
|
break;
|
|
case 0x46:
|
|
case 0x47:
|
|
/* GPO Port Output Value */
|
|
dev->regs.gpo_val = ((dev->regs.gpo_val & ~(0xff << shift16)) | (val << shift16)) & 0xffff;
|
|
break;
|
|
default:
|
|
acpi_reg_write_via_common(size, addr, val, priv);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_via_596b(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
|
|
addr &= 0x7f;
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x28:
|
|
case 0x29:
|
|
/* GLBSTS - Global Status Register (IO) */
|
|
dev->regs.glbsts &= ~((val << shift16) & 0xfdff);
|
|
break;
|
|
case 0x2a:
|
|
case 0x2b:
|
|
/* GLBEN - Global Enable Register (IO) */
|
|
dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0xfdff;
|
|
break;
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
/* Primary Activity Detect Status */
|
|
dev->regs.padsts &= ~((val << shift32) & 0x000007ff);
|
|
break;
|
|
case 0x34:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
/* Primary Activity Detect Enable */
|
|
dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000007ff;
|
|
if (dev->trap_update)
|
|
dev->trap_update(dev->trap_priv);
|
|
break;
|
|
case 0x40: /* Extended I/O Trap Status (686A/B) */
|
|
dev->regs.extiotrapsts &= ~(val & 0x13);
|
|
break;
|
|
case 0x42: /* Extended I/O Trap Enable (686A/B) */
|
|
dev->regs.extiotrapen = val & 0x13;
|
|
break;
|
|
case 0x4c:
|
|
case 0x4d:
|
|
case 0x4e:
|
|
case 0x4f:
|
|
/* GPO Port Output Value */
|
|
dev->regs.gpo_val = ((dev->regs.gpo_val & ~(0xff << shift32)) | (val << shift32)) & 0x7fffffff;
|
|
break;
|
|
default:
|
|
acpi_reg_write_via_common(size, addr, val, priv);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_smc(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
addr &= 0x0f;
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.glbctl &= ~0x0001;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.glbsts |= 0x01;
|
|
if (dev->regs.glben & 0x01)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_aux_reg_write_smc(UNUSED(int size), uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
|
|
addr &= 0x07;
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
shift16 = (addr & 1) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x00:
|
|
case 0x01:
|
|
/* SCI Status Register */
|
|
dev->regs.gpscists &= ~((val << shift16) & 0x000c);
|
|
break;
|
|
case 0x02:
|
|
case 0x03:
|
|
/* SCI Enable Register */
|
|
dev->regs.gpscien = ((dev->regs.gpscien & ~(0xff << shift16)) | (val << shift16)) & 0x3fff;
|
|
break;
|
|
case 0x04:
|
|
case 0x05:
|
|
/* Miscellanous Status Register */
|
|
dev->regs.glbsts &= ~((val << shift16) & 0x001f);
|
|
break;
|
|
case 0x06:
|
|
/* Miscellaneous Enable Register */
|
|
dev->regs.glben = (uint16_t) (val & 0x03);
|
|
break;
|
|
case 0x07:
|
|
/* Miscellaneous Control Register */
|
|
dev->regs.glbctl = (uint16_t) (val & 0x03);
|
|
/* Setting BIOS_RLS also sets GBL_STS and generates SMI. */
|
|
if (dev->regs.glbctl & 0x0001) {
|
|
dev->regs.pmsts |= 0x20;
|
|
if (dev->regs.pmen & 0x20)
|
|
acpi_update_irq(dev);
|
|
}
|
|
if (dev->regs.glbctl & 0x0002) {
|
|
dev->regs.pmsts |= 0x10;
|
|
if (dev->regs.pmcntrl & 0x02)
|
|
acpi_update_irq(dev);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_sis5582_pmu_event(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
dev->regs.reg_25 |= 0x02;
|
|
if (dev->regs.reg_26 & 0x02)
|
|
smi_raise();
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_sis_5582(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
uint8_t old;
|
|
|
|
addr &= 0x3f;
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
#endif
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
dev->regs.reg_0c &= ~((val << shift32) & 0x007e);
|
|
break;
|
|
case 0x10:
|
|
dev->regs.enter_c2_ps = val;
|
|
break;
|
|
case 0x11:
|
|
dev->regs.enter_c3_ps = val;
|
|
break;
|
|
case 0x12:
|
|
dev->regs.reg_12 = val & 0x01;
|
|
break;
|
|
case 0x13:
|
|
dev->regs.reg_13 = val;
|
|
acpi_gp_timer_update(dev, (val != 0x00) && (dev->regs.reg_16 & 0x2000), val);
|
|
break;
|
|
case 0x14:
|
|
case 0x15:
|
|
dev->regs.reg_14 &= ~((val << shift32) & 0xff9f);
|
|
break;
|
|
case 0x16:
|
|
case 0x17:
|
|
dev->regs.reg_16 = ((dev->regs.reg_16 & ~(0xff << shift16)) | (val << shift16)) & 0xff1f;
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
dev->regs.reg_18 = ((dev->regs.reg_18 & ~(0xff << shift16)) | (val << shift16)) & 0x07ff;
|
|
break;
|
|
case 0x1a:
|
|
case 0x1b:
|
|
dev->regs.reg_1a = ((dev->regs.reg_1a & ~(0xff << shift16)) | (val << shift16)) & 0x0387;
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
dev->regs.reg_1c = ((dev->regs.reg_1c & ~(0xff << shift16)) | (val << shift16)) & 0x3f7f;
|
|
/* Setting BIOS_RLS also sets GBL_STS and generates SMI. */
|
|
if (dev->regs.reg_1c & 0x0400) {
|
|
dev->regs.pmsts |= 0x20;
|
|
if (dev->regs.pmen & 0x20)
|
|
acpi_update_irq(dev);
|
|
}
|
|
break;
|
|
case 0x20:
|
|
/* SMI Command Port */
|
|
dev->regs.smi_cmd = val;
|
|
if (val == dev->regs.smi_en_val) {
|
|
dev->regs.reg_25 |= 0x08;
|
|
if (dev->regs.reg_26 & 0x08)
|
|
smi_raise();
|
|
} else if (val == dev->regs.smi_dis_val) {
|
|
dev->regs.reg_25 |= 0x10;
|
|
if (dev->regs.reg_26 & 0x10)
|
|
smi_raise();
|
|
}
|
|
break;
|
|
case 0x24:
|
|
dev->regs.reg_24 = val & 0x43;
|
|
break;
|
|
case 0x25:
|
|
dev->regs.reg_25 &= ~(val & 0x1f);
|
|
break;
|
|
case 0x26:
|
|
old = dev->regs.reg_26;
|
|
dev->regs.reg_26 = val & 0x3f;
|
|
if (!(old & 0x04) && (val & 0x04))
|
|
timer_on_auto(&dev->per_timer, 16000000.0);
|
|
else if ((old & 0x04) && !(val & 0x04))
|
|
timer_stop(&dev->per_timer);
|
|
break;
|
|
case 0x28:
|
|
dev->regs.smi_en_val = val;
|
|
break;
|
|
case 0x29:
|
|
dev->regs.smi_dis_val = val;
|
|
break;
|
|
case 0x2a:
|
|
dev->regs.mail_box = val;
|
|
break;
|
|
case 0x2b:
|
|
dev->regs.reg_2b = val & 0x01;
|
|
break;
|
|
default:
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.reg_1c &= ~0x0400;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.reg_25 |= 0x01;
|
|
if (dev->regs.reg_26 & 0x01)
|
|
acpi_raise_smi(dev, 1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_sis5595_pmu_event(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
acpi_sis5595_smi_raise(dev);
|
|
else if (dev->regs.gpe_en & 0x00001000) {
|
|
dev->regs.gpe_sts |= 0x00001000;
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_sis5595_smbus_event(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->regs.gpe_en & 0x00000800) {
|
|
dev->regs.gpe_sts |= 0x00000800;
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_sis5595_software_smi(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->regs.leg_en & 0x01) {
|
|
dev->regs.leg_sts |= 0x01;
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_sis_5595(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
int shift16;
|
|
int shift32;
|
|
uint8_t old;
|
|
uint8_t do_smi = 0;
|
|
|
|
addr &= 0x3f;
|
|
#ifdef ENABLE_ACPI_LOG
|
|
if (size != 1)
|
|
acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val);
|
|
#endif
|
|
shift16 = (addr & 1) << 3;
|
|
shift32 = (addr & 3) << 3;
|
|
|
|
switch (addr) {
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
dev->regs.reg_0c &= ~((val << shift32) & 0x001e);
|
|
break;
|
|
case 0x10:
|
|
dev->regs.enter_c2_ps = val;
|
|
break;
|
|
case 0x11:
|
|
dev->regs.enter_c3_ps = val;
|
|
break;
|
|
case 0x12:
|
|
dev->regs.reg_12 = val & 0x01;
|
|
break;
|
|
case 0x13:
|
|
dev->regs.reg_13 = val;
|
|
/* Setting BIOS_RLS also sets GBL_STS and generates SMI. */
|
|
if (dev->regs.reg_13 & 0x02) {
|
|
dev->regs.pmsts |= 0x20;
|
|
if (dev->regs.pmen & 0x20)
|
|
acpi_update_irq(dev);
|
|
}
|
|
break;
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
dev->regs.gpe_sts &= ~((val << shift32) & 0xff03ffbf);
|
|
else
|
|
dev->regs.gpe_sts &= ~((val << shift32) & 0xff83ffff);
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
dev->regs.gpe_en = ((dev->regs.gpe_en & ~(0xff << shift32)) | (val << shift32));
|
|
else
|
|
dev->regs.gpe_en = ((dev->regs.gpe_en & ~(0xff << shift32)) |
|
|
(val << shift32)) & 0xff83ffff;
|
|
break;
|
|
case 0x1c:
|
|
dev->regs.gpe_pin = ((dev->regs.gpe_pin & ~(0xff << shift32)) | ((val & 0xff) << shift32));
|
|
if (!strcmp(machine_get_internal_name(), "m747") && (val & 0x10) &&
|
|
!(dev->regs.gpe_io & 0x00000010))
|
|
resetx86();
|
|
break;
|
|
case 0x1d:
|
|
dev->regs.gpe_pin = ((dev->regs.gpe_pin & ~(0x0f << shift32)) | ((val & 0x0f) << shift32));
|
|
break;
|
|
case 0x1e:
|
|
dev->regs.gpe_pin = ((dev->regs.gpe_pin & ~(0x03 << shift32)) | ((val & 0x03) << shift32));
|
|
break;
|
|
case 0x1f:
|
|
dev->regs.gp_tmr = val;
|
|
acpi_gp_timer_update(dev, (val != 0x00) && (dev->regs.gpe_en & 0x00000400), val);
|
|
break;
|
|
case 0x20:
|
|
dev->regs.gpe_io = ((dev->regs.gpe_io & ~(0x9f << shift32)) | ((val & 0x9f) << shift32));
|
|
break;
|
|
case 0x21:
|
|
dev->regs.gpe_io = ((dev->regs.gpe_io & ~(0x0f << shift32)) | ((val & 0x0f) << shift32));
|
|
break;
|
|
case 0x22:
|
|
dev->regs.gpe_io = ((dev->regs.gpe_io & ~(0x03 << shift32)) | ((val & 0x03) << shift32));
|
|
break;
|
|
case 0x24:
|
|
dev->regs.gpe_pol = ((dev->regs.gpe_pol & ~(0xbf << shift32)) | ((val & 0xbf) << shift32));
|
|
break;
|
|
case 0x25:
|
|
dev->regs.gpe_pol = ((dev->regs.gpe_pol & ~(0x0f << shift32)) | ((val & 0x0f) << shift32));
|
|
break;
|
|
case 0x26:
|
|
dev->regs.gpe_pol = ((dev->regs.gpe_pol & ~(0x03 << shift32)) | ((val & 0x03) << shift32));
|
|
break;
|
|
case 0x27:
|
|
dev->regs.gpe_pol = ((dev->regs.gpe_pol & ~(0x10 << shift32)) | ((val & 0x10) << shift32));
|
|
break;
|
|
case 0x28:
|
|
dev->regs.gpe_mul = ((dev->regs.gpe_mul & ~(0xf9 << shift16)) | ((val & 0xf9) << shift16));
|
|
break;
|
|
case 0x29:
|
|
dev->regs.gpe_mul = ((dev->regs.gpe_mul & ~(0x13 << shift16)) | ((val & 0x13) << shift16));
|
|
break;
|
|
case 0x2a:
|
|
case 0x2b:
|
|
dev->regs.gpe_ctl = ((dev->regs.gpe_ctl & ~(0xff << shift16)) | ((val & 0xff) << shift16));
|
|
break;
|
|
case 0x2c:
|
|
case 0x2d:
|
|
dev->regs.gpe_smi = ((dev->regs.gpe_smi & ~(0xff << shift16)) | ((val & 0xff) << shift16));
|
|
break;
|
|
case 0x2e:
|
|
case 0x2f:
|
|
dev->regs.gpe_rl = ((dev->regs.gpe_rl & ~(0xff << shift16)) | ((val & 0xff) << shift16));
|
|
break;
|
|
case 0x30:
|
|
dev->regs.leg_sts &= ~val;
|
|
break;
|
|
case 0x31:
|
|
old = dev->regs.leg_en;
|
|
dev->regs.leg_en = val;
|
|
if (!(old & 0x04) && (val & 0x04))
|
|
timer_on_auto(&dev->per_timer, 16000000.0);
|
|
else if ((old & 0x04) && !(val & 0x04))
|
|
timer_stop(&dev->per_timer);
|
|
break;
|
|
case 0x32:
|
|
if (dev->vendor == VEN_SIS_5595_1997) {
|
|
/* SMI Command Port */
|
|
dev->regs.smi_cmd = val;
|
|
if (val == dev->regs.smi_en_val) {
|
|
dev->regs.leg_sts |= 0x08;
|
|
if (dev->regs.leg_en & 0x08)
|
|
acpi_sis5595_smi_raise(dev);
|
|
} else if (val == dev->regs.smi_dis_val) {
|
|
dev->regs.leg_sts |= 0x10;
|
|
if (dev->regs.leg_en & 0x10)
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
}
|
|
break;
|
|
case 0x33:
|
|
dev->regs.tst_ctl = val & 0x01;
|
|
break;
|
|
case 0x34:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
dev->regs.smi_en_val = val;
|
|
else
|
|
dev->regs.reg_34 = val;
|
|
break;
|
|
case 0x35:
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
dev->regs.smi_dis_val = val;
|
|
else {
|
|
/* SMI Command Port */
|
|
dev->regs.smi_cmd = val;
|
|
dev->regs.leg_sts |= 0x10;
|
|
if (dev->regs.leg_en & 0x10)
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
break;
|
|
case 0x36:
|
|
dev->regs.mail_box = val;
|
|
break;
|
|
case 0x38:
|
|
if (dev->vendor == VEN_SIS_5595) {
|
|
dev->regs.index = val;
|
|
smbus_sis5595_write_index(dev->smbus, val);
|
|
}
|
|
break;
|
|
case 0x39:
|
|
if (dev->vendor == VEN_SIS_5595) {
|
|
dev->regs.reg_ff = val & 0x3f;
|
|
smbus_sis5595_write_data(dev->smbus, val);
|
|
if (val & 0x20) { /* Set GPIO5_STS of GPE_STS */
|
|
dev->regs.gpe_sts |= 0x00000008;
|
|
do_smi |= (dev->regs.gpe_en & 0x00000004);
|
|
} else if (val & 0x10) { /* Set GPIO10_STS of GPE_STS */
|
|
dev->regs.gpe_sts |= 0x00000004;
|
|
do_smi |= (dev->regs.gpe_en & 0x00000008);
|
|
} else if (val & 0x08) { /* Set RI_STS in GPE_STS */
|
|
dev->regs.gpe_sts |= 0x00000002;
|
|
do_smi |= (dev->regs.gpe_en & 0x00000002);
|
|
} else if (val & 0x04) /* Set WAK_STS of PM1_STS */
|
|
dev->regs.pmsts |= 0x8000;
|
|
else if (val & 0x02) { /* Set RTC_STS of PM1_STS */
|
|
dev->regs.pmsts |= 0x0400;
|
|
do_smi |= (dev->regs.pmen & 0x0400);
|
|
} else if (val & 0x01) { /* Set PWRBTN_STS of PM1_STS */
|
|
dev->regs.pmsts |= 0x0100;
|
|
do_smi |= (dev->regs.pmen & 0x0100);
|
|
}
|
|
|
|
if (do_smi)
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
break;
|
|
default:
|
|
acpi_reg_write_common_regs(size, addr, val, priv);
|
|
/* Setting GBL_RLS also sets BIOS_STS and generates SMI. */
|
|
if ((addr == 0x00) && !(dev->regs.pmsts & 0x20))
|
|
dev->regs.reg_13 &= ~0x02;
|
|
else if ((addr == 0x04) && (dev->regs.pmcntrl & 0x0004)) {
|
|
dev->regs.leg_sts |= 0x01;
|
|
if (dev->regs.leg_en & 0x01)
|
|
acpi_sis5595_smi_raise(dev);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_read_common(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint8_t ret = 0xff;
|
|
|
|
switch (dev->vendor) {
|
|
case VEN_ALI:
|
|
ret = acpi_reg_read_ali(size, addr, priv);
|
|
break;
|
|
case VEN_VIA:
|
|
ret = acpi_reg_read_via(size, addr, priv);
|
|
break;
|
|
case VEN_VIA_596B:
|
|
ret = acpi_reg_read_via_596b(size, addr, priv);
|
|
break;
|
|
case VEN_INTEL:
|
|
ret = acpi_reg_read_intel(size, addr, priv);
|
|
break;
|
|
case VEN_SMC:
|
|
ret = acpi_reg_read_smc(size, addr, priv);
|
|
break;
|
|
case VEN_SIS_5582:
|
|
ret = acpi_reg_read_sis_5582(size, addr, priv);
|
|
break;
|
|
case VEN_SIS_5595_1997:
|
|
case VEN_SIS_5595:
|
|
ret = acpi_reg_read_sis_5595(size, addr, priv);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write_common(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
|
|
switch (dev->vendor) {
|
|
case VEN_ALI:
|
|
acpi_reg_write_ali(size, addr, val, priv);
|
|
break;
|
|
case VEN_VIA:
|
|
acpi_reg_write_via(size, addr, val, priv);
|
|
break;
|
|
case VEN_VIA_596B:
|
|
acpi_reg_write_via_596b(size, addr, val, priv);
|
|
break;
|
|
case VEN_INTEL:
|
|
acpi_reg_write_intel(size, addr, val, priv);
|
|
break;
|
|
case VEN_SMC:
|
|
acpi_reg_write_smc(size, addr, val, priv);
|
|
break;
|
|
case VEN_SIS_5582:
|
|
acpi_reg_write_sis_5582(size, addr, val, priv);
|
|
break;
|
|
case VEN_SIS_5595_1997:
|
|
case VEN_SIS_5595:
|
|
acpi_reg_write_sis_5595(size, addr, val, priv);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_aux_reg_read_common(int size, uint16_t addr, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint8_t ret = 0xff;
|
|
|
|
if (dev->vendor == VEN_SMC)
|
|
ret = acpi_aux_reg_read_smc(size, addr, priv);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
acpi_aux_reg_write_common(int size, uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->vendor == VEN_SMC)
|
|
acpi_aux_reg_write_smc(size, addr, val, priv);
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_reg_readl(uint16_t addr, void *priv)
|
|
{
|
|
uint32_t ret = 0x00000000;
|
|
|
|
ret = acpi_reg_read_common(4, addr, priv);
|
|
ret |= (acpi_reg_read_common(4, addr + 1, priv) << 8);
|
|
ret |= (acpi_reg_read_common(4, addr + 2, priv) << 16);
|
|
ret |= (acpi_reg_read_common(4, addr + 3, priv) << 24);
|
|
|
|
acpi_log("ACPI: Read L %08X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint16_t
|
|
acpi_reg_readw(uint16_t addr, void *priv)
|
|
{
|
|
uint16_t ret = 0x0000;
|
|
|
|
ret = acpi_reg_read_common(2, addr, priv);
|
|
ret |= (acpi_reg_read_common(2, addr + 1, priv) << 8);
|
|
|
|
acpi_log("ACPI: Read W %08X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint8_t
|
|
acpi_reg_read(uint16_t addr, void *priv)
|
|
{
|
|
uint8_t ret = 0x00;
|
|
|
|
ret = acpi_reg_read_common(1, addr, priv);
|
|
|
|
acpi_log("ACPI: Read B %02X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint32_t
|
|
acpi_aux_reg_readl(uint16_t addr, void *priv)
|
|
{
|
|
uint32_t ret = 0x00000000;
|
|
|
|
ret = acpi_aux_reg_read_common(4, addr, priv);
|
|
ret |= (acpi_aux_reg_read_common(4, addr + 1, priv) << 8);
|
|
ret |= (acpi_aux_reg_read_common(4, addr + 2, priv) << 16);
|
|
ret |= (acpi_aux_reg_read_common(4, addr + 3, priv) << 24);
|
|
|
|
acpi_log("ACPI: Read Aux L %08X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint16_t
|
|
acpi_aux_reg_readw(uint16_t addr, void *priv)
|
|
{
|
|
uint16_t ret = 0x0000;
|
|
|
|
ret = acpi_aux_reg_read_common(2, addr, priv);
|
|
ret |= (acpi_aux_reg_read_common(2, addr + 1, priv) << 8);
|
|
|
|
acpi_log("ACPI: Read Aux W %04X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint8_t
|
|
acpi_aux_reg_read(uint16_t addr, void *priv)
|
|
{
|
|
uint8_t ret = 0x00;
|
|
|
|
ret = acpi_aux_reg_read_common(1, addr, priv);
|
|
|
|
acpi_log("ACPI: Read Aux B %02X from %04X\n", ret, addr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
acpi_reg_writel(uint16_t addr, uint32_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write L %08X to %04X\n", val, addr);
|
|
|
|
acpi_reg_write_common(4, addr, val & 0xff, priv);
|
|
acpi_reg_write_common(4, addr + 1, (val >> 8) & 0xff, priv);
|
|
acpi_reg_write_common(4, addr + 2, (val >> 16) & 0xff, priv);
|
|
acpi_reg_write_common(4, addr + 3, (val >> 24) & 0xff, priv);
|
|
}
|
|
|
|
static void
|
|
acpi_reg_writew(uint16_t addr, uint16_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write W %04X to %04X\n", val, addr);
|
|
|
|
acpi_reg_write_common(2, addr, val & 0xff, priv);
|
|
acpi_reg_write_common(2, addr + 1, (val >> 8) & 0xff, priv);
|
|
}
|
|
|
|
static void
|
|
acpi_reg_write(uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write B %02X to %04X\n", val, addr);
|
|
|
|
acpi_reg_write_common(1, addr, val, priv);
|
|
}
|
|
|
|
static void
|
|
acpi_aux_reg_writel(uint16_t addr, uint32_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write Aux L %08X to %04X\n", val, addr);
|
|
|
|
acpi_aux_reg_write_common(4, addr, val & 0xff, priv);
|
|
acpi_aux_reg_write_common(4, addr + 1, (val >> 8) & 0xff, priv);
|
|
acpi_aux_reg_write_common(4, addr + 2, (val >> 16) & 0xff, priv);
|
|
acpi_aux_reg_write_common(4, addr + 3, (val >> 24) & 0xff, priv);
|
|
}
|
|
|
|
static void
|
|
acpi_aux_reg_writew(uint16_t addr, uint16_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write Aux W %04X to %04X\n", val, addr);
|
|
|
|
acpi_aux_reg_write_common(2, addr, val & 0xff, priv);
|
|
acpi_aux_reg_write_common(2, addr + 1, (val >> 8) & 0xff, priv);
|
|
}
|
|
|
|
static void
|
|
acpi_aux_reg_write(uint16_t addr, uint8_t val, void *priv)
|
|
{
|
|
acpi_log("ACPI: Write Aux B %02X to %04X\n", val, addr);
|
|
|
|
acpi_aux_reg_write_common(1, addr, val, priv);
|
|
}
|
|
|
|
void
|
|
acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en)
|
|
{
|
|
int size;
|
|
|
|
switch (dev->vendor) {
|
|
default:
|
|
case VEN_ALI:
|
|
case VEN_INTEL:
|
|
case VEN_SIS_5582:
|
|
case VEN_SIS_5595_1997:
|
|
case VEN_SIS_5595:
|
|
size = 0x040;
|
|
break;
|
|
case VEN_SMC:
|
|
size = 0x010;
|
|
break;
|
|
case VEN_VIA:
|
|
size = 0x100;
|
|
break;
|
|
case VEN_VIA_596B:
|
|
size = 0x080;
|
|
break;
|
|
}
|
|
|
|
acpi_log("ACPI: Update I/O %04X to %04X (%sabled)\n", dev->io_base, base, chipset_en ? "en" : "dis");
|
|
|
|
if (dev->io_base != 0x0000) {
|
|
io_removehandler(dev->io_base, size,
|
|
acpi_reg_read, acpi_reg_readw, acpi_reg_readl,
|
|
acpi_reg_write, acpi_reg_writew, acpi_reg_writel, dev);
|
|
}
|
|
|
|
dev->io_base = base;
|
|
|
|
if (chipset_en && (dev->io_base != 0x0000)) {
|
|
io_sethandler(dev->io_base, size,
|
|
acpi_reg_read, acpi_reg_readw, acpi_reg_readl,
|
|
acpi_reg_write, acpi_reg_writew, acpi_reg_writel, dev);
|
|
}
|
|
}
|
|
|
|
void
|
|
acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en)
|
|
{
|
|
int size;
|
|
|
|
switch (dev->vendor) {
|
|
case VEN_SMC:
|
|
size = 0x008;
|
|
break;
|
|
default:
|
|
size = 0x000;
|
|
break;
|
|
}
|
|
|
|
acpi_log("ACPI: Update Aux I/O %04X to %04X (%sabled)\n", dev->aux_io_base, base, chipset_en ? "en" : "dis");
|
|
|
|
if (dev->aux_io_base != 0x0000) {
|
|
io_removehandler(dev->aux_io_base, size,
|
|
acpi_aux_reg_read, acpi_aux_reg_readw, acpi_aux_reg_readl,
|
|
acpi_aux_reg_write, acpi_aux_reg_writew, acpi_aux_reg_writel, dev);
|
|
}
|
|
|
|
dev->aux_io_base = base;
|
|
|
|
if (chipset_en && (dev->aux_io_base != 0x0000)) {
|
|
io_sethandler(dev->aux_io_base, size,
|
|
acpi_aux_reg_read, acpi_aux_reg_readw, acpi_aux_reg_readl,
|
|
acpi_aux_reg_write, acpi_aux_reg_writew, acpi_aux_reg_writel, dev);
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_timer_resume(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
dev->regs.pmsts |= 0x8000;
|
|
|
|
/* Nasty workaround for ASUS P2B-LS and potentially others, where the PMCNTRL
|
|
SMI trap handler clears the resume bit before returning control to the OS. */
|
|
if (in_smm)
|
|
timer_set_delay_u64(&dev->resume_timer, 50 * TIMER_USEC);
|
|
}
|
|
|
|
void
|
|
acpi_init_gporeg(acpi_t *dev, uint8_t val0, uint8_t val1, uint8_t val2, uint8_t val3)
|
|
{
|
|
dev->regs.gporeg[0] = dev->gporeg_default[0] = val0;
|
|
dev->regs.gporeg[1] = dev->gporeg_default[1] = val1;
|
|
dev->regs.gporeg[2] = dev->gporeg_default[2] = val2;
|
|
dev->regs.gporeg[3] = dev->gporeg_default[3] = val3;
|
|
acpi_log("acpi_init_gporeg(): %02X %02X %02X %02X\n", dev->regs.gporeg[0], dev->regs.gporeg[1], dev->regs.gporeg[2], dev->regs.gporeg[3]);
|
|
}
|
|
|
|
void
|
|
acpi_set_timer32(acpi_t *dev, uint8_t timer32)
|
|
{
|
|
dev->regs.timer32 = timer32;
|
|
}
|
|
|
|
void
|
|
acpi_set_slot(acpi_t *dev, int slot)
|
|
{
|
|
dev->slot = slot;
|
|
}
|
|
|
|
void
|
|
acpi_set_irq_mode(acpi_t *dev, int irq_mode)
|
|
{
|
|
dev->irq_mode = irq_mode;
|
|
}
|
|
|
|
void
|
|
acpi_set_irq_pin(acpi_t *dev, int irq_pin)
|
|
{
|
|
dev->irq_pin = irq_pin;
|
|
}
|
|
|
|
void
|
|
acpi_set_irq_line(acpi_t *dev, int irq_line)
|
|
{
|
|
dev->irq_line = irq_line;
|
|
}
|
|
|
|
void
|
|
acpi_set_mirq_is_level(acpi_t *dev, int mirq_is_level)
|
|
{
|
|
dev->mirq_is_level = mirq_is_level;
|
|
}
|
|
|
|
void
|
|
acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default)
|
|
{
|
|
dev->gpireg2_default = gpireg2_default;
|
|
dev->regs.gpireg[2] = dev->gpireg2_default;
|
|
}
|
|
|
|
void
|
|
acpi_set_nvr(acpi_t *dev, nvr_t *nvr)
|
|
{
|
|
dev->nvr = nvr;
|
|
}
|
|
|
|
void
|
|
acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv)
|
|
{
|
|
dev->trap_update = update;
|
|
dev->trap_priv = priv;
|
|
}
|
|
|
|
uint8_t
|
|
acpi_ali_soft_smi_status_read(acpi_t *dev)
|
|
{
|
|
return dev->regs.ali_soft_smi = 1;
|
|
}
|
|
|
|
void
|
|
acpi_ali_soft_smi_status_write(acpi_t *dev, uint8_t soft_smi)
|
|
{
|
|
dev->regs.ali_soft_smi = soft_smi;
|
|
}
|
|
|
|
void
|
|
acpi_pwrbtn_timer(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
timer_on_auto(&dev->pwrbtn_timer, 16. * 1000.);
|
|
if (acpi_pwrbut_pressed) {
|
|
acpi_pwrbut_pressed = 0;
|
|
if (dev->regs.pmen & PWRBTN_EN) {
|
|
dev->regs.pmsts |= PWRBTN_STS;
|
|
acpi_update_irq(dev);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_apm_out(uint16_t port, uint8_t val, void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
acpi_log("[%04X:%08X] APM write: %04X = %02X (AX = %04X, BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, AX, BX, CX);
|
|
|
|
port &= 0x0001;
|
|
|
|
if (dev->vendor == VEN_ALI) {
|
|
if (port == 0x0001) {
|
|
acpi_log("ALi SOFT SMI# status set (%i)\n", dev->apm->do_smi);
|
|
dev->apm->cmd = val;
|
|
#if 0
|
|
acpi_raise_smi(dev, dev->apm->do_smi);
|
|
#endif
|
|
if (dev->apm->do_smi)
|
|
smi_raise();
|
|
dev->regs.ali_soft_smi = 1;
|
|
} else if (port == 0x0003)
|
|
dev->apm->stat = val;
|
|
} else {
|
|
if (port == 0x0000) {
|
|
dev->apm->cmd = val;
|
|
if (dev->vendor == VEN_INTEL)
|
|
dev->regs.glbsts |= 0x20;
|
|
acpi_raise_smi(dev, dev->apm->do_smi);
|
|
} else
|
|
dev->apm->stat = val;
|
|
}
|
|
}
|
|
|
|
static uint8_t
|
|
acpi_apm_in(uint16_t port, void *priv)
|
|
{
|
|
const acpi_t *dev = (acpi_t *) priv;
|
|
uint8_t ret = 0xff;
|
|
|
|
port &= 0x0001;
|
|
|
|
if (dev->vendor == VEN_ALI) {
|
|
if (port == 0x0001)
|
|
ret = dev->apm->cmd;
|
|
else if (port == 0x0003)
|
|
ret = dev->apm->stat;
|
|
} else {
|
|
if (port == 0x0000)
|
|
ret = dev->apm->cmd;
|
|
else
|
|
ret = dev->apm->stat;
|
|
}
|
|
|
|
acpi_log("[%04X:%08X] APM read: %04X = %02X\n", CS, cpu_state.pc, port, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
acpi_reset(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
memset(&dev->regs, 0x00, sizeof(acpi_regs_t));
|
|
/* PC Chips M773:
|
|
- Bit 3: 80-conductor cable on unknown IDE channel (active low)
|
|
- Bit 1: 80-conductor cable on unknown IDE channel (active low) */
|
|
dev->regs.gpireg[0] = !strcmp(machine_get_internal_name(), "m773") ? 0xf5 : 0xff;
|
|
dev->regs.gpireg[1] = 0xff;
|
|
/* A-Trend ATC7020BXII:
|
|
- Bit 3: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 2: 80-conductor cable on primary IDE channel (active low)
|
|
Gigabyte GA-686BX:
|
|
- Bit 1: CMOS battery low (active high) */
|
|
dev->regs.gpireg[2] = dev->gpireg2_default;
|
|
for (uint8_t i = 0; i < 4; i++)
|
|
dev->regs.gporeg[i] = dev->gporeg_default[i];
|
|
if (dev->vendor == VEN_VIA_596B) {
|
|
dev->regs.gpo_val = 0x7fffffff;
|
|
/* FIC VA-503A:
|
|
- Bit 11: ATX power (active high)
|
|
- Bit 4: 80-conductor cable on primary IDE channel (active low)
|
|
- Bit 3: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 2: password cleared (active low)
|
|
ASUS P3V4X:
|
|
- Bit 15: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 5: 80-conductor cable on primary IDE channel (active low)
|
|
BCM GT694VA:
|
|
- Bit 19: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 17: 80-conductor cable on primary IDE channel (active low)
|
|
ASUS CUV4X-LS:
|
|
- Bit 2: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 1: 80-conductor cable on primary IDE channel (active low)
|
|
Acorp 6VIA90AP:
|
|
- Bit 3: 80-conductor cable on secondary IDE channel (active low)
|
|
- Bit 1: 80-conductor cable on primary IDE channel (active low) */
|
|
dev->regs.gpi_val = 0xfff57fc1;
|
|
if (!strcmp(machine_get_internal_name(), "ficva503a") || !strcmp(machine_get_internal_name(), "6via90ap"))
|
|
dev->regs.gpi_val |= 0x00000004;
|
|
/*
|
|
TriGem Delhi-III second GPI word:
|
|
- Bit 7 = Save CMOS (must be set);
|
|
- Bit 6 = Password jumper (must be set);
|
|
- Bit 5 = Enable Setup (must be set).
|
|
*/
|
|
else if (!strcmp(machine_get_internal_name(), "delhi3"))
|
|
dev->regs.gpi_val |= 0x00008000;
|
|
}
|
|
|
|
if (acpi_power_on) {
|
|
/* Power on always generates a resume event. */
|
|
dev->regs.pmsts |= 0x8100;
|
|
acpi_power_on = 0;
|
|
}
|
|
|
|
/* The Gateway Tomahawk requires the LID polarity bit to be set. */
|
|
if (!strcmp(machine_get_internal_name(), "tomahawk"))
|
|
dev->regs.glbctl |= 0x02000000;
|
|
|
|
acpi_rtc_status = 0;
|
|
|
|
acpi_update_irq(dev);
|
|
dev->irq_state = 0;
|
|
|
|
timer_disable(&dev->gp_timer);
|
|
|
|
acpi_last_clock = 0ULL;
|
|
acpi_count = 0;
|
|
|
|
timer_disable(&dev->per_timer);
|
|
|
|
if ((dev->vendor == VEN_SIS_5595_1997) || (dev->vendor == VEN_SIS_5595)) {
|
|
dev->regs.reg_13 = 0x20;
|
|
dev->regs.gp_tmr = 0xff;
|
|
dev->regs.gpe_io = 0x00030b9f;
|
|
dev->regs.gpe_mul = 0x1001;
|
|
}
|
|
}
|
|
|
|
static void
|
|
acpi_speed_changed(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock;
|
|
bool timer_enabled = timer_is_enabled(&dev->timer);
|
|
timer_stop(&dev->timer);
|
|
|
|
if (timer_enabled)
|
|
timer_on_auto(&dev->timer, acpi_get_overflow_period(dev));
|
|
|
|
if ((dev->vendor & 0xffff) == 0x1039) {
|
|
if (timer_is_on(&dev->gp_timer)) {
|
|
timer_stop(&dev->gp_timer);
|
|
|
|
if (dev->vendor == VEN_SIS_5595_1997)
|
|
acpi_gp_timer_update(dev, (dev->regs.gpe_en & 0x20000000), acpi_count);
|
|
else if (dev->vendor == VEN_SIS_5595)
|
|
acpi_gp_timer_update(dev, (dev->regs.gpe_en & 0x00000400), acpi_count);
|
|
else
|
|
acpi_gp_timer_update(dev, (dev->regs.reg_16 & 0x2000), acpi_count);
|
|
}
|
|
|
|
if (timer_is_on(&dev->per_timer)) {
|
|
timer_stop(&dev->per_timer);
|
|
|
|
timer_on_auto(&dev->per_timer, 16000000.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void *
|
|
acpi_get_smbus(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
return dev->smbus;
|
|
}
|
|
|
|
static void
|
|
acpi_close(void *priv)
|
|
{
|
|
acpi_t *dev = (acpi_t *) priv;
|
|
|
|
if (dev->i2c) {
|
|
if (i2c_smbus == i2c_gpio_get_bus(dev->i2c))
|
|
i2c_smbus = NULL;
|
|
i2c_gpio_close(dev->i2c);
|
|
}
|
|
|
|
timer_stop(&dev->timer);
|
|
|
|
free(dev);
|
|
}
|
|
|
|
static void *
|
|
acpi_init(const device_t *info)
|
|
{
|
|
acpi_t *dev;
|
|
|
|
dev = (acpi_t *) calloc(1, sizeof(acpi_t));
|
|
if (dev == NULL)
|
|
return NULL;
|
|
|
|
cpu_to_acpi = ACPI_TIMER_FREQ / cpuclock;
|
|
dev->vendor = info->local;
|
|
|
|
dev->irq_line = 9;
|
|
|
|
if ((dev->vendor == VEN_INTEL) || (dev->vendor == VEN_ALI)) {
|
|
if (dev->vendor == VEN_ALI)
|
|
dev->irq_mode = 2;
|
|
dev->apm = device_add(&apm_pci_acpi_device);
|
|
if (dev->vendor == VEN_ALI) {
|
|
acpi_log("Setting I/O handler at port B1\n");
|
|
io_sethandler(0x00b1, 0x0003, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev);
|
|
} else
|
|
io_sethandler(0x00b2, 0x0002, acpi_apm_in, NULL, NULL, acpi_apm_out, NULL, NULL, dev);
|
|
} else if (dev->vendor == VEN_VIA) {
|
|
dev->i2c = i2c_gpio_init("smbus_vt82c586b");
|
|
i2c_smbus = i2c_gpio_get_bus(dev->i2c);
|
|
}
|
|
|
|
switch (dev->vendor) {
|
|
case VEN_ALI:
|
|
dev->suspend_types[0] = SUS_POWER_OFF;
|
|
dev->suspend_types[1] = SUS_POWER_OFF;
|
|
dev->suspend_types[2] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI;
|
|
dev->suspend_types[3] = SUS_SUSPEND;
|
|
dev->suspend_types[5] = SUS_POWER_OFF; /* undocumented, used for S4/S5 by ASUS P5A ACPI table */
|
|
dev->suspend_types[7] = SUS_POWER_OFF; /* undocumented, used for S5 by Gigabyte GA-5AX ACPI table */
|
|
break;
|
|
|
|
case VEN_VIA:
|
|
dev->suspend_types[0] = SUS_POWER_OFF;
|
|
dev->suspend_types[2] = SUS_SUSPEND;
|
|
break;
|
|
|
|
case VEN_VIA_596B:
|
|
dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI;
|
|
dev->suspend_types[2] = SUS_POWER_OFF;
|
|
dev->suspend_types[4] = SUS_SUSPEND;
|
|
dev->suspend_types[5] = SUS_SUSPEND | SUS_RESET_CPU;
|
|
dev->suspend_types[6] = SUS_SUSPEND | SUS_RESET_CPU | SUS_RESET_PCI;
|
|
break;
|
|
|
|
case VEN_INTEL:
|
|
dev->suspend_types[0] = SUS_POWER_OFF;
|
|
dev->suspend_types[1] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI;
|
|
dev->suspend_types[2] = SUS_SUSPEND | SUS_RESET_CPU;
|
|
dev->suspend_types[3] = SUS_SUSPEND | SUS_RESET_CACHE;
|
|
dev->suspend_types[4] = SUS_SUSPEND;
|
|
break;
|
|
|
|
case VEN_SIS_5582:
|
|
dev->suspend_types[0] = SUS_SUSPEND; /* S1 */
|
|
dev->suspend_types[4] = SUS_POWER_OFF; /* S5 */
|
|
|
|
timer_add(&dev->gp_timer, acpi_gp_timer, dev, 0);
|
|
timer_add(&dev->per_timer, acpi_per_timer, dev, 0);
|
|
break;
|
|
|
|
case VEN_SIS_5595_1997:
|
|
case VEN_SIS_5595:
|
|
dev->suspend_types[1] = SUS_SUSPEND;
|
|
dev->suspend_types[2] = SUS_SUSPEND;
|
|
dev->suspend_types[3] = SUS_SUSPEND | SUS_NVR | SUS_RESET_CPU | SUS_RESET_PCI;
|
|
dev->suspend_types[4] = SUS_POWER_OFF;
|
|
dev->suspend_types[5] = SUS_POWER_OFF;
|
|
|
|
timer_add(&dev->gp_timer, acpi_gp_timer, dev, 0);
|
|
timer_add(&dev->per_timer, acpi_per_timer, dev, 0);
|
|
|
|
dev->smbus = device_add(&sis5595_smbus_device);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
timer_add(&dev->timer, acpi_timer_overflow, dev, 0);
|
|
timer_add(&dev->resume_timer, acpi_timer_resume, dev, 0);
|
|
timer_add(&dev->pwrbtn_timer, acpi_pwrbtn_timer, dev, 0);
|
|
|
|
timer_on_auto(&dev->pwrbtn_timer, 16. * 1000.);
|
|
|
|
acpi_reset(dev);
|
|
|
|
acpi_enabled = 1;
|
|
acpi_power_on = 1;
|
|
|
|
return dev;
|
|
}
|
|
|
|
const device_t acpi_ali_device = {
|
|
.name = "ALi M7101 ACPI",
|
|
.internal_name = "acpi_ali",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_ALI,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_intel_device = {
|
|
.name = "Intel ACPI",
|
|
.internal_name = "acpi_intel",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_INTEL,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_via_device = {
|
|
.name = "VIA ACPI",
|
|
.internal_name = "acpi_via",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_VIA,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_via_596b_device = {
|
|
.name = "VIA VT82C596 ACPI",
|
|
.internal_name = "acpi_via_596b",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_VIA_596B,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_smc_device = {
|
|
.name = "SMC FDC73C931APM ACPI",
|
|
.internal_name = "acpi_smc",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_SMC,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_sis_5582_device = {
|
|
.name = "SiS 5582 ACPI",
|
|
.internal_name = "acpi_sis_5582",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_SIS_5582,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_sis_5595_1997_device = {
|
|
.name = "SiS 5595 (1997) ACPI",
|
|
.internal_name = "acpi_sis_5595_1997",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_SIS_5595_1997,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|
|
|
|
const device_t acpi_sis_5595_device = {
|
|
.name = "SiS 5595 ACPI",
|
|
.internal_name = "acpi_sis_5595",
|
|
.flags = DEVICE_PCI,
|
|
.local = VEN_SIS_5595,
|
|
.init = acpi_init,
|
|
.close = acpi_close,
|
|
.reset = acpi_reset,
|
|
.available = NULL,
|
|
.speed_changed = acpi_speed_changed,
|
|
.force_redraw = NULL,
|
|
.config = NULL
|
|
};
|