123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- /*
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2022 StarFive
- *
- * 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_bitops.h>
- #include <sbi/sbi_system.h>
- #include <sbi/sbi_console.h>
- #include <sbi/sbi_timer.h>
- #include <sbi/riscv_io.h>
- #include <sbi_utils/fdt/fdt_helper.h>
- #include <sbi_utils/reset/fdt_reset.h>
- #include <sbi_utils/i2c/fdt_i2c.h>
- struct pmic {
- struct i2c_adapter *adapter;
- u32 dev_addr;
- const char *compatible;
- };
- struct jh7110 {
- u64 pmu_reg_base;
- u64 clk_reg_base;
- u32 i2c_index;
- };
- static struct pmic pmic_inst;
- static struct jh7110 jh7110_inst;
- static u32 selected_hartid = -1;
- /* 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 BIT(7)
- #define AXP15060_RESET_BIT BIT(6)
- #define I2C_APB_CLK_OFFSET 0x228
- #define I2C_APB_CLK_ENABLE_BIT BIT(31)
- 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:
- return 255;
- default:
- break;
- }
- return 0;
- }
- static int wait_pmu_pd_state(u32 mask)
- {
- int count = 0;
- unsigned long addr = jh7110_inst.pmu_reg_base;
- u32 val;
- do {
- val = readl((void *)(addr + 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(void)
- {
- unsigned long addr = jh7110_inst.pmu_reg_base;
- u32 curr_mode;
- int ret = 0;
- curr_mode = readl((void *)(addr + CURR_POWER_MODE));
- curr_mode &= DEVICE_PD_MASK;
- if (curr_mode) {
- writel(curr_mode, (void *)(addr + SW_TURN_OFF_POWER_MODE));
- writel(SW_MODE_ENCOURAGE_ON, (void *)(addr + SW_ENCOURAGE));
- writel(SW_MODE_ENCOURAGE_DIS_LO, (void *)(addr + SW_ENCOURAGE));
- writel(SW_MODE_ENCOURAGE_DIS_HI, (void *)(addr + SW_ENCOURAGE));
- ret = wait_pmu_pd_state(SYSTOP_CPU_PD_MASK);
- if (ret)
- sbi_printf("%s shutdown device power %x error\n",
- __func__, curr_mode);
- }
- return ret;
- }
- static void pmic_ops(struct pmic *pmic, int type)
- {
- int ret = 0;
- u8 val;
- ret = shutdown_device_power_domain();
- if (ret)
- return;
- if (!sbi_strcmp("stf,axp15060-regulator", pmic->compatible)) {
- ret = i2c_adapter_reg_read(pmic->adapter, pmic->dev_addr,
- AXP15060_POWER_REG, &val);
- if (ret) {
- sbi_printf("%s: cannot read pmic power register\n",
- __func__);
- return;
- }
- val |= AXP15060_POWER_OFF_BIT;
- if (type == SBI_SRST_RESET_TYPE_SHUTDOWN)
- val |= AXP15060_POWER_OFF_BIT;
- else
- val |= AXP15060_RESET_BIT;
- ret = i2c_adapter_reg_write(pmic->adapter, pmic->dev_addr,
- AXP15060_POWER_REG, val);
- if (ret)
- sbi_printf("%s: cannot write pmic power register\n",
- __func__);
- }
- }
- static void pmic_i2c_clk_enable(void)
- {
- unsigned long clock_base;
- unsigned int val;
- clock_base = jh7110_inst.clk_reg_base +
- I2C_APB_CLK_OFFSET +
- (jh7110_inst.i2c_index << 2);
- val = readl((void *)clock_base);
- if (!val)
- writel(I2C_APB_CLK_ENABLE_BIT, (void *)clock_base);
- }
- static void pm_system_reset(u32 type, u32 reason)
- {
- if (pmic_inst.adapter) {
- switch (type) {
- case SBI_SRST_RESET_TYPE_SHUTDOWN:
- case SBI_SRST_RESET_TYPE_COLD_REBOOT:
- /* i2c clk may be disabled by kernel driver */
- pmic_i2c_clk_enable();
- pmic_ops(&pmic_inst, type);
- break;
- default:
- break;
- }
- }
- 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 pm_reset_init(void *fdt, int nodeoff,
- const struct fdt_match *match)
- {
- int rc;
- int i2c_bus;
- struct i2c_adapter *adapter;
- u64 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 const struct fdt_match pm_reset_match[] = {
- { .compatible = "stf,axp15060-regulator", .data = (void *)true },
- { },
- };
- static struct fdt_reset fdt_reset_pmic = {
- .match_table = pm_reset_match,
- .init = pm_reset_init,
- };
- static int starfive_jh7110_inst_init(void *fdt)
- {
- int noff, rc = 0;
- const char *name;
- u64 addr;
- noff = fdt_node_offset_by_compatible(fdt, -1, "starfive,jh7110-pmu");
- if (-1 < noff) {
- rc = fdt_get_node_addr_size(fdt, noff, 0, &addr, NULL);
- if (rc)
- goto err;
- jh7110_inst.pmu_reg_base = addr;
- }
- noff = fdt_node_offset_by_compatible(fdt, -1, "starfive,jh7110-clkgen");
- if (-1 < noff) {
- rc = fdt_get_node_addr_size(fdt, noff, 0, &addr, NULL);
- if (rc)
- goto err;
- jh7110_inst.clk_reg_base = addr;
- }
- if (pmic_inst.adapter) {
- name = fdt_get_name(fdt, pmic_inst.adapter->id, NULL);
- if (!sbi_strncmp(name, "i2c", 3))
- jh7110_inst.i2c_index = name[3] - '0';
- else
- rc = SBI_EINVAL;
- }
- err:
- return rc;
- }
- static int starfive_jh7110_final_init(bool cold_boot,
- const struct fdt_match *match)
- {
- void *fdt = fdt_get_address();
- if (cold_boot) {
- fdt_reset_driver_init(fdt, &fdt_reset_pmic);
- return starfive_jh7110_inst_init(fdt);
- }
- return 0;
- }
- static bool starfive_jh7110_cold_boot_allowed(u32 hartid,
- const struct fdt_match *match)
- {
- if (selected_hartid != -1)
- return (selected_hartid == hartid);
- return true;
- }
- static void starfive_jh7110_fw_init(void *fdt, const struct fdt_match *match)
- {
- const fdt32_t *val;
- int len, coff;
- coff = fdt_path_offset(fdt, "/chosen");
- if (-1 < coff) {
- val = fdt_getprop(fdt, coff, "starfive,boot-hart-id", &len);
- if (val && len >= sizeof(fdt32_t))
- selected_hartid = (u32) fdt32_to_cpu(*val);
- }
- }
- static const struct fdt_match starfive_jh7110_match[] = {
- { .compatible = "starfive,jh7110" },
- { },
- };
- 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,
- };
|