Add PowerPC power-management state check callback.
[qemu] / hw / acpi.c
index e78e56d..6e3f69e 100644 (file)
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -1,8 +1,8 @@
 /*
  * ACPI implementation
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License version 2 as published by the Free Software Foundation.
@@ -24,7 +24,6 @@
 #define PM_FREQ 3579545
 
 #define ACPI_DBG_IO_ADDR  0xb044
-#define SMB_IO_BASE       0xb100
 
 typedef struct PIIX4PMState {
     PCIDevice dev;
@@ -35,7 +34,7 @@ typedef struct PIIX4PMState {
     uint8_t apms;
     QEMUTimer *tmr_timer;
     int64_t tmr_overflow_time;
-    SMBusDevice *smb_dev[128];
+    i2c_bus *smbus;
     uint8_t smb_stat;
     uint8_t smb_ctl;
     uint8_t smb_cmd;
@@ -55,6 +54,9 @@ typedef struct PIIX4PMState {
 
 #define SUS_EN (1 << 13)
 
+#define ACPI_ENABLE 0xf1
+#define ACPI_DISABLE 0xf0
+
 #define SMBHSTSTS 0x00
 #define SMBHSTCNT 0x02
 #define SMBHSTCMD 0x03
@@ -63,9 +65,6 @@ typedef struct PIIX4PMState {
 #define SMBHSTDAT1 0x06
 #define SMBBLKDAT 0x07
 
-/* Note: only used for piix4_smbus_register_device */
-static PIIX4PMState *piix4_pm_state;
-
 static uint32_t get_pmtmr(PIIX4PMState *s)
 {
     uint32_t d;
@@ -88,9 +87,9 @@ static void pm_update_sci(PIIX4PMState *s)
 {
     int sci_level, pmsts;
     int64_t expire_time;
-    
+
     pmsts = get_pmsts(s);
-    sci_level = (((pmsts & s->pmen) & 
+    sci_level = (((pmsts & s->pmen) &
                   (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
     qemu_set_irq(s->dev.irq[0], sci_level);
     /* schedule a timer interruption if needed */
@@ -220,6 +219,14 @@ static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
 #endif
     if (addr == 0) {
         s->apmc = val;
+
+        /* ACPI specs 3.0, 4.7.2.5 */
+        if (val == ACPI_ENABLE) {
+            s->pmcntrl |= SCI_EN;
+        } else if (val == ACPI_DISABLE) {
+            s->pmcntrl &= ~SCI_EN;
+        }
+
         if (s->dev.config[0x5b] & (1 << 1)) {
             cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
         }
@@ -232,7 +239,7 @@ static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
 {
     PIIX4PMState *s = opaque;
     uint32_t val;
-    
+
     addr &= 1;
     if (addr == 0) {
         val = s->apmc;
@@ -258,59 +265,44 @@ static void smb_transaction(PIIX4PMState *s)
     uint8_t read = s->smb_addr & 0x01;
     uint8_t cmd = s->smb_cmd;
     uint8_t addr = s->smb_addr >> 1;
-    SMBusDevice *dev = s->smb_dev[addr];
+    i2c_bus *bus = s->smbus;
 
 #ifdef DEBUG
     printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
 #endif
-    if (!dev) goto error;
-
     switch(prot) {
     case 0x0:
-        if (!dev->quick_cmd) goto error;
-        (*dev->quick_cmd)(dev, read);
+        smbus_quick_command(bus, addr, read);
         break;
     case 0x1:
         if (read) {
-            if (!dev->receive_byte) goto error;
-            s->smb_data0 = (*dev->receive_byte)(dev);
-        }
-        else {
-            if (!dev->send_byte) goto error;
-            (*dev->send_byte)(dev, cmd);
+            s->smb_data0 = smbus_receive_byte(bus, addr);
+        } else {
+            smbus_send_byte(bus, addr, cmd);
         }
         break;
     case 0x2:
         if (read) {
-            if (!dev->read_byte) goto error;
-            s->smb_data0 = (*dev->read_byte)(dev, cmd);
-        }
-        else {
-            if (!dev->write_byte) goto error;
-            (*dev->write_byte)(dev, cmd, s->smb_data0);
+            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+        } else {
+            smbus_write_byte(bus, addr, cmd, s->smb_data0);
         }
         break;
     case 0x3:
         if (read) {
             uint16_t val;
-            if (!dev->read_word) goto error;
-            val = (*dev->read_word)(dev, cmd);
+            val = smbus_read_word(bus, addr, cmd);
             s->smb_data0 = val;
             s->smb_data1 = val >> 8;
-        }
-        else {
-            if (!dev->write_word) goto error;
-            (*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0);
+        } else {
+            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
         }
         break;
     case 0x5:
         if (read) {
-            if (!dev->read_block) goto error;
-            s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data);
-        }
-        else {
-            if (!dev->write_block) goto error;
-            (*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data);
+            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+        } else {
+            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
         }
         break;
     default:
@@ -408,7 +400,7 @@ static void pm_io_space_update(PIIX4PMState *s)
 
     if (s->dev.config[0x80] & 1) {
         pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
-        pm_io_base &= 0xfffe;
+        pm_io_base &= 0xffc0;
 
         /* XXX: need to improve memory and ioport allocation */
 #if defined(DEBUG)
@@ -421,7 +413,7 @@ static void pm_io_space_update(PIIX4PMState *s)
     }
 }
 
-static void pm_write_config(PCIDevice *d, 
+static void pm_write_config(PCIDevice *d,
                             uint32_t address, uint32_t val, int len)
 {
     pci_default_write_config(d, address, val, len);
@@ -469,11 +461,10 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id)
     return 0;
 }
 
-void piix4_pm_init(PCIBus *bus, int devfn)
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
 {
     PIIX4PMState *s;
     uint8_t *pci_conf;
-    uint32_t pm_io_base, smb_io_base;
 
     s = (PIIX4PMState *)pci_register_device(bus,
                                          "PM", sizeof(PIIX4PMState),
@@ -483,15 +474,17 @@ void piix4_pm_init(PCIBus *bus, int devfn)
     pci_conf[0x01] = 0x80;
     pci_conf[0x02] = 0x13;
     pci_conf[0x03] = 0x71;
+    pci_conf[0x06] = 0x80;
+    pci_conf[0x07] = 0x02;
     pci_conf[0x08] = 0x00; // revision number
     pci_conf[0x09] = 0x00;
     pci_conf[0x0a] = 0x80; // other bridge device
     pci_conf[0x0b] = 0x06; // bridge device
     pci_conf[0x0e] = 0x00; // header_type
     pci_conf[0x3d] = 0x01; // interrupt pin 1
-    
+
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
-    
+
     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
 
@@ -504,7 +497,6 @@ void piix4_pm_init(PCIBus *bus, int devfn)
     pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
        (serial_hds[1] != NULL ? 0x90 : 0);
 
-    smb_io_base = SMB_IO_BASE;
     pci_conf[0x90] = smb_io_base | 1;
     pci_conf[0x91] = smb_io_base >> 8;
     pci_conf[0xd2] = 0x09;
@@ -514,10 +506,7 @@ void piix4_pm_init(PCIBus *bus, int devfn)
     s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
 
     register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
-    piix4_pm_state = s;
-}
 
-void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr)
-{
-    piix4_pm_state->smb_dev[addr] = dev;
+    s->smbus = i2c_init_bus();
+    return s->smbus;
 }