[PATCH v2 2/2] config: starfive: add PMIC power ops in JH7110 visionfive2 board

Minda Chen minda.chen at starfivetech.com
Wed Mar 8 02:13:03 PST 2023



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