[PATCH 1/2] hw/misc: Add Tenstorrent Atlantis PRCM model
Anirudh Srinivasan <[email protected]> Wed, 29 Jul 2026 10:21:34 -0500
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
This device present in Tenstorrent Atlantis has registers that control clocks, reset and other misc functionality in the SoC. This commit adds models for the RCPU, HSIO, PCIE, MM and 2 DDR PRCMs. Co-developed-by: Portia Stephens <[email protected]> Signed-off-by: Portia Stephens <[email protected]> Signed-off-by: Anirudh Srinivasan <[email protected]> --- MAINTAINERS | 2 + hw/misc/meson.build | 1 + hw/misc/trace-events | 4 + hw/misc/tt_atlantis_prcm.c | 436 +++++++++++++++++++++++++++++++++++++ include/hw/misc/tt_atlantis_prcm.h | 51 +++++ 5 files changed, 494 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e25df9493c..49c1a5ad76 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1802,7 +1802,9 @@ R: Portia Stephens <[email protected]> L: [email protected] S: Supported F: docs/system/riscv/tt_*.rst +F: hw/misc/tt_*.c F: hw/riscv/tt_*.c +F: include/hw/misc/tt_*.h F: include/hw/riscv/tt_*.h F: tests/functional/riscv64/test_tt_*.py diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 23265f6035..26627013f3 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -36,6 +36,7 @@ system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) system_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) +system_ss.add(when: 'CONFIG_TENSTORRENT', if_true: files('tt_atlantis_prcm.c')) subdir('macio') diff --git a/hw/misc/trace-events b/hw/misc/trace-events index c9a868b3ef..9359a4e66d 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -442,3 +442,7 @@ iommu_testdev_dma_read(uint64_t gva, uint32_t len) "gva=0x%" PRIx64 " len=%u" iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=0x%x actual=0x%x" iommu_testdev_dma_result(uint32_t result) "DMA completed result=0x%x" iommu_testdev_dma_armed(bool armed) "armed=%d" + +# tt_atlantis_prcm.c +tt_atlantis_prcm_read(uint32_t domain, uint64_t offset, uint64_t data) "domain 0x%02x offset 0x%" PRIx64 " data 0x%" PRIx64 +tt_atlantis_prcm_write(uint32_t domain, uint64_t offset, uint64_t data) "domain 0x%02x offset 0x%" PRIx64 " data 0x%" PRIx64 diff --git a/hw/misc/tt_atlantis_prcm.c b/hw/misc/tt_atlantis_prcm.c new file mode 100644 index 0000000000..d341e1a8c3 --- /dev/null +++ b/hw/misc/tt_atlantis_prcm.c @@ -0,0 +1,436 @@ +/* + * PRCM (Clock and Reset Controller) in Tenstorrent Atlantis SoC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright 2026 Tenstorrent + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/misc/tt_atlantis_prcm.h" +#include "hw/core/qdev-properties.h" +#include "hw/core/registerfields.h" +#include "hw/core/irq.h" +#include "trace.h" + +#define TO_REG(offset) ((offset) >> 2) + +#define PLL_LOCK_BIT 31 +#define PLL_FBDIV_LSB 14 +#define PLL_POSTDIV2_LSB 11 +#define PLL_POSTDIV1_LSB 8 +#define PLL_REFDIV_LSB 2 +#define PLL_BYPASS_BIT 1 + +#define PLL_RESET_VAL(BYPASS, REFDIV, POSTDIV1, POSTDIV2, FBDIV, LOCK) \ + ((LOCK << PLL_LOCK_BIT) | (FBDIV << PLL_FBDIV_LSB) | \ + (POSTDIV2 << PLL_POSTDIV2_LSB) | (POSTDIV1 << PLL_POSTDIV1_LSB) | \ + (REFDIV << PLL_REFDIV_LSB) | (BYPASS << PLL_BYPASS_BIT)) + +#define RCPU_PLL_RCPU_CFG TO_REG(0) +#define RCPU_PLL_NOCC_CFG TO_REG(0x4) +#define RCPU_NOCC_CLK_CFG TO_REG(0x8) +#define RCPU_RCPU_DIV_CFG TO_REG(0xc) +#define RCPU_RCPU_BLK_CG TO_REG(0x14) +#define RCPU_LSIO_BLK_CG TO_REG(0x18) +#define RCPU_RCPU_BLK_RST TO_REG(0x1c) +#define RCPU_LSIO_BLK_RST TO_REG(0x20) +#define RCPU_PLL_RCPU_EN TO_REG(0x11c) +#define RCPU_PLL_NOCC_EN TO_REG(0x120) +#define RCPU_PLL_MM_EN TO_REG(0x0124) +#define RCPU_PLL1_MM_EN TO_REG(0x0128) +#define RCPU_PLL_HSIO_EN TO_REG(0x12c) +#define RCPU_PLL_PCIE_EN TO_REG(0x138) +#define RCPU_PLL_I2S_EN TO_REG(0x13C) +#define RCPU_PLL_MM_CFG TO_REG(0x19c) +#define RCPU_PLL_HSIO_CFG TO_REG(0x1a0) +#define RCPU_PLL_PCIE_CFG TO_REG(0x1ac) +#define RCPU_BOOT_MODE_CFG TO_REG(0x1b0) +#define RCPU_PLL_I2S_CFG TO_REG(0x1f4) +#define RCPU_I2S_DIV_CFG TO_REG(0x1f8) +#define RCPU_BUS_CFG TO_REG(0x1fc) +#define RCPU_PLL1_MM_CFG TO_REG(0x2a4) + +#define HSIO_HSIO_DIV_CFG TO_REG(0x0) +#define HSIO_HSIO_DIV_CFG1 TO_REG(0x4) +#define HSIO_HSIO_BLK_CG TO_REG(0x8) +#define HSIO_HSIO_BLK_RST TO_REG(0xc) +#define HSIO_HSIO_GMAC_DIV_CFG TO_REG(0x10) + +#define PCIE_SUBS_RST_CTL TO_REG(0x0) +#define PCIE_SUBS_CG_CTL TO_REG(0x4) +#define PCIE_SUBS_CK_CTL TO_REG(0x8) + +#define MM_MM_CLK_GATE_CFG TO_REG(0x8) +#define MM_MM_CLK_DIV_CFG TO_REG(0xC) +#define MM_MM_CLK_SEL_CFG TO_REG(0x10) +#define MM_MM_RSTN TO_REG(0x14) +#define MM_MM_CLK_DIV_CFG1 TO_REG(0x130) + +#define DDRC_STAT TO_REG(0x10014) +#define DDRC_DFISTAT TO_REG(0x10514) +#define DDRC_SWSTAT TO_REG(0x10c84) + +#define PLL_EN BIT(0) +#define RCPU_PLL_BUS_CG_EN BIT(7) +#define HSIO_PLL_BUS_CG_EN BIT(3) +#define PCIE_PLL_BUS_CG_EN BIT(1) +#define NOCC_PLL_BUS_CG_EN BIT(0) + +#define RCPU_BOOT_MODE_UART (0x0 << 4) +#define RCPU_BOOT_MODE_NOR (0x1 << 4) +#define RCPU_BOOT_MODE_SD (0x2 << 4) + +#define RCPU_DOMAIN_SIZE 0x10000 +#define HSIO_DOMAIN_SIZE 0x510 +#define PCIE_DOMAIN_SIZE 0x100 +#define MM_DOMAIN_SIZE 0x1000 +#define DDRC0_DOMAIN_SIZE 0x101000 +#define DDRC1_DOMAIN_SIZE 0x101000 + +static uint64_t tt_atlantis_prcm_read(void *opaque, hwaddr offset, + unsigned size) { + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(opaque); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_GET_CLASS(s); + uint32_t data; + + if (offset >= c->regs_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return 0; + } + data = s->regs[TO_REG(offset)]; + + trace_tt_atlantis_prcm_read(c->domain, offset, data); + return data; +} + +static void tt_atlantis_prcm_write(void *opaque, hwaddr offset, + uint64_t data, unsigned size) { + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(opaque); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_GET_CLASS(s); + + trace_tt_atlantis_prcm_write(c->domain, offset, data); + + if (offset >= c->regs_size) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + return; + } + + switch (TO_REG(offset)) { + default: + s->regs[TO_REG(offset)] = data; + break; + } +} + +static void tt_atlantis_prcm_rcpu_write(void *opaque, hwaddr offset, + uint64_t data, unsigned size) { + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(opaque); + + tt_atlantis_prcm_write(opaque, offset, data, size); + + bool pll_en_written = false; + uint32_t pll_reg_offset; + switch TO_REG(offset) + { + case RCPU_PLL_RCPU_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_RCPU_CFG; + break; + case RCPU_PLL_NOCC_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_NOCC_CFG; + break; + case RCPU_PLL_HSIO_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_HSIO_CFG; + break; + case RCPU_PLL_PCIE_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_PCIE_CFG; + break; + case RCPU_PLL_MM_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_MM_CFG; + break; + case RCPU_PLL1_MM_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL1_MM_CFG; + break; + case RCPU_PLL_I2S_EN: + pll_en_written = true; + pll_reg_offset = RCPU_PLL_I2S_CFG; + break; + } + if (pll_en_written) { + if (data & PLL_EN) { + s->regs[pll_reg_offset] |= BIT(PLL_LOCK_BIT); + } else { + s->regs[pll_reg_offset] &= ~BIT(PLL_LOCK_BIT); + } + } +} + +static const MemoryRegionOps tt_atlantis_prcm_ops = { + .read = tt_atlantis_prcm_read, + .write = tt_atlantis_prcm_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static const MemoryRegionOps tt_atlantis_prcm_rcpu_ops = { + .read = tt_atlantis_prcm_read, + .write = tt_atlantis_prcm_rcpu_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static void tt_atlantis_prcm_realize(DeviceState *dev, Error **errp) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_GET_CLASS(s); + + if (c->domain >= PRCM_DOMAIN_COUNT) { + error_setg(errp, + "domain %d is larger than max number of possible domains %d", + c->domain, PRCM_DOMAIN_COUNT); + return; + } + s->regs = g_new0(uint32_t, TO_REG(c->regs_size)); + + memory_region_init_io(&s->mmio, OBJECT(s), c->ops, s, + TYPE_TT_ATLANTIS_PRCM, c->regs_size); + sysbus_init_mmio(sbd, &s->mmio); +} + +static void tt_atlantis_prcm_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_GET_CLASS(s); + + memset(s->regs, 0, c->regs_size); +} + +static void tt_atlantis_prcm_rcpu_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + tt_atlantis_prcm_reset(dev); + + s->regs[RCPU_PLL_RCPU_CFG] = PLL_RESET_VAL(1, 0, 4, 0, 100, 1); + s->regs[RCPU_PLL_NOCC_CFG] = PLL_RESET_VAL(0, 2, 2, 2, 267, 1); + s->regs[RCPU_NOCC_CLK_CFG] = (0x25f31 << 1) | BIT(0); + s->regs[RCPU_RCPU_DIV_CFG] = (0xb8c2 << 1); + s->regs[RCPU_RCPU_BLK_CG] = 0; + s->regs[RCPU_LSIO_BLK_CG] = 0; + s->regs[RCPU_RCPU_BLK_RST] = 0xffffffff; + s->regs[RCPU_LSIO_BLK_RST] = 0xffffffff; + s->regs[RCPU_PLL_RCPU_EN] = PLL_EN; + s->regs[RCPU_PLL_NOCC_EN] = PLL_EN; + s->regs[RCPU_PLL_HSIO_EN] = 0; + s->regs[RCPU_PLL_MM_EN] = 0; + s->regs[RCPU_PLL1_MM_EN] = 0; + s->regs[RCPU_PLL_I2S_EN] = 0; + s->regs[RCPU_PLL_PCIE_EN] = 0; + s->regs[RCPU_PLL_HSIO_CFG] = PLL_RESET_VAL(0, 1, 2, 1, 50, 0); + s->regs[RCPU_PLL_PCIE_CFG] = PLL_RESET_VAL(0, 2, 3, 1, 250, 0); + s->regs[RCPU_BOOT_MODE_CFG] = RCPU_BOOT_MODE_SD; + s->regs[RCPU_PLL_MM_CFG] = PLL_RESET_VAL(0, 1, 2, 1, 50, 1); + s->regs[RCPU_PLL1_MM_CFG] = PLL_RESET_VAL(0, 1, 2, 1, 50, 1); + s->regs[RCPU_PLL_I2S_CFG] = PLL_RESET_VAL(0, 1, 6, 6, 33, 0); + s->regs[RCPU_I2S_DIV_CFG] = 0xde69ad31; + s->regs[RCPU_BUS_CFG] = NOCC_PLL_BUS_CG_EN | HSIO_PLL_BUS_CG_EN; +} + +static void tt_atlantis_prcm_ddrc_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + tt_atlantis_prcm_reset(dev); + + s->regs[DDRC_STAT] = 0x1; + s->regs[DDRC_DFISTAT] = 0x1; + s->regs[DDRC_SWSTAT] = 0x1; +} + +static void tt_atlantis_prcm_hsio_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + tt_atlantis_prcm_reset(dev); + + s->regs[HSIO_HSIO_DIV_CFG] = 0x20821731; + s->regs[HSIO_HSIO_DIV_CFG1] = 0x8; + s->regs[HSIO_HSIO_BLK_CG] = 0; + s->regs[HSIO_HSIO_BLK_RST] = 0; + s->regs[HSIO_HSIO_GMAC_DIV_CFG] = 0; +} + +static void tt_atlantis_prcm_pcie_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + tt_atlantis_prcm_reset(dev); + + s->regs[PCIE_SUBS_RST_CTL] = 0; + s->regs[PCIE_SUBS_CG_CTL] = 0; + s->regs[PCIE_SUBS_CK_CTL] = 0x44908; +} + +static void tt_atlantis_prcm_mm_reset(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + tt_atlantis_prcm_reset(dev); + + s->regs[MM_MM_CLK_GATE_CFG] = 0; + s->regs[MM_MM_CLK_DIV_CFG] = 0xddc8312; + s->regs[MM_MM_CLK_SEL_CFG] = 0; + s->regs[MM_MM_RSTN] = 0; + s->regs[MM_MM_CLK_DIV_CFG1] = 0x333; +} + +static void tt_atlantis_prcm_unrealize(DeviceState *dev) +{ + TTAtlantisPRCMState *s = TT_ATLANTIS_PRCM(dev); + + g_free(s->regs); +} + +static void tt_atlantis_prcm_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + dc->unrealize = tt_atlantis_prcm_unrealize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_reset); + dc->desc = "Tenstorrent Atlantis PRCM Controller"; + c->ops = &tt_atlantis_prcm_ops; +} + +static void tt_atlantis_prcm_rcpu_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_rcpu_reset); + dc->desc = "Tenstorrent Atlantis RCPU PRCM Controller"; + c->domain = PRCM_DOMAIN_RCPU; + c->regs_size = RCPU_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_rcpu_ops; +} + +static void tt_atlantis_prcm_hsio_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_hsio_reset); + dc->desc = "Tenstorrent Atlantis HSIO PRCM Controller"; + c->domain = PRCM_DOMAIN_HSIO; + c->regs_size = HSIO_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_ops; +} + +static void tt_atlantis_prcm_pcie_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_pcie_reset); + dc->desc = "Tenstorrent Atlantis PCIE PRCM Controller"; + c->domain = PRCM_DOMAIN_PCIE; + c->regs_size = PCIE_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_ops; +} + +static void tt_atlantis_prcm_mm_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_mm_reset); + dc->desc = "Tenstorrent Atlantis MM PRCM Controller"; + c->domain = PRCM_DOMAIN_MM; + c->regs_size = MM_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_ops; +} + +static void tt_atlantis_prcm_ddrc0_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_ddrc_reset); + dc->desc = "Tenstorrent Atlantis DDR Memory Controller 0 PRCM"; + c->domain = PRCM_DOMAIN_DDRC0; + c->regs_size = DDRC0_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_ops; +} + +static void tt_atlantis_prcm_ddrc1_class_init(ObjectClass *klass, + const void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + TTAtlantisPRCMClass *c = TT_ATLANTIS_PRCM_CLASS(klass); + + dc->realize = tt_atlantis_prcm_realize; + device_class_set_legacy_reset(dc, tt_atlantis_prcm_ddrc_reset); + dc->desc = "Tenstorrent Atlantis DDR Memory Controller 1 PRCM"; + c->domain = PRCM_DOMAIN_DDRC1; + c->regs_size = DDRC1_DOMAIN_SIZE; + c->ops = &tt_atlantis_prcm_ops; +} + +static const TypeInfo tt_atlantis_prcm_types[] = { + { + .name = TYPE_TT_ATLANTIS_PRCM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TTAtlantisPRCMState), + .class_init = tt_atlantis_prcm_class_init, + .class_size = sizeof(TTAtlantisPRCMClass), + .abstract = true, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_RCPU, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_rcpu_class_init, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_HSIO, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_hsio_class_init, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_PCIE, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_pcie_class_init, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_MM, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_mm_class_init, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_DDRC0, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_ddrc0_class_init, + }, + { + .name = TYPE_TT_ATLANTIS_PRCM_DDRC1, + .parent = TYPE_TT_ATLANTIS_PRCM, + .class_init = tt_atlantis_prcm_ddrc1_class_init, + }, +}; + +DEFINE_TYPES(tt_atlantis_prcm_types); diff --git a/include/hw/misc/tt_atlantis_prcm.h b/include/hw/misc/tt_atlantis_prcm.h new file mode 100644 index 0000000000..acb8a9b38b --- /dev/null +++ b/include/hw/misc/tt_atlantis_prcm.h @@ -0,0 +1,51 @@ +/* + * Clock, Reset, Pinctrl PRCM in Tenstorrent Atlantis SoC + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright 2026 Tenstorrent + */ + +#ifndef TT_ATLANTIS_PRCM_H +#define TT_ATLANTIS_PRCM_H + +#include "hw/core/sysbus.h" + +#define TYPE_TT_ATLANTIS_PRCM "tt.atlantis.prcm" +#define TYPE_TT_ATLANTIS_PRCM_RCPU "tt.atlantis.prcm.rcpu" +#define TYPE_TT_ATLANTIS_PRCM_HSIO "tt.atlantis.prcm.hsio" +#define TYPE_TT_ATLANTIS_PRCM_PCIE "tt.atlantis.prcm.pcie" +#define TYPE_TT_ATLANTIS_PRCM_MM "tt.atlantis.prcm.mm" +#define TYPE_TT_ATLANTIS_PRCM_DDRC0 "tt.atlantis.prcm.ddrc0" +#define TYPE_TT_ATLANTIS_PRCM_DDRC1 "tt.atlantis.prcm.ddrc1" +OBJECT_DECLARE_TYPE(TTAtlantisPRCMState, TTAtlantisPRCMClass, + TT_ATLANTIS_PRCM); + + +enum { + PRCM_DOMAIN_RCPU = 0, + PRCM_DOMAIN_HSIO = 1, + PRCM_DOMAIN_PCIE = 2, + PRCM_DOMAIN_MM = 3, + PRCM_DOMAIN_DDRC0 = 4, + PRCM_DOMAIN_DDRC1 = 5, + PRCM_DOMAIN_COUNT = 6 +}; + +struct TTAtlantisPRCMState { + SysBusDevice parent; + + MemoryRegion mmio; + + uint32_t *regs; +}; + +struct TTAtlantisPRCMClass { + SysBusDeviceClass parent_class; + + uint32_t domain; + uint32_t regs_size; + const MemoryRegionOps *ops; +}; + +#endif -- 2.43.0