summaryrefslogtreecommitdiff
path: root/platform/generic/starfive/jh7110.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/generic/starfive/jh7110.c')
-rw-r--r--platform/generic/starfive/jh7110.c296
1 files changed, 296 insertions, 0 deletions
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,
};