[PATCH v4 09/11] platform: sifive: Add SiFive TMC0 driver

Nick Hu nick.hu at sifive.com
Mon Sep 1 03:07:05 PDT 2025


On Sat, Aug 30, 2025 at 7:02 PM Anup Patel <apatel at ventanamicro.com> wrote:
>
> On Thu, Aug 28, 2025 at 10:53 PM Nick Hu <nick.hu at sifive.com> wrote:
> >
> > On Tue, Aug 26, 2025 at 4:52 PM Anup Patel <anup at brainfault.org> wrote:
> > >
> > > On Wed, Aug 20, 2025 at 9:03 AM Nick Hu <nick.hu at sifive.com> wrote:
> > > >
> > > > The SiFive TMC0 controls the tile power domains on SiFive platform. The
> > > > CPU enters the low power state via the `CEASE` instruction after
> > > > configuring the TMC0. Any devices that inside the tile power domain will
> > > > be power gated, including the private cache. Therefore flushing the
> > > > private cache before entering the low power state.
> > > >
> > > > Co-developed-by: Vincent Chen <vincent.chen at sifive.com>
> > > > Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> > > > Signed-off-by: Nick Hu <nick.hu at sifive.com>
> > > > Reviewed-by: Cyan Yang <cyan.yang at sifive.com>
> > > > ---
> > > >  include/sbi_utils/hsm/fdt_hsm_sifive_inst.h   |  20 +
> > > >  include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h   |  16 +
> > > >  lib/utils/hsm/Kconfig                         |   5 +
> > > >  lib/utils/hsm/fdt_hsm_sifive_tmc0.c           | 380 ++++++++++++++++++
> > > >  lib/utils/hsm/objects.mk                      |   2 +
> > > >  platform/generic/Kconfig                      |   5 +
> > > >  platform/generic/configs/defconfig            |   2 +
> > > >  platform/generic/sifive/objects.mk            |   3 +
> > > >  platform/generic/sifive/sifive_dev_platform.c |  57 +++
> > > >  9 files changed, 490 insertions(+)
> > > >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > > >  create mode 100644 include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > > >  create mode 100644 lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > > >  create mode 100644 platform/generic/sifive/sifive_dev_platform.c
> > > >
> > > > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > > > new file mode 100644
> > > > index 00000000..de8aba19
> > > > --- /dev/null
> > > > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_inst.h
> > > > @@ -0,0 +1,20 @@
> > > > +/*
> > > > + * SPDX-License-Identifier: BSD-2-Clause
> > > > + *
> > > > + * Copyright (c) 2025 SiFive Inc.
> > > > + */
> > > > +
> > > > +#ifndef __FDT_HSM_SIFIVE_INST_H__
> > > > +#define __FDT_HSM_SIFIVE_INST_H__
> > > > +
> > > > +static inline void sifive_cease(void)
> > > > +{
> > > > +       __asm__ __volatile__(".insn 0x30500073" ::: "memory");
> > > > +}
> > > > +
> > > > +static inline void sifive_cflush(void)
> > > > +{
> > > > +       __asm__ __volatile__(".insn 0xfc000073" ::: "memory");
> > > > +}
> > > > +
> > > > +#endif
> > > > diff --git a/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > > > new file mode 100644
> > > > index 00000000..4ba048b9
> > > > --- /dev/null
> > > > +++ b/include/sbi_utils/hsm/fdt_hsm_sifive_tmc0.h
> > > > @@ -0,0 +1,16 @@
> > > > +/*
> > > > + * SPDX-License-Identifier: BSD-2-Clause
> > > > + *
> > > > + * Copyright (c) 2025 SiFive Inc.
> > > > + */
> > > > +
> > > > +#ifndef __FDT_HSM_SIFIVE_TMC0_H__
> > > > +#define __FDT_HSM_SIFIVE_TMC0_H__
> > > > +
> > > > +#ifdef CONFIG_FDT_HSM_SIFIVE_TMC0
> > > > +int fdt_hsm_sifive_tmc0_cold_init(void);
> > > > +#else
> > > > +static inline int fdt_hsm_sifive_tmc0_cold_init(void) { return 0; }
> > > > +#endif
> > > > +
> > > > +#endif
> > > > diff --git a/lib/utils/hsm/Kconfig b/lib/utils/hsm/Kconfig
> > > > index 1ad7958f..3e6f8909 100644
> > > > --- a/lib/utils/hsm/Kconfig
> > > > +++ b/lib/utils/hsm/Kconfig
> > > > @@ -14,6 +14,11 @@ config FDT_HSM_RPMI
> > > >         depends on FDT_MAILBOX && RPMI_MAILBOX
> > > >         default n
> > > >
> > > > +config FDT_HSM_SIFIVE_TMC0
> > > > +       bool "FDT SiFive TMC v0 driver"
> > > > +       depends on PLATFORM_SIFIVE_DEV
> > > > +       default n
> > > > +
> > > >  endif
> > > >
> > > >  endmenu
> > > > diff --git a/lib/utils/hsm/fdt_hsm_sifive_tmc0.c b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > > > new file mode 100644
> > > > index 00000000..83f86c88
> > > > --- /dev/null
> > > > +++ b/lib/utils/hsm/fdt_hsm_sifive_tmc0.c
> > > > @@ -0,0 +1,380 @@
> > > > +/*
> > > > + * SPDX-License-Identifier: BSD-2-Clause
> > > > + *
> > > > + * Copyright (c) 2025 SiFive
> > > > + */
> > > > +
> > > > +#include <libfdt.h>
> > > > +#include <sbi/riscv_asm.h>
> > > > +#include <sbi/riscv_io.h>
> > > > +#include <sbi/sbi_bitops.h>
> > > > +#include <sbi/sbi_console.h>
> > > > +#include <sbi/sbi_error.h>
> > > > +#include <sbi/sbi_hart.h>
> > > > +#include <sbi/sbi_heap.h>
> > > > +#include <sbi/sbi_hsm.h>
> > > > +#include <sbi/sbi_ipi.h>
> > > > +#include <sbi_utils/cache/fdt_cmo_helper.h>
> > > > +#include <sbi_utils/fdt/fdt_driver.h>
> > > > +#include <sbi_utils/fdt/fdt_helper.h>
> > > > +#include <sbi_utils/hsm/fdt_hsm_sifive_inst.h>
> > > > +#include <sbi_utils/hsm/fdt_hsm_sifive_tmc0.h>
> > > > +#include <sbi_utils/ipi/aclint_mswi.h>
> > > > +
> > > > +struct sifive_tmc0 {
> > > > +       unsigned long reg;
> > > > +       struct sbi_dlist node;
> > > > +       u32 id;
> > > > +};
> > > > +
> > > > +static SBI_LIST_HEAD(tmc0_list);
> > > > +static unsigned long tmc0_offset;
> > > > +
> > > > +#define tmc0_ptr_get(__scratch)                                \
> > > > +       sbi_scratch_read_type((__scratch), struct sifive_tmc0 *, tmc0_offset)
> > > > +
> > > > +#define tmc0_ptr_set(__scratch, __tmc0)                        \
> > > > +       sbi_scratch_write_type((__scratch), struct sifive_tmc0 *, tmc0_offset, (__tmc0))
> > > > +
> > > > +/* TMC.PGPREP */
> > > > +#define SIFIVE_TMC_PGPREP_OFF                  0x0
> > > > +#define SIFIVE_TMC_PGPREP_ENA_REQ              BIT(31)
> > > > +#define SIFIVE_TMC_PGPREP_ENA_ACK              BIT(30)
> > > > +#define SIFIVE_TMC_PGPREP_DIS_REQ              BIT(29)
> > > > +#define SIFIVE_TMC_PGPREP_DIS_ACK              BIT(28)
> > > > +#define SIFIVE_TMC_PGPREP_CLFPNOTQ             BIT(18)
> > > > +#define SIFIVE_TMC_PGPREP_PMCENAERR            BIT(17)
> > > > +#define SIFIVE_TMC_PGPREP_PMCDENY              BIT(16)
> > > > +#define SIFIVE_TMC_PGPREP_BUSERR               BIT(15)
> > > > +#define SIFIVE_TMC_PGPREP_WAKE_DETECT          BIT(12)
> > > > +#define SIFIVE_TMC_PGPREP_INTERNAL_ABORT       BIT(2)
> > > > +#define SIFIVE_TMC_PGPREP_ENARSP               (SIFIVE_TMC_PGPREP_CLFPNOTQ | \
> > > > +                                                SIFIVE_TMC_PGPREP_PMCENAERR | \
> > > > +                                                SIFIVE_TMC_PGPREP_PMCDENY | \
> > > > +                                                SIFIVE_TMC_PGPREP_BUSERR | \
> > > > +                                                SIFIVE_TMC_PGPREP_WAKE_DETECT)
> > > > +
> > > > +/* TMC.PG */
> > > > +#define SIFIVE_TMC_PG_OFF                      0x4
> > > > +#define SIFIVE_TMC_PG_ENA_REQ                  BIT(31)
> > > > +#define SIFIVE_TMC_PG_ENA_ACK                  BIT(30)
> > > > +#define SIFIVE_TMC_PG_DIS_REQ                  BIT(29)
> > > > +#define SIFIVE_TMC_PG_DIS_ACK                  BIT(28)
> > > > +#define SIFIVE_TMC_PG_PMC_ENA_ERR              BIT(17)
> > > > +#define SIFIVE_TMC_PG_PMC_DENY                 BIT(16)
> > > > +#define SIFIVE_TMC_PG_BUS_ERR                  BIT(15)
> > > > +#define SIFIVE_TMC_PG_MASTNOTQ                 BIT(14)
> > > > +#define SIFIVE_TMC_PG_WARM_RESET               BIT(1)
> > > > +#define SIFIVE_TMC_PG_ENARSP                   (SIFIVE_TMC_PG_PMC_ENA_ERR | \
> > > > +                                                SIFIVE_TMC_PG_PMC_DENY | \
> > > > +                                                SIFIVE_TMC_PG_BUS_ERR | \
> > > > +                                                SIFIVE_TMC_PG_MASTNOTQ)
> > > > +
> > > > +/* TMC.RESUMEPC */
> > > > +#define SIFIVE_TMC_RESUMEPC_LO                 0x10
> > > > +#define SIFIVE_TMC_RESUMEPC_HI                 0x14
> > > > +
> > > > +/* TMC.WAKEMASK */
> > > > +#define SIFIVE_TMC_WAKE_MASK_OFF               0x20
> > > > +#define SIFIVE_TMC_WAKE_MASK_WREQ              BIT(31)
> > > > +#define SIFIVE_TMC_WAKE_MASK_ACK               BIT(30)
> > > > +
> > > > +static void sifive_tmc0_set_resumepc(physical_addr_t addr)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > > +
> > > > +       writel((u32)addr, (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_LO));
> > > > +#if __riscv_xlen > 32
> > > > +       writel((u32)(addr >> 32), (void *)(tmc0->reg + SIFIVE_TMC_RESUMEPC_HI));
> > > > +#endif
> > > > +}
> > > > +
> > > > +static u32 sifive_tmc0_set_pgprep_enareq(void)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > > +       u32 v = readl((void *)reg);
> > > > +
> > > > +       writel(v | SIFIVE_TMC_PGPREP_ENA_REQ, (void *)reg);
> > > > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_ENA_ACK));
> > > > +
> > > > +       v = readl((void *)reg);
> > > > +       return v & SIFIVE_TMC_PGPREP_INTERNAL_ABORT;
> > > > +}
> > > > +
> > > > +static void sifive_tmc0_set_pgprep_disreq(void)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > > +       u32 v = readl((void *)reg);
> > > > +
> > > > +       writel(v | SIFIVE_TMC_PGPREP_DIS_REQ, (void *)reg);
> > > > +       while (!(readl((void *)reg) & SIFIVE_TMC_PGPREP_DIS_ACK));
> > > > +}
> > > > +
> > > > +static u32 sifive_tmc0_get_pgprep_enarsp(void)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PGPREP_OFF;
> > > > +       u32 v = readl((void *)reg);
> > > > +
> > > > +       return v & SIFIVE_TMC_PGPREP_ENARSP;
> > > > +}
> > > > +
> > > > +static void sifive_tmc0_set_pg_enareq(void)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0 = tmc0_ptr_get(sbi_scratch_thishart_ptr());
> > > > +       unsigned long reg = tmc0->reg + SIFIVE_TMC_PG_OFF;
> > > > +       u32 v = readl((void *)reg);
> > > > +
> > > > +       writel(v | SIFIVE_TMC_PG_ENA_REQ, (void *)reg);
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_prep(void)
> > > > +{
> > > > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > > > +       u32 rc;
> > > > +
> > > > +       if (!tmc0_ptr_get(scratch))
> > > > +               return SBI_ENODEV;
> > > > +
> > > > +       rc = sifive_tmc0_set_pgprep_enareq();
> > > > +       if (rc) {
> > > > +               sbi_printf("TMC0 error: Internal Abort (Wake detect)\n");
> > > > +               goto fail;
> > > > +       }
> > > > +
> > > > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > > > +       if (rc) {
> > > > +               sifive_tmc0_set_pgprep_disreq();
> > > > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > > > +               goto fail;
> > > > +       }
> > > > +
> > > > +       sifive_tmc0_set_resumepc(scratch->warmboot_addr);
> > > > +
> > > > +       return SBI_OK;
> > > > +
> > > > +fail:
> > > > +       return SBI_EFAIL;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_enter(void)
> > > > +{
> > > > +       struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> > > > +       u32 rc;
> > > > +
> > > > +       /* Flush cache and check if there is wake detect or bus error */
> > > > +       if (fdt_cmo_private_flc_flush_all() &&
> > > > +           sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CFLUSH_D_L1))
> > > > +               sifive_cflush();
> > > > +
> > > > +       rc = sifive_tmc0_get_pgprep_enarsp();
> > > > +       if (rc) {
> > > > +               sbi_printf("TMC0 error: error response code: 0x%x\n", rc);
> > > > +               goto fail;
> > > > +       }
> > > > +
> > > > +       if (sbi_hart_has_extension(scratch, SBI_HART_EXT_XSIFIVE_CEASE)) {
> > > > +               sifive_tmc0_set_pg_enareq();
> > > > +               while (1)
> > > > +                       sifive_cease();
> > > > +       }
> > > > +
> > > > +       rc = SBI_ENOTSUPP;
> > > > +fail:
> > > > +       sifive_tmc0_set_pgprep_disreq();
> > > > +       return rc;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_tile_pg(void)
> > > > +{
> > > > +       int rc;
> > > > +
> > > > +       rc = sifive_tmc0_prep();
> > > > +       if (rc)
> > > > +               return rc;
> > > > +
> > > > +       return sifive_tmc0_enter();
> > > > +}
> > > > +
> > > > +static struct sifive_tmc0 *sifive_tmc0_find(u32 id)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0;
> > > > +
> > > > +       sbi_list_for_each_entry(tmc0, &tmc0_list, node) {
> > > > +               if (tmc0->id == id)
> > > > +                       return tmc0;
> > > > +       }
> > > > +
> > > > +       return NULL;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_add(struct sifive_tmc0 *tmc0)
> > > > +{
> > > > +       if (!tmc0)
> > > > +               return SBI_ENODEV;
> > > > +
> > > > +       if (sifive_tmc0_find(tmc0->id))
> > > > +               return SBI_EALREADY;
> > > > +
> > > > +       sbi_list_add(&tmc0->node, &tmc0_list);
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_probe(const void *fdt, int nodeoff, const struct fdt_match *match)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0;
> > > > +       int rc;
> > > > +       u64 addr;
> > > > +
> > > > +       tmc0 = sbi_zalloc(sizeof(*tmc0));
> > > > +       if (!tmc0)
> > > > +               return SBI_ENOMEM;
> > > > +
> > > > +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
> > > > +       if (rc)
> > > > +               goto free_tmc0;
> > > > +
> > > > +       tmc0->reg = (unsigned long)addr;
> > > > +       tmc0->id = nodeoff;
> > > > +
> > > > +       rc = sifive_tmc0_add(tmc0);
> > > > +       if (rc)
> > > > +               goto free_tmc0;
> > > > +
> > > > +       return SBI_OK;
> > > > +
> > > > +free_tmc0:
> > > > +       sbi_free(tmc0);
> > > > +       return rc;
> > > > +}
> > > > +
> > > > +static const struct fdt_match sifive_tmc0_match[] = {
> > > > +       { .compatible = "sifive,tmc0" },
> > > > +       { },
> > > > +};
> > > > +
> > > > +const struct fdt_driver fdt_hsm_sifive_tmc0 = {
> > > > +       .match_table = sifive_tmc0_match,
> > > > +       .init = sifive_tmc0_probe,
> > > > +};
> > > > +
> > > > +static const struct fdt_driver *const fdt_hsm_sifive_tmc0_drivers[] = {
> > > > +       &fdt_hsm_sifive_tmc0,
> > > > +       NULL
> > > > +};
> > > > +
> > > > +static int fdt_sifive_tmc0_get(const void *fdt, int noff, struct sifive_tmc0 **out)
> > > > +{
> > > > +       struct sifive_tmc0 *tmc0;
> > > > +       int rc;
> > > > +
> > > > +       noff = fdt_node_offset_by_phandle(fdt, noff);
> > > > +       if (noff < 0)
> > > > +               return noff;
> > > > +
> > > > +       rc = fdt_driver_init_by_offset(fdt, noff, fdt_hsm_sifive_tmc0_drivers);
> > > > +       if (rc)
> > > > +               return rc;
> > > > +
> > > > +       tmc0 = sifive_tmc0_find(noff);
> > > > +       if (!tmc0)
> > > > +               return SBI_EFAIL;
> > > > +
> > > > +       if (out)
> > > > +               *out = tmc0;
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > > > +
> > > > +static int fdt_sifive_tmc0_cold_init(const void *fdt)
> > > > +{
> > > > +       struct sbi_scratch *scratch;
> > > > +       struct sifive_tmc0 *tmc0;
> > > > +       const fdt32_t *val;
> > > > +       int cpus_off, cpu_off, rc;
> > > > +       u32 hartid;
> > > > +
> > > > +       cpus_off = fdt_path_offset(fdt, "/cpus");
> > > > +       if (cpus_off < 0)
> > > > +               return SBI_ENOENT;
> > > > +
> > > > +       fdt_for_each_subnode(cpu_off, fdt, cpus_off) {
> > > > +               rc = fdt_parse_hart_id(fdt, cpu_off, &hartid);
> > > > +               if (rc)
> > > > +                       continue;
> > > > +
> > > > +               val = fdt_getprop(fdt, cpu_off, "power-domains", NULL);
> > > > +               if (!val)
> > > > +                       return SBI_ENOENT;
> > > > +
> > > > +               rc = fdt_sifive_tmc0_get(fdt, fdt32_to_cpu(val[0]), &tmc0);
> > > > +               if (rc)
> > > > +                       return rc;
> > > > +
> > > > +               scratch = sbi_hartid_to_scratch(hartid);
> > > > +               if (!scratch)
> > > > +                       continue;
> > > > +
> > > > +               tmc0_ptr_set(scratch, tmc0);
> > > > +       }
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_start(u32 hartid, ulong saddr)
> > > > +{
> > > > +       struct sbi_ipi_device *clint = aclint_mswi_get();
> > > > +
> > > > +       /*
> > > > +        * In system suspend, the IMSIC will be reset in SiFive platform so
> > > > +        * we use the CLINT IPI as the wake event.
> > > > +        */
> > > > +       if (clint && clint->ipi_send)
> > > > +               clint->ipi_send(sbi_hartid_to_hartindex(hartid));
> > > > +       else
> > > > +               sbi_ipi_raw_send(sbi_hartid_to_hartindex(hartid));
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > > > +
> > > > +static int sifive_tmc0_stop(void)
> > > > +{
> > > > +       unsigned long mie = csr_read(CSR_MIE);
> > > > +       int rc;
> > > > +       // Set IPI as wake up source
> > >
> > > Please don't use c++ style "//" comments.
> > >
> > Will fix it in the next version
> >
> > > > +       csr_set(CSR_MIE, MIP_MEIP | MIP_MSIP);
> > > > +
> > > > +       rc = sifive_tmc0_tile_pg();
> > > > +       if (rc) {
> > > > +               csr_write(CSR_MIE, mie);
> > > > +               return rc;
> > > > +       }
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > > > +
> > > > +static struct sbi_hsm_device tmc0_hsm_dev = {
> > > > +       .name = "SiFive TMC0",
> > > > +       .hart_start = sifive_tmc0_start,
> > > > +       .hart_stop = sifive_tmc0_stop,
> > > > +};
> > > > +
> > > > +int fdt_hsm_sifive_tmc0_cold_init(void)
> > > > +{
> > > > +       int rc;
> > > > +
> > > > +       tmc0_offset = sbi_scratch_alloc_type_offset(struct sifive_tmc0 *);
> > > > +       if (!tmc0_offset)
> > > > +               return SBI_ENOMEM;
> > > > +
> > > > +       rc = fdt_sifive_tmc0_cold_init(fdt_get_address());
> > > > +       if (rc)
> > > > +               return rc;
> > > > +
> > > > +       sbi_hsm_set_device(&tmc0_hsm_dev);
> > > > +
> > > > +       return SBI_OK;
> > > > +}
> > >
> > > Why can't the SiFive TMC driver probe as fdt_early_driver ?
> > >
> > Yes, it can. This requires updating the logic for binding the TMC to
> > the corresponding CPU.
> > In the current implementation, we iterate over each CPU DT node to
> > probe the TMC driver via its power-domains property and then bind the
> > TMC to that CPU.
> >
> > If the TMC driver is registered as an fdt_early_driver, we instead
> > need to iterate over each CPU node during every TMC driver probe and
> > bind the TMC to the CPU whose power-domains property references the
> > current TMC node.
>
> I think it's better to have the TMC driver as an fdt_early_driver.
> If required you can add helper routines to parse power-domain
> from the CPU DT node.
>
I will update it in the next version. Thanks.

> Regards,
> Anup



More information about the opensbi mailing list