* [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct
@ 2026-07-01 12:19 AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 1/4] dt-bindings: power: mediatek: Add support for MT8196 direct HFRP AngeloGioacchino Del Regno
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:19 UTC (permalink / raw)
To: ulfh
Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
nfraprado, irving-ch.lin, macpaul.lin, aford173, mbrugger,
devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-mediatek, justin.yeh, kernel
This series adds support for the DirectCTL HFRPSYS power domains found
on the MT8196 SoC (the ones without HW Voter support) and also adds a
fix to respect the power domain relationships during error cleanup,
which avoids HW lockups in case probe deferrals in the specific case
of "almost fully probed" power domains (where most of them probed and
got set up but a probe deferral happened almost at the end), behavior
seen on the MT8189 SoC during bringup (but honestly I have no idea how
are the current ones working fine without this fix...!).
This was tested on MT8173, MT8186, MT8188, MT8189, MT8192, MT8195 and
also on MT8196, over months of development, both manually and over CI,
with no regressions detected.
AngeloGioacchino Del Regno (4):
dt-bindings: power: mediatek: Add support for MT8196 direct HFRP
pmdomain: mediatek: Respect PD relationships during error cleanup
pmdomain: mediatek: Add support for Direct CTL simple power sequence
pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains
.../power/mediatek,power-controller.yaml | 1 +
drivers/pmdomain/mediatek/mt8196-pm-domains.h | 27 ++++
drivers/pmdomain/mediatek/mtk-pm-domains.c | 134 ++++++++++++++----
drivers/pmdomain/mediatek/mtk-pm-domains.h | 1 +
.../dt-bindings/power/mediatek,mt8196-power.h | 4 +
5 files changed, 141 insertions(+), 26 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/4] dt-bindings: power: mediatek: Add support for MT8196 direct HFRP
2026-07-01 12:19 [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct AngeloGioacchino Del Regno
@ 2026-07-01 12:19 ` AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup AngeloGioacchino Del Regno
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:19 UTC (permalink / raw)
To: ulfh
Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
nfraprado, irving-ch.lin, macpaul.lin, aford173, mbrugger,
devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-mediatek, justin.yeh, kernel
Add support for the HFRPSYS direct control power domains in the
MT8196 SoC, controlling power for the DisplayPort and for the
Embedded DisplayPort Transmitter IPs.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../devicetree/bindings/power/mediatek,power-controller.yaml | 1 +
include/dt-bindings/power/mediatek,mt8196-power.h | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
index 07f046277f8a..070c6e5666dc 100644
--- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
+++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml
@@ -34,6 +34,7 @@ properties:
- mediatek,mt8189-power-controller
- mediatek,mt8192-power-controller
- mediatek,mt8195-power-controller
+ - mediatek,mt8196-hfrp-power-controller
- mediatek,mt8196-hwv-hfrp-power-controller
- mediatek,mt8196-hwv-scp-power-controller
- mediatek,mt8196-power-controller
diff --git a/include/dt-bindings/power/mediatek,mt8196-power.h b/include/dt-bindings/power/mediatek,mt8196-power.h
index 0f622a93c807..085790bf8124 100644
--- a/include/dt-bindings/power/mediatek,mt8196-power.h
+++ b/include/dt-bindings/power/mediatek,mt8196-power.h
@@ -30,6 +30,10 @@
#define MT8196_POWER_DOMAIN_MM_PROC_DORMANT 0
#define MT8196_POWER_DOMAIN_SSR 1
+/* HFRPSYS Multimedia Power Control (MMPC) - Direct Control */
+#define MT8196_POWER_DOMAIN_EDPTX 0
+#define MT8196_POWER_DOMAIN_DPTX 1
+
/* HFRPSYS MultiMedia Power Control (MMPC) - HW Voter */
#define MT8196_POWER_DOMAIN_VDE0 0
#define MT8196_POWER_DOMAIN_VDE1 1
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup
2026-07-01 12:19 [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 1/4] dt-bindings: power: mediatek: Add support for MT8196 direct HFRP AngeloGioacchino Del Regno
@ 2026-07-01 12:19 ` AngeloGioacchino Del Regno
2026-07-01 12:35 ` sashiko-bot
2026-07-01 12:19 ` [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains AngeloGioacchino Del Regno
3 siblings, 1 reply; 8+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:19 UTC (permalink / raw)
To: ulfh
Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
nfraprado, irving-ch.lin, macpaul.lin, aford173, mbrugger,
devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-mediatek, justin.yeh, kernel
In case any probe error occurs (usually, a probe deferral) the
power domains shall be cleaned up while respecting their child
to parent relationship, or the system may freeze.
In order to do that without any memory footprint impacts after
the fact, allocate a temporary array in the probe function and
use it to store the indices of the added power domains in the
correct order.
This will be used in the error cleanup path and will be freed
at the end regardless of the probe status as, when the probing
succeeds, the genpd API takes care of unregistering all PDs in
the correct order anyway.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/pmdomain/mediatek/mtk-pm-domains.c | 43 +++++++++++++++++-----
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index e1cfd4223473..db543d4b1813 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -738,7 +738,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
}
static struct
-generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
+generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node,
+ u8 *domains_idx, u8 *num_domains)
{
const struct scpsys_domain_data *domain_data;
const struct scpsys_hwv_domain_data *hwv_domain_data;
@@ -906,6 +907,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
else
pm_genpd_init(&pd->genpd, NULL, false);
+ domains_idx[(*num_domains)++] = (u8) id;
scpsys->domains[id] = &pd->genpd;
return scpsys->pd_data.domains[id];
@@ -917,7 +919,8 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
return ERR_PTR(ret);
}
-static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent)
+static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent,
+ u8 *domains_idx, u8 *num_domains)
{
struct generic_pm_domain *child_pd, *parent_pd;
struct device_node *child;
@@ -940,7 +943,7 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren
parent_pd = scpsys->pd_data.domains[id];
- child_pd = scpsys_add_one_domain(scpsys, child);
+ child_pd = scpsys_add_one_domain(scpsys, child, domains_idx, num_domains);
if (IS_ERR(child_pd)) {
ret = PTR_ERR(child_pd);
dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
@@ -949,7 +952,7 @@ static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *paren
}
/* recursive call to add all subdomains */
- ret = scpsys_add_subdomain(scpsys, child);
+ ret = scpsys_add_subdomain(scpsys, child, domains_idx, num_domains);
if (ret)
goto err_put_node;
@@ -991,14 +994,16 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd)
clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
}
-static void scpsys_domain_cleanup(struct scpsys *scpsys)
+static void scpsys_domain_cleanup(struct scpsys *scpsys, u8 *domains_idx, u8 num_probed)
{
struct generic_pm_domain *genpd;
struct scpsys_domain *pd;
int i;
- for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
- genpd = scpsys->pd_data.domains[i];
+ for (i = num_probed - 1; i >= 0; i--) {
+ u8 pd_idx = domains_idx[i];
+
+ genpd = scpsys->pd_data.domains[pd_idx];
if (genpd) {
pd = to_scpsys_domain(genpd);
scpsys_remove_one_domain(pd);
@@ -1215,6 +1220,8 @@ static int scpsys_probe(struct platform_device *pdev)
struct device *parent;
struct scpsys *scpsys;
int num_domains, ret;
+ u8 num_added_pds = 0;
+ u8 *added_pds_idx;
soc = of_device_get_match_data(&pdev->dev);
if (!soc) {
@@ -1228,6 +1235,19 @@ static int scpsys_probe(struct platform_device *pdev)
if (!scpsys)
return -ENOMEM;
+ /*
+ * Temporarily store the IDs of the power domains that are added as in
+ * case of a probe deferral this can be used to correctly cleanup all
+ * of what was added before.
+ *
+ * Note that this array is used only in the probe function and must be
+ * freed at the end, regardless of whether all of the power domains were
+ * probed successfully or any failure happened.
+ */
+ added_pds_idx = devm_kmalloc_array(dev, num_domains, sizeof(*added_pds_idx), GFP_KERNEL);
+ if (!added_pds_idx)
+ return -ENOMEM;
+
scpsys->dev = dev;
scpsys->soc_data = soc;
@@ -1258,13 +1278,15 @@ static int scpsys_probe(struct platform_device *pdev)
for_each_available_child_of_node_scoped(np, node) {
struct generic_pm_domain *domain;
- domain = scpsys_add_one_domain(scpsys, node);
+ domain = scpsys_add_one_domain(scpsys, node,
+ added_pds_idx, &num_added_pds);
if (IS_ERR(domain)) {
ret = PTR_ERR(domain);
goto err_cleanup_domains;
}
- ret = scpsys_add_subdomain(scpsys, node);
+ ret = scpsys_add_subdomain(scpsys, node,
+ added_pds_idx, &num_added_pds);
if (ret)
goto err_cleanup_domains;
}
@@ -1280,10 +1302,11 @@ static int scpsys_probe(struct platform_device *pdev)
goto err_cleanup_domains;
}
+ devm_kfree(dev, added_pds_idx);
return 0;
err_cleanup_domains:
- scpsys_domain_cleanup(scpsys);
+ scpsys_domain_cleanup(scpsys, added_pds_idx, num_added_pds);
return ret;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence
2026-07-01 12:19 [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 1/4] dt-bindings: power: mediatek: Add support for MT8196 direct HFRP AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup AngeloGioacchino Del Regno
@ 2026-07-01 12:19 ` AngeloGioacchino Del Regno
2026-07-01 12:44 ` sashiko-bot
2026-07-01 12:19 ` [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains AngeloGioacchino Del Regno
3 siblings, 1 reply; 8+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:19 UTC (permalink / raw)
To: ulfh
Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
nfraprado, irving-ch.lin, macpaul.lin, aford173, mbrugger,
devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-mediatek, justin.yeh, kernel
Some new SoCs like MT8196, MT6991, and others, have got one
additional power controller (usually in the HFRP Multimedia
block) which needs a simplified power on/off sequence while
using Direct Control strategy.
Domains using the "simple power sequence" are not backed by
the RTFF hardware, have no Bus Protection mechanism, lacks
the ISO, PWR_ON, PWR_ON_2ND bits, and therefore get enabled
automatically after getting out of reset.
This simple power sequence is then a subset of the full one
as only needs the enablement of the specific power domain's
clock input and reset (where, again, after getting out of
reset, the ISO and PWR_ON bits are automatically internally
getting flipped) to enable or disable (power on or off).
Moreover, the simple power sequence power domains guarantee
that they always get enabled/disabled after executing the
relevant power sequence (on/off) so, differently from the
others, there is also no need to poll for a PWR_ACK.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/pmdomain/mediatek/mtk-pm-domains.c | 87 ++++++++++++++++++----
drivers/pmdomain/mediatek/mtk-pm-domains.h | 1 +
2 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index db543d4b1813..5276adea1d04 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -549,9 +549,11 @@ static int scpsys_ctl_pwrseq_on(struct scpsys_domain *pd)
return 0;
}
-static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
+static int scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
+ bool tmp;
+ int ret;
switch (pd->data->rtff_type) {
case SCPSYS_RTFF_TYPE_GENERIC:
@@ -583,6 +585,41 @@ static void scpsys_ctl_pwrseq_off(struct scpsys_domain *pd)
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
+
+ /* wait until PWR_ACK = 0 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
+ MTK_POLL_TIMEOUT);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int scpsys_simple_pwrseq_on(struct scpsys_domain *pd)
+{
+ struct scpsys *scpsys = pd->scpsys;
+
+ /* Enable subsys clock input and trigger power domain reset state */
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+
+ /* Wait for the hardware to stabilize */
+ udelay(1);
+
+ /* Get out of reset: set power on */
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+
+ return 0;
+}
+
+static int scpsys_simple_pwrseq_off(struct scpsys_domain *pd)
+{
+ struct scpsys *scpsys = pd->scpsys;
+
+ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+ regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
+
+ return 0;
}
static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd)
@@ -605,14 +642,24 @@ static int scpsys_modem_pwrseq_on(struct scpsys_domain *pd)
return 0;
}
-static void scpsys_modem_pwrseq_off(struct scpsys_domain *pd)
+static int scpsys_modem_pwrseq_off(struct scpsys_domain *pd)
{
struct scpsys *scpsys = pd->scpsys;
+ bool tmp;
+ int ret;
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SKIP_RESET_B))
regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
+
+ /* wait until PWR_ACK = 0 */
+ ret = readx_poll_timeout(scpsys_domain_is_on, pd, 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)
@@ -635,6 +682,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
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);
else
ret = scpsys_ctl_pwrseq_on(pd);
@@ -662,9 +711,11 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
goto err_pwr_ack;
}
- ret = scpsys_sram_enable(pd);
- if (ret < 0)
- goto err_disable_subsys_clks;
+ if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) {
+ ret = scpsys_sram_enable(pd);
+ if (ret < 0)
+ goto err_disable_subsys_clks;
+ }
ret = scpsys_bus_protect_disable(pd, 0);
if (ret < 0)
@@ -682,7 +733,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
err_enable_bus_protect:
scpsys_bus_protect_enable(pd, 0);
err_disable_sram:
- scpsys_sram_disable(pd);
+ if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
+ scpsys_sram_disable(pd);
err_disable_subsys_clks:
if (!MTK_SCPD_CAPS(pd, MTK_SCPD_STRICT_BUS_PROTECTION))
clk_bulk_disable_unprepare(pd->num_subsys_clks,
@@ -698,16 +750,17 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
{
struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
struct scpsys *scpsys = pd->scpsys;
- bool tmp;
int ret;
ret = scpsys_bus_protect_enable(pd, 0);
if (ret < 0)
return ret;
- ret = scpsys_sram_disable(pd);
- if (ret < 0)
- return ret;
+ if (!MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ)) {
+ ret = scpsys_sram_disable(pd);
+ if (ret < 0)
+ return ret;
+ }
if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO))
regmap_set_bits(scpsys->base, pd->data->ext_buck_iso_offs,
@@ -721,15 +774,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
scpsys_modem_pwrseq_off(pd);
+ else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
+ ret = scpsys_simple_pwrseq_off(pd);
else
scpsys_ctl_pwrseq_off(pd);
- /* wait until PWR_ACK = 0 */
- ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
- MTK_POLL_TIMEOUT);
- if (ret < 0)
- return ret;
-
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
scpsys_regulator_disable(pd->supply);
@@ -1083,6 +1132,12 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s
regmap[2] = NULL;
}
+ /* If no access controllers are needed, don't allocate and don't fail */
+ if (num_regmaps == 0) {
+ scpsys->bus_prot = NULL;
+ return 0;
+ }
+
scpsys->bus_prot = devm_kmalloc_array(dev, num_regmaps,
sizeof(*scpsys->bus_prot), GFP_KERNEL);
if (!scpsys->bus_prot)
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h
index a5dca24cbc2f..092403de66fa 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h
@@ -17,6 +17,7 @@
#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_SIMPLE_PWRSEQ BIT(13)
#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data ? \
(_scpd)->data->caps & (_x) : \
(_scpd)->hwv_data->caps & (_x))
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains
2026-07-01 12:19 [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct AngeloGioacchino Del Regno
` (2 preceding siblings ...)
2026-07-01 12:19 ` [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence AngeloGioacchino Del Regno
@ 2026-07-01 12:19 ` AngeloGioacchino Del Regno
2026-07-01 13:00 ` sashiko-bot
3 siblings, 1 reply; 8+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:19 UTC (permalink / raw)
To: ulfh
Cc: robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
nfraprado, irving-ch.lin, macpaul.lin, aford173, mbrugger,
devicetree, linux-kernel, linux-pm, linux-arm-kernel,
linux-mediatek, justin.yeh, kernel
Add support for the power domains provided by the HFRPSYS Power
Controller of the MT8196 SoC.
Those control power to the eDP and DP Transmitter IPs.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/pmdomain/mediatek/mt8196-pm-domains.h | 27 +++++++++++++++++++
drivers/pmdomain/mediatek/mtk-pm-domains.c | 4 +++
2 files changed, 31 insertions(+)
diff --git a/drivers/pmdomain/mediatek/mt8196-pm-domains.h b/drivers/pmdomain/mediatek/mt8196-pm-domains.h
index 2e4b28720659..d704c9fa9337 100644
--- a/drivers/pmdomain/mediatek/mt8196-pm-domains.h
+++ b/drivers/pmdomain/mediatek/mt8196-pm-domains.h
@@ -602,6 +602,27 @@ static const struct scpsys_hwv_domain_data hfrpsys_hwv_domain_data_mt8196[] = {
},
};
+static const struct scpsys_domain_data hfrpsys_domain_data_mt8196[] = {
+ [MT8196_POWER_DOMAIN_EDPTX] = {
+ .name = "edp-tx",
+ .sta_mask = MT8196_PWR_ACK,
+ .sta2nd_mask = MT8196_PWR_ACK_2ND,
+ .ctl_offs = 0x74,
+ .pwr_sta_offs = 0x74,
+ .pwr_sta2nd_offs = 0x74,
+ .caps = MTK_SCPD_SIMPLE_PWRSEQ,
+ },
+ [MT8196_POWER_DOMAIN_DPTX] = {
+ .name = "dp-tx",
+ .sta_mask = MT8196_PWR_ACK,
+ .sta2nd_mask = MT8196_PWR_ACK_2ND,
+ .ctl_offs = 0x78,
+ .pwr_sta_offs = 0x78,
+ .pwr_sta2nd_offs = 0x78,
+ .caps = MTK_SCPD_SIMPLE_PWRSEQ,
+ },
+};
+
static const struct scpsys_soc_data mt8196_scpsys_data = {
.domains_data = scpsys_domain_data_mt8196,
.num_domains = ARRAY_SIZE(scpsys_domain_data_mt8196),
@@ -616,6 +637,12 @@ static const struct scpsys_soc_data mt8196_scpsys_hwv_data = {
.type = SCPSYS_MTCMOS_TYPE_HW_VOTER,
};
+static const struct scpsys_soc_data mt8196_hfrpsys_data = {
+ .domains_data = hfrpsys_domain_data_mt8196,
+ .num_domains = ARRAY_SIZE(hfrpsys_domain_data_mt8196),
+ .type = SCPSYS_MTCMOS_TYPE_DIRECT_CTL,
+};
+
static const struct scpsys_soc_data mt8196_hfrpsys_hwv_data = {
.hwv_domains_data = hfrpsys_hwv_domain_data_mt8196,
.num_hwv_domains = ARRAY_SIZE(hfrpsys_hwv_domain_data_mt8196),
diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
index 5276adea1d04..f69cf69ba0f6 100644
--- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
+++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
@@ -1252,6 +1252,10 @@ static const struct of_device_id scpsys_of_match[] = {
.compatible = "mediatek,mt8196-power-controller",
.data = &mt8196_scpsys_data,
},
+ {
+ .compatible = "mediatek,mt8196-hfrp-power-controller",
+ .data = &mt8196_hfrpsys_data,
+ },
{
.compatible = "mediatek,mt8196-hwv-hfrp-power-controller",
.data = &mt8196_hfrpsys_hwv_data,
--
2.54.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup
2026-07-01 12:19 ` [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup AngeloGioacchino Del Regno
@ 2026-07-01 12:35 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-07-01 12:35 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The return value of pm_genpd_init() is ignored, which leads to a NULL pointer dereference crash during error cleanup if initialization fails.
--
commit 356604344a98472f2a371cddf8d5683735700cda
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
pmdomain: mediatek: Respect PD relationships during error cleanup
This commit allocates a temporary array during probe to track the addition
order of power domains. If an error occurs, it uses this array to clean up
the domains in the exact reverse order, avoiding system freezes.
> diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> index e1cfd42234734..db543d4b1813c 100644
> --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
> +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
[ ... ]
> @@ -906,6 +907,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no
> else
> pm_genpd_init(&pd->genpd, NULL, false);
>
> + domains_idx[(*num_domains)++] = (u8) id;
[Severity: High]
This is a pre-existing issue, but does ignoring the return value of
pm_genpd_init() here lead to a NULL pointer dereference crash during error
cleanup if initialization fails?
If pm_genpd_init() fails (e.g., due to a memory allocation failure), the domain
is partially initialized and its gpd_list_node remains zero-initialized.
Because the error isn't caught, the driver still considers the domain
successfully added and tracks it in scpsys->domains.
Later during probe, if an error triggers the cleanup path,
scpsys_domain_cleanup() then invokes scpsys_remove_one_domain() ->
pm_genpd_remove() on this uninitialized domain.
pm_genpd_remove() unconditionally calls list_del(&genpd->gpd_list_node), which
attempts to access next->prev on NULL pointers, resulting in a kernel panic.
> scpsys->domains[id] = &pd->genpd;
>
> return scpsys->pd_data.domains[id];
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260701121920.19347-1-angelogioacchino.delregno@collabora.com?part=2
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence
2026-07-01 12:19 ` [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence AngeloGioacchino Del Regno
@ 2026-07-01 12:44 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-07-01 12:44 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] The return values of the power-off sequence functions (`scpsys_modem_pwrseq_off`, `scpsys_ctl_pwrseq_off`, and `scpsys_simple_pwrseq_off`) are ignored in `scpsys_power_off()`, silently dropping timeouts and masking hardware failures.
Pre-existing issues:
- [High] Incomplete error handling in `scpsys_power_on` leaves the hardware domain powered on if subsequent initialization steps fail.
- [High] Subsystem clocks are left permanently disabled if the bus protection enable step fails during the power-off sequence.
- [High] Missing GENPD_FLAG_NO_STAY_ON for domains supplied by regulators risks delayed regulator cleanup while domains remain active.
- [High] The function `scpsys_power_on()` fails to restore the ext_buck_iso hardware state on its error path.
--
commit 893d0afc69c059985945081fa1e299e1362c2611
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Subject: pmdomain: mediatek: Add support for Direct CTL simple power sequence
This commit introduces support for a Direct CTL simple power sequence for
new MediaTek SoCs. The simple power sequence applies to domains without RTFF
hardware or bus protection, simplifying the power on/off process. It enables
the specific power domain's clock input and reset without needing to poll
for a power acknowledge signal.
> diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c
> index db543d4b1813c..5276adea1d041 100644
> --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c
> +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c
[ ... ]
> @@ -721,15 +774,11 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
>
> if (MTK_SCPD_CAPS(pd, MTK_SCPD_MODEM_PWRSEQ))
> scpsys_modem_pwrseq_off(pd);
> + else if (MTK_SCPD_CAPS(pd, MTK_SCPD_SIMPLE_PWRSEQ))
> + ret = scpsys_simple_pwrseq_off(pd);
> else
> scpsys_ctl_pwrseq_off(pd);
>
> - /* wait until PWR_ACK = 0 */
> - ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
> - MTK_POLL_TIMEOUT);
> - if (ret < 0)
> - return ret;
> -
> clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
[Severity: High]
Does this code silently ignore the return values of the power-off sequence
functions?
By moving the timeout check into the individual off functions and changing
them to return an error code, if readx_poll_timeout() fails, they return the
error.
However, scpsys_power_off() does not check these return values (nor the
assigned ret variable for the simple sequence), meaning the timeout is
completely ignored.
Could this cause the driver to unconditionally tear down clocks and regulators
despite a physical power-off failure, potentially causing a system hang?
[ ... ]
While reviewing this patch, I noticed a few pre-existing issues in the same
file.
[Severity: High]
This is a pre-existing issue, but does the error path in scpsys_power_on()
fail to call the corresponding power-off sequence before disabling clocks and
regulators?
drivers/pmdomain/mediatek/mtk-pm-domains.c:scpsys_power_on() {
...
err_pwr_ack:
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
err_reg:
scpsys_regulator_disable(pd->supply);
return ret;
}
If a step like bus protection or SRAM enablement fails during power-on, the
framework considers the domain off, but the physical hardware may remain
powered on without its necessary clocks and regulators.
Could this lead to state desynchronization and potential crashes?
[Severity: High]
This is a pre-existing issue, but are subsystem clocks left permanently
disabled if the bus protection enable step fails during the power-off sequence?
drivers/pmdomain/mediatek/mtk-pm-domains.c:scpsys_power_off() {
...
clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
ret = scpsys_bus_protect_enable(pd, BUS_PROT_IGNORE_SUBCLK);
if (ret < 0)
return ret;
...
}
If scpsys_bus_protect_enable() fails, the operation aborts and returns an
error, leaving the domain considered ON by the genpd framework.
However, because subsystem clocks were already disabled and are never
re-enabled, could subsequent accesses to the domain cause a system crash or
lockup?
[Severity: High]
This is a pre-existing issue, but does scpsys_add_one_domain() implicitly
activate the stay_on mechanism without an opt-out flag?
drivers/pmdomain/mediatek/mtk-pm-domains.c:scpsys_add_one_domain() {
...
if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
pm_genpd_init(&pd->genpd, NULL, true);
else
pm_genpd_init(&pd->genpd, NULL, false);
...
}
For domains supplied by regulators, if a consumer device does not probe
successfully, the genpd stay_on flag is never cleared because sync_state never
fires.
The regulator core will asynchronously disable unused regulators after a delay,
causing the hardware to lose power while its power domain registers are still
active.
Should this include GENPD_FLAG_NO_STAY_ON to prevent this?
[Severity: High]
This is a pre-existing issue, but does the error path in scpsys_power_on()
fail to restore the ext_buck_iso hardware state?
drivers/pmdomain/mediatek/mtk-pm-domains.c:scpsys_power_on() {
...
if (pd->data->ext_buck_iso_offs && MTK_SCPD_CAPS(pd, MTK_SCPD_EXT_BUCK_ISO))
regmap_clear_bits(scpsys->base, pd->data->ext_buck_iso_offs,
pd->data->ext_buck_iso_mask);
...
err_pwr_ack:
clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
err_reg:
scpsys_regulator_disable(pd->supply);
return ret;
}
If a step fails after the ext_buck_iso bits are cleared, the function jumps to
err_pwr_ack which disables clocks and regulators but fails to set the bits back
to restore isolation.
Could this lead to hardware state inconsistency and potential leakage current?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260701121920.19347-1-angelogioacchino.delregno@collabora.com?part=3
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains
2026-07-01 12:19 ` [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains AngeloGioacchino Del Regno
@ 2026-07-01 13:00 ` sashiko-bot
0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-07-01 13:00 UTC (permalink / raw)
To: AngeloGioacchino Del Regno; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The MT8196 `edp-tx` and `dp-tx` power domains are missing the `MTK_SCPD_KEEP_DEFAULT_OFF` capability flag, which incorrectly forces them ON during boot.
--
commit eb4f187de58f0a2cc70a0933e40d0337d20d3ddb
Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains
This commit adds support for the power domains provided by the HFRPSYS Power
Controller of the MT8196 SoC. These domains control power to the eDP and DP
Transmitter IPs.
> diff --git a/drivers/pmdomain/mediatek/mt8196-pm-domains.h b/drivers/pmdomain/mediatek/mt8196-pm-domains.h
> --- a/drivers/pmdomain/mediatek/mt8196-pm-domains.h
> +++ b/drivers/pmdomain/mediatek/mt8196-pm-domains.h
> @@ -602,6 +602,27 @@ static const struct scpsys_hwv_domain_data hfrpsys_hwv_domain_data_mt8196[] = {
[ ... ]
> +static const struct scpsys_domain_data hfrpsys_domain_data_mt8196[] = {
> + [MT8196_POWER_DOMAIN_EDPTX] = {
> + .name = "edp-tx",
> + .sta_mask = MT8196_PWR_ACK,
> + .sta2nd_mask = MT8196_PWR_ACK_2ND,
> + .ctl_offs = 0x74,
> + .pwr_sta_offs = 0x74,
> + .pwr_sta2nd_offs = 0x74,
> + .caps = MTK_SCPD_SIMPLE_PWRSEQ,
> + },
> + [MT8196_POWER_DOMAIN_DPTX] = {
> + .name = "dp-tx",
> + .sta_mask = MT8196_PWR_ACK,
> + .sta2nd_mask = MT8196_PWR_ACK_2ND,
> + .ctl_offs = 0x78,
> + .pwr_sta_offs = 0x78,
> + .pwr_sta2nd_offs = 0x78,
> + .caps = MTK_SCPD_SIMPLE_PWRSEQ,
[Severity: Medium]
Should these domains also include the MTK_SCPD_KEEP_DEFAULT_OFF capability?
Without it, the domains are initialized with is_off=false, which sets
stay_on=true in the genpd core. If the eDP or DP consumers never probe,
sync_state will never fire, and the domains will stay powered on indefinitely.
> + },
> +};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260701121920.19347-1-angelogioacchino.delregno@collabora.com?part=4
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-07-01 13:00 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-01 12:19 [PATCH 0/4] pmdomains: Fixes and add support for HFRP Direct AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 1/4] dt-bindings: power: mediatek: Add support for MT8196 direct HFRP AngeloGioacchino Del Regno
2026-07-01 12:19 ` [PATCH 2/4] pmdomain: mediatek: Respect PD relationships during error cleanup AngeloGioacchino Del Regno
2026-07-01 12:35 ` sashiko-bot
2026-07-01 12:19 ` [PATCH 3/4] pmdomain: mediatek: Add support for Direct CTL simple power sequence AngeloGioacchino Del Regno
2026-07-01 12:44 ` sashiko-bot
2026-07-01 12:19 ` [PATCH 4/4] pmdomain: mediatek: Add support for MT8196 HFRP DirectCTL domains AngeloGioacchino Del Regno
2026-07-01 13:00 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox