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 <root@stephanos.io>
+ *
+ * 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:
+        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;
+    }
+
+    /* Compute PLL output frequency */
+    pll_freq = pll_src / pll_prediv * pll_mult / pll_postdiv;
+
+    /* 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;
+    }
+
+    /* 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;
+    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 <root@stephanos.io>
+ *
+ * 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;
+        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;
+        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;
+        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
