diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 8309a4b46afb..5b4d860318a4 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -57,6 +57,10 @@ #define MTK_SIP_KERNEL_HWCCF_CONTROL MTK_SIP_SMC_CMD(0x540) +/* Secure MTCMOS commands for modem subsystem */ +#define MTK_MD_MTCMOS_ENABLE 18 +#define MTK_MD_MTCMOS_DISABLE 19 + struct scpsys_domain { struct generic_pm_domain genpd; const struct scpsys_domain_data *data; @@ -668,6 +672,34 @@ static int scpsys_modem_pwrseq_off(struct scpsys_domain *pd) return 0; } +static bool scpsys_modem_sec_poll(unsigned long cmd) +{ + struct arm_smccc_res res; + + arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, cmd, 1, 0, 0, 0, 0, 0, &res); + + return res.a0 == 0; +} + +static int scpsys_modem_sec_power_on(bool on) +{ + struct arm_smccc_res res; + unsigned long cmd = on ? MTK_MD_MTCMOS_ENABLE : MTK_MD_MTCMOS_DISABLE; + bool tmp; + int ret; + + arm_smccc_smc(MTK_SIP_KERNEL_CCCI_CONTROL, cmd, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 == 0) + return 0; + + ret = readx_poll_timeout(scpsys_modem_sec_poll, cmd, tmp, tmp, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); @@ -686,7 +718,9 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs, pd->data->ext_buck_iso_mask); - if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) + if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) + ret = scpsys_modem_sec_power_on(true); + else if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ)) ret = scpsys_modem_pwrseq_on(pd); else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) ret = scpsys_simple_pwrseq_on(pd); @@ -717,7 +751,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) goto err_pwr_ack; } - if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) { + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ) && + !MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) { ret = scpsys_sram_enable(pd); if (ret < 0) goto err_disable_subsys_clks; @@ -739,7 +774,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) err_enable_bus_protect: scpsys_bus_protect_enable(pd, 0); err_disable_sram: - if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) + if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ) && + !MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) scpsys_sram_disable(pd); err_disable_subsys_clks: if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION)) @@ -761,7 +797,11 @@ static int scpsys_power_off_internal(struct scpsys_domain *pd) if (ret < 0) return ret; - if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) { + if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) { + ret = scpsys_modem_sec_power_on(false); + if (ret) + return ret; + } else if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) { ret = scpsys_sram_disable(pd); if (ret < 0) return ret; @@ -781,7 +821,7 @@ static int scpsys_power_off_internal(struct scpsys_domain *pd) ret = scpsys_modem_pwrseq_off(pd); else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) ret = scpsys_simple_pwrseq_off(pd); - else + else if (!MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_SECURE_PWRSEQ)) ret = scpsys_ctl_pwrseq_off(pd); if (ret < 0) { diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index 092403de66fa..8690690335ad 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h @@ -18,6 +18,7 @@ #define MTK_SCPD_SKIP_RESET_B BIT(11) #define MTK_SCPD_INFRA_PWR_CTL BIT(12) #define MTK_SCPD_SIMPLE_PWRSEQ BIT(13) +#define MTK_SCPD_MODEM_SECURE_PWRSEQ BIT(14) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \ (_scpd)->data->caps & (_x) : \ (_scpd)->hwv_data->caps & (_x)) diff --git a/include/linux/soc/mediatek/mtk_sip_svc.h b/include/linux/soc/mediatek/mtk_sip_svc.h index abe24a73ee19..6c95a29b79fa 100644 --- a/include/linux/soc/mediatek/mtk_sip_svc.h +++ b/include/linux/soc/mediatek/mtk_sip_svc.h @@ -22,6 +22,9 @@ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \ ARM_SMCCC_OWNER_SIP, fn_id) +/* Modem related SMC call */ +#define MTK_SIP_KERNEL_CCCI_CONTROL MTK_SIP_SMC_CMD(0x505) + /* DVFSRC SMC calls */ #define MTK_SIP_DVFSRC_VCOREFS_CONTROL MTK_SIP_SMC_CMD(0x506)