Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pmdomain: mediatek: Add support for RTFF Hardware in MT8196/MT6991

New generation SoCs use a new RTFF Hardware to save power during
operation of various IPs, other than managing isolation of the
internal buck converters during powerup/down of power domains.

Since some of the power domains need different RTFF handling, add
a new scpys_rtff_type enumeration and hold the value for each
power domain in struct scpsys_domain_data.

If RTFF HW is available, the RTFF additional power sequences are
handled in scpsys_ctl_pwrseq_{on,off}().

Reviewed-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20250805074746.29457-9-angelogioacchino.delregno@collabora.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

AngeloGioacchino Del Regno and committed by
Ulf Hansson
9d02c943 16d861d2

+111 -1
+93 -1
drivers/pmdomain/mediatek/mtk-pm-domains.c
··· 39 39 #define PWR_SRAM_CLKISO_BIT BIT(5) 40 40 #define PWR_SRAM_ISOINT_B_BIT BIT(6) 41 41 42 + #define PWR_RTFF_SAVE BIT(24) 43 + #define PWR_RTFF_NRESTORE BIT(25) 44 + #define PWR_RTFF_CLK_DIS BIT(26) 45 + #define PWR_RTFF_SAVE_FLAG BIT(27) 46 + #define PWR_RTFF_UFS_CLK_DIS BIT(28) 47 + 42 48 struct scpsys_domain { 43 49 struct generic_pm_domain genpd; 44 50 const struct scpsys_domain_data *data; ··· 253 247 static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd) 254 248 { 255 249 struct scpsys *scpsys = pd->scpsys; 256 - bool tmp; 250 + bool do_rtff_nrestore, tmp; 257 251 int ret; 258 252 259 253 /* subsys power on */ ··· 266 260 if (ret < 0) 267 261 return ret; 268 262 263 + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) 264 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 265 + 269 266 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); 270 267 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); 268 + 269 + /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */ 270 + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) 271 + udelay(5); 272 + 271 273 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); 274 + 275 + /* 276 + * RTFF HW state may be modified by secure world or remote processors. 277 + * 278 + * With the only exception of STOR_UFS, which always needs save/restore, 279 + * check if this power domain's RTFF is already on before trying to do 280 + * the NRESTORE procedure, otherwise the system will lock up. 281 + */ 282 + switch (pd->data->rtff_type) { 283 + case SCPSYS_RTFF_TYPE_GENERIC: 284 + case SCPSYS_RTFF_TYPE_PCIE_PHY: 285 + { 286 + u32 ctl_status; 287 + 288 + regmap_read(scpsys->base, pd->data->ctl_offs, &ctl_status); 289 + do_rtff_nrestore = ctl_status & PWR_RTFF_SAVE_FLAG; 290 + break; 291 + } 292 + case SCPSYS_RTFF_TYPE_STOR_UFS: 293 + /* STOR_UFS always needs NRESTORE */ 294 + do_rtff_nrestore = true; 295 + break; 296 + default: 297 + do_rtff_nrestore = false; 298 + break; 299 + } 300 + 301 + /* Return early if RTFF NRESTORE shall not be done */ 302 + if (!do_rtff_nrestore) 303 + return 0; 304 + 305 + switch (pd->data->rtff_type) { 306 + case SCPSYS_RTFF_TYPE_GENERIC: 307 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); 308 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 309 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 310 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 311 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 312 + break; 313 + case SCPSYS_RTFF_TYPE_PCIE_PHY: 314 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); 315 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 316 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 317 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 318 + break; 319 + case SCPSYS_RTFF_TYPE_STOR_UFS: 320 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); 321 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 322 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_NRESTORE); 323 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); 324 + break; 325 + default: 326 + break; 327 + } 272 328 273 329 return 0; 274 330 } ··· 339 271 { 340 272 struct scpsys *scpsys = pd->scpsys; 341 273 274 + switch (pd->data->rtff_type) { 275 + case SCPSYS_RTFF_TYPE_GENERIC: 276 + case SCPSYS_RTFF_TYPE_PCIE_PHY: 277 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 278 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); 279 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); 280 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_CLK_DIS); 281 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE_FLAG); 282 + break; 283 + case SCPSYS_RTFF_TYPE_STOR_UFS: 284 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); 285 + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); 286 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_SAVE); 287 + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RTFF_UFS_CLK_DIS); 288 + break; 289 + default: 290 + break; 291 + } 292 + 342 293 /* subsys power off */ 343 294 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); 295 + 296 + /* Wait for RTFF HW to sync buck isolation state if this is PCIe PHY RTFF */ 297 + if (pd->data->rtff_type == SCPSYS_RTFF_TYPE_PCIE_PHY) 298 + udelay(1); 299 + 344 300 regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); 345 301 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); 346 302 regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
+18
drivers/pmdomain/mediatek/mtk-pm-domains.h
··· 109 109 }; 110 110 111 111 /** 112 + * enum scpsys_rtff_type - Type of RTFF Hardware for power domain 113 + * @SCPSYS_RTFF_NONE: RTFF HW not present or domain not RTFF managed 114 + * @SCPSYS_RTFF_TYPE_GENERIC: Non-CPU, peripheral-generic RTFF HW 115 + * @SCPSYS_RTFF_TYPE_PCIE_PHY: PCI-Express PHY specific RTFF HW 116 + * @SCPSYS_RTFF_TYPE_STOR_UFS: Storage (UFS) specific RTFF HW 117 + * @SCPSYS_RTFF_TYPE_MAX: Number of supported RTFF HW Types 118 + */ 119 + enum scpsys_rtff_type { 120 + SCPSYS_RTFF_NONE = 0, 121 + SCPSYS_RTFF_TYPE_GENERIC, 122 + SCPSYS_RTFF_TYPE_PCIE_PHY, 123 + SCPSYS_RTFF_TYPE_STOR_UFS, 124 + SCPSYS_RTFF_TYPE_MAX 125 + }; 126 + 127 + /** 112 128 * struct scpsys_domain_data - scp domain data for power on/off flow 113 129 * @name: The name of the power domain. 114 130 * @sta_mask: The mask for power on/off status bit. ··· 134 118 * @ext_buck_iso_offs: The offset for external buck isolation 135 119 * @ext_buck_iso_mask: The mask for external buck isolation 136 120 * @caps: The flag for active wake-up action. 121 + * @rtff_type: The power domain RTFF HW type 137 122 * @bp_cfg: bus protection configuration for any subsystem 138 123 */ 139 124 struct scpsys_domain_data { ··· 146 129 int ext_buck_iso_offs; 147 130 u32 ext_buck_iso_mask; 148 131 u16 caps; 132 + enum scpsys_rtff_type rtff_type; 149 133 const struct scpsys_bus_prot_data bp_cfg[SPM_MAX_BUS_PROT_DATA]; 150 134 int pwr_sta_offs; 151 135 int pwr_sta2nd_offs;