mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
hw/misc/xlnx-versal-crl: refactor device reset logic
Refactor the device reset logic to have a common register write callback for all the devices. This uses a decode function to map the register address to the actual peripheral to reset. This refactoring changes the CPU property name from cpu_r5[*] to rpu[*] to ease with the connections in the Versal SoC. It also fixes a bug where the gem device pointer was mapped to the usb link property. Signed-off-by: Luc Michel <luc.michel@amd.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20250926070806.292065-33-luc.michel@amd.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
committed by
Peter Maydell
parent
c27ca57288
commit
ff789d1556
+91
-78
@@ -55,90 +55,99 @@ static uint64_t crl_disable_prew(RegisterInfo *reg, uint64_t val64)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev,
|
||||
bool rst_old, bool rst_new)
|
||||
static DeviceState **versal_decode_periph_rst(XlnxVersalCRLBase *s,
|
||||
hwaddr addr, size_t *count)
|
||||
{
|
||||
device_cold_reset(dev);
|
||||
}
|
||||
size_t idx;
|
||||
XlnxVersalCRL *xvc = XLNX_VERSAL_CRL(s);
|
||||
|
||||
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));
|
||||
*count = 1;
|
||||
|
||||
switch (addr) {
|
||||
case A_RST_CPU_R5:
|
||||
return xvc->cfg.rpu;
|
||||
|
||||
case A_RST_ADMA:
|
||||
/* A single register fans out to all DMA reset inputs */
|
||||
*count = ARRAY_SIZE(xvc->cfg.adma);
|
||||
return xvc->cfg.adma;
|
||||
|
||||
case A_RST_UART0 ... A_RST_UART1:
|
||||
idx = (addr - A_RST_UART0) / sizeof(uint32_t);
|
||||
return xvc->cfg.uart + idx;
|
||||
|
||||
case A_RST_GEM0 ... A_RST_GEM1:
|
||||
idx = (addr - A_RST_GEM0) / sizeof(uint32_t);
|
||||
return xvc->cfg.gem + idx;
|
||||
|
||||
case A_RST_USB0:
|
||||
return xvc->cfg.usb;
|
||||
|
||||
default:
|
||||
/* invalid or unimplemented */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
static uint64_t crl_rst_cpu_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
|
||||
XlnxVersalCRLBase *s = XLNX_VERSAL_CRL_BASE(reg->opaque);
|
||||
XlnxVersalCRLBaseClass *xvcbc = XLNX_VERSAL_CRL_BASE_GET_CLASS(s);
|
||||
DeviceState **dev;
|
||||
size_t i, count;
|
||||
|
||||
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;
|
||||
}
|
||||
dev = xvcbc->decode_periph_rst(s, reg->access->addr, &count);
|
||||
|
||||
static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
|
||||
int i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
bool prev, new;
|
||||
uint64_t aff;
|
||||
|
||||
/* 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]);
|
||||
prev = extract32(s->regs[reg->access->addr / 4], i, 1);
|
||||
new = extract32(val64, i, 1);
|
||||
|
||||
if (prev == new) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aff = arm_cpu_mp_affinity(ARM_CPU(dev[i]));
|
||||
|
||||
if (new) {
|
||||
arm_set_cpu_off(aff);
|
||||
} else {
|
||||
arm_set_cpu_on_and_reset(aff);
|
||||
}
|
||||
}
|
||||
|
||||
return val64;
|
||||
}
|
||||
|
||||
static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64)
|
||||
static uint64_t crl_rst_dev_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
|
||||
XlnxVersalCRLBase *s = XLNX_VERSAL_CRL_BASE(reg->opaque);
|
||||
XlnxVersalCRLBaseClass *xvcbc = XLNX_VERSAL_CRL_BASE_GET_CLASS(s);
|
||||
DeviceState **dev;
|
||||
bool prev, new;
|
||||
size_t i, count;
|
||||
|
||||
REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]);
|
||||
return val64;
|
||||
}
|
||||
dev = xvcbc->decode_periph_rst(s, reg->access->addr, &count);
|
||||
|
||||
static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
|
||||
if (dev == NULL) {
|
||||
return val64;
|
||||
}
|
||||
|
||||
REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]);
|
||||
return val64;
|
||||
}
|
||||
prev = s->regs[reg->access->addr / 4] & 0x1;
|
||||
new = val64 & 0x1;
|
||||
|
||||
static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64)
|
||||
{
|
||||
XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque);
|
||||
if (prev == new) {
|
||||
return val64;
|
||||
}
|
||||
|
||||
REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]);
|
||||
return val64;
|
||||
}
|
||||
for (i = 0; i < count; i++) {
|
||||
if (dev[i]) {
|
||||
device_cold_reset(dev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -244,27 +253,27 @@ static const RegisterAccessInfo crl_regs_info[] = {
|
||||
},{ .name = "RST_CPU_R5", .addr = A_RST_CPU_R5,
|
||||
.reset = 0x17,
|
||||
.rsvd = 0x8,
|
||||
.pre_write = crl_rst_r5_prew,
|
||||
.pre_write = crl_rst_cpu_prew,
|
||||
},{ .name = "RST_ADMA", .addr = A_RST_ADMA,
|
||||
.reset = 0x1,
|
||||
.pre_write = crl_rst_adma_prew,
|
||||
.pre_write = crl_rst_dev_prew,
|
||||
},{ .name = "RST_GEM0", .addr = A_RST_GEM0,
|
||||
.reset = 0x1,
|
||||
.pre_write = crl_rst_gem0_prew,
|
||||
.pre_write = crl_rst_dev_prew,
|
||||
},{ .name = "RST_GEM1", .addr = A_RST_GEM1,
|
||||
.reset = 0x1,
|
||||
.pre_write = crl_rst_gem1_prew,
|
||||
.pre_write = crl_rst_dev_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,
|
||||
.pre_write = crl_rst_dev_prew,
|
||||
},{ .name = "RST_UART0", .addr = A_RST_UART0,
|
||||
.reset = 0x1,
|
||||
.pre_write = crl_rst_uart0_prew,
|
||||
.pre_write = crl_rst_dev_prew,
|
||||
},{ .name = "RST_UART1", .addr = A_RST_UART1,
|
||||
.reset = 0x1,
|
||||
.pre_write = crl_rst_uart1_prew,
|
||||
.pre_write = crl_rst_dev_prew,
|
||||
},{ .name = "RST_SPI0", .addr = A_RST_SPI0,
|
||||
.reset = 0x1,
|
||||
},{ .name = "RST_SPI1", .addr = A_RST_SPI1,
|
||||
@@ -343,9 +352,9 @@ static void versal_crl_init(Object *obj)
|
||||
sysbus_init_mmio(sbd, &xvcb->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],
|
||||
for (i = 0; i < ARRAY_SIZE(s->cfg.rpu); ++i) {
|
||||
object_property_add_link(obj, "rpu[*]", TYPE_ARM_CPU,
|
||||
(Object **)&s->cfg.rpu[i],
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_STRONG);
|
||||
}
|
||||
@@ -371,10 +380,12 @@ static void versal_crl_init(Object *obj)
|
||||
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);
|
||||
for (i = 0; i < ARRAY_SIZE(s->cfg.usb); ++i) {
|
||||
object_property_add_link(obj, "usb[*]", TYPE_DEVICE,
|
||||
(Object **)&s->cfg.usb[i],
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_STRONG);
|
||||
}
|
||||
}
|
||||
|
||||
static void crl_finalize(Object *obj)
|
||||
@@ -396,11 +407,13 @@ static const VMStateDescription vmstate_versal_crl = {
|
||||
static void versal_crl_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
XlnxVersalCRLBaseClass *xvcc = XLNX_VERSAL_CRL_BASE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_versal_crl;
|
||||
rc->phases.enter = versal_crl_reset_enter;
|
||||
rc->phases.hold = versal_crl_reset_hold;
|
||||
xvcc->decode_periph_rst = versal_decode_periph_rst;
|
||||
}
|
||||
|
||||
static const TypeInfo crl_base_info = {
|
||||
|
||||
@@ -220,8 +220,6 @@ REG32(PSM_RST_MODE, 0x370)
|
||||
|
||||
#define CRL_R_MAX (R_PSM_RST_MODE + 1)
|
||||
|
||||
#define RPU_MAX_CPU 2
|
||||
|
||||
struct XlnxVersalCRLBase {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
@@ -231,6 +229,8 @@ struct XlnxVersalCRLBase {
|
||||
|
||||
struct XlnxVersalCRLBaseClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
DeviceState ** (*decode_periph_rst)(XlnxVersalCRLBase *s, hwaddr, size_t *);
|
||||
};
|
||||
|
||||
struct XlnxVersalCRL {
|
||||
@@ -238,11 +238,11 @@ struct XlnxVersalCRL {
|
||||
qemu_irq irq;
|
||||
|
||||
struct {
|
||||
ARMCPU *cpu_r5[RPU_MAX_CPU];
|
||||
DeviceState *rpu[2];
|
||||
DeviceState *adma[8];
|
||||
DeviceState *uart[2];
|
||||
DeviceState *gem[2];
|
||||
DeviceState *usb;
|
||||
DeviceState *usb[1];
|
||||
} cfg;
|
||||
|
||||
uint32_t regs[CRL_R_MAX];
|
||||
|
||||
Reference in New Issue
Block a user