mirror of https://github.com/xemu-project/xemu.git
hw/misc: Add a basic Aspeed LPC controller model
This is a very minimal framework to access registers which are used to configure the AHB memory mapping of the flash chips on the LPC HC Firmware address space. Signed-off-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Message-Id: <20210302014317.915120-5-andrew@aj.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
parent
6820588efa
commit
2ecf17264d
|
@ -48,6 +48,7 @@ Supported devices
|
||||||
* UART
|
* UART
|
||||||
* Ethernet controllers
|
* Ethernet controllers
|
||||||
* Front LEDs (PCA9552 on I2C bus)
|
* Front LEDs (PCA9552 on I2C bus)
|
||||||
|
* LPC Peripheral Controller (a subset of subdevices are supported)
|
||||||
|
|
||||||
|
|
||||||
Missing devices
|
Missing devices
|
||||||
|
@ -56,7 +57,6 @@ Missing devices
|
||||||
* Coprocessor support
|
* Coprocessor support
|
||||||
* ADC (out of tree implementation)
|
* ADC (out of tree implementation)
|
||||||
* PWM and Fan Controller
|
* PWM and Fan Controller
|
||||||
* LPC Bus Controller
|
|
||||||
* Slave GPIO Controller
|
* Slave GPIO Controller
|
||||||
* Super I/O Controller
|
* Super I/O Controller
|
||||||
* Hash/Crypto Engine
|
* Hash/Crypto Engine
|
||||||
|
|
|
@ -211,6 +211,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
|
||||||
|
|
||||||
object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0],
|
object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0],
|
||||||
TYPE_SYSBUS_SDHCI);
|
TYPE_SYSBUS_SDHCI);
|
||||||
|
|
||||||
|
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -462,6 +464,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]);
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]);
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
|
||||||
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
|
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
|
||||||
|
|
||||||
|
/* LPC */
|
||||||
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
|
||||||
|
aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
|
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
|
||||||
|
|
|
@ -211,6 +211,8 @@ static void aspeed_soc_init(Object *obj)
|
||||||
object_initialize_child(obj, "sdhci[*]", &s->sdhci.slots[i],
|
object_initialize_child(obj, "sdhci[*]", &s->sdhci.slots[i],
|
||||||
TYPE_SYSBUS_SDHCI);
|
TYPE_SYSBUS_SDHCI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||||
|
@ -393,6 +395,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||||
sc->memmap[ASPEED_DEV_SDHCI]);
|
sc->memmap[ASPEED_DEV_SDHCI]);
|
||||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
|
||||||
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
|
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
|
||||||
|
|
||||||
|
/* LPC */
|
||||||
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
|
||||||
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
|
||||||
|
aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
|
||||||
}
|
}
|
||||||
static Property aspeed_soc_properties[] = {
|
static Property aspeed_soc_properties[] = {
|
||||||
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
|
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* ASPEED LPC Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2018 IBM Corp.
|
||||||
|
*
|
||||||
|
* This code is licensed under the GPL version 2 or later. See
|
||||||
|
* the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/log.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
|
#include "hw/misc/aspeed_lpc.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
|
#include "hw/qdev-properties.h"
|
||||||
|
#include "migration/vmstate.h"
|
||||||
|
|
||||||
|
#define TO_REG(offset) ((offset) >> 2)
|
||||||
|
|
||||||
|
#define HICR0 TO_REG(0x00)
|
||||||
|
#define HICR1 TO_REG(0x04)
|
||||||
|
#define HICR2 TO_REG(0x08)
|
||||||
|
#define HICR3 TO_REG(0x0C)
|
||||||
|
#define HICR4 TO_REG(0x10)
|
||||||
|
#define HICR5 TO_REG(0x80)
|
||||||
|
#define HICR6 TO_REG(0x84)
|
||||||
|
#define HICR7 TO_REG(0x88)
|
||||||
|
#define HICR8 TO_REG(0x8C)
|
||||||
|
|
||||||
|
static uint64_t aspeed_lpc_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
|
{
|
||||||
|
AspeedLPCState *s = ASPEED_LPC(opaque);
|
||||||
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
|
if (reg >= ARRAY_SIZE(s->regs)) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
|
||||||
|
__func__, offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s->regs[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_lpc_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
AspeedLPCState *s = ASPEED_LPC(opaque);
|
||||||
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
|
if (reg >= ARRAY_SIZE(s->regs)) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
|
||||||
|
__func__, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->regs[reg] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps aspeed_lpc_ops = {
|
||||||
|
.read = aspeed_lpc_read,
|
||||||
|
.write = aspeed_lpc_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.valid = {
|
||||||
|
.min_access_size = 1,
|
||||||
|
.max_access_size = 4,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_lpc_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
struct AspeedLPCState *s = ASPEED_LPC(dev);
|
||||||
|
|
||||||
|
memset(s->regs, 0, sizeof(s->regs));
|
||||||
|
|
||||||
|
s->regs[HICR7] = s->hicr7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_lpc_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
AspeedLPCState *s = ASPEED_LPC(dev);
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
|
|
||||||
|
sysbus_init_irq(sbd, &s->irq);
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_lpc_ops, s,
|
||||||
|
TYPE_ASPEED_LPC, 0x1000);
|
||||||
|
|
||||||
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription vmstate_aspeed_lpc = {
|
||||||
|
.name = TYPE_ASPEED_LPC,
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_UINT32_ARRAY(regs, AspeedLPCState, ASPEED_LPC_NR_REGS),
|
||||||
|
VMSTATE_END_OF_LIST(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Property aspeed_lpc_properties[] = {
|
||||||
|
DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_lpc_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = aspeed_lpc_realize;
|
||||||
|
dc->reset = aspeed_lpc_reset;
|
||||||
|
dc->desc = "Aspeed LPC Controller",
|
||||||
|
dc->vmsd = &vmstate_aspeed_lpc;
|
||||||
|
device_class_set_props(dc, aspeed_lpc_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo aspeed_lpc_info = {
|
||||||
|
.name = TYPE_ASPEED_LPC,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(AspeedLPCState),
|
||||||
|
.class_init = aspeed_lpc_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_lpc_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&aspeed_lpc_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(aspeed_lpc_register_types);
|
|
@ -102,7 +102,12 @@ softmmu_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
|
softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
|
softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
|
softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_scu.c', 'aspeed_sdmc.c', 'aspeed_xdma.c'))
|
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
|
||||||
|
'aspeed_lpc.c',
|
||||||
|
'aspeed_scu.c',
|
||||||
|
'aspeed_sdmc.c',
|
||||||
|
'aspeed_xdma.c'))
|
||||||
|
|
||||||
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
|
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
|
||||||
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
|
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "hw/sd/aspeed_sdhci.h"
|
#include "hw/sd/aspeed_sdhci.h"
|
||||||
#include "hw/usb/hcd-ehci.h"
|
#include "hw/usb/hcd-ehci.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
#include "hw/misc/aspeed_lpc.h"
|
||||||
|
|
||||||
#define ASPEED_SPIS_NUM 2
|
#define ASPEED_SPIS_NUM 2
|
||||||
#define ASPEED_EHCIS_NUM 2
|
#define ASPEED_EHCIS_NUM 2
|
||||||
|
@ -61,6 +62,7 @@ struct AspeedSoCState {
|
||||||
AspeedGPIOState gpio_1_8v;
|
AspeedGPIOState gpio_1_8v;
|
||||||
AspeedSDHCIState sdhci;
|
AspeedSDHCIState sdhci;
|
||||||
AspeedSDHCIState emmc;
|
AspeedSDHCIState emmc;
|
||||||
|
AspeedLPCState lpc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TYPE_ASPEED_SOC "aspeed-soc"
|
#define TYPE_ASPEED_SOC "aspeed-soc"
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* ASPEED LPC Controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2018 IBM Corp.
|
||||||
|
*
|
||||||
|
* This code is licensed under the GPL version 2 or later. See
|
||||||
|
* the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASPEED_LPC_H
|
||||||
|
#define ASPEED_LPC_H
|
||||||
|
|
||||||
|
#include "hw/sysbus.h"
|
||||||
|
|
||||||
|
#define TYPE_ASPEED_LPC "aspeed.lpc"
|
||||||
|
#define ASPEED_LPC(obj) OBJECT_CHECK(AspeedLPCState, (obj), TYPE_ASPEED_LPC)
|
||||||
|
|
||||||
|
#define ASPEED_LPC_NR_REGS (0x260 >> 2)
|
||||||
|
|
||||||
|
typedef struct AspeedLPCState {
|
||||||
|
/* <private> */
|
||||||
|
SysBusDevice parent;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
MemoryRegion iomem;
|
||||||
|
qemu_irq irq;
|
||||||
|
|
||||||
|
uint32_t regs[ASPEED_LPC_NR_REGS];
|
||||||
|
uint32_t hicr7;
|
||||||
|
} AspeedLPCState;
|
||||||
|
|
||||||
|
#endif /* _ASPEED_LPC_H_ */
|
Loading…
Reference in New Issue