[PATCH qemu 1/2] hw/misc: Add a model for the ASPEED System Control Unit
Cédric Le Goater
clg at kaod.org
Thu Jun 9 21:29:22 AEST 2016
On 06/09/2016 10:14 AM, Andrew Jeffery wrote:
> The SCU is a collection of chip-level control registers that manage the
> various functions supported by the AST2400. Typically the bits control
> interactions with clocks, external hardware or reset behaviour, and we
> can largly take a hands-off approach to reads and writes.
>
> Firmware makes heavy use of the state to determine how to boot, but the
> reset values vary from SoC to SoC. Object properties are exposed so
> that the integrating SoC model can configure the appropriate reset
> values.
>
> Signed-off-by: Andrew Jeffery <andrew at aj.id.au>
> ---
> hw/misc/Makefile.objs | 1 +
> hw/misc/aspeed_scu.c | 295 +++++++++++++++++++++++++++++++++++++++++++
> include/hw/misc/aspeed_scu.h | 105 +++++++++++++++
> trace-events | 3 +
> 4 files changed, 404 insertions(+)
> create mode 100644 hw/misc/aspeed_scu.c
> create mode 100644 include/hw/misc/aspeed_scu.h
>
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index bc0dd2cc7567..4895e950b377 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -51,3 +51,4 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
> obj-$(CONFIG_PVPANIC) += pvpanic.o
> obj-$(CONFIG_EDU) += edu.o
> obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
> +obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o
> diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
> new file mode 100644
> index 000000000000..ae5a4c590bb6
> --- /dev/null
> +++ b/hw/misc/aspeed_scu.c
> @@ -0,0 +1,295 @@
> +/*
> + * ASPEED System Control Unit
> + *
> + * Andrew Jeffery <andrew at aj.id.au>
> + *
> + * Copyright 2016 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 <inttypes.h>
> +#include "hw/misc/aspeed_scu.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
> +#include "qapi/visitor.h"
> +#include "qemu/bitops.h"
> +#include "trace.h"
> +
> +#define SCU_KEY 0x1688A8A8
> +#define SCU_IO_REGION_SIZE 0x20000
> +
> +#define TO_REG(o) ((o) >> 2)
> +#define TO_REG_ID(o) [TO_REG(o)] = stringify(o)
> +
> +static const char *aspeed_scu_reg_ids[ASPEED_SCU_NR_REGS] = {
> + TO_REG_ID(ASPEED_SCU_PROT_KEY),
> + TO_REG_ID(ASPEED_SCU_SYS_RST_CTRL),
> + TO_REG_ID(ASPEED_SCU_CLK_SEL),
> + TO_REG_ID(ASPEED_SCU_CLK_STOP_CTRL),
> + TO_REG_ID(ASPEED_SCU_FREQ_CNTR_CTRL),
> + TO_REG_ID(ASPEED_SCU_FREQ_CNTR_EVAL),
> + TO_REG_ID(ASPEED_SCU_IRQ_CTRL),
> + TO_REG_ID(ASPEED_SCU_D2PLL_PARAM),
> + TO_REG_ID(ASPEED_SCU_MPLL_PARAM),
> + TO_REG_ID(ASPEED_SCU_HPLL_PARAM),
> + TO_REG_ID(ASPEED_SCU_FREQ_CNTR_RANGE),
> + TO_REG_ID(ASPEED_SCU_MISC_CTRL1),
> + TO_REG_ID(ASPEED_SCU_PCI_CTRL1),
> + TO_REG_ID(ASPEED_SCU_PCI_CTRL2),
> + TO_REG_ID(ASPEED_SCU_PCI_CTRL3),
> + TO_REG_ID(ASPEED_SCU_SYS_RST_CTRL),
> + TO_REG_ID(ASPEED_SCU_SOC_SCRATCH1),
> + TO_REG_ID(ASPEED_SCU_SOC_SCRATCH2),
> + TO_REG_ID(ASPEED_SCU_MAC_CLK_DELAY),
> + TO_REG_ID(ASPEED_SCU_MISC_CTRL2),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH1),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH2),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH3),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH4),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH5),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH6),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH7),
> + TO_REG_ID(ASPEED_SCU_VGA_SCRATCH8),
> + TO_REG_ID(ASPEED_SCU_HW_STRAP1),
> + TO_REG_ID(ASPEED_SCU_RNG_CTRL),
> + TO_REG_ID(ASPEED_SCU_RNG_DATA),
> + TO_REG_ID(ASPEED_SCU_REV_ID),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL1),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL2),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL3),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL4),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL5),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL6),
> + TO_REG_ID(ASPEED_SCU_WDT_RST_CTRL),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL7),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL8),
> + TO_REG_ID(ASPEED_SCU_PINMUX_CTRL9),
> + TO_REG_ID(ASPEED_SCU_WAKEUP_EN),
> + TO_REG_ID(ASPEED_SCU_WAKEUP_CTRL),
> + TO_REG_ID(ASPEED_SCU_HW_STRAP2),
> + TO_REG_ID(ASPEED_SCU_FREE_CNTR4),
> + TO_REG_ID(ASPEED_SCU_FREE_CNTR4_EXT),
> + TO_REG_ID(ASPEED_SCU_CPU2_CTRL),
> + TO_REG_ID(ASPEED_SCU_CPU2_BASE_SEG1),
> + TO_REG_ID(ASPEED_SCU_CPU2_BASE_SEG2),
> + TO_REG_ID(ASPEED_SCU_CPU2_BASE_SEG3),
> + TO_REG_ID(ASPEED_SCU_CPU2_BASE_SEG4),
> + TO_REG_ID(ASPEED_SCU_CPU2_BASE_SEG5),
> + TO_REG_ID(ASPEED_SCU_CPU2_CACHE_CTRL),
> + TO_REG_ID(ASPEED_SCU_UART_HPLL_CLK),
> + TO_REG_ID(ASPEED_SCU_PCIE_CTRL),
> + TO_REG_ID(ASPEED_SCU_BMC_MMIO_CTRL),
> + TO_REG_ID(ASPEED_SCU_RELOC_DECODE_BASE1),
> + TO_REG_ID(ASPEED_SCU_RELOC_DECODE_BASE2),
> + TO_REG_ID(ASPEED_SCU_MAILBOX_DECODE_BASE),
> + TO_REG_ID(ASPEED_SCU_SRAM_DECODE_BASE1),
> + TO_REG_ID(ASPEED_SCU_SRAM_DECODE_BASE2),
> + TO_REG_ID(ASPEED_SCU_BMC_REV_ID),
> + TO_REG_ID(ASPEED_SCU_BMC_DEV_ID),
> +};
I would start with a smaller set that we know uboot and the kernel use,
this is minor.
> +void aspeed_scu_configure_reset(AspeedSCUState *scu,
> + const AspeedSCUResetCfg vals[], int n, Error **errp)
> +{
> + int i;
> +
> + for (i = 0; i < n; i++) {
> + const char *name = aspeed_scu_reg_ids[TO_REG(vals[i].offset)];
> +
> + if (name) {
> + object_property_set_int(OBJECT(scu), vals[i].val, name, errp);
> + if (*errp) {
> + return;
> + }
> + }
> + }
> +}
> +
> +static void aspeed_scu_get_reset(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + AspeedSCUState *s = ASPEED_SCU(obj);
> + uint32_t value;
> + int offset, reg;
> +
> + if (sscanf(name, "0x%x", &offset) != 1) {
> + error_setg(errp, "Error reading %s", name);
> + return;
> + }
I thought the name of the property was "ASPEED_SCU_PROT_KEY" according to the
object_property_add() below ?
> + reg = TO_REG(offset);
> +
> + if (reg > ASPEED_SCU_NR_REGS) {
> + error_setg(errp, "Invalid register ID: %s", name);
> + return;
> + }
> +
> + value = s->reset[reg];
> +
> + visit_type_uint32(v, name, &value, errp);
> +}
> +
> +static void aspeed_scu_set_reset(Object *obj, Visitor *v, const char *name,
> + void *opaque, Error **errp)
> +{
> + AspeedSCUState *s = ASPEED_SCU(obj);
> + Error *local_err = NULL;
> + uint32_t value;
> + int offset, reg;
> +
> + visit_type_uint32(v, name, &value, &local_err);
> +
> + if (local_err) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> + if (sscanf(name, "0x%x", &offset) != 1) {
> + error_setg(errp, "Error reading %s", name);
> + }
same comment.
The rest looks fine.
Reviewed-by: Cédric Le Goater <clg at kaod.org>
Thanks,
C.
> + reg = TO_REG(offset);
> +
> + if (reg > ASPEED_SCU_NR_REGS) {
> + error_setg(errp, "Invalid register ID: %s", name);
> + return;
> + }
> +
> + s->reset[reg] = value;
> +}
> +
> +static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + AspeedSCUState *s = ASPEED_SCU(opaque);
> +
> + if (TO_REG(offset) >= 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;
> + }
> +
> + switch (offset) {
> + case ASPEED_SCU_WAKEUP_EN:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Read of write-only offset 0x%" HWADDR_PRIx "\n",
> + __func__, offset);
> + break;
> + }
> +
> + return s->regs[TO_REG(offset)];
> +}
> +
> +static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data,
> + unsigned size)
> +{
> + AspeedSCUState *s = ASPEED_SCU(opaque);
> +
> + if (TO_REG(offset) >= ARRAY_SIZE(s->regs)) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
> + __func__, offset);
> + return;
> + }
> +
> + if (offset > ASPEED_SCU_PROT_KEY && offset < ASPEED_SCU_CPU2_BASE_SEG1 &&
> + s->regs[TO_REG(ASPEED_SCU_PROT_KEY)] != SCU_KEY) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
> + return;
> + }
> +
> + trace_aspeed_scu_write(offset, size, data);
> +
> + switch (offset) {
> + case ASPEED_SCU_FREQ_CNTR_EVAL:
> + case ASPEED_SCU_VGA_SCRATCH1 ... ASPEED_SCU_VGA_SCRATCH8:
> + case ASPEED_SCU_RNG_DATA:
> + case ASPEED_SCU_REV_ID:
> + case ASPEED_SCU_FREE_CNTR4:
> + case ASPEED_SCU_FREE_CNTR4_EXT:
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
> + __func__, offset);
> + return;
> + }
> +
> + s->regs[TO_REG(offset)] = (uint32_t) data;
> +}
> +
> +static const MemoryRegionOps aspeed_scu_ops = {
> + .read = aspeed_scu_read,
> + .write = aspeed_scu_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 4,
> + .valid.unaligned = false,
> +};
> +
> +static void aspeed_scu_reset(DeviceState *dev)
> +{
> + AspeedSCUState *s = ASPEED_SCU(dev);
> +
> + memcpy(s->regs, s->reset, sizeof(s->regs));
> +}
> +
> +static void aspeed_scu_realize(DeviceState *dev, Error **errp)
> +{
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> + AspeedSCUState *s = ASPEED_SCU(dev);
> +
> + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s,
> + TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
> +
> + sysbus_init_mmio(sbd, &s->iomem);
> +}
> +
> +static const VMStateDescription vmstate_aspeed_scu = {
> + .name = "aspeed.new-vic",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS),
> + VMSTATE_UINT32_ARRAY(reset, AspeedSCUState, ASPEED_SCU_NR_REGS),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void aspeed_scu_initfn(Object *obj)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(aspeed_scu_reg_ids); i++) {
> + const char *name = aspeed_scu_reg_ids[i];
> + if (name) {
> + object_property_add(obj, name, "uint32", aspeed_scu_get_reset,
> + aspeed_scu_set_reset, NULL, NULL, NULL);
> + }
> + }
> +}
> +
> +static void aspeed_scu_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + dc->realize = aspeed_scu_realize;
> + dc->reset = aspeed_scu_reset;
> + dc->desc = "ASPEED System Control Unit";
> + dc->vmsd = &vmstate_aspeed_scu;
> +}
> +
> +static const TypeInfo aspeed_scu_info = {
> + .name = TYPE_ASPEED_SCU,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(AspeedSCUState),
> + .instance_init = aspeed_scu_initfn,
> + .class_init = aspeed_scu_class_init,
> +};
> +
> +static void aspeed_scu_register_types(void)
> +{
> + type_register_static(&aspeed_scu_info);
> +}
> +
> +type_init(aspeed_scu_register_types);
> diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h
> new file mode 100644
> index 000000000000..a33975cebcdf
> --- /dev/null
> +++ b/include/hw/misc/aspeed_scu.h
> @@ -0,0 +1,105 @@
> +/*
> + * ASPEED System Control Unit
> + *
> + * Andrew Jeffery <andrew at aj.id.au>
> + *
> + * Copyright 2016 IBM Corp.
> + *
> + * This code is licensed under the GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + */
> +#ifndef ASPEED_SCU_H
> +#define ASPEED_SCU_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_ASPEED_SCU "aspeed.scu"
> +#define ASPEED_SCU(obj) OBJECT_CHECK(AspeedSCUState, (obj), TYPE_ASPEED_SCU)
> +
> +#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
> +
> +#define ASPEED_SCU_PROT_KEY 0x00
> +#define ASPEED_SCU_SYS_RST_CTRL 0x04
> +#define ASPEED_SCU_CLK_SEL 0x08
> +#define ASPEED_SCU_CLK_STOP_CTRL 0x0C
> +#define ASPEED_SCU_FREQ_CNTR_CTRL 0x10
> +#define ASPEED_SCU_FREQ_CNTR_EVAL 0x14
> +#define ASPEED_SCU_IRQ_CTRL 0x18
> +#define ASPEED_SCU_D2PLL_PARAM 0x1C
> +#define ASPEED_SCU_MPLL_PARAM 0x20
> +#define ASPEED_SCU_HPLL_PARAM 0x24
> +#define ASPEED_SCU_FREQ_CNTR_RANGE 0x28
> +#define ASPEED_SCU_MISC_CTRL1 0x2C
> +#define ASPEED_SCU_PCI_CTRL1 0x30
> +#define ASPEED_SCU_PCI_CTRL2 0x34
> +#define ASPEED_SCU_PCI_CTRL3 0x38
> +#define ASPEED_SCU_SYS_RST_STATUS 0x3C
> +#define ASPEED_SCU_SOC_SCRATCH1 0x40
> +#define ASPEED_SCU_SOC_SCRATCH2 0x44
> +#define ASPEED_SCU_MAC_CLK_DELAY 0x48
> +#define ASPEED_SCU_MISC_CTRL2 0x4C
> +#define ASPEED_SCU_VGA_SCRATCH1 0x50
> +#define ASPEED_SCU_VGA_SCRATCH2 0x54
> +#define ASPEED_SCU_VGA_SCRATCH3 0x58
> +#define ASPEED_SCU_VGA_SCRATCH4 0x5C
> +#define ASPEED_SCU_VGA_SCRATCH5 0x60
> +#define ASPEED_SCU_VGA_SCRATCH6 0x64
> +#define ASPEED_SCU_VGA_SCRATCH7 0x68
> +#define ASPEED_SCU_VGA_SCRATCH8 0x6C
> +#define ASPEED_SCU_HW_STRAP1 0x70
> +#define ASPEED_SCU_RNG_CTRL 0x74
> +#define ASPEED_SCU_RNG_DATA 0x78
> +#define ASPEED_SCU_REV_ID 0x7C
> +#define ASPEED_SCU_PINMUX_CTRL1 0x80
> +#define ASPEED_SCU_PINMUX_CTRL2 0x84
> +#define ASPEED_SCU_PINMUX_CTRL3 0x88
> +#define ASPEED_SCU_PINMUX_CTRL4 0x8C
> +#define ASPEED_SCU_PINMUX_CTRL5 0x90
> +#define ASPEED_SCU_PINMUX_CTRL6 0x94
> +#define ASPEED_SCU_WDT_RST_CTRL 0x9C
> +#define ASPEED_SCU_PINMUX_CTRL7 0xA0
> +#define ASPEED_SCU_PINMUX_CTRL8 0xA4
> +#define ASPEED_SCU_PINMUX_CTRL9 0xA8
> +#define ASPEED_SCU_WAKEUP_EN 0xC0
> +#define ASPEED_SCU_WAKEUP_CTRL 0xC4
> +#define ASPEED_SCU_HW_STRAP2 0xD0
> +#define ASPEED_SCU_FREE_CNTR4 0xE0
> +#define ASPEED_SCU_FREE_CNTR4_EXT 0xE4
> +#define ASPEED_SCU_CPU2_CTRL 0x100
> +#define ASPEED_SCU_CPU2_BASE_SEG1 0x104
> +#define ASPEED_SCU_CPU2_BASE_SEG2 0x108
> +#define ASPEED_SCU_CPU2_BASE_SEG3 0x10C
> +#define ASPEED_SCU_CPU2_BASE_SEG4 0x110
> +#define ASPEED_SCU_CPU2_BASE_SEG5 0x114
> +#define ASPEED_SCU_CPU2_CACHE_CTRL 0x118
> +#define ASPEED_SCU_UART_HPLL_CLK 0x160
> +#define ASPEED_SCU_PCIE_CTRL 0x180
> +#define ASPEED_SCU_BMC_MMIO_CTRL 0x184
> +#define ASPEED_SCU_RELOC_DECODE_BASE1 0x188
> +#define ASPEED_SCU_RELOC_DECODE_BASE2 0x18C
> +#define ASPEED_SCU_MAILBOX_DECODE_BASE 0x190
> +#define ASPEED_SCU_SRAM_DECODE_BASE1 0x194
> +#define ASPEED_SCU_SRAM_DECODE_BASE2 0x198
> +#define ASPEED_SCU_BMC_REV_ID 0x19C
> +#define ASPEED_SCU_BMC_DEV_ID 0x1A4
> +
> +typedef struct AspeedSCUState {
> + /*< private >*/
> + SysBusDevice parent_obj;
> +
> + /*< public >*/
> + MemoryRegion iomem;
> +
> + uint32_t regs[ASPEED_SCU_NR_REGS];
> + uint32_t reset[ASPEED_SCU_NR_REGS];
> +} AspeedSCUState;
> +
> +typedef struct AspeedSCUResetCfg {
> + uint32_t offset;
> + uint32_t val;
> +} AspeedSCUResetCfg;
>
> +void aspeed_scu_configure_reset(AspeedSCUState *scu,
> + const struct AspeedSCUResetCfg vals[], int n, Error **errp);
> +
> +#endif /* ASPEED_SCU_H */
> diff --git a/trace-events b/trace-events
> index 421d89f476b6..83994907f48e 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -2163,3 +2163,6 @@ e1000e_cfg_support_virtio(bool support) "Virtio header supported: %d"
>
> e1000e_vm_state_running(void) "VM state is running"
> e1000e_vm_state_stopped(void) "VM state is stopped"
> +
> +# hw/misc/aspeed_scu.c
> +aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
>
More information about the openbmc
mailing list