diff --git a/hw/arm/svd/meson.build b/hw/arm/svd/meson.build
index 22f75880f5..72a7421c6f 100644
--- a/hw/arm/svd/meson.build
+++ b/hw/arm/svd/meson.build
@@ -26,3 +26,11 @@ genh += custom_target('flexspi.h',
                       output: 'flexspi.h',
                       input: 'MIMXRT595S_cm33.xml',
                       command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'FLEXSPI0', '-t', 'FLEXSPI'])
+genh += custom_target('rt500_rstctl0.h',
+                      output: 'rt500_rstctl0.h',
+                      input: 'MIMXRT595S_cm33.xml',
+                      command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL0', '-t', 'RT500_RSTCTL0'])
+genh += custom_target('rt500_rstctl1.h',
+                      output: 'rt500_rstctl1.h',
+                      input: 'MIMXRT595S_cm33.xml',
+                      command: [ svd_gen_header, '-i', '@INPUT@', '-o', '@OUTPUT@', '-p', 'RSTCTL1', '-t', 'RT500_RSTCTL1'])
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 392ae9e84f..70a2a269ac 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -222,4 +222,7 @@ config RT500_CLKCTL0
 config RT500_CLKCTL1
     bool
 
+config RT500_RSTCTL
+    bool
+
 source macio/Kconfig
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 68929949a6..5e2728e982 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -160,3 +160,4 @@ system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c'))
 system_ss.add(when: 'CONFIG_FLEXCOMM', if_true: files('flexcomm.c'))
 system_ss.add(when: 'CONFIG_RT500_CLKCTL0', if_true: files('rt500_clkctl0.c'))
 system_ss.add(when: 'CONFIG_RT500_CLKCTL1', if_true: files('rt500_clkctl1.c'))
+system_ss.add(when: 'CONFIG_RT500_RSTCTL', if_true: files('rt500_rstctl.c'))
diff --git a/hw/misc/rt500_rstctl.c b/hw/misc/rt500_rstctl.c
new file mode 100644
index 0000000000..2806a94150
--- /dev/null
+++ b/hw/misc/rt500_rstctl.c
@@ -0,0 +1,219 @@
+/*
+ * QEMU model for RT500 Reset Controller
+ *
+ * Copyright (c) 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "exec/address-spaces.h"
+#include "hw/regs.h"
+#include "hw/misc/rt500_rstctl.h"
+
+#include "trace.h"
+
+/*
+ * There are two intances for RSTCTL with the same register names but
+ * with different fields.
+ */
+#define reg(field) offsetof(RT500_RSTCTL0_Type, field)
+#define regi(x) (reg(x) / sizeof(uint32_t))
+#define REG_NO (sizeof(RT500_RSTCTL0_Type) / sizeof(uint32_t))
+
+#define RSTCTL_SYSRSTSTAT_WMASK (BITS(7, 4) | BIT(0))
+#define RSTCL0_PRSCTL0_WMASK (BITS(30, 26) | BITS(24, 20) | BIT(18) | \
+                              BIT(16) | BITS(12, 8) | BIT(3) | BIT(1))
+#define RSTCL0_PRSCTL1_WMASK (BIT(24) | BITS(16, 15) | BITS(3, 2))
+#define RSTCL0_PRSCTL2_WMASK (BITS(1, 0))
+#define RSTCL1_PRSCTL0_WMASK (BIT(29) | BIT(27) |  BITS(25, 8))
+#define RSTCL1_PRSCTL1_WMASK (BIT(31) | BITS(29, 28) | BITS(24, 23) | \
+                              BIT(16) | BITS(7, 0))
+#define RSTCL1_PRSCTL2_WMASK (BITS(31, 30) | BITS(17, 16) | BIT(10) | \
+                              BIT(8) | BITS(4, 0))
+
+static RT500_RSTCTL0_REGISTER_NAMES_ARRAY(reg_names);
+
+static MemTxResult rt500_rstctl_read(void *opaque, hwaddr addr,
+                                     uint64_t *data, unsigned size,
+                                     MemTxAttrs attrs)
+{
+    RT500RstCtlState *s = opaque;
+    MemTxResult ret = MEMTX_OK;
+
+    if (s->num > 1 || !reg32_aligned_access(addr, size)) {
+        ret = MEMTX_ERROR;
+        goto out;
+    }
+
+    switch (addr) {
+    case reg(SYSRSTSTAT):
+    case reg(PRSTCTL0):
+    case reg(PRSTCTL1):
+    case reg(PRSTCTL2):
+        *data = reg32_read(&s->regs.ctl0, addr);
+        break;
+    default:
+        ret = MEMTX_ERROR;
+    }
+
+out:
+    trace_rt500_rstctl_reg_read(DEVICE(s)->id, reg_names[addr], addr, *data);
+    return ret;
+}
+
+static MemTxResult rt500_rstctl_write(void *opaque, hwaddr addr,
+                                      uint64_t value, unsigned size,
+                                      MemTxAttrs attrs)
+{
+    RT500RstCtlState *s = opaque;
+    static uint32_t mask0[REG_NO] = {
+        [regi(SYSRSTSTAT)] = RSTCTL_SYSRSTSTAT_WMASK,
+        [regi(PRSTCTL0)] = RSTCL0_PRSCTL0_WMASK,
+        [regi(PRSTCTL1)] = RSTCL0_PRSCTL1_WMASK,
+        [regi(PRSTCTL2)] = RSTCL0_PRSCTL2_WMASK,
+        [regi(PRSTCTL0_SET)] = RSTCL0_PRSCTL0_WMASK,
+        [regi(PRSTCTL1_SET)] = RSTCL0_PRSCTL1_WMASK,
+        [regi(PRSTCTL2_SET)] = RSTCL0_PRSCTL2_WMASK,
+        [regi(PRSTCTL0_CLR)] = RSTCL0_PRSCTL0_WMASK,
+        [regi(PRSTCTL1_CLR)] = RSTCL0_PRSCTL1_WMASK,
+        [regi(PRSTCTL2_CLR)] = RSTCL0_PRSCTL2_WMASK,
+    };
+    static uint32_t mask1[REG_NO] = {
+        [regi(SYSRSTSTAT)] = RSTCTL_SYSRSTSTAT_WMASK,
+        [regi(PRSTCTL0)] = RSTCL1_PRSCTL0_WMASK,
+        [regi(PRSTCTL1)] = RSTCL1_PRSCTL1_WMASK,
+        [regi(PRSTCTL2)] = RSTCL1_PRSCTL2_WMASK,
+        [regi(PRSTCTL0_SET)] = RSTCL1_PRSCTL0_WMASK,
+        [regi(PRSTCTL1_SET)] = RSTCL1_PRSCTL1_WMASK,
+        [regi(PRSTCTL2_SET)] = RSTCL1_PRSCTL2_WMASK,
+        [regi(PRSTCTL0_CLR)] = RSTCL1_PRSCTL0_WMASK,
+        [regi(PRSTCTL1_CLR)] = RSTCL1_PRSCTL1_WMASK,
+        [regi(PRSTCTL2_CLR)] = RSTCL1_PRSCTL2_WMASK,
+    };
+    uint32_t mask;
+
+    trace_rt500_rstctl_reg_write(DEVICE(s)->id, reg_names[addr], addr, value);
+
+    if (s->num > 1 || !reg32_aligned_access(addr, size)) {
+        return MEMTX_ERROR;
+    }
+
+    if (s->num == 0) {
+        mask = mask0[addr / sizeof(uint32_t)];
+    } else {
+        mask = mask1[addr / sizeof(uint32_t)];
+    }
+
+    switch (addr) {
+    case reg(SYSRSTSTAT):
+    {
+        /* write 1 to clear bits */
+        s->regs.ctl0.SYSRSTSTAT &= ~(value & mask);
+        break;
+    }
+    case reg(PRSTCTL0):
+    case reg(PRSTCTL1):
+    case reg(PRSTCTL2):
+    {
+        uint32_t idx = addr / sizeof(uint32_t);
+
+        s->regs.raw[idx] = (value & mask);
+        break;
+    }
+    case reg(PRSTCTL0_SET):
+    case reg(PRSTCTL1_SET):
+    case reg(PRSTCTL2_SET):
+    {
+        uint32_t idx;
+
+        idx = (reg(PRSTCTL0) + (addr - reg(PRSTCTL0_SET))) / sizeof(uint32_t);
+        s->regs.raw[idx] |= (value & mask);
+        break;
+    }
+    case reg(PRSTCTL0_CLR):
+    case reg(PRSTCTL1_CLR):
+    case reg(PRSTCTL2_CLR):
+    {
+        uint32_t idx;
+
+        idx = (reg(PRSTCTL0) + (addr - reg(PRSTCTL0_CLR))) / sizeof(uint32_t);
+        s->regs.raw[idx] &= ~(value & mask);
+        break;
+    }
+    }
+
+    return MEMTX_OK;
+}
+
+
+static const MemoryRegionOps rt500_rstctl_ops = {
+    .read_with_attrs = rt500_rstctl_read,
+    .write_with_attrs = rt500_rstctl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static Property rt500_rstctl_properties[] = {
+    DEFINE_PROP_UINT32("num", RT500RstCtlState, num, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rt500_rstctl_reset(DeviceState *dev)
+{
+    RT500RstCtlState *s = RT500_RSTCTL(dev);
+
+    memset(&s->regs, 0, sizeof(s->regs));
+
+    switch (s->num) {
+    case 0:
+        rt500_rstctl0_reset_registers(&s->regs.ctl0);
+        break;
+    case 1:
+        rt500_rstctl1_reset_registers(&s->regs.ctl1);
+        break;
+    }
+}
+
+static void rt500_rstctl_init(Object *obj)
+{
+    RT500RstCtlState *s = RT500_RSTCTL(obj);
+
+    memory_region_init_io(&s->mmio, obj, &rt500_rstctl_ops, s,
+                          TYPE_RT500_RSTCTL, sizeof(s->regs));
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void rt500_rstctl_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void rt500_rstctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = rt500_rstctl_reset;
+    device_class_set_props(dc, rt500_rstctl_properties);
+    dc->realize = rt500_rstctl_realize;
+}
+
+static const TypeInfo rt500_rstctl_info = {
+    .name          = TYPE_RT500_RSTCTL,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RT500RstCtlState),
+    .instance_init = rt500_rstctl_init,
+    .class_init    = rt500_rstctl_class_init,
+};
+
+static void rt500_rstctl_register_types(void)
+{
+    type_register_static(&rt500_rstctl_info);
+}
+
+type_init(rt500_rstctl_register_types)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index e65fcfa613..41a94d5ef6 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -365,3 +365,7 @@ rt500_clkctl0_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x
 # rt500_clkctl1.c
 rt500_clkctl1_reg_read(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] -> 0x%08x"
 rt500_clkctl1_reg_write(const char *regname, uint32_t addr, uint32_t val) "%s[0x%04x] <- 0x%08x"
+
+# rt500_rstctl.c
+rt500_rstctl_reg_read(const char *id, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] -> 0x%08x"
+rt500_rstctl_reg_write(const char *id, const char *regname, uint32_t addr, uint32_t val) "%s: %s[0x%04x] <- 0x%08x"
diff --git a/include/hw/misc/rt500_rstctl.h b/include/hw/misc/rt500_rstctl.h
new file mode 100644
index 0000000000..d9726df5f6
--- /dev/null
+++ b/include/hw/misc/rt500_rstctl.h
@@ -0,0 +1,38 @@
+/*
+ * QEMU model for RT500 Reset Controller
+ *
+ * Copyright (c) 2024 Google LLC
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef HW_MISC_RT500_RSTCTL_H
+#define HW_MISC_RT500_RSTCTL_H
+
+#include "hw/arm/svd/rt500_rstctl0.h"
+#include "hw/arm/svd/rt500_rstctl1.h"
+#include "hw/sysbus.h"
+
+#define RSTCTL_Type RSTCTL0_Type
+
+#define TYPE_RT500_RSTCTL "rt500-rstctl"
+#define RT500_RSTCTL(o) OBJECT_CHECK(RT500RstCtlState, o, TYPE_RT500_RSTCTL)
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+    uint32_t num;
+    union {
+        RT500_RSTCTL0_Type ctl0;
+        RT500_RSTCTL1_Type ctl1;
+        uint32_t raw[sizeof(RT500_RSTCTL0_Type) / sizeof(uint32_t)];
+    } regs;
+} RT500RstCtlState;
+
+#endif /* HW_MISC_RT500_RSTCTL_H */
