diff mbox series

[2/3] phy: qcom: qmp-pcie: add current load vote/devote for PCIe PHY

Message ID 20241204105249.3544114-3-quic_ziyuzhan@quicinc.com (mailing list archive)
State Not Applicable
Headers show
Series pci: qcom: Add PCIe setting current load support | expand

Commit Message

Ziyue Zhang Dec. 4, 2024, 10:52 a.m. UTC
On some platform (eg.qcs615), the current that phy consumes will exceed
the maximum current the regulator can provide in LPM mode, leading to
over current protection and system boot up stuck. Fix this issue by
setting regulator load to an expected value getting from phy device tree
node during init so that the regulator can scale up to HPM to allow a
larger current load.
This change will also set load to zero during deinit to let regulator
scale down to LPM mode to reduce itself's power consumptionif PCIe
suspend.

Signed-off-by: Ziyue Zhang <quic_ziyuzhan@quicinc.com>
---
 drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 35 ++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

Comments

Konrad Dybcio Dec. 5, 2024, 4:31 p.m. UTC | #1
On 4.12.2024 11:52 AM, Ziyue Zhang wrote:
> On some platform (eg.qcs615), the current that phy consumes will exceed
> the maximum current the regulator can provide in LPM mode, leading to
> over current protection and system boot up stuck. Fix this issue by
> setting regulator load to an expected value getting from phy device tree
> node during init so that the regulator can scale up to HPM to allow a
> larger current load.
> This change will also set load to zero during deinit to let regulator
> scale down to LPM mode to reduce itself's power consumptionif PCIe
> suspend.
> 
> Signed-off-by: Ziyue Zhang <quic_ziyuzhan@quicinc.com>
> ---
>  drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 35 ++++++++++++++++++++++--
>  1 file changed, 33 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> index c8e39c147ba4..782d51ab5cf1 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> @@ -39,6 +39,7 @@
>  #include "phy-qcom-qmp-pcie-qhp.h"
>  
>  #define PHY_INIT_COMPLETE_TIMEOUT		10000
> +#define MAX_PROP_SIZE		   32
>  
>  /* set of registers with offsets different per-PHY */
>  enum qphy_reg_layout {
> @@ -2905,6 +2906,7 @@ struct qmp_pcie {
>  	struct reset_control_bulk_data *resets;
>  	struct reset_control *nocsr_reset;
>  	struct regulator_bulk_data *vregs;
> +	u32 *max_current_load;
>  
>  	struct phy *phy;
>  	int mode;
> @@ -4087,6 +4089,17 @@ static int qmp_pcie_init(struct phy *phy)
>  	const struct qmp_phy_cfg *cfg = qmp->cfg;
>  	int ret;
>  
> +	for (int i = 0; i < cfg->num_vregs; i++) {
> +		if (qmp->max_current_load[i]) {
> +			ret = regulator_set_load(qmp->vregs[i].consumer, qmp->max_current_load[i]);

I think it's better if we just put this info in the driver, like with
e.g. the DSI PHY

Konrad
diff mbox series

Patch

diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index c8e39c147ba4..782d51ab5cf1 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -39,6 +39,7 @@ 
 #include "phy-qcom-qmp-pcie-qhp.h"
 
 #define PHY_INIT_COMPLETE_TIMEOUT		10000
+#define MAX_PROP_SIZE		   32
 
 /* set of registers with offsets different per-PHY */
 enum qphy_reg_layout {
@@ -2905,6 +2906,7 @@  struct qmp_pcie {
 	struct reset_control_bulk_data *resets;
 	struct reset_control *nocsr_reset;
 	struct regulator_bulk_data *vregs;
+	u32 *max_current_load;
 
 	struct phy *phy;
 	int mode;
@@ -4087,6 +4089,17 @@  static int qmp_pcie_init(struct phy *phy)
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 	int ret;
 
+	for (int i = 0; i < cfg->num_vregs; i++) {
+		if (qmp->max_current_load[i]) {
+			ret = regulator_set_load(qmp->vregs[i].consumer, qmp->max_current_load[i]);
+			if (ret) {
+				dev_err(&phy->dev,
+					"failed to set load at %s\n", qmp->vregs[i].supply);
+				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);
@@ -4129,6 +4142,7 @@  static int qmp_pcie_init(struct phy *phy)
 
 static int qmp_pcie_exit(struct phy *phy)
 {
+	int ret;
 	struct qmp_pcie *qmp = phy_get_drvdata(phy);
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 
@@ -4137,7 +4151,16 @@  static int qmp_pcie_exit(struct phy *phy)
 	clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks);
 
 	regulator_bulk_disable(cfg->num_vregs, qmp->vregs);
-
+	for (int i = 0; i < cfg->num_vregs; i++) {
+		if (qmp->max_current_load[i]) {
+			ret = regulator_set_load(qmp->vregs[i].consumer, 0);
+			if (ret) {
+				dev_err(&phy->dev,
+					"failed to set load at %s\n", qmp->vregs[i].supply);
+				return ret;
+			}
+		}
+	}
 	return 0;
 }
 
@@ -4274,14 +4297,22 @@  static int qmp_pcie_vreg_init(struct qmp_pcie *qmp)
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 	struct device *dev = qmp->dev;
 	int num = cfg->num_vregs;
+	char prop_name[MAX_PROP_SIZE];
 	int i;
 
 	qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL);
 	if (!qmp->vregs)
 		return -ENOMEM;
 
-	for (i = 0; i < num; i++)
+	qmp->max_current_load = devm_kcalloc(dev, num, sizeof(*qmp->max_current_load), GFP_KERNEL);
+	if (!qmp->max_current_load)
+		return -ENOMEM;
+
+	for (i = 0; i < num; i++) {
 		qmp->vregs[i].supply = cfg->vreg_list[i];
+		snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", qmp->vregs[i].supply);
+		of_property_read_u32(qmp->dev->of_node, prop_name, &qmp->max_current_load[i]);
+	}
 
 	return devm_regulator_bulk_get(dev, num, qmp->vregs);
 }