[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 16/25] hw/arm/stellaris: Convert SSYS to QOM device
From: |
Luc Michel |
Subject: |
Re: [PATCH 16/25] hw/arm/stellaris: Convert SSYS to QOM device |
Date: |
Fri, 22 Jan 2021 21:26:04 +0100 |
On 19:06 Thu 21 Jan , Peter Maydell wrote:
> Convert the SSYS code in the Stellaris boards (which encapsulates the
> system registers) to a proper QOM device. This will provide us with
> somewhere to put the output Clock whose frequency depends on the
> setting of the PLL configuration registers.
>
> This is a migration compatibility break for lm3s811evb, lm3s6965evb.
>
> We use 3-phase reset here because the Clock will need to propagate
> its value in the hold phase.
>
> For the moment we reset the device during the board creation so that
> the system_clock_scale global gets set; this will be removed in a
> subsequent commit.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Luc Michel <luc@lmichel.fr>
> ---
> hw/arm/stellaris.c | 132 ++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 107 insertions(+), 25 deletions(-)
>
> diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
> index 652823195b1..0194ede2fe0 100644
> --- a/hw/arm/stellaris.c
> +++ b/hw/arm/stellaris.c
> @@ -357,7 +357,12 @@ static void stellaris_gptm_realize(DeviceState *dev,
> Error **errp)
>
> /* System controller. */
>
> -typedef struct {
> +#define TYPE_STELLARIS_SYS "stellaris-sys"
> +OBJECT_DECLARE_SIMPLE_TYPE(ssys_state, STELLARIS_SYS)
> +
> +struct ssys_state {
> + SysBusDevice parent_obj;
> +
> MemoryRegion iomem;
> uint32_t pborctl;
> uint32_t ldopctl;
> @@ -371,11 +376,18 @@ typedef struct {
> uint32_t dcgc[3];
> uint32_t clkvclr;
> uint32_t ldoarst;
> + qemu_irq irq;
> + /* Properties (all read-only registers) */
> uint32_t user0;
> uint32_t user1;
> - qemu_irq irq;
> - stellaris_board_info *board;
> -} ssys_state;
> + uint32_t did0;
> + uint32_t did1;
> + uint32_t dc0;
> + uint32_t dc1;
> + uint32_t dc2;
> + uint32_t dc3;
> + uint32_t dc4;
> +};
>
> static void ssys_update(ssys_state *s)
> {
> @@ -430,7 +442,7 @@ static uint32_t pllcfg_fury[16] = {
>
> static int ssys_board_class(const ssys_state *s)
> {
> - uint32_t did0 = s->board->did0;
> + uint32_t did0 = s->did0;
> switch (did0 & DID0_VER_MASK) {
> case DID0_VER_0:
> return DID0_CLASS_SANDSTORM;
> @@ -456,19 +468,19 @@ static uint64_t ssys_read(void *opaque, hwaddr offset,
>
> switch (offset) {
> case 0x000: /* DID0 */
> - return s->board->did0;
> + return s->did0;
> case 0x004: /* DID1 */
> - return s->board->did1;
> + return s->did1;
> case 0x008: /* DC0 */
> - return s->board->dc0;
> + return s->dc0;
> case 0x010: /* DC1 */
> - return s->board->dc1;
> + return s->dc1;
> case 0x014: /* DC2 */
> - return s->board->dc2;
> + return s->dc2;
> case 0x018: /* DC3 */
> - return s->board->dc3;
> + return s->dc3;
> case 0x01c: /* DC4 */
> - return s->board->dc4;
> + return s->dc4;
> case 0x030: /* PBORCTL */
> return s->pborctl;
> case 0x034: /* LDOPCTL */
> @@ -646,9 +658,9 @@ static const MemoryRegionOps ssys_ops = {
> .endianness = DEVICE_NATIVE_ENDIAN,
> };
>
> -static void ssys_reset(void *opaque)
> +static void stellaris_sys_reset_enter(Object *obj, ResetType type)
> {
> - ssys_state *s = (ssys_state *)opaque;
> + ssys_state *s = STELLARIS_SYS(obj);
>
> s->pborctl = 0x7ffd;
> s->rcc = 0x078e3ac0;
> @@ -661,9 +673,19 @@ static void ssys_reset(void *opaque)
> s->rcgc[0] = 1;
> s->scgc[0] = 1;
> s->dcgc[0] = 1;
> +}
> +
> +static void stellaris_sys_reset_hold(Object *obj)
> +{
> + ssys_state *s = STELLARIS_SYS(obj);
> +
> ssys_calculate_system_clock(s);
> }
>
> +static void stellaris_sys_reset_exit(Object *obj)
> +{
> +}
> +
> static int stellaris_sys_post_load(void *opaque, int version_id)
> {
> ssys_state *s = opaque;
> @@ -695,27 +717,66 @@ static const VMStateDescription vmstate_stellaris_sys =
> {
> }
> };
>
> +static Property stellaris_sys_properties[] = {
> + DEFINE_PROP_UINT32("user0", ssys_state, user0, 0),
> + DEFINE_PROP_UINT32("user1", ssys_state, user1, 0),
> + DEFINE_PROP_UINT32("did0", ssys_state, did0, 0),
> + DEFINE_PROP_UINT32("did1", ssys_state, did1, 0),
> + DEFINE_PROP_UINT32("dc0", ssys_state, dc0, 0),
> + DEFINE_PROP_UINT32("dc1", ssys_state, dc1, 0),
> + DEFINE_PROP_UINT32("dc2", ssys_state, dc2, 0),
> + DEFINE_PROP_UINT32("dc3", ssys_state, dc3, 0),
> + DEFINE_PROP_UINT32("dc4", ssys_state, dc4, 0),
> + DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static void stellaris_sys_instance_init(Object *obj)
> +{
> + ssys_state *s = STELLARIS_SYS(obj);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(s);
> +
> + memory_region_init_io(&s->iomem, obj, &ssys_ops, s, "ssys", 0x00001000);
> + sysbus_init_mmio(sbd, &s->iomem);
> + sysbus_init_irq(sbd, &s->irq);
> +}
> +
> static int stellaris_sys_init(uint32_t base, qemu_irq irq,
> stellaris_board_info * board,
> uint8_t *macaddr)
> {
> - ssys_state *s;
> + DeviceState *dev = qdev_new(TYPE_STELLARIS_SYS);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>
> - s = g_new0(ssys_state, 1);
> - s->irq = irq;
> - s->board = board;
> /* Most devices come preprogrammed with a MAC address in the user data.
> */
> - s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
> - s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
> + qdev_prop_set_uint32(dev, "user0",
> + macaddr[0] | (macaddr[1] << 8) | (macaddr[2] <<
> 16));
> + qdev_prop_set_uint32(dev, "user1",
> + macaddr[3] | (macaddr[4] << 8) | (macaddr[5] <<
> 16));
> + qdev_prop_set_uint32(dev, "did0", board->did0);
> + qdev_prop_set_uint32(dev, "did1", board->did1);
> + qdev_prop_set_uint32(dev, "dc0", board->dc0);
> + qdev_prop_set_uint32(dev, "dc1", board->dc1);
> + qdev_prop_set_uint32(dev, "dc2", board->dc2);
> + qdev_prop_set_uint32(dev, "dc3", board->dc3);
> + qdev_prop_set_uint32(dev, "dc4", board->dc4);
> +
> + sysbus_realize_and_unref(sbd, &error_fatal);
> + sysbus_mmio_map(sbd, 0, base);
> + sysbus_connect_irq(sbd, 0, irq);
> +
> + /*
> + * Normally we should not be resetting devices like this during
> + * board creation. For the moment we need to do so, because
> + * system_clock_scale will only get set when the STELLARIS_SYS
> + * device is reset, and we need its initial value to pass to
> + * the watchdog device. This hack can be removed once the
> + * watchdog has been converted to use a Clock input instead.
> + */
> + device_cold_reset(dev);
>
> - memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000);
> - memory_region_add_subregion(get_system_memory(), base, &s->iomem);
> - ssys_reset(s);
> - vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_stellaris_sys,
> s);
> return 0;
> }
>
> -
> /* I2C controller. */
>
> #define TYPE_STELLARIS_I2C "stellaris-i2c"
> @@ -1553,11 +1614,32 @@ static const TypeInfo stellaris_adc_info = {
> .class_init = stellaris_adc_class_init,
> };
>
> +static void stellaris_sys_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + dc->vmsd = &vmstate_stellaris_sys;
> + rc->phases.enter = stellaris_sys_reset_enter;
> + rc->phases.hold = stellaris_sys_reset_hold;
> + rc->phases.exit = stellaris_sys_reset_exit;
> + device_class_set_props(dc, stellaris_sys_properties);
> +}
> +
> +static const TypeInfo stellaris_sys_info = {
> + .name = TYPE_STELLARIS_SYS,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(ssys_state),
> + .instance_init = stellaris_sys_instance_init,
> + .class_init = stellaris_sys_class_init,
> +};
> +
> static void stellaris_register_types(void)
> {
> type_register_static(&stellaris_i2c_info);
> type_register_static(&stellaris_gptm_info);
> type_register_static(&stellaris_adc_info);
> + type_register_static(&stellaris_sys_info);
> }
>
> type_init(stellaris_register_types)
> --
> 2.20.1
>
--
[PATCH 20/25] hw/watchdog/cmsdk-apb-watchdog: Convert to use Clock input, Peter Maydell, 2021/01/21
[PATCH 21/25] tests/qtest/cmsdk-apb-watchdog-test: Test clock changes, Peter Maydell, 2021/01/21
[PATCH 22/25] hw/arm/armsse: Use Clock to set system_clock_scale, Peter Maydell, 2021/01/21