[PATCH v2 2/2] config: starfive: add PMIC power ops in JH7110 visionfive2 board
Anup Patel
anup at brainfault.org
Wed Mar 8 03:29:00 PST 2023
On Wed, Mar 8, 2023 at 3:43 PM Minda Chen <minda.chen at starfivetech.com> wrote:
>
>
>
> On 2023/3/7 21:32, Anup Patel wrote:
> > On Mon, Mar 6, 2023 at 2:15 PM Minda Chen <minda.chen at starfivetech.com> wrote:
> >>
> >> add reboot and poweroff support. The whole reboot and shutdown
> >> pm op includes shutdown jh7110 pmu device power domain
> >> and access on board pmic register through I2C.
> >>
> >> Signed-off-by: Minda Chen <minda.chen at starfivetech.com>
> >
> > This patch was already reviewed by me.
> >
> > Please add Reviewed-by tags obtained in previous patch revision.
> > This helps reviewers to know which patches were already reviewed.
> >
> > Reviewed-by: Anup Patel <anup at brainfault.org>
> >
> > Regards,
> > Anup
> >
> I am sorry about this. I will add reviewed tag in patch v3. Thanks.
Please use "platform: startfive:" as patch subject prefix instead of
"config: starfive:" in the next revision.
Regards,
Anup
> >> ---
> >> platform/generic/configs/defconfig | 1 +
> >> platform/generic/starfive/jh7110.c | 272 +++++++++++++++++++++++++++++
> >> 2 files changed, 273 insertions(+)
> >>
> >> diff --git a/platform/generic/configs/defconfig b/platform/generic/configs/defconfig
> >> index 2ad953d..ee0df38 100644
> >> --- a/platform/generic/configs/defconfig
> >> +++ b/platform/generic/configs/defconfig
> >> @@ -9,6 +9,7 @@ CONFIG_FDT_GPIO_SIFIVE=y
> >> CONFIG_FDT_GPIO_STARFIVE=y
> >> CONFIG_FDT_I2C=y
> >> CONFIG_FDT_I2C_SIFIVE=y
> >> +CONFIG_FDT_I2C_DW=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..31c6bd3 100644
> >> --- a/platform/generic/starfive/jh7110.c
> >> +++ b/platform/generic/starfive/jh7110.c
> >> @@ -5,14 +5,285 @@
> >> *
> >> * Authors:
> >> * Wei Liang Lim <weiliang.lim at starfivetech.com>
> >> + * Minda Chen <minda.chen at 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)
> >> +{
> >> + u64 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)
> >> {
> >> @@ -44,4 +315,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,
> >> };
> >> --
> >> 2.17.1
> >>
> >>
> >> --
> >> opensbi mailing list
> >> opensbi at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/opensbi
More information about the opensbi
mailing list