[PATCH v3 2/2] platform: starfive: add PMIC power ops in JH7110 visionfive2 board

Anup Patel anup at brainfault.org
Thu Mar 9 07:50:44 PST 2023


On Thu, Mar 9, 2023 at 11:50 AM 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>
> Reviewed-by: Anup Patel <anup at brainfault.org>
> ---
>  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;

This function fails to compile for RV32 so I have changed
the data type of clock_based to unsigned long at the time
of merging this patch.

Applied this patch to the riscv/opensbi repo.

Thanks,
Anup

> +       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