* [PATCH 0/2] Add support for SA8797P in the phy-snps-eusb2 phy driver
@ 2026-10-26 9:41 Hiren Gohel
2026-10-26 9:41 ` [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY Hiren Gohel
2026-10-26 9:41 ` [PATCH 2/2] phy: snps-eusb2: Add support for SA8797P Hiren Gohel
0 siblings, 2 replies; 4+ messages in thread
From: Hiren Gohel @ 2026-10-26 9:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Manivannan Sadhasivam
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Hiren Gohel
From: Hiren Gohel <vhiren@qti.qualcomm.com>
The Qualcomm automotive SA8797p 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.
Hiren Gohel (2):
dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY
phy: snps-eusb2: Add support for SA8797P
.../phy/qcom,sa8797p-snps-eusb2-phy.yaml | 68 +++++++
drivers/phy/phy-snps-eusb2.c | 183 ++++++++++++++----
2 files changed, 208 insertions(+), 43 deletions(-)
create mode 100644 Documentation/devicetree/bindings/phy/qcom,sa8797p-snps-eusb2-phy.yaml
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY
2026-10-26 9:41 [PATCH 0/2] Add support for SA8797P in the phy-snps-eusb2 phy driver Hiren Gohel
@ 2026-10-26 9:41 ` Hiren Gohel
2026-10-27 11:00 ` Konrad Dybcio
2026-10-26 9:41 ` [PATCH 2/2] phy: snps-eusb2: Add support for SA8797P Hiren Gohel
1 sibling, 1 reply; 4+ messages in thread
From: Hiren Gohel @ 2026-10-26 9:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Manivannan Sadhasivam
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Hiren Gohel
SA8797p platform abstracts resources such as resets, clocks and
regulators in firmware. The SCMI firmware exposes multiple protocols to
control such resources which are identified by protocol_id.
For this USB phy, 2 SCMI protocols are exposed by the firmware:
* power domain management protocol (protocol_id=0x11)
* performance domain management protocol (protocol_id=0x13)
The power domain has 2 indices: 'core' and 'transfer'.
* core controls the regulators, the clocks and the reset
* transfer only controls the clocks
For example, to power on/off the PHY, we should use the 'core' domain.
To disable data transfer and keeping power enabled, we should use the
'transfer' domain.
Add a new binding for the Synopsys eusb2 High-Speed USB PHY
found in SA8797P.
Note: the performance domain (0x13) exposes opaques values (0xa to 0x11)
for which we don't have any information. Since it is not mandatory
for the PHY to be functional, we have ommited it from the bindings.
We can document it (and make them part of the dt ABI) once we have more
information.
Signed-off-by: Hiren Gohel <hiren.gohel@oss.qualcomm.com>
---
.../phy/qcom,sa8797p-snps-eusb2-phy.yaml | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/qcom,sa8797p-snps-eusb2-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/qcom,sa8797p-snps-eusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sa8797p-snps-eusb2-phy.yaml
new file mode 100644
index 000000000000..0a9f44199490
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/qcom,sa8797p-snps-eusb2-phy.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/qcom,sa8797p-snps-eusb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SA8797P Synopsys eUSB2 PHY
+
+maintainers:
+ - Hiren Gohel <hiren.gohel@oss.qualcomm.com>
+
+description:
+ The Qualcomm SA8797P platform delegates control of the eUSB2 PHY clocks,
+ reset, and other platform resources to firmware. The SCMI power protocol
+ exposes two power domains for the PHY. The core domain controls the PHY
+ power, reset, and clocks, while the transfer domain controls the clocks used
+ for data transfer. The SCMI performance domain is not required for PHY
+ operation and its opaque performance values are not part of this binding.
+
+properties:
+ compatible:
+ const: qcom,sa8797p-snps-eusb2-phy
+
+ reg:
+ maxItems: 1
+
+ "#phy-cells":
+ const: 0
+
+ power-domains:
+ items:
+ - description: Core domain controlling PHY power, reset, and clocks
+ - description: Transfer domain controlling the data-transfer clocks
+
+ power-domain-names:
+ items:
+ - const: core
+ - const: transfer
+
+ phys:
+ maxItems: 1
+ description:
+ Phandle to the eUSB2 to USB 2.0 repeater.
+
+required:
+ - compatible
+ - reg
+ - "#phy-cells"
+ - power-domains
+ - power-domain-names
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ phy@88e3000 {
+ compatible = "qcom,sa8797p-snps-eusb2-phy";
+ reg = <0x0 0x088e3000 0x0 0x154>;
+ #phy-cells = <0>;
+
+ power-domains = <&scmi12_pd 1>, <&scmi12_pd 0>;
+ power-domain-names = "core", "transfer";
+ };
+ };
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] phy: snps-eusb2: Add support for SA8797P
2026-10-26 9:41 [PATCH 0/2] Add support for SA8797P in the phy-snps-eusb2 phy driver Hiren Gohel
2026-10-26 9:41 ` [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY Hiren Gohel
@ 2026-10-26 9:41 ` Hiren Gohel
1 sibling, 0 replies; 4+ messages in thread
From: Hiren Gohel @ 2026-10-26 9:41 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, Manivannan Sadhasivam
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel, Hiren Gohel
The Qualcomm automotive SA8797p 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: Hiren Gohel <hiren.gohel@oss.qualcomm.com>
---
drivers/phy/phy-snps-eusb2.c | 183 +++++++++++++++++++++++++++--------
1 file changed, 140 insertions(+), 43 deletions(-)
diff --git a/drivers/phy/phy-snps-eusb2.c b/drivers/phy/phy-snps-eusb2.c
index af4fa17ac6cb..b246ab52b409 100644
--- a/drivers/phy/phy-snps-eusb2.c
+++ b/drivers/phy/phy-snps-eusb2.c
@@ -9,6 +9,7 @@
#include <linux/iopoll.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>
@@ -157,9 +158,11 @@ struct snps_eusb2_phy_drvdata {
int (*phy_init)(struct phy *p);
const char * const *clk_names;
int num_clks;
+ bool fw_managed;
};
struct snps_eusb2_hsphy {
+ struct device *dev;
struct phy *phy;
void __iomem *base;
@@ -174,8 +177,62 @@ struct snps_eusb2_hsphy {
struct phy *repeater;
const struct snps_eusb2_phy_drvdata *data;
+ struct dev_pm_domain_list *pd_list;
};
+static void snps_eusb2_hsphy_domain_detach(void *data)
+{
+ struct snps_eusb2_hsphy *phy = data;
+
+ dev_pm_domain_detach_list(phy->pd_list);
+}
+
+static int snps_eusb2_hsphy_domain_attach(struct snps_eusb2_hsphy *phy)
+{
+ struct dev_pm_domain_attach_data pd_data = {
+ .pd_flags = PD_FLAG_NO_DEV_LINK,
+ .pd_names = (const char * const []) { "core", "transfer" },
+ .num_pd_names = 2,
+ };
+ struct device *dev = phy->dev;
+ int ret;
+
+ ret = dev_pm_domain_attach_list(dev, &pd_data, &phy->pd_list);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "domain attach failed\n");
+
+ return 0;
+}
+
+/* d3_to_d0 transition by turning on all the suppliers */
+static int snps_eusb2_hsphy_d3_to_d0(struct snps_eusb2_hsphy *phy)
+{
+ int ret;
+
+ if (!phy->pd_list)
+ return 0;
+
+ ret = pm_runtime_resume_and_get(phy->pd_list->pd_devs[0]);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(phy->pd_list->pd_devs[1]);
+ if (ret)
+ pm_runtime_put_sync(phy->pd_list->pd_devs[0]);
+
+ return ret;
+}
+
+/* d0_to_d3 transition by turning off all the suppliers */
+static void snps_eusb2_hsphy_d0_to_d3(struct snps_eusb2_hsphy *phy)
+{
+ if (!phy->pd_list)
+ return;
+
+ pm_runtime_put_sync(phy->pd_list->pd_devs[1]);
+ pm_runtime_put_sync(phy->pd_list->pd_devs[0]);
+}
+
static int snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode)
{
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
@@ -282,7 +339,12 @@ static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk[] = {
static int qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy)
{
const struct snps_eusb2_ref_clk *config = NULL;
- unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk);
+ unsigned long ref_clk_freq;
+
+ if (phy->data->fw_managed)
+ return 0;
+
+ ref_clk_freq = clk_get_rate(phy->ref_clk);
for (int i = 0; i < ARRAY_SIZE(qcom_eusb2_ref_clk); i++) {
if (qcom_eusb2_ref_clk[i].freq == ref_clk_freq) {
@@ -452,19 +514,32 @@ static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = {
.num_clks = ARRAY_SIZE(qcom_eusb2_hsphy_clock_names),
};
+static const struct snps_eusb2_phy_drvdata sa8797p_snps_eusb2_phy = {
+ .phy_init = qcom_snps_eusb2_hsphy_init,
+ .fw_managed = true,
+};
+
static int snps_eusb2_hsphy_init(struct phy *p)
{
struct snps_eusb2_hsphy *phy = phy_get_drvdata(p);
int ret;
- ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
- if (ret)
- return ret;
+ if (phy->data->fw_managed) {
+ ret = snps_eusb2_hsphy_d3_to_d0(phy);
+ if (ret < 0) {
+ dev_err(phy->dev, "Failed to transition to d0 state\n");
+ return ret;
+ }
+ } else {
+ ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs);
+ if (ret)
+ return ret;
+ }
ret = phy_init(phy->repeater);
if (ret) {
dev_err(&p->dev, "repeater init failed: %d\n", ret);
- goto disable_vreg;
+ goto power_off;
}
ret = clk_bulk_prepare_enable(phy->data->num_clks, phy->clks);
@@ -497,8 +572,11 @@ static int snps_eusb2_hsphy_init(struct phy *p)
clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks);
exit_repeater:
phy_exit(phy->repeater);
-disable_vreg:
- regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
+power_off:
+ if (phy->data->fw_managed)
+ snps_eusb2_hsphy_d0_to_d3(phy);
+ else
+ regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
return ret;
}
@@ -509,10 +587,14 @@ static int snps_eusb2_hsphy_exit(struct phy *p)
clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks);
- regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
+ if (!phy->data->fw_managed)
+ regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs);
phy_exit(phy->repeater);
+ if (phy->data->fw_managed)
+ snps_eusb2_hsphy_d0_to_d3(phy);
+
return 0;
}
@@ -537,6 +619,7 @@ static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
if (!phy)
return -ENOMEM;
+ phy->dev = dev;
phy->data = device_get_match_data(dev);
if (!phy->data)
return -EINVAL;
@@ -545,45 +628,56 @@ static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
if (IS_ERR(phy->base))
return PTR_ERR(phy->base);
- phy->phy_reset = devm_reset_control_get_optional_exclusive(dev, NULL);
- if (IS_ERR(phy->phy_reset))
- return PTR_ERR(phy->phy_reset);
-
- phy->clks = devm_kcalloc(dev, phy->data->num_clks, sizeof(*phy->clks),
- GFP_KERNEL);
- if (!phy->clks)
- return -ENOMEM;
-
- for (i = 0; i < phy->data->num_clks; ++i)
- phy->clks[i].id = phy->data->clk_names[i];
-
- ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks);
- if (ret)
- return dev_err_probe(dev, ret,
- "failed to get phy clock(s)\n");
-
- phy->ref_clk = NULL;
- for (i = 0; i < phy->data->num_clks; ++i) {
- if (!strcmp(phy->clks[i].id, "ref")) {
- phy->ref_clk = phy->clks[i].clk;
- break;
+ if (phy->data->fw_managed) {
+ ret = snps_eusb2_hsphy_domain_attach(phy);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev,
+ snps_eusb2_hsphy_domain_detach,
+ phy);
+ if (ret)
+ return ret;
+ } else {
+ phy->phy_reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(phy->phy_reset))
+ return PTR_ERR(phy->phy_reset);
+
+ phy->clks = devm_kcalloc(dev, phy->data->num_clks,
+ sizeof(*phy->clks), GFP_KERNEL);
+ if (!phy->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < phy->data->num_clks; ++i)
+ phy->clks[i].id = phy->data->clk_names[i];
+
+ ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get phy clock(s)\n");
+
+ for (i = 0; i < phy->data->num_clks; ++i) {
+ if (!strcmp(phy->clks[i].id, "ref")) {
+ phy->ref_clk = phy->clks[i].clk;
+ break;
+ }
}
- }
- if (IS_ERR_OR_NULL(phy->ref_clk)) {
- ret = phy->ref_clk ? PTR_ERR(phy->ref_clk) : -ENOENT;
- return dev_err_probe(dev, ret,
- "failed to get ref clk\n");
- }
+ if (IS_ERR_OR_NULL(phy->ref_clk)) {
+ ret = phy->ref_clk ? PTR_ERR(phy->ref_clk) : -ENOENT;
+ return dev_err_probe(dev, ret,
+ "failed to get ref clk\n");
+ }
- num = ARRAY_SIZE(phy->vregs);
- for (i = 0; i < num; i++)
- phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
+ num = ARRAY_SIZE(phy->vregs);
+ for (i = 0; i < num; i++)
+ phy->vregs[i].supply = eusb2_hsphy_vreg_names[i];
- ret = devm_regulator_bulk_get(dev, num, phy->vregs);
- if (ret)
- return dev_err_probe(dev, ret,
- "failed to get regulator supplies\n");
+ ret = devm_regulator_bulk_get(dev, num, phy->vregs);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get regulator supplies\n");
+ }
phy->repeater = devm_of_phy_optional_get(dev, np, NULL);
if (IS_ERR(phy->repeater))
@@ -608,6 +702,9 @@ static int snps_eusb2_hsphy_probe(struct platform_device *pdev)
static const struct of_device_id snps_eusb2_hsphy_of_match_table[] = {
{
+ .compatible = "qcom,sa8797p-snps-eusb2-phy",
+ .data = &sa8797p_snps_eusb2_phy,
+ }, {
.compatible = "qcom,sm8550-snps-eusb2-phy",
.data = &sm8550_snps_eusb2_phy,
}, {
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY
2026-10-26 9:41 ` [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY Hiren Gohel
@ 2026-10-27 11:00 ` Konrad Dybcio
0 siblings, 0 replies; 4+ messages in thread
From: Konrad Dybcio @ 2026-10-27 11:00 UTC (permalink / raw)
To: Hiren Gohel, Vinod Koul, Neil Armstrong, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel,
Manivannan Sadhasivam
Cc: linux-arm-msm, linux-phy, devicetree, linux-kernel
On 10/26/26 10:41 AM, Hiren Gohel wrote:
> SA8797p platform abstracts resources such as resets, clocks and
> regulators in firmware. The SCMI firmware exposes multiple protocols to
> control such resources which are identified by protocol_id.
>
> For this USB phy, 2 SCMI protocols are exposed by the firmware:
> * power domain management protocol (protocol_id=0x11)
> * performance domain management protocol (protocol_id=0x13)
>
> The power domain has 2 indices: 'core' and 'transfer'.
> * core controls the regulators, the clocks and the reset
> * transfer only controls the clocks
>
> For example, to power on/off the PHY, we should use the 'core' domain.
> To disable data transfer and keeping power enabled, we should use the
> 'transfer' domain.
>
> Add a new binding for the Synopsys eusb2 High-Speed USB PHY
> found in SA8797P.
>
> Note: the performance domain (0x13) exposes opaques values (0xa to 0x11)
> for which we don't have any information.
How come we don't have any information for what the firmware
that ""we"" wrote does?
Konrad
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-10-27 11:00 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 9:41 [PATCH 0/2] Add support for SA8797P in the phy-snps-eusb2 phy driver Hiren Gohel
2026-10-26 9:41 ` [PATCH 1/2] dt-bindings: phy: qcom: Add SA8797P eUSB2 PHY Hiren Gohel
2026-10-27 11:00 ` Konrad Dybcio
2026-10-26 9:41 ` [PATCH 2/2] phy: snps-eusb2: Add support for SA8797P Hiren Gohel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®