qemu/hw/misc/xlnx-versal-crl.c
Peter Maydell ad80e36744 hw, target: Add ResetType argument to hold and exit phase methods
We pass a ResetType argument to the Resettable class enter
phase method, but we don't pass it to hold and exit, even though
the callsites have it readily available. This means that if
a device cared about the ResetType it would need to record it
in the enter phase method to use later on. Pass the type to
all three of the phase methods to avoid having to do that.

Commit created with

  for dir in hw target include; do \
      spatch --macro-file scripts/cocci-macro-file.h \
             --sp-file scripts/coccinelle/reset-type.cocci \
             --keep-comments --smpl-spacing --in-place \
             --include-headers --dir $dir; done

and no manual edits.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Luc Michel <luc.michel@amd.com>
Message-id: 20240412160809.1260625-5-peter.maydell@linaro.org
2024-04-25 10:21:06 +01:00

423 lines
13 KiB
C

/*
* QEMU model of the Clock-Reset-LPD (CRL).
*
* Copyright (c) 2022 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Written by Edgar E. Iglesias <edgar.iglesias@amd.com>
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "qemu/bitops.h"
#include "migration/vmstate.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/register.h"
#include "hw/resettable.h"
#include "target/arm/arm-powerctl.h"
#include "target/arm/multiprocessing.h"
#include "hw/misc/xlnx-versal-crl.h"
#ifndef XLNX_VERSAL_CRL_ERR_DEBUG
#define XLNX_VERSAL_CRL_ERR_DEBUG 0
#endif
static void crl_update_irq(XlnxVersalCRL *s)
{
bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK];
qemu_set_irq(s->irq, pending);
}
static void crl_status_postw(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
crl_update_irq(s);
}
static uint64_t crl_enable_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
uint32_t val = val64;
s->regs[R_IR_MASK] &= ~val;
crl_update_irq(s);
return 0;
}
static uint64_t crl_disable_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
uint32_t val = val64;
s->regs[R_IR_MASK] |= val;
crl_update_irq(s);
return 0;
}
static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev,
bool rst_old, bool rst_new)
{
device_cold_reset(dev);
}
static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu,
bool rst_old, bool rst_new)
{
if (rst_new) {
arm_set_cpu_off(arm_cpu_mp_affinity(armcpu));
} else {
arm_set_cpu_on_and_reset(arm_cpu_mp_affinity(armcpu));
}
}
#define REGFIELD_RESET(type, s, reg, f, new_val, dev) { \
bool old_f = ARRAY_FIELD_EX32((s)->regs, reg, f); \
bool new_f = FIELD_EX32(new_val, reg, f); \
\
/* Detect edges. */ \
if (dev && old_f != new_f) { \
crl_reset_ ## type(s, dev, old_f, new_f); \
} \
}
static uint64_t crl_rst_r5_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU0, val64, s->cfg.cpu_r5[0]);
REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU1, val64, s->cfg.cpu_r5[1]);
return val64;
}
static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
int i;
/* A single register fans out to all ADMA reset inputs. */
for (i = 0; i < ARRAY_SIZE(s->cfg.adma); i++) {
REGFIELD_RESET(dev, s, RST_ADMA, RESET, val64, s->cfg.adma[i]);
}
return val64;
}
static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]);
return val64;
}
static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]);
return val64;
}
static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]);
return val64;
}
static uint64_t crl_rst_gem1_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(dev, s, RST_GEM1, RESET, val64, s->cfg.gem[1]);
return val64;
}
static uint64_t crl_rst_usb_prew(RegisterInfo *reg, uint64_t val64)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
REGFIELD_RESET(dev, s, RST_USB0, RESET, val64, s->cfg.usb);
return val64;
}
static const RegisterAccessInfo crl_regs_info[] = {
{ .name = "ERR_CTRL", .addr = A_ERR_CTRL,
},{ .name = "IR_STATUS", .addr = A_IR_STATUS,
.w1c = 0x1,
.post_write = crl_status_postw,
},{ .name = "IR_MASK", .addr = A_IR_MASK,
.reset = 0x1,
.ro = 0x1,
},{ .name = "IR_ENABLE", .addr = A_IR_ENABLE,
.pre_write = crl_enable_prew,
},{ .name = "IR_DISABLE", .addr = A_IR_DISABLE,
.pre_write = crl_disable_prew,
},{ .name = "WPROT", .addr = A_WPROT,
},{ .name = "PLL_CLK_OTHER_DMN", .addr = A_PLL_CLK_OTHER_DMN,
.reset = 0x1,
.rsvd = 0xe,
},{ .name = "RPLL_CTRL", .addr = A_RPLL_CTRL,
.reset = 0x24809,
.rsvd = 0xf88c00f6,
},{ .name = "RPLL_CFG", .addr = A_RPLL_CFG,
.reset = 0x2000000,
.rsvd = 0x1801210,
},{ .name = "RPLL_FRAC_CFG", .addr = A_RPLL_FRAC_CFG,
.rsvd = 0x7e330000,
},{ .name = "PLL_STATUS", .addr = A_PLL_STATUS,
.reset = R_PLL_STATUS_RPLL_STABLE_MASK |
R_PLL_STATUS_RPLL_LOCK_MASK,
.rsvd = 0xfa,
.ro = 0x5,
},{ .name = "RPLL_TO_XPD_CTRL", .addr = A_RPLL_TO_XPD_CTRL,
.reset = 0x2000100,
.rsvd = 0xfdfc00ff,
},{ .name = "LPD_TOP_SWITCH_CTRL", .addr = A_LPD_TOP_SWITCH_CTRL,
.reset = 0x6000300,
.rsvd = 0xf9fc00f8,
},{ .name = "LPD_LSBUS_CTRL", .addr = A_LPD_LSBUS_CTRL,
.reset = 0x2000800,
.rsvd = 0xfdfc00f8,
},{ .name = "CPU_R5_CTRL", .addr = A_CPU_R5_CTRL,
.reset = 0xe000300,
.rsvd = 0xe1fc00f8,
},{ .name = "IOU_SWITCH_CTRL", .addr = A_IOU_SWITCH_CTRL,
.reset = 0x2000500,
.rsvd = 0xfdfc00f8,
},{ .name = "GEM0_REF_CTRL", .addr = A_GEM0_REF_CTRL,
.reset = 0xe000a00,
.rsvd = 0xf1fc00f8,
},{ .name = "GEM1_REF_CTRL", .addr = A_GEM1_REF_CTRL,
.reset = 0xe000a00,
.rsvd = 0xf1fc00f8,
},{ .name = "GEM_TSU_REF_CTRL", .addr = A_GEM_TSU_REF_CTRL,
.reset = 0x300,
.rsvd = 0xfdfc00f8,
},{ .name = "USB0_BUS_REF_CTRL", .addr = A_USB0_BUS_REF_CTRL,
.reset = 0x2001900,
.rsvd = 0xfdfc00f8,
},{ .name = "UART0_REF_CTRL", .addr = A_UART0_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "UART1_REF_CTRL", .addr = A_UART1_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "SPI0_REF_CTRL", .addr = A_SPI0_REF_CTRL,
.reset = 0x600,
.rsvd = 0xfdfc00f8,
},{ .name = "SPI1_REF_CTRL", .addr = A_SPI1_REF_CTRL,
.reset = 0x600,
.rsvd = 0xfdfc00f8,
},{ .name = "CAN0_REF_CTRL", .addr = A_CAN0_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "CAN1_REF_CTRL", .addr = A_CAN1_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "I2C0_REF_CTRL", .addr = A_I2C0_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "I2C1_REF_CTRL", .addr = A_I2C1_REF_CTRL,
.reset = 0xc00,
.rsvd = 0xfdfc00f8,
},{ .name = "DBG_LPD_CTRL", .addr = A_DBG_LPD_CTRL,
.reset = 0x300,
.rsvd = 0xfdfc00f8,
},{ .name = "TIMESTAMP_REF_CTRL", .addr = A_TIMESTAMP_REF_CTRL,
.reset = 0x2000c00,
.rsvd = 0xfdfc00f8,
},{ .name = "CRL_SAFETY_CHK", .addr = A_CRL_SAFETY_CHK,
},{ .name = "PSM_REF_CTRL", .addr = A_PSM_REF_CTRL,
.reset = 0xf04,
.rsvd = 0xfffc00f8,
},{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL,
.reset = 0x300,
.rsvd = 0xfdfc00f8,
},{ .name = "CPM_TOPSW_REF_CTRL", .addr = A_CPM_TOPSW_REF_CTRL,
.reset = 0x300,
.rsvd = 0xfdfc00f8,
},{ .name = "USB3_DUAL_REF_CTRL", .addr = A_USB3_DUAL_REF_CTRL,
.reset = 0x3c00,
.rsvd = 0xfdfc00f8,
},{ .name = "RST_CPU_R5", .addr = A_RST_CPU_R5,
.reset = 0x17,
.rsvd = 0x8,
.pre_write = crl_rst_r5_prew,
},{ .name = "RST_ADMA", .addr = A_RST_ADMA,
.reset = 0x1,
.pre_write = crl_rst_adma_prew,
},{ .name = "RST_GEM0", .addr = A_RST_GEM0,
.reset = 0x1,
.pre_write = crl_rst_gem0_prew,
},{ .name = "RST_GEM1", .addr = A_RST_GEM1,
.reset = 0x1,
.pre_write = crl_rst_gem1_prew,
},{ .name = "RST_SPARE", .addr = A_RST_SPARE,
.reset = 0x1,
},{ .name = "RST_USB0", .addr = A_RST_USB0,
.reset = 0x1,
.pre_write = crl_rst_usb_prew,
},{ .name = "RST_UART0", .addr = A_RST_UART0,
.reset = 0x1,
.pre_write = crl_rst_uart0_prew,
},{ .name = "RST_UART1", .addr = A_RST_UART1,
.reset = 0x1,
.pre_write = crl_rst_uart1_prew,
},{ .name = "RST_SPI0", .addr = A_RST_SPI0,
.reset = 0x1,
},{ .name = "RST_SPI1", .addr = A_RST_SPI1,
.reset = 0x1,
},{ .name = "RST_CAN0", .addr = A_RST_CAN0,
.reset = 0x1,
},{ .name = "RST_CAN1", .addr = A_RST_CAN1,
.reset = 0x1,
},{ .name = "RST_I2C0", .addr = A_RST_I2C0,
.reset = 0x1,
},{ .name = "RST_I2C1", .addr = A_RST_I2C1,
.reset = 0x1,
},{ .name = "RST_DBG_LPD", .addr = A_RST_DBG_LPD,
.reset = 0x33,
.rsvd = 0xcc,
},{ .name = "RST_GPIO", .addr = A_RST_GPIO,
.reset = 0x1,
},{ .name = "RST_TTC", .addr = A_RST_TTC,
.reset = 0xf,
},{ .name = "RST_TIMESTAMP", .addr = A_RST_TIMESTAMP,
.reset = 0x1,
},{ .name = "RST_SWDT", .addr = A_RST_SWDT,
.reset = 0x1,
},{ .name = "RST_OCM", .addr = A_RST_OCM,
},{ .name = "RST_IPI", .addr = A_RST_IPI,
},{ .name = "RST_FPD", .addr = A_RST_FPD,
.reset = 0x3,
},{ .name = "PSM_RST_MODE", .addr = A_PSM_RST_MODE,
.reset = 0x1,
.rsvd = 0xf8,
}
};
static void crl_reset_enter(Object *obj, ResetType type)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
register_reset(&s->regs_info[i]);
}
}
static void crl_reset_hold(Object *obj, ResetType type)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
crl_update_irq(s);
}
static const MemoryRegionOps crl_ops = {
.read = register_read_memory,
.write = register_write_memory,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void crl_init(Object *obj)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
int i;
s->reg_array =
register_init_block32(DEVICE(obj), crl_regs_info,
ARRAY_SIZE(crl_regs_info),
s->regs_info, s->regs,
&crl_ops,
XLNX_VERSAL_CRL_ERR_DEBUG,
CRL_R_MAX * 4);
sysbus_init_mmio(sbd, &s->reg_array->mem);
sysbus_init_irq(sbd, &s->irq);
for (i = 0; i < ARRAY_SIZE(s->cfg.cpu_r5); ++i) {
object_property_add_link(obj, "cpu_r5[*]", TYPE_ARM_CPU,
(Object **)&s->cfg.cpu_r5[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
for (i = 0; i < ARRAY_SIZE(s->cfg.adma); ++i) {
object_property_add_link(obj, "adma[*]", TYPE_DEVICE,
(Object **)&s->cfg.adma[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
for (i = 0; i < ARRAY_SIZE(s->cfg.uart); ++i) {
object_property_add_link(obj, "uart[*]", TYPE_DEVICE,
(Object **)&s->cfg.uart[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
for (i = 0; i < ARRAY_SIZE(s->cfg.gem); ++i) {
object_property_add_link(obj, "gem[*]", TYPE_DEVICE,
(Object **)&s->cfg.gem[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
object_property_add_link(obj, "usb", TYPE_DEVICE,
(Object **)&s->cfg.gem[i],
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_STRONG);
}
static void crl_finalize(Object *obj)
{
XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj);
register_finalize_block(s->reg_array);
}
static const VMStateDescription vmstate_crl = {
.name = TYPE_XLNX_VERSAL_CRL,
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, XlnxVersalCRL, CRL_R_MAX),
VMSTATE_END_OF_LIST(),
}
};
static void crl_class_init(ObjectClass *klass, void *data)
{
ResettableClass *rc = RESETTABLE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_crl;
rc->phases.enter = crl_reset_enter;
rc->phases.hold = crl_reset_hold;
}
static const TypeInfo crl_info = {
.name = TYPE_XLNX_VERSAL_CRL,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxVersalCRL),
.class_init = crl_class_init,
.instance_init = crl_init,
.instance_finalize = crl_finalize,
};
static void crl_register_types(void)
{
type_register_static(&crl_info);
}
type_init(crl_register_types)