summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorminda.chen <minda.chen@starfivetech.com>2023-01-09 10:07:00 +0300
committerminda.chen <minda.chen@starfivetech.com>2023-01-09 10:16:35 +0300
commitcf4ae775ac4652125ade9d047f28e30e91e8827f (patch)
treec74298d5fd1f9ef28bf8073a2536ad226be13c82
parent8020df8733b060f01e35b0b2bcb2b41e6b992e9b (diff)
downloadopensbi-cf4ae775ac4652125ade9d047f28e30e91e8827f.tar.xz
pm: move the pm modification to the master-ups branch
7110 platform has been upstream. PM modification merge to master branch. Signed-off-by: minda.chen <minda.chen@starfivetech.com>
-rw-r--r--lib/utils/i2c/Kconfig4
-rw-r--r--lib/utils/i2c/fdt_i2c_starfive.c282
-rw-r--r--lib/utils/i2c/objects.mk3
-rw-r--r--platform/generic/configs/defconfig1
-rw-r--r--platform/generic/starfive/jh7110.c296
5 files changed, 586 insertions, 0 deletions
diff --git a/lib/utils/i2c/Kconfig b/lib/utils/i2c/Kconfig
index 46a3454..e586083 100644
--- a/lib/utils/i2c/Kconfig
+++ b/lib/utils/i2c/Kconfig
@@ -14,6 +14,10 @@ config FDT_I2C_SIFIVE
bool "SiFive I2C FDT driver"
default n
+config FDT_I2C_STARFIVE
+ bool "STARFIVE I2C FDT driver"
+ default n
+
endif
config I2C
diff --git a/lib/utils/i2c/fdt_i2c_starfive.c b/lib/utils/i2c/fdt_i2c_starfive.c
new file mode 100644
index 0000000..cfac9a4
--- /dev/null
+++ b/lib/utils/i2c/fdt_i2c_starfive.c
@@ -0,0 +1,282 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 starfivetech.com
+ *
+ * Authors:
+ * minda.chen <minda.chen@starfivetech.com>
+ */
+
+#include <sbi/riscv_io.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_console.h>
+#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/i2c/fdt_i2c.h>
+#include <libfdt.h>
+#include <sbi/sbi_string.h>
+
+#define DW_IC_CON 0x00
+#define DW_IC_TAR 0x04
+#define DW_IC_SAR 0x08
+#define DW_IC_DATA_CMD 0x10
+#define DW_IC_SS_SCL_HCNT 0x14
+#define DW_IC_SS_SCL_LCNT 0x18
+#define DW_IC_FS_SCL_HCNT 0x1c
+#define DW_IC_FS_SCL_LCNT 0x20
+#define DW_IC_HS_SCL_HCNT 0x24
+#define DW_IC_HS_SCL_LCNT 0x28
+#define DW_IC_INTR_STAT 0x2c
+#define DW_IC_INTR_MASK 0x30
+#define DW_IC_RAW_INTR_STAT 0x34
+#define DW_IC_RX_TL 0x38
+#define DW_IC_TX_TL 0x3c
+#define DW_IC_CLR_INTR 0x40
+#define DW_IC_CLR_RX_UNDER 0x44
+#define DW_IC_CLR_RX_OVER 0x48
+#define DW_IC_CLR_TX_OVER 0x4c
+#define DW_IC_CLR_RD_REQ 0x50
+#define DW_IC_CLR_TX_ABRT 0x54
+#define DW_IC_CLR_RX_DONE 0x58
+#define DW_IC_CLR_ACTIVITY 0x5c
+#define DW_IC_CLR_STOP_DET 0x60
+#define DW_IC_CLR_START_DET 0x64
+#define DW_IC_CLR_GEN_CALL 0x68
+#define DW_IC_ENABLE 0x6c
+#define DW_IC_STATUS 0x70
+#define DW_IC_TXFLR 0x74
+#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
+#define DW_IC_TX_ABRT_SOURCE 0x80
+#define DW_IC_ENABLE_STATUS 0x9c
+#define DW_IC_CLR_RESTART_DET 0xa8
+#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+
+
+#define DRV_I2C_DEVADDR_DEPTH7 0
+#define DRV_I2C_DEVADDR_DEPTH10 1
+
+#define DRV_I2C_REG_DEPTH8 0
+#define DRV_I2C_REG_DEPTH16 1
+
+#define STARFIVE_I2C_STATUS_TXFIFO_EMPTY (1 << 2)
+#define STARFIVE_I2C_STATUS_RXFIFO_NOT_EMPTY (1 << 3)
+#define DW_IC_CON_10BITADDR_MASTER (1 << 4)
+#define I2C_APB_CLK_BASE 0x13020228
+
+#define STARFIVE_I2C_ADAPTER_MAX 7
+
+#define IC_DATA_CMD_READ (1 << 8)
+#define IC_DATA_CMD_STOP (1 << 9)
+#define IC_DATA_CMD_RESTART (1 << 10)
+#define IC_INT_STATUS_STOPDET (1 << 9)
+
+
+struct starfive_i2c_adapter {
+ unsigned long addr;
+ int index;
+ struct i2c_adapter adapter;
+};
+
+static unsigned int starfive_i2c_adapter_count;
+static struct starfive_i2c_adapter
+ starfive_i2c_adapter_array[STARFIVE_I2C_ADAPTER_MAX];
+
+extern struct fdt_i2c_adapter fdt_i2c_adapter_starfive;
+
+static inline void starfive_i2c_setreg(struct starfive_i2c_adapter *adap,
+ uint8_t reg, uint32_t value)
+{
+ writel(value, (volatile char *)adap->addr + reg);
+}
+
+static inline uint32_t starfive_i2c_getreg(struct starfive_i2c_adapter *adap,
+ uint8_t reg)
+{
+ return readl((volatile char *)adap->addr + reg);
+}
+
+static int starfive_i2c_adapter_poll(struct starfive_i2c_adapter *adap,
+ uint32_t mask, uint32_t addr, bool inverted)
+{
+ unsigned int timeout = 10; /* [msec] */
+ int count = 0;
+ uint32_t val;
+
+ do {
+ val = starfive_i2c_getreg(adap, addr);
+ if (inverted) {
+ if (!(val & mask))
+ return 0;
+ } else {
+ if (val & mask)
+ return 0;
+ }
+ sbi_timer_udelay(2);
+ count += 1;
+ if (count == (timeout * 1000))
+ return SBI_ETIMEDOUT;
+ } while (1);
+}
+
+#define starfive_i2c_adapter_poll_rxrdy(adap) \
+ starfive_i2c_adapter_poll(adap, STARFIVE_I2C_STATUS_RXFIFO_NOT_EMPTY, DW_IC_STATUS, 0)
+#define starfive_i2c_adapter_poll_txfifo_ready(adap) \
+ starfive_i2c_adapter_poll(adap, STARFIVE_I2C_STATUS_TXFIFO_EMPTY, DW_IC_STATUS, 0)
+
+static int starfive_i2c_write_addr(struct starfive_i2c_adapter *adap,
+ uint8_t addr)
+{
+ unsigned long clock_base = (I2C_APB_CLK_BASE + adap->index * 4);
+ unsigned int val;
+
+ val = readl((volatile char *)clock_base);
+ if (!val) {
+ writel(0x1 << 31, (volatile char *)(clock_base));
+ }
+
+ starfive_i2c_setreg(adap, DW_IC_ENABLE, 0);
+ starfive_i2c_setreg(adap, DW_IC_TAR, addr);
+ starfive_i2c_setreg(adap, DW_IC_ENABLE, 1);
+
+ return 0;
+}
+
+
+static int starfive_i2c_adapter_read(struct i2c_adapter *ia, uint8_t addr,
+ uint8_t reg, uint8_t *buffer, int len)
+{
+ struct starfive_i2c_adapter *adap =
+ container_of(ia, struct starfive_i2c_adapter, adapter);
+ int rc;
+
+ starfive_i2c_write_addr(adap, addr); /* only support 8bit value device now */
+
+ rc = starfive_i2c_adapter_poll_txfifo_ready(adap);
+ if (rc) {
+ sbi_printf("i2c read: write daddr %x to\n", addr);
+ return rc;
+ }
+
+ /* set register address */
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, reg);
+
+ /* set value */
+ while (len) {
+ /*
+ * Avoid writing to ic_cmd_data multiple times
+ * in case this loop spins too quickly and the
+ * ic_status RFNE bit isn't set after the first
+ * write. Subsequent writes to ic_cmd_data can
+ * trigger spurious i2c transfer.
+ */
+ if (len == 1)
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, IC_DATA_CMD_READ | IC_DATA_CMD_STOP);
+ else
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, IC_DATA_CMD_READ);
+
+ rc = starfive_i2c_adapter_poll_rxrdy(adap);
+ if (rc) {
+ sbi_printf("i2c read: read reg %x to\n", reg);
+ return rc;
+ }
+ *buffer = starfive_i2c_getreg(adap, DW_IC_DATA_CMD) & 0xff;
+ buffer++;
+ len--;
+ }
+
+ return 0;
+}
+
+static int starfive_i2c_adapter_write(struct i2c_adapter *ia, uint8_t addr,
+ uint8_t reg, uint8_t *buffer, int len)
+{
+ struct starfive_i2c_adapter *adap =
+ container_of(ia, struct starfive_i2c_adapter, adapter);
+ int rc;
+ uint8_t val = 0;
+
+ starfive_i2c_write_addr(adap, addr);
+
+ rc = starfive_i2c_adapter_poll_txfifo_ready(adap);
+ if (rc) {
+ sbi_printf("i2c write: write daddr %x to\n", addr);
+ return rc;
+ }
+ /* set register address */
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, reg);
+
+ while (len) {
+
+ rc = starfive_i2c_adapter_poll_txfifo_ready(adap);
+ if (rc) {
+ sbi_printf("i2c write: write reg %x to\n", reg);
+ return rc;
+ }
+
+ if (len == 1)
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer | IC_DATA_CMD_STOP);
+ else
+ starfive_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer);
+
+ val = *buffer;
+ buffer++;
+ len--;
+ }
+ rc = starfive_i2c_adapter_poll_txfifo_ready(adap);
+ if (rc) {
+ sbi_printf("i2c write: write reg %x val %x to\n", reg, val);
+ return rc;
+ }
+ return 0;
+}
+
+static int starfive_i2c_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ struct starfive_i2c_adapter *adapter;
+ uint64_t addr;
+ const char *name;
+
+ if (starfive_i2c_adapter_count >= STARFIVE_I2C_ADAPTER_MAX)
+ return SBI_ENOSPC;
+
+ adapter = &starfive_i2c_adapter_array[starfive_i2c_adapter_count];
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
+ if (rc)
+ return rc;
+
+ name = fdt_get_name(fdt, nodeoff, NULL);
+ if (!sbi_strncmp(name, "i2c", 3)) {
+ adapter->index = name[3] - '0';
+ } else
+ return SBI_EINVAL;
+
+ adapter->addr = addr;
+ adapter->adapter.driver = &fdt_i2c_adapter_starfive;
+ adapter->adapter.id = nodeoff;
+ adapter->adapter.write = starfive_i2c_adapter_write;
+ adapter->adapter.read = starfive_i2c_adapter_read;
+ rc = i2c_adapter_add(&adapter->adapter);
+ if (rc)
+ return rc;
+
+ starfive_i2c_adapter_count++;
+
+ return 0;
+}
+
+static const struct fdt_match starfive_i2c_match[] = {
+ { .compatible = "snps,designware-i2c" },
+ { },
+};
+
+struct fdt_i2c_adapter fdt_i2c_adapter_starfive = {
+ .match_table = starfive_i2c_match,
+ .init = starfive_i2c_init,
+};
+
+
diff --git a/lib/utils/i2c/objects.mk b/lib/utils/i2c/objects.mk
index a0fbbb5..d03f5eb 100644
--- a/lib/utils/i2c/objects.mk
+++ b/lib/utils/i2c/objects.mk
@@ -14,3 +14,6 @@ libsbiutils-objs-$(CONFIG_FDT_I2C) += i2c/fdt_i2c_adapter_drivers.o
carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_SIFIVE) += fdt_i2c_adapter_sifive
libsbiutils-objs-$(CONFIG_FDT_I2C_SIFIVE) += i2c/fdt_i2c_sifive.o
+
+carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_STARFIVE) += fdt_i2c_adapter_starfive
+libsbiutils-objs-$(CONFIG_FDT_I2C_STARFIVE) += i2c/fdt_i2c_starfive.o
diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
index 4b0842e..3db7050 100644
--- a/platform/generic/configs/defconfig
+++ b/platform/generic/configs/defconfig
@@ -8,6 +8,7 @@ CONFIG_FDT_GPIO=y
CONFIG_FDT_GPIO_SIFIVE=y
CONFIG_FDT_I2C=y
CONFIG_FDT_I2C_SIFIVE=y
+CONFIG_FDT_I2C_STARFIVE=y
CONFIG_FDT_IPI=y
CONFIG_FDT_IPI_MSWI=y
CONFIG_FDT_IPI_PLICSW=y
diff --git a/platform/generic/starfive/jh7110.c b/platform/generic/starfive/jh7110.c
index c665658..1e9da7e 100644
--- a/platform/generic/starfive/jh7110.c
+++ b/platform/generic/starfive/jh7110.c
@@ -5,14 +5,309 @@
*
* Authors:
* Wei Liang Lim <weiliang.lim@starfivetech.com>
+ * Minda chen <minda.chen@starfivetech.com>
*/
#include <libfdt.h>
#include <platform_override.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hart.h>
+#include <sbi/sbi_system.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_hsm.h>
+#include <sbi/sbi_ipi.h>
+#include <sbi/sbi_timer.h>
+#include <sbi/sbi_domain.h>
+#include <sbi/riscv_io.h>
#include <sbi_utils/fdt/fdt_helper.h>
+#include <sbi_utils/fdt/fdt_fixup.h>
+#include <sbi_utils/reset/fdt_reset.h>
+#include <sbi_utils/i2c/fdt_i2c.h>
+struct pmic {
+ struct i2c_adapter *adapter;
+ uint32_t dev_addr;
+ const char *compatible;
+};
+
+static struct pmic pmic_inst;
static u32 selected_hartid = -1;
+#define PMU_REG_BASE 0x17030000
+#define SYS_CRG_BASE 0x13020000
+#define SYS_CRG_CORE_CLK_BASE 0x13020064
+#define SYS_CRG_CORE_TRACE_CLK_BASE 0x13020080
+
+/* PMU register define */
+#define HW_EVENT_TURN_ON_MASK 0x04
+#define HW_EVENT_TURN_OFF_MASK 0x08
+#define SW_TURN_ON_POWER_MODE 0x0C
+#define SW_TURN_OFF_POWER_MODE 0x10
+#define SW_ENCOURAGE 0x44
+#define PMU_INT_MASK 0x48
+#define PCH_BYPASS 0x4C
+#define PCH_PSTATE 0x50
+#define PCH_TIMEOUT 0x54
+#define LP_TIMEOUT 0x58
+#define HW_TURN_ON_MODE 0x5C
+#define CURR_POWER_MODE 0x80
+#define PMU_EVENT_STATUS 0x88
+#define PMU_INT_STATUS 0x8C
+
+/* sw encourage cfg */
+#define SW_MODE_ENCOURAGE_EN_LO 0x05
+#define SW_MODE_ENCOURAGE_EN_HI 0x50
+#define SW_MODE_ENCOURAGE_DIS_LO 0x0A
+#define SW_MODE_ENCOURAGE_DIS_HI 0xA0
+#define SW_MODE_ENCOURAGE_ON 0xFF
+
+#define DEVICE_PD_MASK 0xfc
+#define SYSTOP_CPU_PD_MASK 0x3
+
+#define TIMEOUT_COUNT 100000
+#define AXP15060_POWER_REG 0x32
+#define AXP15060_POWER_OFF_BIT (0x1 << 7)
+
+static int pm_system_reset_check(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ return 1;
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ if (pmic_inst.adapter)
+ return 255;
+ break;
+ }
+
+ return 0;
+}
+
+static int wait_pmu_pd_state(uint32_t mask)
+{
+ int count = 0;
+ uint32_t val;
+
+ do {
+ val = readl((volatile void *)(PMU_REG_BASE + CURR_POWER_MODE));
+ if (val == mask)
+ return 0;
+
+ sbi_timer_udelay(2);
+ count += 1;
+ if (count == TIMEOUT_COUNT)
+ return SBI_ETIMEDOUT;
+ } while (1);
+}
+
+static int shutdown_device_power_domain()
+{
+ unsigned long addr = PMU_REG_BASE;
+ uint32_t curr_mode;
+ int ret;
+
+ curr_mode = readl((volatile void *)(addr + CURR_POWER_MODE));
+ curr_mode &= DEVICE_PD_MASK;
+
+ if (curr_mode) {
+ writel(curr_mode, (volatile void *)(addr + SW_TURN_OFF_POWER_MODE));
+ writel(SW_MODE_ENCOURAGE_ON, (volatile void *)(addr + SW_ENCOURAGE));
+ writel(SW_MODE_ENCOURAGE_DIS_LO, (volatile void *)(addr + SW_ENCOURAGE));
+ writel(SW_MODE_ENCOURAGE_DIS_HI, (volatile void *)(addr + SW_ENCOURAGE));
+ ret = wait_pmu_pd_state(SYSTOP_CPU_PD_MASK);
+ if (ret)
+ sbi_printf("shutdown device power %x error\n", curr_mode);
+ }
+ return ret;
+}
+
+static int shutdown_cpu_systop_domain()
+{
+ unsigned long addr = PMU_REG_BASE;
+ uint32_t curr_mode;
+ int ret;
+
+ curr_mode = readl((volatile void *)(addr + CURR_POWER_MODE));
+
+ if (curr_mode != SYSTOP_CPU_PD_MASK) {
+ shutdown_device_power_domain();
+ }
+ if (curr_mode) {
+ writel(curr_mode, (volatile void *)(addr + SW_TURN_OFF_POWER_MODE));
+ writel(SW_MODE_ENCOURAGE_ON, (volatile void *)(addr + SW_ENCOURAGE));
+ writel(SW_MODE_ENCOURAGE_DIS_LO, (volatile void *)(addr + SW_ENCOURAGE));
+ writel(SW_MODE_ENCOURAGE_DIS_HI, (volatile void *)(addr + SW_ENCOURAGE));
+ }
+ while (1) {
+ wfi(); /* wait for power down */
+ }
+ return ret;
+}
+
+static int pmic_shutdown(struct pmic *pmic)
+{
+ int ret = 0;
+ uint8_t val;
+ int retry = 10;
+
+ shutdown_device_power_domain();
+
+ if (!sbi_strcmp("stf,axp15060-regulator", pmic->compatible)) {
+ do {
+ ret = i2c_adapter_reg_read(pmic->adapter, pmic->dev_addr,
+ AXP15060_POWER_REG, &val);
+ retry--;
+ } while (ret && retry);
+
+ if (ret) {
+ sbi_printf("cannot read pmic power register\n");
+ goto err;
+ }
+
+ retry = 10;
+ val |= AXP15060_POWER_OFF_BIT;
+
+ do {
+ ret = i2c_adapter_reg_write(pmic->adapter, pmic->dev_addr,
+ AXP15060_POWER_REG, val);
+ retry--;
+ } while (ret && retry);
+
+ if (ret) {
+ sbi_printf("cannot write pmic power register\n");
+ }
+ }
+
+err:
+ while (1) {
+ wfi();
+ }
+ return 0;
+}
+
+static int pmic_reset(struct pmic *pmic)
+{
+ return 0;
+}
+
+static int pmu_shutdown()
+{
+ shutdown_device_power_domain();
+ shutdown_cpu_systop_domain();
+
+ return 0;
+}
+
+static void pm_system_reset(u32 type, u32 reason)
+{
+ switch (type) {
+ case SBI_SRST_RESET_TYPE_SHUTDOWN:
+ if (pmic_inst.adapter)
+ pmic_shutdown(&pmic_inst);
+ else
+ pmu_shutdown();
+ break;
+ case SBI_SRST_RESET_TYPE_COLD_REBOOT:
+ case SBI_SRST_RESET_TYPE_WARM_REBOOT:
+ if (pmic_inst.adapter)
+ pmic_reset(&pmic_inst);
+ break;
+ default:
+ goto skip_reset;
+ }
+ return;
+
+skip_reset:
+ sbi_hart_hang();
+}
+
+
+static struct sbi_system_reset_device pm_reset = {
+ .name = "pm-reset",
+ .system_reset_check = pm_system_reset_check,
+ .system_reset = pm_system_reset
+};
+
+static int pmic_reset_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ int rc;
+ int i2c_bus;
+ struct i2c_adapter *adapter;
+ uint64_t addr;
+
+ rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
+ if (rc)
+ return rc;
+
+ pmic_inst.dev_addr = addr;
+ pmic_inst.compatible = match->compatible;
+
+ i2c_bus = fdt_parent_offset(fdt, nodeoff);
+ if (i2c_bus < 0)
+ return i2c_bus;
+
+ /* i2c adapter get */
+ rc = fdt_i2c_adapter_get(fdt, i2c_bus, &adapter);
+ if (rc)
+ return rc;
+
+ pmic_inst.adapter = adapter;
+
+ sbi_system_reset_add_device(&pm_reset);
+
+ return 0;
+}
+
+static int pm_reset_init(void *fdt, int nodeoff,
+ const struct fdt_match *match)
+{
+ if (!sbi_strcmp(match->compatible, "starfive,jh7110-pmu")) {
+ sbi_system_reset_add_device(&pm_reset);
+ return 0;
+ }
+ return pmic_reset_init(fdt, nodeoff, match);
+}
+
+static const struct fdt_match pm_reset_match[] = {
+ { .compatible = "stf,axp15060-regulator", .data = (void *)true },
+ { },
+};
+
+struct fdt_reset fdt_reset_pmic = {
+ .match_table = pm_reset_match,
+ .init = pm_reset_init,
+};
+
+static int starfive_jh7110_hart_suspend(u32 suspend_type)
+{
+ wfi();
+ return SBI_ENOTSUPP; /* 7110 not support STR */
+}
+
+static void starfive_jh7110_hart_resume(void)
+{
+}
+
+static const struct sbi_hsm_device jh7110_hsm_device = {
+ .name = "jh7110-hsm",
+ .hart_suspend = starfive_jh7110_hart_suspend,
+ .hart_resume = starfive_jh7110_hart_resume,
+};
+
+static int starfive_jh7110_final_init(bool cold_boot,
+ const struct fdt_match *match)
+{
+ void *fdt = fdt_get_address();
+
+ if (cold_boot) {
+ sbi_hsm_set_device(&jh7110_hsm_device);
+ fdt_reset_driver_init(fdt, &fdt_reset_pmic);
+ }
+
+ return 0;
+}
+
static bool starfive_jh7110_cold_boot_allowed(u32 hartid,
const struct fdt_match *match)
{
@@ -44,4 +339,5 @@ const struct platform_override starfive_jh7110 = {
.match_table = starfive_jh7110_match,
.cold_boot_allowed = starfive_jh7110_cold_boot_allowed,
.fw_init = starfive_jh7110_fw_init,
+ .final_init = starfive_jh7110_final_init,
};