qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] hw/arm/stm32f405: Add preliminary RCC emulation support


From: Alistair Francis
Subject: Re: [PATCH] hw/arm/stm32f405: Add preliminary RCC emulation support
Date: Fri, 6 Mar 2020 18:13:29 -0800

On Thu, Mar 5, 2020 at 5:06 PM Stephanos Ioannidis <address@hidden> wrote:
>
> > These should at least be numbers (if not macros) instead of binary.
>
> Just wanted to follow the convention that the reference manual uses (it lists 
> the field values in binary).

The one I read was both, in this case I think the binary form is more
complex then just the decimal values.

>
> > Can't you just do (rcc_pllcfgr.pllp + 1) * 2 instead of a switch case?
> > I don't think we need a switch statement here
> > if (rcc_cfgr.hpre) <= 8) {
> >   ahb_div = 1;
> > } else {
> >   ahb_div = (rcc_cfgr.hpre - 7) * 2
> > }
>
> I wanted to be as verbose as possible and leave any optimisation up to the 
> compiler. After all, when reading code, the switch implementation is a direct 
> representation of the value mapping on and is therefore much easier to 
> understand- given that it is not excessively long.

Fair, this one isn't too bad.

>
> > Where does this come from? I can't seem to find it in the RM.
>
> This is an equation representation of the clock tree diagram (refer to the  
> "Figure 21. Clock tree" from RM0900).
>
> > Shouldn't this be 0x0477 7F33?
>
> No, that is for STM32F42xxx and STM32F43xxx. See "7.3.19 RCC APB2 peripheral 
> clock enabled in low power mode register (RCC_APB2LPENR)" from RM0900.

Ah, I opened the wrong one then.

>
> > Shouldn't this be PLLSAIRDYF?
> > Aren't you missing a PLLSAIRDYIE
>
> No, PLLSAIRDYF and PLLSAIRDYIE are for STM32F42xxx and STM32F43xxx. STM32F405 
> does not have these fields.

Same as above.

Alistair

>
> Stephanos
>
> -----Original Message-----
> From: Alistair Francis <address@hidden>
> Sent: Friday, March 6, 2020 4:40 AM
> To: Stephanos Ioannidis <address@hidden>
> Cc: Peter Maydell <address@hidden>; Alistair Francis <address@hidden>; open 
> list:All patches CC here <address@hidden>; open list:ARM TCG CPUs 
> <address@hidden>
> Subject: Re: [PATCH] hw/arm/stm32f405: Add preliminary RCC emulation support
>
>  =  heOn Sat, Feb 29, 2020 at 6:12 AM Stephanos Ioannidis <address@hidden> 
> wrote:
> >
> > The RCC (reset and clock control) is a hardware peripheral reset and
> > clock configuration controller available on the STM32F4xx series
> > devices.
> >
> > This commit adds preliminary support for the RCC peripheral emulation,
> > in order to support proper emulation of the firmware images that use
> > the STM32Cube driver, which configures and validates the RCC registers
> > during system initialisation.
> >
> > In addition, the current STM32F405 SoC implementation does not specify
> > the Cortex-M SysTick clock scaling factor and this causes the QEMU to
> > become unresponsive as soon as the SysTick timer is enabled by the
> > guest. This problem is addressed by configuring the SysTick clock
> > scaling factor from the AHB clock frequency computed using the RCC
> > clock configurations.
> >
> > Signed-off-by: Stephanos Ioannidis <address@hidden>
> > ---
> >  hw/arm/Kconfig                  |   1 +
> >  hw/arm/netduinoplus2.c          |   1 +
> >  hw/arm/stm32f405_soc.c          |  17 +-
> >  hw/misc/Kconfig                 |   3 +
> >  hw/misc/Makefile.objs           |   1 +
> >  hw/misc/stm32f4xx_rcc.c         | 472 ++++++++++++++++++++++++++++++++
> >  hw/misc/trace-events            |   4 +
> >  include/hw/arm/stm32f405_soc.h  |   3 +
> >  include/hw/misc/stm32f4xx_rcc.h | 316 +++++++++++++++++++++
> >  9 files changed, 817 insertions(+), 1 deletion(-)  create mode 100644
> > hw/misc/stm32f4xx_rcc.c  create mode 100644
> > include/hw/misc/stm32f4xx_rcc.h
> >
> > diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index
> > 3d86691ae0..16442b3c4b 100644
> > --- a/hw/arm/Kconfig
> > +++ b/hw/arm/Kconfig
> > @@ -314,6 +314,7 @@ config STM32F205_SOC  config STM32F405_SOC
> >      bool
> >      select ARM_V7M
> > +    select STM32F4XX_RCC
> >      select STM32F4XX_SYSCFG
> >      select STM32F4XX_EXTI
> >
> > diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c index
> > e5e247edbe..37d57dafe4 100644
> > --- a/hw/arm/netduinoplus2.c
> > +++ b/hw/arm/netduinoplus2.c
> > @@ -36,6 +36,7 @@ static void netduinoplus2_init(MachineState
> > *machine)
> >
> >      dev = qdev_create(NULL, TYPE_STM32F405_SOC);
> >      qdev_prop_set_string(dev, "cpu-type",
> > ARM_CPU_TYPE_NAME("cortex-m4"));
> > +    qdev_prop_set_uint32(dev, "hse-frequency", 25000000);
> >      object_property_set_bool(OBJECT(dev), true, "realized",
> > &error_fatal);
> >
> >      armv7m_load_kernel(ARM_CPU(first_cpu),
> > diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index
> > 9bcad97853..5abbbc96c0 100644
> > --- a/hw/arm/stm32f405_soc.c
> > +++ b/hw/arm/stm32f405_soc.c
> > @@ -30,6 +30,7 @@
> >  #include "hw/arm/stm32f405_soc.h"
> >  #include "hw/misc/unimp.h"
> >
> > +#define RCC_ADDR                       0x40023800
> >  #define SYSCFG_ADD                     0x40013800
> >  static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
> >                                         0x40004C00, 0x40005000,
> > 0x40011400, @@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj)
> >      sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m),
> >                            TYPE_ARMV7M);
> >
> > +    sysbus_init_child_obj(obj, "rcc", &s->rcc, sizeof(s->rcc),
> > +                          TYPE_STM32F4XX_RCC);
> > +
> >      sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg),
> >                            TYPE_STM32F4XX_SYSCFG);
> >
> > @@ -130,6 +134,17 @@ static void stm32f405_soc_realize(DeviceState 
> > *dev_soc, Error **errp)
> >          return;
> >      }
> >
> > +    /* Reset and clock control */
> > +    dev = DEVICE(&s->rcc);
> > +    qdev_prop_set_uint32(dev, "hse-frequency", s->hse_frequency);
> > +    object_property_set_bool(OBJECT(&s->rcc), true, "realized", &err);
> > +    if (err != NULL) {
> > +        error_propagate(errp, err);
> > +        return;
> > +    }
> > +    busdev = SYS_BUS_DEVICE(dev);
> > +    sysbus_mmio_map(busdev, 0, RCC_ADDR);
> > +
> >      /* System configuration controller */
> >      dev = DEVICE(&s->syscfg);
> >      object_property_set_bool(OBJECT(&s->syscfg), true, "realized",
> > &err); @@ -260,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState 
> > *dev_soc, Error **errp)
> >      create_unimplemented_device("GPIOH",       0x40021C00, 0x400);
> >      create_unimplemented_device("GPIOI",       0x40022000, 0x400);
> >      create_unimplemented_device("CRC",         0x40023000, 0x400);
> > -    create_unimplemented_device("RCC",         0x40023800, 0x400);
> >      create_unimplemented_device("Flash Int",   0x40023C00, 0x400);
> >      create_unimplemented_device("BKPSRAM",     0x40024000, 0x400);
> >      create_unimplemented_device("DMA1",        0x40026000, 0x400);
> > @@ -274,6 +288,7 @@ static void stm32f405_soc_realize(DeviceState
> > *dev_soc, Error **errp)
> >
> >  static Property stm32f405_soc_properties[] = {
> >      DEFINE_PROP_STRING("cpu-type", STM32F405State, cpu_type),
> > +    DEFINE_PROP_UINT32("hse-frequency", STM32F405State,
> > + hse_frequency, 0),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> >
> > diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index
> > bdd77d8020..0cb5f2af68 100644
> > --- a/hw/misc/Kconfig
> > +++ b/hw/misc/Kconfig
> > @@ -79,6 +79,9 @@ config IMX
> >      select SSI
> >      select USB_EHCI_SYSBUS
> >
> > +config STM32F4XX_RCC
> > +    bool
> > +
> >  config STM32F2XX_SYSCFG
> >      bool
> >
> > diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index
> > da993f45b7..58a856c00d 100644
> > --- a/hw/misc/Makefile.objs
> > +++ b/hw/misc/Makefile.objs
> > @@ -58,6 +58,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
> >  common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
> >  common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
> >  common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
> > +common-obj-$(CONFIG_STM32F4XX_RCC) += stm32f4xx_rcc.o
> >  common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
> >  common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o
> >  common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o diff --git
> > a/hw/misc/stm32f4xx_rcc.c b/hw/misc/stm32f4xx_rcc.c new file mode
> > 100644 index 0000000000..297f2430b8
> > --- /dev/null
> > +++ b/hw/misc/stm32f4xx_rcc.c
> > @@ -0,0 +1,472 @@
> > +/*
> > + * STM32F4xx RCC
> > + *
> > + * Copyright (c) 2020 Stephanos Ioannidis <address@hidden>
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > +obtaining a copy
> > + * of this software and associated documentation files (the
> > +"Software"), to deal
> > + * in the Software without restriction, including without limitation
> > +the rights
> > + * to use, copy, modify, merge, publish, distribute, sublicense,
> > +and/or sell
> > + * copies of the Software, and to permit persons to whom the Software
> > +is
> > + * furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be
> > +included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > +EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > +MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
> > +SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> > +OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > +ARISING FROM,
> > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> > +DEALINGS IN
> > + * THE SOFTWARE.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu/log.h"
> > +#include "trace.h"
> > +#include "hw/irq.h"
> > +#include "hw/qdev-properties.h"
> > +#include "migration/vmstate.h"
> > +#include "hw/misc/stm32f4xx_rcc.h"
> > +#include "hw/timer/armv7m_systick.h"
> > +
> > +#define HSI_FREQ    (16000000)
> > +
> > +static void rcc_update_clock(STM32F4xxRccState *s) {
> > +    uint32_t pll_src, pll_prediv, pll_mult, pll_postdiv, pll_freq;
> > +    uint32_t ahb_div, ahb_freq;
> > +    uint32_t sysclk_freq;
> > +    uint32_t systick_freq;
> > +
> > +    /* Resolve PLL clock source */
> > +    pll_src = s->rcc_pllcfgr.pllsrc ? s->hse_frequency : HSI_FREQ;
> > +
> > +    /* Resolve PLL input division factor */
> > +    switch (s->rcc_pllcfgr.pllm) {
> > +    case 0b000010 ... 0b111111:
> > +        pll_prediv = s->rcc_pllcfgr.pllm;
> > +        break;
> > +    default:
> > +        qemu_log_mask(
> > +            LOG_GUEST_ERROR,
> > +            "%s: Invalid PLLM\n", __func__);
> > +        return;
> > +    }
> > +
> > +    /* Resolve PLL VCO multiplication factor */
> > +    switch (s->rcc_pllcfgr.plln) {
> > +    case 0b000110010 ... 0b110110000:
>
> These should at least be numbers (if not macros) instead of binary.
>
> > +        pll_mult = s->rcc_pllcfgr.plln;
> > +        break;
> > +    default:
> > +        qemu_log_mask(
> > +            LOG_GUEST_ERROR,
> > +            "%s: Invalid PLLN\n", __func__);
> > +        return;
> > +    }
> > +
> > +    /* Resolve PLL output division factor */
> > +    switch (s->rcc_pllcfgr.pllp) {
> > +    case 0b00:
> > +        pll_postdiv = 2;
> > +        break;
> > +    case 0b01:
> > +        pll_postdiv = 4;
> > +        break;
> > +    case 0b10:
> > +        pll_postdiv = 6;
> > +        break;
> > +    case 0b11:
> > +        pll_postdiv = 8;
> > +        break;
> > +    }
>
> Can't you just do (rcc_pllcfgr.pllp + 1) * 2 instead of a switch case?
>
> > +
> > +    /* Compute PLL output frequency */
> > +    pll_freq = pll_src / pll_prediv * pll_mult / pll_postdiv;
>
> Where does this come from? I can't seem to find it in the RM.
>
> > +
> > +    /* Resolve SYSCLK frequency */
> > +    switch (s->rcc_cfgr.sw) {
> > +    case 0b00: /* High-speed internal oscillator (fixed at 16MHz) */
> > +        sysclk_freq = HSI_FREQ;
> > +        break;
> > +    case 0b01: /* High-speed external oscillator */
> > +        sysclk_freq = s->hse_frequency;
> > +        break;
> > +    case 0b10: /* PLL */
> > +        sysclk_freq = pll_freq;
> > +        break;
> > +    default:
> > +        qemu_log_mask(
> > +            LOG_GUEST_ERROR,
> > +            "%s: Invalid system clock source selected\n", __func__);
> > +        return;
> > +    }
> > +
> > +    /* Resolve AHB prescaler division ratio */
> > +    switch (s->rcc_cfgr.hpre) {
> > +    case 0b0000 ... 0b0111:
> > +        ahb_div = 1;
> > +        break;
> > +    case 0b1000:
> > +        ahb_div = 2;
> > +        break;
> > +    case 0b1001:
> > +        ahb_div = 4;
> > +        break;
> > +    case 0b1010:
> > +        ahb_div = 8;
> > +        break;
> > +    case 0b1011:
> > +        ahb_div = 16;
> > +        break;
> > +    case 0b1100:
> > +        ahb_div = 64;
> > +        break;
> > +    case 0b1101:
> > +        ahb_div = 128;
> > +        break;
> > +    case 0b1110:
> > +        ahb_div = 256;
> > +        break;
> > +    case 0b1111:
> > +        ahb_div = 512;
> > +        break;
> > +    }
>
> I don't think we need a switch statement here
>
> if (rcc_cfgr.hpre) <= 8) {
>   ahb_div = 1;
> } else {
>   ahb_div = (rcc_cfgr.hpre - 7) * 2
> }
>
> > +
> > +    /* Compute AHB frequency */
> > +    ahb_freq = sysclk_freq / ahb_div;
> > +
> > +    /* Compute and set Cortex-M SysTick timer clock frequency */
> > +    systick_freq = ahb_freq / 8;
> > +    system_clock_scale = 1000000000 / systick_freq; }
> > +
> > +static void stm32f4xx_rcc_reset(DeviceState *dev) {
> > +    STM32F4xxRccState *s = STM32F4XX_RCC(dev);
> > +
> > +    /* Initialise register values */
> > +    s->rcc_cr.reg = 0x00000083;
> > +    s->rcc_pllcfgr.reg = 0x24003010;
> > +    s->rcc_cfgr.reg = 0x00000000;
> > +    s->rcc_cir.reg = 0x00000000;
> > +    s->rcc_ahb1rstr.reg = 0x00000000;
> > +    s->rcc_ahb2rstr.reg = 0x00000000;
> > +    s->rcc_ahb3rstr.reg = 0x00000000;
> > +    s->rcc_apb1rstr.reg = 0x00000000;
> > +    s->rcc_apb2rstr.reg = 0x00000000;
> > +    s->rcc_ahb1enr.reg = 0x00100000;
> > +    s->rcc_ahb2enr.reg = 0x00000000;
> > +    s->rcc_ahb3enr.reg = 0x00000000;
> > +    s->rcc_apb1enr.reg = 0x00000000;
> > +    s->rcc_apb2enr.reg = 0x00000000;
> > +    s->rcc_ahb1lpenr.reg = 0x7E6791FF;
> > +    s->rcc_ahb2lpenr.reg = 0x000000F1;
> > +    s->rcc_ahb3lpenr.reg = 0x00000001;
> > +    s->rcc_apb1lpenr.reg = 0x36FEC9FF;
> > +    s->rcc_apb2lpenr.reg = 0x00075F33;
>
> Shouldn't this be 0x0477 7F33?
>
> > +    s->rcc_bdcr.reg = 0x00000000;
> > +    s->rcc_csr.reg = 0x0E000000;
> > +    s->rcc_sscgr.reg = 0x00000000;
> > +    s->rcc_plli2scfgr.reg = 0x20003000;
> > +
> > +    /* Update clock based on the reset state */
> > +    rcc_update_clock(s);
> > +}
> > +
> > +static void rcc_cr_write(STM32F4xxRccState *s, RccCrType val) {
> > +    /* Set internal high-speed clock state */
> > +    s->rcc_cr.hsirdy = s->rcc_cr.hsion = val.hsion;
> > +    /* Set external high-speed clock state */
> > +    s->rcc_cr.hserdy = s->rcc_cr.hseon = val.hseon;
> > +    /* Set external clock bypass state */
> > +    s->rcc_cr.hsebyp = s->rcc_cr.hserdy && val.hsebyp;
> > +    /* Set PLL state */
> > +    s->rcc_cr.pllrdy = s->rcc_cr.pllon = val.pllon;
> > +    /* Set I2S PLL state */
> > +    s->rcc_cr.plli2srdy = s->rcc_cr.plli2son = val.plli2son;
> > +
> > +    /* Update clock */
> > +    rcc_update_clock(s);
> > +}
> > +
> > +static void rcc_pllcfgr_write(STM32F4xxRccState *s, RccPllcfgrType
> > +val) {
> > +    /* Set PLL entry clock source */
> > +    s->rcc_pllcfgr.pllsrc = val.pllsrc;
> > +    /* Set main PLL input division factor */
> > +    s->rcc_pllcfgr.pllm = val.pllm;
> > +    /* Set main PLL multiplication factor for VCO */
> > +    s->rcc_pllcfgr.plln = val.plln;
> > +    /* Set main PLL output division factor */
> > +    s->rcc_pllcfgr.pllp = val.pllp;
> > +
> > +    /* Update clock */
> > +    rcc_update_clock(s);
> > +}
> > +
> > +static void rcc_cfgr_write(STM32F4xxRccState *s, RccCfgrType val) {
> > +    /* Set clock switch status */
> > +    s->rcc_cfgr.sw = s->rcc_cfgr.sws = val.sw;
> > +    /* Set AHB prescaler clock division factor */
> > +    s->rcc_cfgr.hpre = val.hpre;
> > +
> > +    /* Update clock */
> > +    rcc_update_clock(s);
> > +}
> > +
> > +static void rcc_csr_write(STM32F4xxRccState *s, RccCsrType val) {
> > +    /* Set internal low-speed oscillator state */
> > +    s->rcc_csr.lsirdy = s->rcc_csr.lsion = val.lsion;
> > +
> > +    /* Update clock */
> > +    rcc_update_clock(s);
> > +}
> > +
> > +static uint64_t stm32f4xx_rcc_read(void *opaque, hwaddr addr,
> > +                                     unsigned int size) {
> > +    STM32F4xxRccState *s = opaque;
> > +
> > +    trace_stm32f4xx_rcc_read(addr);
> > +
> > +    switch (addr) {
> > +    case RCC_CR:
> > +        return s->rcc_cr.reg;
> > +    case RCC_PLLCFGR:
> > +        return s->rcc_pllcfgr.reg;
> > +    case RCC_CFGR:
> > +        return s->rcc_cfgr.reg;
> > +    case RCC_CIR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Clock interrupt configuration is not supported in QEMU\n",
> > +            __func__);
> > +        return s->rcc_cir.reg;
> > +    case RCC_AHB1RSTR:
> > +        return s->rcc_ahb1rstr.reg;
> > +    case RCC_AHB2RSTR:
> > +        return s->rcc_ahb2rstr.reg;
> > +    case RCC_AHB3RSTR:
> > +        return s->rcc_ahb3rstr.reg;
> > +    case RCC_APB1RSTR:
> > +        return s->rcc_apb1rstr.reg;
> > +    case RCC_APB2RSTR:
> > +        return s->rcc_apb2rstr.reg;
> > +    case RCC_AHB1ENR:
> > +        return s->rcc_ahb1enr.reg;
> > +    case RCC_AHB2ENR:
> > +        return s->rcc_ahb2enr.reg;
> > +    case RCC_AHB3ENR:
> > +        return s->rcc_ahb3enr.reg;
> > +    case RCC_APB1ENR:
> > +        return s->rcc_apb1enr.reg;
> > +    case RCC_APB2ENR:
> > +        return s->rcc_apb2enr.reg;
> > +    case RCC_AHB1LPENR:
> > +        return s->rcc_ahb1lpenr.reg;
> > +    case RCC_AHB2LPENR:
> > +        return s->rcc_ahb2lpenr.reg;
> > +    case RCC_AHB3LPENR:
> > +        return s->rcc_ahb3lpenr.reg;
> > +    case RCC_APB1LPENR:
> > +        return s->rcc_apb1lpenr.reg;
> > +    case RCC_APB2LPENR:
> > +        return s->rcc_apb2lpenr.reg;
> > +    case RCC_BDCR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Backup domain control is not supported in QEMU\n",
> > +            __func__);
> > +        return s->rcc_bdcr.reg;
> > +    case RCC_CSR:
> > +        return s->rcc_csr.reg;
> > +    case RCC_SSCGR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Spread spectrum clock generation is not supported in 
> > QEMU\n",
> > +            __func__);
> > +        return s->rcc_sscgr.reg;
> > +    case RCC_PLLI2SCFGR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: PLLI2S configuration is not supported in QEMU\n",
> > +            __func__);
> > +        return s->rcc_plli2scfgr.reg;
> > +    default:
> > +        qemu_log_mask(
> > +            LOG_GUEST_ERROR,
> > +            "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +        return 0;
> > +    }
> > +}
> > +
> > +static void stm32f4xx_rcc_write(void *opaque, hwaddr addr,
> > +                       uint64_t val64, unsigned int size) {
> > +    STM32F4xxRccState *s = opaque;
> > +    uint32_t value = val64;
> > +
> > +    trace_stm32f4xx_rcc_write(value, addr);
> > +
> > +    switch (addr) {
> > +    case RCC_CR:
> > +        rcc_cr_write(s, (RccCrType)value);
> > +        return;
> > +    case RCC_PLLCFGR:
> > +        rcc_pllcfgr_write(s, (RccPllcfgrType)value);
> > +        return;
> > +    case RCC_CFGR:
> > +        rcc_cfgr_write(s, (RccCfgrType)value);
> > +        return;
> > +    case RCC_CIR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Clock interrupt configuration is not supported in QEMU\n",
> > +            __func__);
> > +        return;
> > +    case RCC_AHB1RSTR ... RCC_APB2RSTR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Peripheral reset is a no-op in QEMU\n", __func__);
> > +        return;
> > +    case RCC_AHB1ENR:
> > +        /* Store peripheral enable status; otherwise, this is no-op */
> > +        s->rcc_ahb1enr.reg = value;
> > +        return;
> > +    case RCC_AHB2ENR:
> > +        s->rcc_ahb2enr.reg = value;
> > +        return;
> > +    case RCC_AHB3ENR:
> > +        s->rcc_ahb3enr.reg = value;
> > +        return;
> > +    case RCC_APB1ENR:
> > +        s->rcc_apb1enr.reg = value;
> > +        return;
> > +    case RCC_APB2ENR:
> > +        s->rcc_apb2enr.reg = value;
> > +        return;
> > +    case RCC_AHB1LPENR:
> > +        /* Store peripheral low power status; otherwise, this is no-op */
> > +        s->rcc_ahb1lpenr.reg = value;
> > +        return;
> > +    case RCC_AHB2LPENR:
> > +        s->rcc_ahb2lpenr.reg = value;
> > +        return;
> > +    case RCC_AHB3LPENR:
> > +        s->rcc_ahb3lpenr.reg = value;
> > +        return;
> > +    case RCC_APB1LPENR:
> > +        s->rcc_apb1lpenr.reg = value;
> > +        return;
> > +    case RCC_APB2LPENR:
> > +        s->rcc_apb2lpenr.reg = value;
> > +        return;
> > +    case RCC_BDCR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Backup domain control is not supported in QEMU\n",
> > +            __func__);
> > +        return;
> > +    case RCC_CSR:
> > +        rcc_csr_write(s, (RccCsrType)value);
> > +        return;
> > +    case RCC_SSCGR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: Spread spectrum clock generation is not supported in 
> > QEMU\n",
> > +            __func__);
> > +        return;
> > +    case RCC_PLLI2SCFGR:
> > +        qemu_log_mask(
> > +            LOG_UNIMP,
> > +            "%s: PLLI2S configuration is not supported in QEMU\n",
> > +            __func__);
> > +        return;
> > +    default:
> > +        qemu_log_mask(
> > +            LOG_GUEST_ERROR,
> > +            "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> > +    }
> > +}
> > +
> > +static const MemoryRegionOps stm32f4xx_rcc_ops = {
> > +    .read = stm32f4xx_rcc_read,
> > +    .write = stm32f4xx_rcc_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN, };
> > +
> > +static void stm32f4xx_rcc_init(Object *obj) {
> > +    STM32F4xxRccState *s = STM32F4XX_RCC(obj);
> > +
> > +    memory_region_init_io(&s->mmio, obj, &stm32f4xx_rcc_ops, s,
> > +                          TYPE_STM32F4XX_RCC, 0x400);
> > +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); }
> > +
> > +static const VMStateDescription vmstate_stm32f4xx_rcc = {
> > +    .name = TYPE_STM32F4XX_RCC,
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_UINT32(rcc_cr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_pllcfgr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_cfgr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_cir.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb1rstr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb2rstr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb3rstr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb1rstr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb2rstr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb1enr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb2enr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb3enr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb1enr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb2enr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb1lpenr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb2lpenr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_ahb3lpenr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb1lpenr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_apb2lpenr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_bdcr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_csr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_sscgr.reg, STM32F4xxRccState),
> > +        VMSTATE_UINT32(rcc_plli2scfgr.reg, STM32F4xxRccState),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static Property stm32f4xx_rcc_properties[] = {
> > +    DEFINE_PROP_UINT32("hse-frequency", STM32F4xxRccState, hse_frequency, 
> > 0),
> > +    DEFINE_PROP_END_OF_LIST()
> > +};
> > +
> > +static void stm32f4xx_rcc_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->reset = stm32f4xx_rcc_reset;
> > +    dc->vmsd = &vmstate_stm32f4xx_rcc;
> > +    device_class_set_props(dc, stm32f4xx_rcc_properties); }
> > +
> > +static const TypeInfo stm32f4xx_rcc_info = {
> > +    .name          = TYPE_STM32F4XX_RCC,
> > +    .parent        = TYPE_SYS_BUS_DEVICE,
> > +    .instance_size = sizeof(STM32F4xxRccState),
> > +    .instance_init = stm32f4xx_rcc_init,
> > +    .class_init    = stm32f4xx_rcc_class_init,
> > +};
> > +
> > +static void stm32f4xx_rcc_register_types(void)
> > +{
> > +    type_register_static(&stm32f4xx_rcc_info);
> > +}
> > +
> > +type_init(stm32f4xx_rcc_register_types)
> > diff --git a/hw/misc/trace-events b/hw/misc/trace-events index
> > 7f0f5dff3a..0fa47598b5 100644
> > --- a/hw/misc/trace-events
> > +++ b/hw/misc/trace-events
> > @@ -84,6 +84,10 @@ mos6522_set_sr_int(void) "set sr_int"
> >  mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 "
> > val=0x%"PRIx64  mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " 
> > val=0x%x"
> >
> > +# stm32f4xx_rcc
> > +stm32f4xx_rcc_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
> > +stm32f4xx_rcc_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" 
> > PRIx64 " val: 0x%" PRIx64 ""
> > +
> >  # stm32f4xx_syscfg
> >  stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: 
> > %d, Line: %d; Level: %d"
> >  stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
> > diff --git a/include/hw/arm/stm32f405_soc.h
> > b/include/hw/arm/stm32f405_soc.h index 1fe97f8c3a..037db62a58 100644
> > --- a/include/hw/arm/stm32f405_soc.h
> > +++ b/include/hw/arm/stm32f405_soc.h
> > @@ -25,6 +25,7 @@
> >  #ifndef HW_ARM_STM32F405_SOC_H
> >  #define HW_ARM_STM32F405_SOC_H
> >
> > +#include "hw/misc/stm32f4xx_rcc.h"
> >  #include "hw/misc/stm32f4xx_syscfg.h"
> >  #include "hw/timer/stm32f2xx_timer.h"
> >  #include "hw/char/stm32f2xx_usart.h"
> > @@ -54,9 +55,11 @@ typedef struct STM32F405State {
> >      /*< public >*/
> >
> >      char *cpu_type;
> > +    uint32_t hse_frequency;
> >
> >      ARMv7MState armv7m;
> >
> > +    STM32F4xxRccState rcc;
> >      STM32F4xxSyscfgState syscfg;
> >      STM32F4xxExtiState exti;
> >      STM32F2XXUsartState usart[STM_NUM_USARTS]; diff --git
> > a/include/hw/misc/stm32f4xx_rcc.h b/include/hw/misc/stm32f4xx_rcc.h
> > new file mode 100644 index 0000000000..5c269753c0
> > --- /dev/null
> > +++ b/include/hw/misc/stm32f4xx_rcc.h
> > @@ -0,0 +1,316 @@
> > +/*
> > + * STM32F4xx RCC
> > + *
> > + * Copyright (c) 2020 Stephanos Ioannidis <address@hidden>
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> > +obtaining a copy
> > + * of this software and associated documentation files (the
> > +"Software"), to deal
> > + * in the Software without restriction, including without limitation
> > +the rights
> > + * to use, copy, modify, merge, publish, distribute, sublicense,
> > +and/or sell
> > + * copies of the Software, and to permit persons to whom the Software
> > +is
> > + * furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be
> > +included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > +EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > +MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
> > +SHALL
> > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
> > +OR OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> > +ARISING FROM,
> > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> > +DEALINGS IN
> > + * THE SOFTWARE.
> > + */
> > +
> > +#ifndef HW_STM_RCC_H
> > +#define HW_STM_RCC_H
> > +
> > +#include "hw/sysbus.h"
> > +#include "hw/hw.h"
> > +
> > +#define TYPE_STM32F4XX_RCC "stm32f4xx-rcc"
> > +#define STM32F4XX_RCC(obj) \
> > +    OBJECT_CHECK(STM32F4xxRccState, (obj), TYPE_STM32F4XX_RCC)
> > +
> > +#define RCC_CR         0x00
> > +#define RCC_PLLCFGR    0x04
> > +#define RCC_CFGR       0x08
> > +#define RCC_CIR        0x0C
> > +#define RCC_AHB1RSTR   0x10
> > +#define RCC_AHB2RSTR   0x14
> > +#define RCC_AHB3RSTR   0x18
> > +#define RCC_APB1RSTR   0x20
> > +#define RCC_APB2RSTR   0x24
> > +#define RCC_AHB1ENR    0x30
> > +#define RCC_AHB2ENR    0x34
> > +#define RCC_AHB3ENR    0x38
> > +#define RCC_APB1ENR    0x40
> > +#define RCC_APB2ENR    0x44
> > +#define RCC_AHB1LPENR  0x50
> > +#define RCC_AHB2LPENR  0x54
> > +#define RCC_AHB3LPENR  0x58
> > +#define RCC_APB1LPENR  0x60
> > +#define RCC_APB2LPENR  0x64
> > +#define RCC_BDCR       0x70
> > +#define RCC_CSR        0x74
> > +#define RCC_SSCGR      0x80
> > +#define RCC_PLLI2SCFGR 0x84
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t hsion : 1;
> > +        uint32_t hsirdy : 1;
> > +        uint32_t reserved0 : 1;
> > +        uint32_t hsitrim : 5;
> > +        uint32_t hsical : 8;
> > +        uint32_t hseon : 1;
> > +        uint32_t hserdy : 1;
> > +        uint32_t hsebyp : 1;
> > +        uint32_t csson : 1;
> > +        uint32_t reserved1 : 4;
> > +        uint32_t pllon : 1;
> > +        uint32_t pllrdy : 1;
> > +        uint32_t plli2son : 1;
> > +        uint32_t plli2srdy : 1;
> > +        uint32_t reserved2 : 4;
> > +    };
> > +    uint32_t reg;
> > +} RccCrType;
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t pllm : 6;
> > +        uint32_t plln : 9;
> > +        uint32_t reserved0 : 1;
> > +        uint32_t pllp : 2;
> > +        uint32_t reserved1 : 4;
> > +        uint32_t pllsrc : 1;
> > +        uint32_t reserved2 : 1;
> > +        uint32_t pllq : 4;
> re?> +        uint32_t reserved3 : 4;
> > +    };
> > +    uint32_t reg;
> > +} RccPllcfgrType;
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t sw : 2;
> > +        uint32_t sws : 2;
> > +        uint32_t hpre : 4;
> > +        uint32_t reserved0 : 2;
> > +        uint32_t ppre1 : 3;
> > +        uint32_t ppre2: 3;
> > +        uint32_t rtcpre : 5;
> > +        uint32_t mco1 : 2;
> > +        uint32_t i2sscr : 1;
> > +        uint32_t mco1pre : 3;
> > +        uint32_t mco2pre : 3;
> > +        uint32_t mco2 : 2;
> > +    };
> > +    uint32_t reg;
> > +} RccCfgrType;
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t lsirdyf : 1;
> > +        uint32_t lserdyf : 1;
> > +        uint32_t hsirdyf : 1;
> > +        uint32_t hserdyf : 1;
> > +        uint32_t pllrdyf : 1;
> > +        uint32_t plli2srdyf : 1;
> > +        uint32_t reserved0 : 1;
>
> Shouldn't this be PLLSAIRDYF?
>
> > +        uint32_t cssf : 1;
> > +        uint32_t lsirdyie : 1;
> > +        uint32_t lserdyie : 1;
> > +        uint32_t hsirdyie : 1;
> > +        uint32_t hserdyie : 1;
> > +        uint32_t pllrdyie : 1;
> > +        uint32_t plli2srdyie : 1;
>
> Aren't you missing a PLLSAIRDYIE
>
> Alistair
>
> > +        uint32_t reserved1 : 2;
> > +        uint32_t lsirdyc : 1;
> > +        uint32_t lserdyc : 1;
> > +        uint32_t hsirdyc : 1;
> > +        uint32_t hserdyc : 1;
> > +        uint32_t pllrdyc : 1;
> > +        uint32_t plli2srdyc : 1;
> > +        uint32_t reserved2 : 1;
> > +        uint32_t cssc : 1;
> > +        uint32_t reserved3 : 8;
> > +    };
> > +    uint32_t reg;
> > +} RccCirType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb1rstrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb2rstrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb3rstrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb1rstrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb2rstrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb1enrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb2enrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb3enrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb1enrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb2enrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb1lpenrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb2lpenrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccAhb3lpenrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb1lpenrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccApb2lpenrType;
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t lseon : 1;
> > +        uint32_t lserdy : 1;
> > +        uint32_t lsebyp : 1;
> > +        uint32_t reserved0 : 5;
> > +        uint32_t rtcsel : 2;
> > +        uint32_t reserved1 : 5;
> > +        uint32_t rtcen : 1;
> > +        uint32_t bdrst : 1;
> > +        uint32_t reserved2 : 15;
> > +    };
> > +    uint32_t reg;
> > +} RccBdcrType;
> > +
> > +typedef union {
> > +    struct {
> > +        uint32_t lsion : 1;
> > +        uint32_t lsirdy : 1;
> > +        uint32_t reserved0 : 22;
> > +        uint32_t rmvf : 1;
> > +        uint32_t borrstf : 1;
> > +        uint32_t pinrstf : 1;
> > +        uint32_t porrstf : 1;
> > +        uint32_t sftrstf : 1;
> > +        uint32_t iwdgrstf : 1;
> > +        uint32_t wwdgrstf : 1;
> > +        uint32_t lpwrrstf : 1;
> > +    };
> > +    uint32_t reg;
> > +} RccCsrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccSscgrType;
> > +
> > +typedef struct {
> > +    /* Fields are not specified */
> > +    uint32_t reg;
> > +} RccPlli2scfgrType;
> > +
> > +typedef struct {
> > +    /* <private> */
> > +    SysBusDevice parent_obj;
> > +
> > +    /* <public> */
> > +    MemoryRegion mmio;
> > +    uint32_t hse_frequency;
> > +
> > +    /* Clock control register (RCC_CR) */
> > +    RccCrType rcc_cr;
> > +    /* PLL configuration register (RCC_PLLCFGR) */
> > +    RccPllcfgrType rcc_pllcfgr;
> > +    /* Clock configuration register (RCC_CFGR) */
> > +    RccCfgrType rcc_cfgr;
> > +    /* Clock interrupt register (RCC_CIR) */
> > +    RccCirType rcc_cir;
> > +    /* AHB1 peripheral reset register (RCC_AHB1RSTR) */
> > +    RccAhb1rstrType rcc_ahb1rstr;
> > +    /* AHB2 peripheral reset register (RCC_AHB2RSTR) */
> > +    RccAhb2rstrType rcc_ahb2rstr;
> > +    /* AHB3 peripheral reset register (RCC_AHB3RSTR) */
> > +    RccAhb3rstrType rcc_ahb3rstr;
> > +    /* APB1 peripheral reset register (RCC_APB1RSTR) */
> > +    RccApb1rstrType rcc_apb1rstr;
> > +    /* APB2 peripheral reset register (RCC_APB2RSTR) */
> > +    RccApb2rstrType rcc_apb2rstr;
> > +    /* AHB1 peripheral clock register (RCC_AHB1ENR) */
> > +    RccAhb1enrType rcc_ahb1enr;
> > +    /* AHB2 peripheral clock register (RCC_AHB2ENR) */
> > +    RccAhb2enrType rcc_ahb2enr;
> > +    /* AHB3 peripheral clock register (RCC_AHB3ENR) */
> > +    RccAhb3enrType rcc_ahb3enr;
> > +    /* APB1 peripheral clock register (RCC_APB1ENR) */
> > +    RccApb1enrType rcc_apb1enr;
> > +    /* APB2 peripheral clock register (RCC_APB1ENR) */
> > +    RccApb2enrType rcc_apb2enr;
> > +    /* AHB1 peripheral low power mode register (RCC_AHB1LPENR) */
> > +    RccAhb1lpenrType rcc_ahb1lpenr;
> > +    /* AHB2 peripheral low power mode register (RCC_AHB2LPENR) */
> > +    RccAhb2lpenrType rcc_ahb2lpenr;
> > +    /* AHB3 peripheral low power mode register (RCC_AHB3LPENR) */
> > +    RccAhb3lpenrType rcc_ahb3lpenr;
> > +    /* APB1 peripheral low power mode register (RCC_APB1LPENR) */
> > +    RccApb1lpenrType rcc_apb1lpenr;
> > +    /* APB2 peripheral low power mode register (RCC_APB2LPENR) */
> > +    RccApb2lpenrType rcc_apb2lpenr;
> > +    /* Backup domain control register (RCC_BDCR) */
> > +    RccBdcrType rcc_bdcr;
> > +    /* Clock control and status register (RCC_CSR) */
> > +    RccCsrType rcc_csr;
> > +    /* Spread spectrum clock generation register (RCC_SSCGR) */
> > +    RccSscgrType rcc_sscgr;
> > +    /* PLLI2S configuration register (RCC_PLLI2SCFGR) */
> > +    RccPlli2scfgrType rcc_plli2scfgr; } STM32F4xxRccState;
> > +
> > +#endif
> > --
> > 2.17.1
> >
> >



reply via email to

[Prev in Thread] Current Thread [Next in Thread]