Re: [PATCH 1/2] hw/misc: Add Tenstorrent Atlantis PRCM model

Anirudh Srinivasan <[email protected]> Mon, 3 Aug 2026 10:36:27 -0500
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <CAEev2e_Aj+8PJqH14gxYcn0Ni9qhvprW2Q04_ynu6FL0sPj9tw@mail.gmail.com>
Hi Chao,

On Sun, Aug 2, 2026 at 9:25=E2=80=AFPM Chao Liu <[email protected]=
m> wrote:
>
> On Wed, Jul 29, 2026 at 10:21:34AM +0800, Anirudh Srinivasan wrote:
> > 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_ao=
n.c'))
> >  system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_ot=
p.c'))
> >  system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_p=
rci.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=3D0x%" PRIx64 " len=3D%u"
> >  iommu_testdev_dma_verify(uint32_t expected, uint32_t actual) "expected=
=3D0x%x actual=3D0x%x"
> >  iommu_testdev_dma_result(uint32_t result) "DMA completed result=3D0x%x=
"
> >  iommu_testdev_dma_armed(bool armed) "armed=3D%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 =3D TT_ATLANTIS_PRCM(opaque);
> > +    TTAtlantisPRCMClass *c =3D TT_ATLANTIS_PRCM_GET_CLASS(s);
> > +    uint32_t data;
> > +
> > +    if (offset >=3D c->regs_size) {
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Out-of-bounds read at offset 0x%" HWADDR_PR=
Ix "\n",
> > +                      __func__, offset);
> > +        return 0;
> > +    }
> > +    data =3D 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 si=
ze) {
> Consider aligning the wrapped lines with the first parameter.
>
> > +    TTAtlantisPRCMState *s =3D TT_ATLANTIS_PRCM(opaque);
> > +    TTAtlantisPRCMClass *c =3D TT_ATLANTIS_PRCM_GET_CLASS(s);
> > +
> > +    trace_tt_atlantis_prcm_write(c->domain, offset, data);
> > +
> > +    if (offset >=3D c->regs_size) {
> > +        qemu_log_mask(LOG_GUEST_ERROR,
> > +                      "%s: Out-of-bounds write at offset 0x%" HWADDR_P=
RIx "\n",
> > +                      __func__, offset);
> > +        return;
> > +    }
> > +
> > +    switch (TO_REG(offset)) {
> > +    default:
> > +        s->regs[TO_REG(offset)] =3D data;
> > +        break;
> > +    }
> > +}
> > +
> > +static void tt_atlantis_prcm_rcpu_write(void *opaque, hwaddr offset,
> > +                                            uint64_t data, unsigned si=
ze) {
> > +    TTAtlantisPRCMState *s =3D TT_ATLANTIS_PRCM(opaque);
> > +
> > +    tt_atlantis_prcm_write(opaque, offset, data, size);
> > +
> > +    bool pll_en_written =3D false;
> > +    uint32_t pll_reg_offset;
> > +    switch TO_REG(offset)
> > +    {
> > +        case RCPU_PLL_RCPU_EN:
> > +            pll_en_written =3D true;
> > +            pll_reg_offset =3D RCPU_PLL_RCPU_CFG;
> > +            break;
> This should follow the QEMU coding style:
>
>     switch (TO_REG(offset)) {
>     case RCPU_PLL_RCPU_EN:
>         pll_en_written =3D true;
>         pll_reg_offset =3D RCPU_PLL_RCPU_CFG;
>         break;
>     ...
>     case RCPU_PLL_I2S_EN:
>         pll_en_written =3D true;
>         pll_reg_offset =3D RCPU_PLL_I2S_CFG;
>         break;
>     default:
>       g_assert_not_reached();
>     }

Thanks, checkpatch didn't seem to point these out. Will fix them up in V2.

Regards
Anirudh Srinivasan

> Thanks,
> Chao