xref: /openbmc/qemu/hw/i2c/smbus_ich9.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * ACPI implementation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2006 Fabrice Bellard
549ab747fSPaolo Bonzini  * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
649ab747fSPaolo Bonzini  *               VA Linux Systems Japan K.K.
749ab747fSPaolo Bonzini  * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
849ab747fSPaolo Bonzini  *
96086e300SThomas Huth  * This program is free software; you can redistribute it and/or modify
106086e300SThomas Huth  * it under the terms of the GNU General Public License as published by
116086e300SThomas Huth  * the Free Software Foundation; either version 2 of the License, or
126086e300SThomas Huth  * (at your option) any later version.
1349ab747fSPaolo Bonzini  *
146086e300SThomas Huth  * This program is distributed in the hope that it will be useful,
1549ab747fSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1649ab747fSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
176086e300SThomas Huth  * General Public License for more details.
1849ab747fSPaolo Bonzini  *
196086e300SThomas Huth  * You should have received a copy of the GNU General Public License
206086e300SThomas Huth  * along with this program; if not, see <http://www.gnu.org/licenses/>
2149ab747fSPaolo Bonzini  */
220b8fa32fSMarkus Armbruster 
23b6a0aa05SPeter Maydell #include "qemu/osdep.h"
245588a58cSPhilippe Mathieu-Daudé #include "qemu/range.h"
2549ab747fSPaolo Bonzini #include "hw/i2c/pm_smbus.h"
2649ab747fSPaolo Bonzini #include "hw/pci/pci.h"
27d6454270SMarkus Armbruster #include "migration/vmstate.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
2949ab747fSPaolo Bonzini 
301a6981bbSBernhard Beschow #include "hw/southbridge/ich9.h"
31db1015e9SEduardo Habkost #include "qom/object.h"
324b66ddccSIgor Mammedov #include "hw/acpi/acpi_aml_interface.h"
3349ab747fSPaolo Bonzini 
348063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(ICH9SMBState, ICH9_SMB_DEVICE)
3549ab747fSPaolo Bonzini 
36db1015e9SEduardo Habkost struct ICH9SMBState {
3749ab747fSPaolo Bonzini     PCIDevice dev;
3849ab747fSPaolo Bonzini 
39e724385aSCorey Minyard     bool irq_enabled;
40e724385aSCorey Minyard 
4149ab747fSPaolo Bonzini     PMSMBus smb;
42db1015e9SEduardo Habkost };
4349ab747fSPaolo Bonzini 
ich9_vmstate_need_smbus(void * opaque,int version_id)444ab2f2a8SCorey Minyard static bool ich9_vmstate_need_smbus(void *opaque, int version_id)
454ab2f2a8SCorey Minyard {
464ab2f2a8SCorey Minyard     return pm_smbus_vmstate_needed();
474ab2f2a8SCorey Minyard }
484ab2f2a8SCorey Minyard 
4949ab747fSPaolo Bonzini static const VMStateDescription vmstate_ich9_smbus = {
5049ab747fSPaolo Bonzini     .name = "ich9_smb",
5149ab747fSPaolo Bonzini     .version_id = 1,
5249ab747fSPaolo Bonzini     .minimum_version_id = 1,
53*01d9442aSRichard Henderson     .fields = (const VMStateField[]) {
544ab2f2a8SCorey Minyard         VMSTATE_PCI_DEVICE(dev, ICH9SMBState),
554ab2f2a8SCorey Minyard         VMSTATE_BOOL_TEST(irq_enabled, ICH9SMBState, ich9_vmstate_need_smbus),
564ab2f2a8SCorey Minyard         VMSTATE_STRUCT_TEST(smb, ICH9SMBState, ich9_vmstate_need_smbus, 1,
574ab2f2a8SCorey Minyard                             pmsmb_vmstate, PMSMBus),
5849ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
5949ab747fSPaolo Bonzini     }
6049ab747fSPaolo Bonzini };
6149ab747fSPaolo Bonzini 
ich9_smbus_write_config(PCIDevice * d,uint32_t address,uint32_t val,int len)6249ab747fSPaolo Bonzini static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
6349ab747fSPaolo Bonzini                                     uint32_t val, int len)
6449ab747fSPaolo Bonzini {
6549ab747fSPaolo Bonzini     ICH9SMBState *s = ICH9_SMB_DEVICE(d);
6649ab747fSPaolo Bonzini 
6749ab747fSPaolo Bonzini     pci_default_write_config(d, address, val, len);
6849ab747fSPaolo Bonzini     if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
6949ab747fSPaolo Bonzini         uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
7038ad4faeSCorey Minyard         if (hostc & ICH9_SMB_HOSTC_HST_EN) {
7149ab747fSPaolo Bonzini             memory_region_set_enabled(&s->smb.io, true);
7249ab747fSPaolo Bonzini         } else {
7349ab747fSPaolo Bonzini             memory_region_set_enabled(&s->smb.io, false);
7449ab747fSPaolo Bonzini         }
7538ad4faeSCorey Minyard         s->smb.i2c_enable = (hostc & ICH9_SMB_HOSTC_I2C_EN) != 0;
7638ad4faeSCorey Minyard         if (hostc & ICH9_SMB_HOSTC_SSRESET) {
7738ad4faeSCorey Minyard             s->smb.reset(&s->smb);
7838ad4faeSCorey Minyard             s->dev.config[ICH9_SMB_HOSTC] &= ~ICH9_SMB_HOSTC_SSRESET;
7938ad4faeSCorey Minyard         }
8049ab747fSPaolo Bonzini     }
8149ab747fSPaolo Bonzini }
8249ab747fSPaolo Bonzini 
ich9_smb_set_irq(PMSMBus * pmsmb,bool enabled)83d73c2b1cSBernhard Beschow static void ich9_smb_set_irq(PMSMBus *pmsmb, bool enabled)
84d73c2b1cSBernhard Beschow {
85d73c2b1cSBernhard Beschow     ICH9SMBState *s = pmsmb->opaque;
86d73c2b1cSBernhard Beschow 
87d73c2b1cSBernhard Beschow     if (enabled == s->irq_enabled) {
88d73c2b1cSBernhard Beschow         return;
89d73c2b1cSBernhard Beschow     }
90d73c2b1cSBernhard Beschow 
91d73c2b1cSBernhard Beschow     s->irq_enabled = enabled;
92d73c2b1cSBernhard Beschow     pci_set_irq(&s->dev, enabled);
93d73c2b1cSBernhard Beschow }
94d73c2b1cSBernhard Beschow 
ich9_smbus_realize(PCIDevice * d,Error ** errp)959af21dbeSMarkus Armbruster static void ich9_smbus_realize(PCIDevice *d, Error **errp)
9649ab747fSPaolo Bonzini {
9749ab747fSPaolo Bonzini     ICH9SMBState *s = ICH9_SMB_DEVICE(d);
9849ab747fSPaolo Bonzini 
9949ab747fSPaolo Bonzini     /* TODO? D31IP.SMIP in chipset configuration space */
10049ab747fSPaolo Bonzini     pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
10149ab747fSPaolo Bonzini 
10249ab747fSPaolo Bonzini     pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
10349ab747fSPaolo Bonzini     /* TODO bar0, bar1: 64bit BAR support*/
10449ab747fSPaolo Bonzini 
10545726b6eSCorey Minyard     pm_smbus_init(&d->qdev, &s->smb, false);
10649ab747fSPaolo Bonzini     pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
10749ab747fSPaolo Bonzini                      &s->smb.io);
10807981e8fSBernhard Beschow 
10907981e8fSBernhard Beschow     s->smb.set_irq = ich9_smb_set_irq;
11007981e8fSBernhard Beschow     s->smb.opaque = s;
11149ab747fSPaolo Bonzini }
11249ab747fSPaolo Bonzini 
build_ich9_smb_aml(AcpiDevAmlIf * adev,Aml * scope)1134b66ddccSIgor Mammedov static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope)
1144b66ddccSIgor Mammedov {
1154b66ddccSIgor Mammedov     ICH9SMBState *s = ICH9_SMB_DEVICE(adev);
1164b66ddccSIgor Mammedov     BusState *bus = BUS(s->smb.smbus);
1174b66ddccSIgor Mammedov 
1189c6c0aeaSBernhard Beschow     qbus_build_aml(bus, scope);
1194b66ddccSIgor Mammedov }
1204b66ddccSIgor Mammedov 
ich9_smb_class_init(ObjectClass * klass,void * data)12149ab747fSPaolo Bonzini static void ich9_smb_class_init(ObjectClass *klass, void *data)
12249ab747fSPaolo Bonzini {
12349ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
12449ab747fSPaolo Bonzini     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1254b66ddccSIgor Mammedov     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
12649ab747fSPaolo Bonzini 
12749ab747fSPaolo Bonzini     k->vendor_id = PCI_VENDOR_ID_INTEL;
12849ab747fSPaolo Bonzini     k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
12949ab747fSPaolo Bonzini     k->revision = ICH9_A2_SMB_REVISION;
13049ab747fSPaolo Bonzini     k->class_id = PCI_CLASS_SERIAL_SMBUS;
13149ab747fSPaolo Bonzini     dc->vmsd = &vmstate_ich9_smbus;
13249ab747fSPaolo Bonzini     dc->desc = "ICH9 SMBUS Bridge";
1339af21dbeSMarkus Armbruster     k->realize = ich9_smbus_realize;
13449ab747fSPaolo Bonzini     k->config_write = ich9_smbus_write_config;
135bfa6dfd0SMarkus Armbruster     /*
136bfa6dfd0SMarkus Armbruster      * Reason: part of ICH9 southbridge, needs to be wired up by
137bfa6dfd0SMarkus Armbruster      * pc_q35_init()
138bfa6dfd0SMarkus Armbruster      */
139e90f2a8cSEduardo Habkost     dc->user_creatable = false;
1404b66ddccSIgor Mammedov     adevc->build_dev_aml = build_ich9_smb_aml;
14149ab747fSPaolo Bonzini }
14249ab747fSPaolo Bonzini 
14349ab747fSPaolo Bonzini static const TypeInfo ich9_smb_info = {
14449ab747fSPaolo Bonzini     .name   = TYPE_ICH9_SMB_DEVICE,
14549ab747fSPaolo Bonzini     .parent = TYPE_PCI_DEVICE,
14649ab747fSPaolo Bonzini     .instance_size = sizeof(ICH9SMBState),
14749ab747fSPaolo Bonzini     .class_init = ich9_smb_class_init,
148fd3b02c8SEduardo Habkost     .interfaces = (InterfaceInfo[]) {
149fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1504b66ddccSIgor Mammedov         { TYPE_ACPI_DEV_AML_IF },
151fd3b02c8SEduardo Habkost         { },
152fd3b02c8SEduardo Habkost     },
15349ab747fSPaolo Bonzini };
15449ab747fSPaolo Bonzini 
ich9_smb_register(void)15549ab747fSPaolo Bonzini static void ich9_smb_register(void)
15649ab747fSPaolo Bonzini {
15749ab747fSPaolo Bonzini     type_register_static(&ich9_smb_info);
15849ab747fSPaolo Bonzini }
15949ab747fSPaolo Bonzini 
16049ab747fSPaolo Bonzini type_init(ich9_smb_register);
161