diff options
author | minda.chen <minda.chen@starfivetech.com> | 2023-01-09 10:07:00 +0300 |
---|---|---|
committer | minda.chen <minda.chen@starfivetech.com> | 2023-01-09 10:16:35 +0300 |
commit | cf4ae775ac4652125ade9d047f28e30e91e8827f (patch) | |
tree | c74298d5fd1f9ef28bf8073a2536ad226be13c82 | |
parent | 8020df8733b060f01e35b0b2bcb2b41e6b992e9b (diff) | |
download | opensbi-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/Kconfig | 4 | ||||
-rw-r--r-- | lib/utils/i2c/fdt_i2c_starfive.c | 282 | ||||
-rw-r--r-- | lib/utils/i2c/objects.mk | 3 | ||||
-rw-r--r-- | platform/generic/configs/defconfig | 1 | ||||
-rw-r--r-- | platform/generic/starfive/jh7110.c | 296 |
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, }; |