[PATCH v2 3/5] pmdomain: mediatek: Add support for secure HWCCF infra power on

AngeloGioacchino Del Regno posted 5 patches 6 days, 10 hours ago
[PATCH v2 3/5] pmdomain: mediatek: Add support for secure HWCCF infra power on
Posted by AngeloGioacchino Del Regno 6 days, 10 hours ago
Some SoCs, like the MediaTek Dimensity 9400 (MT6991), have granular
power controls and will disable power to the infracfg to save power
when the platform is in deeper sleep states (or when no IP in the
the infracfg macro-block is in use).

These chips also cannot control the infracfg power states directly
via AP register writes as those are protected by the secure world.

Add a new MTK_SCPD_INFRA_PWR_CTL cap and, if present, make a call
to the secure world to poweron the infracfg block, as the HWV IP
resides in there, when executing HWV domains power sequences.

Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
 drivers/pmdomain/mediatek/mtk-pm-domains.c | 40 ++++++++++++++++++++--
 drivers/pmdomain/mediatek/mtk-pm-domains.h |  1 +
 2 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index 36767f740f57..f400b0c6b5fd 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -15,6 +15,7 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/soc/mediatek/infracfg.h>
+#include <linux/soc/mediatek/mtk_sip_svc.h>
 
 #include "mt6735-pm-domains.h"
 #include "mt6795-pm-domains.h"
@@ -51,6 +52,8 @@
 #define PWR_RTFF_SAVE_FLAG		BIT(27)
 #define PWR_RTFF_UFS_CLK_DIS		BIT(28)
 
+#define MTK_SIP_KERNEL_HWCCF_CONTROL	MTK_SIP_SMC_CMD(0x540)
+
 struct scpsys_domain {
 	struct generic_pm_domain genpd;
 	const struct scpsys_domain_data *data;
@@ -116,6 +119,15 @@ static bool scpsys_hwv_domain_is_enable_done(struct scpsys_domain *pd)
 	return (val[0] & mask) && (val[1] & mask) && !(val[2] & mask);
 }
 
+static int scpsys_sec_infra_power_on(bool on)
+{
+	struct arm_smccc_res res;
+	unsigned long cmd = on ? 1 : 0;
+
+	arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
+	return res.a0;
+}
+
 static int scpsys_sram_enable(struct scpsys_domain *pd)
 {
 	u32 expected_ack, pdn_ack = pd->data->sram_pdn_ack_bits;
@@ -291,9 +303,15 @@ static int scpsys_hwv_power_on(struct generic_pm_domain *genpd)
 	u32 val;
 	int ret;
 
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) {
+		ret = scpsys_sec_infra_power_on(true);
+		if (ret)
+			return ret;
+	}
+
 	ret = scpsys_regulator_enable(pd->supply);
 	if (ret)
-		return ret;
+		goto err_infra;
 
 	ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
 	if (ret)
@@ -344,6 +362,9 @@ static int scpsys_hwv_power_on(struct generic_pm_domain *genpd)
 	/* It's done! Disable the HWV low power subsystem clocks */
 	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
 
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
+		scpsys_sec_infra_power_on(false);
+
 	return 0;
 
 err_disable_subsys_clks:
@@ -352,6 +373,9 @@ static int scpsys_hwv_power_on(struct generic_pm_domain *genpd)
 	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
 err_reg:
 	scpsys_regulator_disable(pd->supply);
+err_infra:
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
+		scpsys_sec_infra_power_on(false);
 	return ret;
 };
 
@@ -363,9 +387,15 @@ static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
 	u32 val;
 	int ret;
 
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL)) {
+		ret = scpsys_sec_infra_power_on(true);
+		if (ret)
+			return ret;
+	}
+
 	ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
 	if (ret)
-		return ret;
+		goto err_infra;
 
 	/* Make sure the HW Voter is idle and able to accept commands */
 	ret = regmap_read_poll_timeout_atomic(scpsys->base, hwv->done, val,
@@ -407,10 +437,16 @@ static int scpsys_hwv_power_off(struct generic_pm_domain *genpd)
 
 	scpsys_regulator_disable(pd->supply);
 
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
+		scpsys_sec_infra_power_on(false);
+
 	return 0;
 
 err_disable_subsys_clks:
 	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
+err_infra:
+	if (MTK_SCPD_CAPS(pd, MTK_SCPD_INFRA_PWR_CTL))
+		scpsys_sec_infra_power_on(false);
 	return ret;
 };
 
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h
index df4bf013709b..36adcfca80c6 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h
@@ -16,6 +16,7 @@
 #define MTK_SCPD_SRAM_PDN_INVERTED	BIT(9)
 #define MTK_SCPD_MODEM_PWRSEQ		BIT(10)
 #define MTK_SCPD_SKIP_RESET_B		BIT(11)
+#define MTK_SCPD_INFRA_PWR_CTL		BIT(12)
 #define MTK_SCPD_CAPS(_scpd, _x)	((_scpd)->data ?		\
 					 (_scpd)->data->caps & (_x) :	\
 					 (_scpd)->hwv_data->caps & (_x))
-- 
2.51.0

Re: [PATCH v2 3/5] pmdomain: mediatek: Add support for secure HWCCF infra power on
Posted by kernel test robot 5 days, 11 hours ago
Hi AngeloGioacchino,

kernel test robot noticed the following build errors:

[auto build test ERROR on next-20250924]
[cannot apply to robh/for-next linus/master v6.17-rc7 v6.17-rc6 v6.17-rc5 v6.17-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/AngeloGioacchino-Del-Regno/dt-bindings-power-Add-support-for-MT8196-power-controllers/20250925-223530
base:   next-20250924
patch link:    https://lore.kernel.org/r/20250925143122.39796-4-angelogioacchino.delregno%40collabora.com
patch subject: [PATCH v2 3/5] pmdomain: mediatek: Add support for secure HWCCF infra power on
config: i386-buildonly-randconfig-001-20250926 (https://download.01.org/0day-ci/archive/20250926/202509262155.Ux4J6K4D-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250926/202509262155.Ux4J6K4D-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509262155.Ux4J6K4D-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/pmdomain/mediatek/mtk-pm-domains.c:124:23: error: variable has incomplete type 'struct arm_smccc_res'
     124 |         struct arm_smccc_res res;
         |                              ^
   drivers/pmdomain/mediatek/mtk-pm-domains.c:124:9: note: forward declaration of 'struct arm_smccc_res'
     124 |         struct arm_smccc_res res;
         |                ^
>> drivers/pmdomain/mediatek/mtk-pm-domains.c:127:2: error: call to undeclared function 'arm_smccc_smc'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     127 |         arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
         |         ^
>> drivers/pmdomain/mediatek/mtk-pm-domains.c:127:16: error: call to undeclared function 'ARM_SMCCC_CALL_VAL'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     127 |         arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
         |                       ^
   drivers/pmdomain/mediatek/mtk-pm-domains.c:55:38: note: expanded from macro 'MTK_SIP_KERNEL_HWCCF_CONTROL'
      55 | #define MTK_SIP_KERNEL_HWCCF_CONTROL    MTK_SIP_SMC_CMD(0x540)
         |                                         ^
   include/linux/soc/mediatek/mtk_sip_svc.h:22:2: note: expanded from macro 'MTK_SIP_SMC_CMD'
      22 |         ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
         |         ^
>> drivers/pmdomain/mediatek/mtk-pm-domains.c:127:16: error: use of undeclared identifier 'ARM_SMCCC_FAST_CALL'
   drivers/pmdomain/mediatek/mtk-pm-domains.c:55:38: note: expanded from macro 'MTK_SIP_KERNEL_HWCCF_CONTROL'
      55 | #define MTK_SIP_KERNEL_HWCCF_CONTROL    MTK_SIP_SMC_CMD(0x540)
         |                                         ^
   include/linux/soc/mediatek/mtk_sip_svc.h:22:21: note: expanded from macro 'MTK_SIP_SMC_CMD'
      22 |         ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
         |                            ^
>> drivers/pmdomain/mediatek/mtk-pm-domains.c:127:16: error: use of undeclared identifier 'ARM_SMCCC_SMC_32'
   drivers/pmdomain/mediatek/mtk-pm-domains.c:55:38: note: expanded from macro 'MTK_SIP_KERNEL_HWCCF_CONTROL'
      55 | #define MTK_SIP_KERNEL_HWCCF_CONTROL    MTK_SIP_SMC_CMD(0x540)
         |                                         ^
   include/linux/soc/mediatek/mtk_sip_svc.h:22:42: note: expanded from macro 'MTK_SIP_SMC_CMD'
      22 |         ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \
         |                                                 ^
   include/linux/soc/mediatek/mtk_sip_svc.h:18:41: note: expanded from macro 'MTK_SIP_SMC_CONVENTION'
      18 | #define MTK_SIP_SMC_CONVENTION          ARM_SMCCC_SMC_32
         |                                         ^
>> drivers/pmdomain/mediatek/mtk-pm-domains.c:127:16: error: use of undeclared identifier 'ARM_SMCCC_OWNER_SIP'
   drivers/pmdomain/mediatek/mtk-pm-domains.c:55:38: note: expanded from macro 'MTK_SIP_KERNEL_HWCCF_CONTROL'
      55 | #define MTK_SIP_KERNEL_HWCCF_CONTROL    MTK_SIP_SMC_CMD(0x540)
         |                                         ^
   include/linux/soc/mediatek/mtk_sip_svc.h:23:7: note: expanded from macro 'MTK_SIP_SMC_CMD'
      23 |                            ARM_SMCCC_OWNER_SIP, fn_id)
         |                            ^
   6 errors generated.


vim +124 drivers/pmdomain/mediatek/mtk-pm-domains.c

    54	
  > 55	#define MTK_SIP_KERNEL_HWCCF_CONTROL	MTK_SIP_SMC_CMD(0x540)
    56	
    57	struct scpsys_domain {
    58		struct generic_pm_domain genpd;
    59		const struct scpsys_domain_data *data;
    60		const struct scpsys_hwv_domain_data *hwv_data;
    61		struct scpsys *scpsys;
    62		int num_clks;
    63		struct clk_bulk_data *clks;
    64		int num_subsys_clks;
    65		struct clk_bulk_data *subsys_clks;
    66		struct regulator *supply;
    67	};
    68	
    69	struct scpsys {
    70		struct device *dev;
    71		struct regmap *base;
    72		const struct scpsys_soc_data *soc_data;
    73		u8 bus_prot_index[BUS_PROT_BLOCK_COUNT];
    74		struct regmap **bus_prot;
    75		struct genpd_onecell_data pd_data;
    76		struct generic_pm_domain *domains[];
    77	};
    78	
    79	#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
    80	
    81	static bool scpsys_domain_is_on(struct scpsys_domain *pd)
    82	{
    83		struct scpsys *scpsys = pd->scpsys;
    84		u32 status, status2;
    85	
    86		regmap_read(scpsys->base, pd->data->pwr_sta_offs, &status);
    87		status &= pd->data->sta_mask;
    88	
    89		regmap_read(scpsys->base, pd->data->pwr_sta2nd_offs, &status2);
    90		status2 &= pd->data->sta_mask;
    91	
    92		/* A domain is on when both status bits are set. */
    93		return status && status2;
    94	}
    95	
    96	static bool scpsys_hwv_domain_is_disable_done(struct scpsys_domain *pd)
    97	{
    98		const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
    99		u32 regs[2] = { hwv->done, hwv->clr_sta };
   100		u32 val[2];
   101		u32 mask = BIT(hwv->setclr_bit);
   102	
   103		regmap_multi_reg_read(pd->scpsys->base, regs, val, 2);
   104	
   105		/* Disable is done when the bit is set in DONE, cleared in CLR_STA */
   106		return (val[0] & mask) && !(val[1] & mask);
   107	}
   108	
   109	static bool scpsys_hwv_domain_is_enable_done(struct scpsys_domain *pd)
   110	{
   111		const struct scpsys_hwv_domain_data *hwv = pd->hwv_data;
   112		u32 regs[3] = { hwv->done, hwv->en, hwv->set_sta };
   113		u32 val[3];
   114		u32 mask = BIT(hwv->setclr_bit);
   115	
   116		regmap_multi_reg_read(pd->scpsys->base, regs, val, 3);
   117	
   118		/* Enable is done when the bit is set in DONE and EN, cleared in SET_STA */
   119		return (val[0] & mask) && (val[1] & mask) && !(val[2] & mask);
   120	}
   121	
   122	static int scpsys_sec_infra_power_on(bool on)
   123	{
 > 124		struct arm_smccc_res res;
   125		unsigned long cmd = on ? 1 : 0;
   126	
 > 127		arm_smccc_smc(MTK_SIP_KERNEL_HWCCF_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res);
   128		return res.a0;
   129	}
   130	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki