* [PATCH v3 0/2] Add support for SA8255P in the qcom-qmp-usb phy driver
@ 2026-07-22 13:45 Mattijs Korpershoek
2026-07-22 13:45 ` [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY Mattijs Korpershoek
2026-07-22 13:45 ` [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P Mattijs Korpershoek
0 siblings, 2 replies; 6+ messages in thread
From: Mattijs Korpershoek @ 2026-07-22 13:45 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Maxime Ripard, linux-arm-msm, linux-phy, devicetree, linux-kernel,
Mattijs Korpershoek, Sriram Dash, Shazad Hussain
The Qualcomm automotive SA8255p SoC relies on firmware to configure
platform resources, including clocks, interconnects and TLMM.
The driver requests resources operations over SCMI using power protocols.
The SCMI power protocol enables or disables resources like clocks,
interconnect paths, and TLMM (GPIOs) using runtime PM framework APIs,
such as resume/suspend, to control power on/off.
Power domain "core" controls the GDSC, resets, and TLMM (GPIOs)
whereas power domain "transfer" controls clocks and interconnects.
Patch 1 adds the binding for sa8255p. Similarly to what has been done
for I2C [1], this is a separate binding.
Patch 2 adds the driver change, which is based on a public vendor
patch from qualcomm [2].
I did the following changes on top of that:
* Use devm_add_action_or_reset() for dev_pm_domain_detach_list() instead
of implementing a driver .remove()
* Drop the .lanes struct member since it no longer exists.
* Re-order some functions
This has been tested on next-20260706 with a Ride4 SA8775P board that
has SCMI firmware (which is compatible).
[1] https://lore.kernel.org/all/20260617-enable-i2c-on-sa8255p-v7-1-ad736dbeab57@oss.qualcomm.com/
[2] https://git.codelinaro.org/clo/le/meta-qti-auto-kernel/-/blob/LY.AU.0.1.0.r1-16800-gen4meta.0/recipes-kernel/linux/files/usb/0011-PENDING-phy-qcom-qmp-usb-Add-support-for-SA8255P.patch
Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
---
Changes in v3:
* Binding changes:
* Use a separate binding file (Krzysztof)
* Remove 'usb_' prefix from power-domain-names (Krzysztof)
* Driver changes:
* Remove 'usb_' prefix from power-domain-names
* Moved sa8255p_usb3_uniphy_cfg before sa8775p_usb3_uniphy_cfg
* Link to v2: https://patch.msgid.link/20260709-phy-qcom-qmp-usb-8255-v2-0-3b6c26a45788@kernel.org
Changes in v2:
* Driver changes:
* Fix comment typo tranfer -> transfer
* Fix print statement to add a missing '(' in the string
* Use dev_err_probe() in qmp_usb_domain_attach() to reduce log noise
* Fix pm_runtime_put_sync() order in qmp_usb_d0_to_d3 (Sashiko)
* Fix runtime PM reference leak on usb_transfer (Sashiko)
* Fix runtime PM reference leak on error in qmp_usb_init (Sashiko)
* Reorder qmp_usb_d0_to_d3() to mirror init ordering in qmp_usb_exit()
(Sashiko)
* Reorder qmp_usb_d0_to_d3() to mirror resume ordering in
qmp_usb_runtime_suspend() (Sashiko)
* Fix error handling in qmp_usb_runtime_resume() (Sashiko)
* Link to v1: https://patch.msgid.link/20260708-phy-qcom-qmp-usb-8255-v1-0-8d852a9535db@kernel.org
---
Mattijs Korpershoek (1):
dt-bindings: phy: Add sa8255p USB PHY
Sriram Dash (1):
phy: qcom: qmp-usb: Add support for SA8255P
.../phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml | 52 ++++++
drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 182 ++++++++++++++++++---
2 files changed, 212 insertions(+), 22 deletions(-)
---
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
change-id: 20260708-phy-qcom-qmp-usb-8255-9986907cdbc9
Best regards,
--
Mattijs Korpershoek <mkorpershoek@kernel.org>
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY
2026-07-22 13:45 [PATCH v3 0/2] Add support for SA8255P in the qcom-qmp-usb phy driver Mattijs Korpershoek
@ 2026-07-22 13:45 ` Mattijs Korpershoek
2026-07-22 13:54 ` sashiko-bot
2026-07-22 13:45 ` [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P Mattijs Korpershoek
1 sibling, 1 reply; 6+ messages in thread
From: Mattijs Korpershoek @ 2026-07-22 13:45 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Maxime Ripard, linux-arm-msm, linux-phy, devicetree, linux-kernel,
Mattijs Korpershoek
SA8255p platform abstracts resources such as clocks, interconnect and
GPIO pins configuration in Firmware. SCMI power protocol is used to
request resource configurations.
Two power domains can be requested: transfer and core.
transfer controls clocks and interconnects and core controls
the GDSC, resets and TLMM (GPIOs)
Add a new binding for the for the Qualcomm QMP Super Speed (SS) UNI PHY
found in SA8255P.
Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
---
.../phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml | 52 ++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml
new file mode 100644
index 000000000000..d274d500fc9c
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SA8255p QMP PHY controller
+
+maintainers:
+ - Mattijs Korpershoek <mkorpershoek@kernel.org>
+
+properties:
+ compatible:
+ const: qcom,sa8255p-qmp-usb3-uni-phy
+
+ reg:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 0
+
+ power-domains:
+ maxItems: 2
+
+ power-domain-names:
+ items:
+ - const: transfer
+ - const: core
+
+required:
+ - compatible
+ - reg
+ - "#phy-cells"
+ - power-domains
+ - power-domain-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ phy@88e8000 {
+ compatible = "qcom,sa8255p-qmp-usb3-uni-phy";
+ reg = <0x0 0x088e8000 0x0 0x2000>;
+ #phy-cells = <0>;
+ power-domains = <&scmi12_pd 2>, <&scmi12_pd 3>;
+ power-domain-names = "transfer", "core";
+ };
+ };
--
2.55.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P
2026-07-22 13:45 [PATCH v3 0/2] Add support for SA8255P in the qcom-qmp-usb phy driver Mattijs Korpershoek
2026-07-22 13:45 ` [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY Mattijs Korpershoek
@ 2026-07-22 13:45 ` Mattijs Korpershoek
2026-07-22 14:01 ` sashiko-bot
1 sibling, 1 reply; 6+ messages in thread
From: Mattijs Korpershoek @ 2026-07-22 13:45 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Maxime Ripard, linux-arm-msm, linux-phy, devicetree, linux-kernel,
Mattijs Korpershoek, Sriram Dash, Shazad Hussain
From: Sriram Dash <quic_sriramd@quicinc.com>
The Qualcomm automotive SA8255p SoC relies on firmware to configure
platform resources, including clocks, interconnects and TLMM.
The driver requests resources operations over SCMI using power protocols.
The SCMI power protocol enables or disables resources like clocks,
interconnect paths, and TLMM (GPIOs) using runtime PM framework APIs,
such as resume/suspend, to control power on/off.
Power domain "core" controls the GDSC, resets, and TLMM (GPIOs)
whereas power domain "transfer" controls clocks and interconnects.
In this variant, two disjoint sets of resources are modeled against
the power domain suppliers which can be turned on/off to achieve modeled
device states. Two modeled low power states d1 and d3 are supported.
transition: d0 <--> d3 :: both core and transfer suppliers
transition: d0 <--> d1 :: only transfer supplier
Signed-off-by: Sriram Dash <quic_sriramd@quicinc.com>
Signed-off-by: Shazad Hussain <quic_shazhuss@quicinc.com>
Signed-off-by: Mattijs Korpershoek <mkorpershoek@kernel.org>
---
drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 182 ++++++++++++++++++++++++++++----
1 file changed, 160 insertions(+), 22 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index c5507168e135..881f4ce23241 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
@@ -1411,6 +1412,9 @@ struct qmp_phy_cfg {
/* Offset from PCS to PCS_USB region */
unsigned int pcs_usb_offset;
+
+ /* true, if the device resources are fw managed */
+ bool fw_managed;
};
struct qmp_usb {
@@ -1437,6 +1441,8 @@ struct qmp_usb {
struct phy *phy;
struct clk_fixed_rate pipe_clk_fixed;
+
+ struct dev_pm_domain_list *pd_list;
};
static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -1631,6 +1637,25 @@ static const struct qmp_phy_cfg qdu1000_usb3_uniphy_cfg = {
.has_pwrdn_delay = true,
};
+static const struct qmp_phy_cfg sa8255p_usb3_uniphy_cfg = {
+ .offsets = &qmp_usb_offsets_v5,
+
+ .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl),
+ .tx_tbl = sc8280xp_usb3_uniphy_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_tx_tbl),
+ .rx_tbl = sc8280xp_usb3_uniphy_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_rx_tbl),
+ .pcs_tbl = sa8775p_usb3_uniphy_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_tbl),
+ .pcs_usb_tbl = sa8775p_usb3_uniphy_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_usb_tbl),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = qmp_v5_usb3phy_regs_layout,
+ .fw_managed = true,
+};
+
static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = {
.offsets = &qmp_usb_offsets_v5,
@@ -1865,6 +1890,77 @@ static const struct qmp_phy_cfg glymur_usb3_uniphy_cfg = {
.regs = qmp_v7_usb3phy_regs_layout,
};
+static int qmp_usb_domain_attach(struct qmp_usb *qmp)
+{
+ struct dev_pm_domain_attach_data pd_data = {
+ .pd_flags = PD_FLAG_NO_DEV_LINK,
+ .pd_names = (const char *[]) { "transfer", "core" },
+ .num_pd_names = 2,
+ };
+ struct device *dev = qmp->dev;
+ int ret;
+
+ ret = dev_pm_domain_attach_list(dev, &pd_data, &qmp->pd_list);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "domain attach failed\n");
+
+ return 0;
+}
+
+static void qmp_usb_domain_detach(void *data)
+{
+ struct qmp_usb *qmp = data;
+
+ dev_pm_domain_detach_list(qmp->pd_list);
+}
+
+/* d3_to_d0 transition by turning on all the suppliers */
+static int qmp_usb_d3_to_d0(struct qmp_usb *qmp)
+{
+ int ret;
+
+ if (!qmp->pd_list)
+ return 0;
+
+ ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[0]);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[1]);
+ if (ret)
+ pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
+
+ return ret;
+}
+
+/* d0_to_d3 transition by turning off all the suppliers */
+static void qmp_usb_d0_to_d3(struct qmp_usb *qmp)
+{
+ if (!qmp->pd_list)
+ return;
+
+ pm_runtime_put_sync(qmp->pd_list->pd_devs[1]);
+ pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
+}
+
+/* d1_to_d0 transition by turning on the 'transfer' supplier */
+static int qmp_usb_d1_to_d0(struct qmp_usb *qmp)
+{
+ if (!qmp->pd_list)
+ return 0;
+
+ return pm_runtime_resume_and_get(qmp->pd_list->pd_devs[0]);
+}
+
+/* d0_to_d1 transition by turning off the 'transfer' supplier */
+static void qmp_usb_d0_to_d1(struct qmp_usb *qmp)
+{
+ if (!qmp->pd_list)
+ return;
+
+ pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
+}
+
static int qmp_usb_serdes_init(struct qmp_usb *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -1884,10 +1980,16 @@ static int qmp_usb_init(struct phy *phy)
void __iomem *pcs = qmp->pcs;
int ret;
+ ret = qmp_usb_d3_to_d0(qmp);
+ if (ret < 0) {
+ dev_err(qmp->dev, "Failed to transition to d0 state\n");
+ return ret;
+ }
+
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
if (ret) {
dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret);
- return ret;
+ goto err_transition_to_d3;
}
ret = reset_control_bulk_assert(qmp->num_resets, qmp->resets);
@@ -1914,6 +2016,8 @@ static int qmp_usb_init(struct phy *phy)
reset_control_bulk_assert(qmp->num_resets, qmp->resets);
err_disable_regulators:
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+err_transition_to_d3:
+ qmp_usb_d0_to_d3(qmp);
return ret;
}
@@ -1929,6 +2033,8 @@ static int qmp_usb_exit(struct phy *phy)
regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
+ qmp_usb_d0_to_d3(qmp);
+
return 0;
}
@@ -2111,6 +2217,8 @@ static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)
clk_disable_unprepare(qmp->pipe_clk);
clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+ qmp_usb_d0_to_d1(qmp);
+
return 0;
}
@@ -2126,14 +2234,23 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
return 0;
}
+ ret = qmp_usb_d1_to_d0(qmp);
+ if (ret < 0) {
+ dev_err(qmp->dev, "Failed to transition to d0 state\n");
+ return ret;
+ }
+
ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);
- if (ret)
+ if (ret) {
+ qmp_usb_d0_to_d1(qmp);
return ret;
+ }
ret = clk_prepare_enable(qmp->pipe_clk);
if (ret) {
dev_err(dev, "pipe_clk enable failed, err=%d\n", ret);
clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+ qmp_usb_d0_to_d1(qmp);
return ret;
}
@@ -2313,10 +2430,12 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np)
qmp->pcs_misc = NULL;
}
- qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
- if (IS_ERR(qmp->pipe_clk)) {
- return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
- "failed to get pipe clock\n");
+ if (!qmp->cfg->fw_managed) {
+ qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL);
+ if (IS_ERR(qmp->pipe_clk)) {
+ return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+ "failed to get pipe clock\n");
+ }
}
ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks);
@@ -2325,10 +2444,12 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np)
qmp->num_clks = ret;
- ret = qmp_usb_reset_init(qmp, usb3phy_legacy_reset_l,
- ARRAY_SIZE(usb3phy_legacy_reset_l));
- if (ret)
- return ret;
+ if (!qmp->cfg->fw_managed) {
+ ret = qmp_usb_reset_init(qmp, usb3phy_legacy_reset_l,
+ ARRAY_SIZE(usb3phy_legacy_reset_l));
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -2362,17 +2483,19 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp)
if (ret)
return ret;
- qmp->pipe_clk = devm_clk_get(dev, "pipe");
- if (IS_ERR(qmp->pipe_clk)) {
- return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
- "failed to get pipe clock\n");
+ if (!qmp->cfg->fw_managed) {
+ qmp->pipe_clk = devm_clk_get(dev, "pipe");
+ if (IS_ERR(qmp->pipe_clk)) {
+ return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk),
+ "failed to get pipe clock\n");
+ }
+
+ ret = qmp_usb_reset_init(qmp, usb3phy_reset_l,
+ ARRAY_SIZE(usb3phy_reset_l));
+ if (ret)
+ return ret;
}
- ret = qmp_usb_reset_init(qmp, usb3phy_reset_l,
- ARRAY_SIZE(usb3phy_reset_l));
- if (ret)
- return ret;
-
return 0;
}
@@ -2395,6 +2518,16 @@ static int qmp_usb_probe(struct platform_device *pdev)
if (!qmp->cfg)
return -EINVAL;
+ if (qmp->cfg->fw_managed) {
+ ret = qmp_usb_domain_attach(qmp);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, qmp_usb_domain_detach, qmp);
+ if (ret)
+ return ret;
+ }
+
ret = devm_regulator_bulk_get_const(dev, qmp->cfg->num_vregs,
qmp->cfg->vreg_list, &qmp->vregs);
if (ret)
@@ -2421,9 +2554,11 @@ static int qmp_usb_probe(struct platform_device *pdev)
*/
pm_runtime_forbid(dev);
- ret = phy_pipe_clk_register(qmp, np);
- if (ret)
- goto err_node_put;
+ if (!qmp->cfg->fw_managed) {
+ ret = phy_pipe_clk_register(qmp, np);
+ if (ret)
+ goto err_node_put;
+ }
qmp->phy = devm_phy_create(dev, np, &qmp_usb_phy_ops);
if (IS_ERR(qmp->phy)) {
@@ -2470,6 +2605,9 @@ static const struct of_device_id qmp_usb_of_match_table[] = {
}, {
.compatible = "qcom,qdu1000-qmp-usb3-uni-phy",
.data = &qdu1000_usb3_uniphy_cfg,
+ }, {
+ .compatible = "qcom,sa8255p-qmp-usb3-uni-phy",
+ .data = &sa8255p_usb3_uniphy_cfg,
}, {
.compatible = "qcom,sa8775p-qmp-usb3-uni-phy",
.data = &sa8775p_usb3_uniphy_cfg,
--
2.55.0
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY
2026-07-22 13:45 ` [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY Mattijs Korpershoek
@ 2026-07-22 13:54 ` sashiko-bot
0 siblings, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-07-22 13:54 UTC (permalink / raw)
To: Mattijs Korpershoek
Cc: devicetree, neil.armstrong, vkoul, olteanv, linux-phy, robh,
conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The schema uses `unevaluatedProperties: false` without referencing any external schema via `$ref`.
--
--- Patch [1]: [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY ---
commit 7b3aaeb1e0d8c8cd82e7d6b2d97dc88cb763da87
Author: Mattijs Korpershoek <mkorpershoek@kernel.org>
Date: Wed Jul 22 13:45:44 2026 +0000
dt-bindings: phy: Add sa8255p USB PHY
This commit introduces a new devicetree binding for the Qualcomm QMP Super
Speed (SS) UNI PHY on the SA8255P platform. The hardware abstracts resources
like clocks and interconnects through firmware via the SCMI power protocol.
> diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml
> new file mode 100644
> index 0000000000000..d274d500fc9c5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom,sa8255p-qmp-usb3-uni-phy.yaml
[ ... ]
> +required:
> + - compatible
> + - reg
> + - "#phy-cells"
> + - power-domains
> + - power-domain-names
> +
> +unevaluatedProperties: false
[Severity: Low]
Since this schema does not reference any external schemas via $ref, should
this be additionalProperties: false instead of unevaluatedProperties: false?
> +
> +examples:
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260722-phy-qcom-qmp-usb-8255-v3-0-e789070b48f7@kernel.org?part=1
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P
2026-07-22 13:45 ` [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P Mattijs Korpershoek
@ 2026-07-22 14:01 ` sashiko-bot
2026-07-22 14:32 ` Mattijs Korpershoek
0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-07-22 14:01 UTC (permalink / raw)
To: Mattijs Korpershoek
Cc: conor+dt, neil.armstrong, olteanv, robh, vkoul, linux-phy,
devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] Incorrect power domain sequencing in `d3_to_d0` and `d0_to_d3` transitions, violating hardware constraints.
Pre-existing issues:
- [High] Unbalanced clock prepare/enable and disable/unprepare, leading to `pipe_clk` enable count leak.
--
--- Patch [2]: [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P ---
commit 2b06432a4f84c161e8379370587f792f91bca968
Author: Sriram Dash <quic_sriramd@quicinc.com>
Subject: phy: qcom: qmp-usb: Add support for SA8255P
The Qualcomm automotive SA8255p SoC relies on firmware to configure
platform resources, including clocks, interconnects and TLMM.
This commit adds support for the SA8255p SoC in the QMP USB driver by
using SCMI power protocols to manage platform resources via runtime PM
framework APIs. Two sets of resources are modeled as "core" and "transfer"
power domain suppliers.
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
> index c5507168e1354..881f4ce23241e 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
[ ... ]
> @@ -1865,6 +1890,77 @@ static const struct qmp_phy_cfg glymur_usb3_uniphy_cfg = {
> .regs = qmp_v7_usb3phy_regs_layout,
> };
>
> +static int qmp_usb_domain_attach(struct qmp_usb *qmp)
> +{
> + struct dev_pm_domain_attach_data pd_data = {
> + .pd_flags = PD_FLAG_NO_DEV_LINK,
> + .pd_names = (const char *[]) { "transfer", "core" },
> + .num_pd_names = 2,
> + };
[ ... ]
> +/* d3_to_d0 transition by turning on all the suppliers */
> +static int qmp_usb_d3_to_d0(struct qmp_usb *qmp)
> +{
> + int ret;
> +
> + if (!qmp->pd_list)
> + return 0;
> +
> + ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[0]);
> + if (ret)
> + return ret;
> +
> + ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[1]);
[Severity: High]
Does resuming the 'transfer' domain before the 'core' domain cause hardware
bus hangs?
The commit message states that the "core" domain controls the GDSC (power),
while the "transfer" domain controls clocks. It appears this sequence turns
on the clocks before enabling power to the logic.
> + if (ret)
> + pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
> +
> + return ret;
> +}
> +
> +/* d0_to_d3 transition by turning off all the suppliers */
> +static void qmp_usb_d0_to_d3(struct qmp_usb *qmp)
> +{
> + if (!qmp->pd_list)
> + return;
> +
> + pm_runtime_put_sync(qmp->pd_list->pd_devs[1]);
> + pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
[Severity: High]
Similarly, does suspending the 'core' domain before the 'transfer' domain
cause issues?
This sequence disables the GDSC (power) before disabling the clocks, which
might also violate hardware constraints and lead to timeouts or freezes.
> +}
[ ... ]
> @@ -2126,14 +2234,23 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
> return 0;
> }
[Severity: High]
This is a pre-existing issue, but does this early bailout lead to a pipe_clk
enable count leak?
The code right above this addition in qmp_usb_runtime_resume() is:
if (!qmp->phy->init_count) {
dev_vdbg(dev, "PHY not initialized, bailing out\n");
return 0;
}
During the standard PHY lifecycle, this check appears to cause an unbalanced
clock prepare/enable and disable/unprepare state:
1. phy_init() starts with init_count == 0, so qmp_usb_runtime_resume() skips
enabling clocks.
2. After phy_init() completes, init_count is 1, so phy_pm_runtime_put() causes
qmp_usb_runtime_suspend() to disable pipe_clk, triggering a clock framework
underflow warning since it was never enabled.
3. Conversely, during phy_exit(), init_count is 1, so qmp_usb_runtime_resume()
enables pipe_clk. Then qmp_usb_exit() decrements init_count to 0.
4. Finally, phy_pm_runtime_put() triggers qmp_usb_runtime_suspend() (which
has a similar bailout check), leaving pipe_clk permanently enabled and
preventing the system from hitting deep sleep states.
Can this state tracking be fixed to ensure the clocks are properly matched
during suspend and resume?
>
> + ret = qmp_usb_d1_to_d0(qmp);
> + if (ret < 0) {
> + dev_err(qmp->dev, "Failed to transition to d0 state\n");
> + return ret;
> + }
> +
> ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);
> - if (ret)
> + if (ret) {
> + qmp_usb_d0_to_d1(qmp);
> return ret;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260722-phy-qcom-qmp-usb-8255-v3-0-e789070b48f7@kernel.org?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P
2026-07-22 14:01 ` sashiko-bot
@ 2026-07-22 14:32 ` Mattijs Korpershoek
0 siblings, 0 replies; 6+ messages in thread
From: Mattijs Korpershoek @ 2026-07-22 14:32 UTC (permalink / raw)
To: sashiko-reviews, Mattijs Korpershoek
Cc: conor+dt, neil.armstrong, olteanv, robh, vkoul, linux-phy,
devicetree
On Wed, Jul 22, 2026 at 14:01, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
>
> New issues:
> - [High] Incorrect power domain sequencing in `d3_to_d0` and `d0_to_d3` transitions, violating hardware constraints.
>
> Pre-existing issues:
> - [High] Unbalanced clock prepare/enable and disable/unprepare, leading to `pipe_clk` enable count leak.
> --
>
> --- Patch [2]: [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P ---
> commit 2b06432a4f84c161e8379370587f792f91bca968
> Author: Sriram Dash <quic_sriramd@quicinc.com>
> Subject: phy: qcom: qmp-usb: Add support for SA8255P
>
> The Qualcomm automotive SA8255p SoC relies on firmware to configure
> platform resources, including clocks, interconnects and TLMM.
> This commit adds support for the SA8255p SoC in the QMP USB driver by
> using SCMI power protocols to manage platform resources via runtime PM
> framework APIs. Two sets of resources are modeled as "core" and "transfer"
> power domain suppliers.
>
>> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
>> index c5507168e1354..881f4ce23241e 100644
>> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
>> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
> [ ... ]
>> @@ -1865,6 +1890,77 @@ static const struct qmp_phy_cfg glymur_usb3_uniphy_cfg = {
>> .regs = qmp_v7_usb3phy_regs_layout,
>> };
>>
>> +static int qmp_usb_domain_attach(struct qmp_usb *qmp)
>> +{
>> + struct dev_pm_domain_attach_data pd_data = {
>> + .pd_flags = PD_FLAG_NO_DEV_LINK,
>> + .pd_names = (const char *[]) { "transfer", "core" },
>> + .num_pd_names = 2,
>> + };
> [ ... ]
>> +/* d3_to_d0 transition by turning on all the suppliers */
>> +static int qmp_usb_d3_to_d0(struct qmp_usb *qmp)
>> +{
>> + int ret;
>> +
>> + if (!qmp->pd_list)
>> + return 0;
>> +
>> + ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[0]);
>> + if (ret)
>> + return ret;
>> +
>> + ret = pm_runtime_resume_and_get(qmp->pd_list->pd_devs[1]);
>
> [Severity: High]
> Does resuming the 'transfer' domain before the 'core' domain cause hardware
> bus hangs?
>
> The commit message states that the "core" domain controls the GDSC (power),
> while the "transfer" domain controls clocks. It appears this sequence turns
> on the clocks before enabling power to the logic.
I have not observed any issues during my testing on a SA8775p board with
SCMI firmware (that's compatible with this driver)
>
>> + if (ret)
>> + pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
>> +
>> + return ret;
>> +}
>> +
>> +/* d0_to_d3 transition by turning off all the suppliers */
>> +static void qmp_usb_d0_to_d3(struct qmp_usb *qmp)
>> +{
>> + if (!qmp->pd_list)
>> + return;
>> +
>> + pm_runtime_put_sync(qmp->pd_list->pd_devs[1]);
>> + pm_runtime_put_sync(qmp->pd_list->pd_devs[0]);
>
> [Severity: High]
> Similarly, does suspending the 'core' domain before the 'transfer' domain
> cause issues?
>
> This sequence disables the GDSC (power) before disabling the clocks, which
> might also violate hardware constraints and lead to timeouts or freezes.
I have not observed any issues during my testing on a SA8775p board with
SCMI firmware (that's compatible with this driver)
>
>> +}
> [ ... ]
>> @@ -2126,14 +2234,23 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
>> return 0;
>> }
>
> [Severity: High]
> This is a pre-existing issue, but does this early bailout lead to a pipe_clk
> enable count leak?
>
> The code right above this addition in qmp_usb_runtime_resume() is:
>
> if (!qmp->phy->init_count) {
> dev_vdbg(dev, "PHY not initialized, bailing out\n");
> return 0;
> }
>
> During the standard PHY lifecycle, this check appears to cause an unbalanced
> clock prepare/enable and disable/unprepare state:
>
> 1. phy_init() starts with init_count == 0, so qmp_usb_runtime_resume() skips
> enabling clocks.
> 2. After phy_init() completes, init_count is 1, so phy_pm_runtime_put() causes
> qmp_usb_runtime_suspend() to disable pipe_clk, triggering a clock framework
> underflow warning since it was never enabled.
> 3. Conversely, during phy_exit(), init_count is 1, so qmp_usb_runtime_resume()
> enables pipe_clk. Then qmp_usb_exit() decrements init_count to 0.
> 4. Finally, phy_pm_runtime_put() triggers qmp_usb_runtime_suspend() (which
> has a similar bailout check), leaving pipe_clk permanently enabled and
> preventing the system from hitting deep sleep states.
>
> Can this state tracking be fixed to ensure the clocks are properly matched
> during suspend and resume?
This is unrelated to the patch I've submitted. Should this be send out
as a seperate fix?
>
>>
>> + ret = qmp_usb_d1_to_d0(qmp);
>> + if (ret < 0) {
>> + dev_err(qmp->dev, "Failed to transition to d0 state\n");
>> + return ret;
>> + }
>> +
>> ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);
>> - if (ret)
>> + if (ret) {
>> + qmp_usb_d0_to_d1(qmp);
>> return ret;
>> + }
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260722-phy-qcom-qmp-usb-8255-v3-0-e789070b48f7@kernel.org?part=2
--
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-22 14:32 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-22 13:45 [PATCH v3 0/2] Add support for SA8255P in the qcom-qmp-usb phy driver Mattijs Korpershoek
2026-07-22 13:45 ` [PATCH v3 1/2] dt-bindings: phy: Add sa8255p USB PHY Mattijs Korpershoek
2026-07-22 13:54 ` sashiko-bot
2026-07-22 13:45 ` [PATCH v3 2/2] phy: qcom: qmp-usb: Add support for SA8255P Mattijs Korpershoek
2026-07-22 14:01 ` sashiko-bot
2026-07-22 14:32 ` Mattijs Korpershoek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox