mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-18 23:52:14 -06:00
watchdog/aspeed: Introduce an object class per SoC
It cleanups the current models for the Aspeed AST2400 and AST2500 SoCs and prepares ground for future SoCs. Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: Joel Stanley <joel@jms.id.au> Message-id: 20190925143248.10000-11-clg@kaod.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
1550d72679
commit
6112bd6d9b
3 changed files with 86 additions and 63 deletions
|
@ -214,10 +214,9 @@ static void aspeed_soc_init(Object *obj)
|
||||||
"max-ram-size", &error_abort);
|
"max-ram-size", &error_abort);
|
||||||
|
|
||||||
for (i = 0; i < sc->info->wdts_num; i++) {
|
for (i = 0; i < sc->info->wdts_num; i++) {
|
||||||
|
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
|
||||||
sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
|
sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
|
||||||
sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
|
sizeof(s->wdt[i]), typename);
|
||||||
qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
|
|
||||||
sc->info->silicon_rev);
|
|
||||||
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
|
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
|
||||||
OBJECT(&s->scu), &error_abort);
|
OBJECT(&s->scu), &error_abort);
|
||||||
}
|
}
|
||||||
|
@ -384,13 +383,15 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
/* Watch dog */
|
/* Watch dog */
|
||||||
for (i = 0; i < sc->info->wdts_num; i++) {
|
for (i = 0; i < sc->info->wdts_num; i++) {
|
||||||
|
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
|
||||||
|
|
||||||
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
|
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||||
sc->info->memmap[ASPEED_WDT] + i * 0x20);
|
sc->info->memmap[ASPEED_WDT] + i * awc->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Net */
|
/* Net */
|
||||||
|
|
|
@ -54,21 +54,6 @@ static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
|
||||||
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
|
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_ast2500(const AspeedWDTState *s)
|
|
||||||
{
|
|
||||||
switch (s->silicon_rev) {
|
|
||||||
case AST2500_A0_SILICON_REV:
|
|
||||||
case AST2500_A1_SILICON_REV:
|
|
||||||
return true;
|
|
||||||
case AST2400_A0_SILICON_REV:
|
|
||||||
case AST2400_A1_SILICON_REV:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
|
static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
{
|
{
|
||||||
AspeedWDTState *s = ASPEED_WDT(opaque);
|
AspeedWDTState *s = ASPEED_WDT(opaque);
|
||||||
|
@ -124,6 +109,7 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
AspeedWDTState *s = ASPEED_WDT(opaque);
|
AspeedWDTState *s = ASPEED_WDT(opaque);
|
||||||
|
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s);
|
||||||
bool enable = data & WDT_CTRL_ENABLE;
|
bool enable = data & WDT_CTRL_ENABLE;
|
||||||
|
|
||||||
offset >>= 2;
|
offset >>= 2;
|
||||||
|
@ -153,24 +139,13 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WDT_RESET_WIDTH:
|
case WDT_RESET_WIDTH:
|
||||||
{
|
if (awc->reset_pulse) {
|
||||||
uint32_t property = data & WDT_POLARITY_MASK;
|
awc->reset_pulse(s, data & WDT_POLARITY_MASK);
|
||||||
|
|
||||||
if (property && is_ast2500(s)) {
|
|
||||||
if (property == WDT_ACTIVE_HIGH_MAGIC) {
|
|
||||||
s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH;
|
|
||||||
} else if (property == WDT_ACTIVE_LOW_MAGIC) {
|
|
||||||
s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH;
|
|
||||||
} else if (property == WDT_PUSH_PULL_MAGIC) {
|
|
||||||
s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL;
|
|
||||||
} else if (property == WDT_OPEN_DRAIN_MAGIC) {
|
|
||||||
s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask;
|
s->regs[WDT_RESET_WIDTH] &= ~awc->ext_pulse_width_mask;
|
||||||
s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask;
|
s->regs[WDT_RESET_WIDTH] |= data & awc->ext_pulse_width_mask;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case WDT_TIMEOUT_STATUS:
|
case WDT_TIMEOUT_STATUS:
|
||||||
case WDT_TIMEOUT_CLEAR:
|
case WDT_TIMEOUT_CLEAR:
|
||||||
qemu_log_mask(LOG_UNIMP,
|
qemu_log_mask(LOG_UNIMP,
|
||||||
|
@ -226,9 +201,10 @@ static void aspeed_wdt_reset(DeviceState *dev)
|
||||||
static void aspeed_wdt_timer_expired(void *dev)
|
static void aspeed_wdt_timer_expired(void *dev)
|
||||||
{
|
{
|
||||||
AspeedWDTState *s = ASPEED_WDT(dev);
|
AspeedWDTState *s = ASPEED_WDT(dev);
|
||||||
|
uint32_t reset_ctrl_reg = ASPEED_WDT_GET_CLASS(s)->reset_ctrl_reg;
|
||||||
|
|
||||||
/* Do not reset on SDRAM controller reset */
|
/* Do not reset on SDRAM controller reset */
|
||||||
if (s->scu->regs[SCU_RESET_CONTROL1] & SCU_RESET_SDRAM) {
|
if (s->scu->regs[reset_ctrl_reg] & SCU_RESET_SDRAM) {
|
||||||
timer_del(s->timer);
|
timer_del(s->timer);
|
||||||
s->regs[WDT_CTRL] = 0;
|
s->regs[WDT_CTRL] = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -256,25 +232,6 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
|
||||||
}
|
}
|
||||||
s->scu = ASPEED_SCU(obj);
|
s->scu = ASPEED_SCU(obj);
|
||||||
|
|
||||||
if (!is_supported_silicon_rev(s->silicon_rev)) {
|
|
||||||
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
|
|
||||||
s->silicon_rev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (s->silicon_rev) {
|
|
||||||
case AST2400_A0_SILICON_REV:
|
|
||||||
case AST2400_A1_SILICON_REV:
|
|
||||||
s->ext_pulse_width_mask = 0xff;
|
|
||||||
break;
|
|
||||||
case AST2500_A0_SILICON_REV:
|
|
||||||
case AST2500_A1_SILICON_REV:
|
|
||||||
s->ext_pulse_width_mask = 0xfffff;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
|
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
|
||||||
|
|
||||||
/* FIXME: This setting should be derived from the SCU hw strapping
|
/* FIXME: This setting should be derived from the SCU hw strapping
|
||||||
|
@ -287,20 +244,15 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property aspeed_wdt_properties[] = {
|
|
||||||
DEFINE_PROP_UINT32("silicon-rev", AspeedWDTState, silicon_rev, 0),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
|
||||||
};
|
|
||||||
|
|
||||||
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
|
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "ASPEED Watchdog Controller";
|
||||||
dc->realize = aspeed_wdt_realize;
|
dc->realize = aspeed_wdt_realize;
|
||||||
dc->reset = aspeed_wdt_reset;
|
dc->reset = aspeed_wdt_reset;
|
||||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
dc->vmsd = &vmstate_aspeed_wdt;
|
dc->vmsd = &vmstate_aspeed_wdt;
|
||||||
dc->props = aspeed_wdt_properties;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo aspeed_wdt_info = {
|
static const TypeInfo aspeed_wdt_info = {
|
||||||
|
@ -308,12 +260,68 @@ static const TypeInfo aspeed_wdt_info = {
|
||||||
.name = TYPE_ASPEED_WDT,
|
.name = TYPE_ASPEED_WDT,
|
||||||
.instance_size = sizeof(AspeedWDTState),
|
.instance_size = sizeof(AspeedWDTState),
|
||||||
.class_init = aspeed_wdt_class_init,
|
.class_init = aspeed_wdt_class_init,
|
||||||
|
.class_size = sizeof(AspeedWDTClass),
|
||||||
|
.abstract = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "ASPEED 2400 Watchdog Controller";
|
||||||
|
awc->offset = 0x20;
|
||||||
|
awc->ext_pulse_width_mask = 0xff;
|
||||||
|
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo aspeed_2400_wdt_info = {
|
||||||
|
.name = TYPE_ASPEED_2400_WDT,
|
||||||
|
.parent = TYPE_ASPEED_WDT,
|
||||||
|
.instance_size = sizeof(AspeedWDTState),
|
||||||
|
.class_init = aspeed_2400_wdt_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_2500_wdt_reset_pulse(AspeedWDTState *s, uint32_t property)
|
||||||
|
{
|
||||||
|
if (property) {
|
||||||
|
if (property == WDT_ACTIVE_HIGH_MAGIC) {
|
||||||
|
s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH;
|
||||||
|
} else if (property == WDT_ACTIVE_LOW_MAGIC) {
|
||||||
|
s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH;
|
||||||
|
} else if (property == WDT_PUSH_PULL_MAGIC) {
|
||||||
|
s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL;
|
||||||
|
} else if (property == WDT_OPEN_DRAIN_MAGIC) {
|
||||||
|
s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "ASPEED 2500 Watchdog Controller";
|
||||||
|
awc->offset = 0x20;
|
||||||
|
awc->ext_pulse_width_mask = 0xfffff;
|
||||||
|
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
|
||||||
|
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo aspeed_2500_wdt_info = {
|
||||||
|
.name = TYPE_ASPEED_2500_WDT,
|
||||||
|
.parent = TYPE_ASPEED_WDT,
|
||||||
|
.instance_size = sizeof(AspeedWDTState),
|
||||||
|
.class_init = aspeed_2500_wdt_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wdt_aspeed_register_types(void)
|
static void wdt_aspeed_register_types(void)
|
||||||
{
|
{
|
||||||
watchdog_add_model(&model);
|
watchdog_add_model(&model);
|
||||||
type_register_static(&aspeed_wdt_info);
|
type_register_static(&aspeed_wdt_info);
|
||||||
|
type_register_static(&aspeed_2400_wdt_info);
|
||||||
|
type_register_static(&aspeed_2500_wdt_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(wdt_aspeed_register_types)
|
type_init(wdt_aspeed_register_types)
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#define TYPE_ASPEED_WDT "aspeed.wdt"
|
#define TYPE_ASPEED_WDT "aspeed.wdt"
|
||||||
#define ASPEED_WDT(obj) \
|
#define ASPEED_WDT(obj) \
|
||||||
OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
|
OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
|
||||||
|
#define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400"
|
||||||
|
#define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500"
|
||||||
|
|
||||||
#define ASPEED_WDT_REGS_MAX (0x20 / 4)
|
#define ASPEED_WDT_REGS_MAX (0x20 / 4)
|
||||||
|
|
||||||
|
@ -30,8 +32,20 @@ typedef struct AspeedWDTState {
|
||||||
|
|
||||||
AspeedSCUState *scu;
|
AspeedSCUState *scu;
|
||||||
uint32_t pclk_freq;
|
uint32_t pclk_freq;
|
||||||
uint32_t silicon_rev;
|
|
||||||
uint32_t ext_pulse_width_mask;
|
|
||||||
} AspeedWDTState;
|
} AspeedWDTState;
|
||||||
|
|
||||||
|
#define ASPEED_WDT_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(AspeedWDTClass, (klass), TYPE_ASPEED_WDT)
|
||||||
|
#define ASPEED_WDT_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(AspeedWDTClass, (obj), TYPE_ASPEED_WDT)
|
||||||
|
|
||||||
|
typedef struct AspeedWDTClass {
|
||||||
|
SysBusDeviceClass parent_class;
|
||||||
|
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t ext_pulse_width_mask;
|
||||||
|
uint32_t reset_ctrl_reg;
|
||||||
|
void (*reset_pulse)(AspeedWDTState *s, uint32_t property);
|
||||||
|
} AspeedWDTClass;
|
||||||
|
|
||||||
#endif /* WDT_ASPEED_H */
|
#endif /* WDT_ASPEED_H */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue