diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index 8525393..1ac1b50 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -21,6 +21,9 @@
 
 #include "phy-qcom-qmp-common.h"
 
+#include <linux/pm_opp.h>
+#include <linux/pm_domain.h>
+
 #include "phy-qcom-qmp.h"
 #include "phy-qcom-qmp-pcs-misc-v3.h"
 #include "phy-qcom-qmp-pcs-misc-v4.h"
@@ -1212,6 +1215,9 @@ struct qmp_phy_cfg {
 	unsigned int pcs_usb_offset;
 };
 
+#define DOMAIN_GENPD_TRANSFER			0
+#define DOMAIN_GENPD_CORE			1
+
 struct qmp_usb {
 	struct device *dev;
 
@@ -1236,6 +1242,19 @@ struct qmp_usb {
 	struct phy *phy;
 
 	struct clk_fixed_rate pipe_clk_fixed;
+
+	struct dev_pm_domain_list *pd_list;
+	struct device *genpd_core;
+	struct device *genpd_transfer;
+
+	bool fw_managed;
+	/* separate resource management for fw_managed vs locally managed devices */
+	struct qmp_usb_device_ops {
+		int (*bus_resume_resource)(struct qmp_usb *qmp);
+		int (*runtime_resume_resource)(struct qmp_usb *qmp);
+		int (*bus_suspend_resource)(struct qmp_usb *qmp);
+		int (*runtime_suspend_resource)(struct qmp_usb *qmp);
+	} qmp_usb_device_ops;
 };
 
 static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val)
@@ -1598,6 +1617,41 @@ static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = {
 	.regs			= qmp_v7_usb3phy_regs_layout,
 };
 
+static void qmp_fw_managed_domain_remove(struct qmp_usb *qmp)
+{
+	dev_pm_domain_detach_list(qmp->pd_list);
+}
+
+static int qmp_fw_managed_domain_init(struct qmp_usb *qmp)
+{
+	struct device *dev = qmp->dev;
+	struct dev_pm_domain_attach_data pd_data = {
+		.pd_flags	= PD_FLAG_NO_DEV_LINK,
+		.pd_names	= (const char*[]) { "usb_transfer", "usb_core" },
+		.num_pd_names	= 2,
+	};
+	int ret = 0;
+
+	if (!dev->pm_domain) {
+		ret = dev_pm_domain_attach_list(dev, &pd_data, &qmp->pd_list);
+		if (ret < 0) {
+			dev_err(dev, "domain attach failed %d)\n", ret);
+			return ret;
+		}
+
+		qmp->genpd_transfer = qmp->pd_list->pd_devs[DOMAIN_GENPD_TRANSFER];
+		qmp->genpd_core = qmp->pd_list->pd_devs[DOMAIN_GENPD_CORE];
+
+
+		dev_dbg(dev, "domains attached successfully\n");
+	} else {
+		dev_dbg(dev, "domain attach fail\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int qmp_usb_serdes_init(struct qmp_usb *qmp)
 {
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -1610,11 +1664,20 @@ static int qmp_usb_serdes_init(struct qmp_usb *qmp)
 	return 0;
 }
 
-static int qmp_usb_init(struct phy *phy)
+static int fw_managed_ssphy_bus_init(struct qmp_usb *qmp)
+{
+	int ret = 0;
+
+	ret = pm_runtime_get_sync(qmp->genpd_core);
+	if (ret < 0)
+		dev_err(qmp->dev, "Failed to enable fw managed resources");
+
+	return ret;
+}
+
+static int locally_managed_ssphy_bus_init(struct qmp_usb *qmp)
 {
-	struct qmp_usb *qmp = phy_get_drvdata(phy);
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
-	void __iomem *pcs = qmp->pcs;
 	int ret;
 
 	ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
@@ -1639,8 +1702,11 @@ static int qmp_usb_init(struct phy *phy)
 	if (ret)
 		goto err_assert_reset;
 
-	qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
-
+	ret = clk_prepare_enable(qmp->pipe_clk);
+	if (ret) {
+		dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
+		return ret;
+	}
 	return 0;
 
 err_assert_reset:
@@ -1651,11 +1717,22 @@ static int qmp_usb_init(struct phy *phy)
 	return ret;
 }
 
-static int qmp_usb_exit(struct phy *phy)
+static int fw_managed_ssphy_bus_exit(struct qmp_usb *qmp)
+{
+	int ret = 0;
+
+	ret = pm_runtime_put_sync(qmp->genpd_core);
+	if (ret < 0)
+		dev_err(qmp->dev, "Failed to disable fw managed resources");
+
+	return 0;
+}
+
+static int locally_managed_ssphy_bus_exit(struct qmp_usb *qmp)
 {
-	struct qmp_usb *qmp = phy_get_drvdata(phy);
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 
+	clk_disable_unprepare(qmp->pipe_clk);
 	reset_control_bulk_assert(qmp->num_resets, qmp->resets);
 
 	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
@@ -1677,13 +1754,9 @@ static int qmp_usb_power_on(struct phy *phy)
 	unsigned int val;
 	int ret;
 
-	qmp_usb_serdes_init(qmp);
+	qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN);
 
-	ret = clk_prepare_enable(qmp->pipe_clk);
-	if (ret) {
-		dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret);
-		return ret;
-	}
+	qmp_usb_serdes_init(qmp);
 
 	/* Tx, Rx, and PCS configurations */
 	qmp_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1);
@@ -1708,15 +1781,10 @@ static int qmp_usb_power_on(struct phy *phy)
 				 PHY_INIT_COMPLETE_TIMEOUT);
 	if (ret) {
 		dev_err(qmp->dev, "phy initialization timed-out\n");
-		goto err_disable_pipe_clk;
+		return ret;
 	}
 
 	return 0;
-
-err_disable_pipe_clk:
-	clk_disable_unprepare(qmp->pipe_clk);
-
-	return ret;
 }
 
 static int qmp_usb_power_off(struct phy *phy)
@@ -1724,8 +1792,6 @@ static int qmp_usb_power_off(struct phy *phy)
 	struct qmp_usb *qmp = phy_get_drvdata(phy);
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 
-	clk_disable_unprepare(qmp->pipe_clk);
-
 	/* PHY reset */
 	qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
 
@@ -1742,27 +1808,30 @@ static int qmp_usb_power_off(struct phy *phy)
 
 static int qmp_usb_enable(struct phy *phy)
 {
+	struct qmp_usb *qmp = phy_get_drvdata(phy);
 	int ret;
 
-	ret = qmp_usb_init(phy);
+	ret = qmp->qmp_usb_device_ops.bus_resume_resource(qmp);
 	if (ret)
 		return ret;
 
 	ret = qmp_usb_power_on(phy);
 	if (ret)
-		qmp_usb_exit(phy);
+		qmp->qmp_usb_device_ops.bus_suspend_resource(qmp);
 
 	return ret;
 }
 
 static int qmp_usb_disable(struct phy *phy)
 {
+	struct qmp_usb *qmp = phy_get_drvdata(phy);
 	int ret;
 
 	ret = qmp_usb_power_off(phy);
 	if (ret)
 		return ret;
-	return qmp_usb_exit(phy);
+
+	return qmp->qmp_usb_device_ops.bus_suspend_resource(qmp);
 }
 
 static int qmp_usb_set_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -1828,6 +1897,25 @@ static void qmp_usb_disable_autonomous_mode(struct qmp_usb *qmp)
 	qphy_clrbits(pcs_usb, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR);
 }
 
+static int locally_managed_ssphy_runtime_exit(struct qmp_usb *qmp)
+{
+	clk_disable_unprepare(qmp->pipe_clk);
+	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+
+	return 0;
+}
+
+static int fw_managed_ssphy_runtime_exit(struct qmp_usb *qmp)
+{
+	int ret = 0;
+
+	ret = pm_runtime_put_sync(qmp->genpd_transfer);
+	if (ret < 0)
+		dev_err(qmp->dev, "Failed to disable fw managed resources");
+
+	return 0;
+}
+
 static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)
 {
 	struct qmp_usb *qmp = dev_get_drvdata(dev);
@@ -1841,16 +1929,44 @@ static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)
 
 	qmp_usb_enable_autonomous_mode(qmp);
 
-	clk_disable_unprepare(qmp->pipe_clk);
-	clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+	qmp->qmp_usb_device_ops.runtime_suspend_resource(qmp);
 
 	return 0;
 }
 
+static int locally_managed_ssphy_runtime_init(struct qmp_usb *qmp)
+{
+	int ret = 0;
+
+	ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(qmp->pipe_clk);
+	if (ret) {
+		dev_err(qmp->dev, "pipe_clk enable failed, err=%d\n", ret);
+		clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int fw_managed_ssphy_runtime_init(struct qmp_usb *qmp)
+{
+	int ret = 0;
+
+	ret = pm_runtime_get_sync(qmp->genpd_transfer);
+	if (ret < 0)
+		dev_err(qmp->dev, "Failed to enable fw managed resources");
+
+	return ret;
+}
+
 static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
 {
+	int ret;
 	struct qmp_usb *qmp = dev_get_drvdata(dev);
-	int ret = 0;
 
 	dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode);
 
@@ -1859,17 +1975,10 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)
 		return 0;
 	}
 
-	ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks);
+	ret = qmp->qmp_usb_device_ops.runtime_resume_resource(qmp);
 	if (ret)
 		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);
-		return ret;
-	}
-
 	qmp_usb_disable_autonomous_mode(qmp);
 
 	return 0;
@@ -2059,22 +2168,24 @@ 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->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);
-	if (ret < 0)
-		return ret;
+		ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks);
+		if (ret < 0)
+			return ret;
 
-	qmp->num_clks = ret;
+		qmp->num_clks = ret;
 
-	ret = qmp_usb_reset_init(qmp, usb3phy_legacy_reset_l,
-				 ARRAY_SIZE(usb3phy_legacy_reset_l));
-	if (ret)
-		return ret;
+		ret = qmp_usb_reset_init(qmp, usb3phy_legacy_reset_l,
+					 ARRAY_SIZE(usb3phy_legacy_reset_l));
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
@@ -2104,21 +2215,23 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp)
 	qmp->tx = base + offs->tx;
 	qmp->rx = base + offs->rx;
 
-	ret = qmp_usb_clk_init(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->fw_managed) {
+		ret = qmp_usb_clk_init(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");
+		}
+
+		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;
 }
 
@@ -2140,9 +2253,36 @@ static int qmp_usb_probe(struct platform_device *pdev)
 	if (!qmp->cfg)
 		return -EINVAL;
 
-	ret = qmp_usb_vreg_init(qmp);
-	if (ret)
-		return ret;
+	qmp->fw_managed  = device_property_read_bool(dev, "qmp,fw-managed");
+	if (qmp->fw_managed) {
+		ret = qmp_fw_managed_domain_init(qmp);
+		if (ret) {
+			dev_err(dev, "Failed to init domains. Bail out");
+			return ret;
+		}
+
+		qmp->qmp_usb_device_ops.bus_resume_resource =
+						fw_managed_ssphy_bus_init;
+		qmp->qmp_usb_device_ops.runtime_resume_resource =
+						fw_managed_ssphy_runtime_init;
+		qmp->qmp_usb_device_ops.bus_suspend_resource =
+						fw_managed_ssphy_bus_exit;
+		qmp->qmp_usb_device_ops.runtime_suspend_resource =
+						fw_managed_ssphy_runtime_exit;
+	} else {
+		ret = qmp_usb_vreg_init(qmp);
+		if (ret)
+			return ret;
+
+		qmp->qmp_usb_device_ops.bus_resume_resource =
+						locally_managed_ssphy_bus_init;
+		qmp->qmp_usb_device_ops.runtime_resume_resource =
+						locally_managed_ssphy_runtime_init;
+		qmp->qmp_usb_device_ops.bus_suspend_resource =
+						locally_managed_ssphy_bus_exit;
+		qmp->qmp_usb_device_ops.runtime_suspend_resource =
+						locally_managed_ssphy_runtime_exit;
+	}
 
 	/* Check for legacy binding with child node. */
 	np = of_get_next_available_child(dev->of_node, NULL);
@@ -2165,9 +2305,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->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)) {
@@ -2186,9 +2328,22 @@ static int qmp_usb_probe(struct platform_device *pdev)
 
 err_node_put:
 	of_node_put(np);
+	if (qmp->fw_managed)
+		qmp_fw_managed_domain_remove(qmp);
 	return ret;
 }
 
+static void qmp_usb_remove(struct platform_device *pdev)
+{
+	struct qmp_usb *qmp = platform_get_drvdata(pdev);
+
+	if (qmp->fw_managed) {
+		pm_runtime_put_sync(qmp->genpd_core);
+		qmp_fw_managed_domain_remove(qmp);
+	}
+}
+
+
 static const struct of_device_id qmp_usb_of_match_table[] = {
 	{
 		.compatible = "qcom,ipq6018-qmp-usb3-phy",
@@ -2239,6 +2394,7 @@ MODULE_DEVICE_TABLE(of, qmp_usb_of_match_table);
 
 static struct platform_driver qmp_usb_driver = {
 	.probe		= qmp_usb_probe,
+	.remove_new	= qmp_usb_remove,
 	.driver = {
 		.name	= "qcom-qmp-usb-phy",
 		.pm	= &qmp_usb_pm_ops,
diff --git a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
index eb0b0f6..9a1377f 100644
--- a/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
+++ b/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c
@@ -17,6 +17,9 @@
 #include <linux/reset.h>
 #include <linux/slab.h>
 
+#include <linux/pm_opp.h>
+#include <linux/pm_domain.h>
+
 #define USB2_PHY_USB_PHY_UTMI_CTRL0		(0x3c)
 #define SLEEPM					BIT(0)
 #define OPMODE_MASK				GENMASK(4, 3)
@@ -89,7 +92,7 @@ struct override_param {
 	u8	reg_val;
 };
 
-struct override_param_map {
+struct snps_femto_v2_priv_data {
 	const char *prop_name;
 	const struct override_param *param_table;
 	u8 table_size;
@@ -106,6 +109,9 @@ struct phy_override_seq {
 
 #define NUM_HSPHY_TUNING_PARAMS	(9)
 
+#define DOMAIN_GENPD_TRANSFER			0
+#define DOMAIN_GENPD_CORE			1
+
 /**
  * struct qcom_snps_hsphy - snps hs phy attributes
  *
@@ -136,8 +142,54 @@ struct qcom_snps_hsphy {
 	bool phy_initialized;
 	enum phy_mode mode;
 	struct phy_override_seq update_seq_cfg[NUM_HSPHY_TUNING_PARAMS];
+
+	struct dev_pm_domain_list *pd_list;
+	struct device *genpd_core;
+	struct device *genpd_transfer;
+
+	bool fw_managed;
+	/* separate resource management for fw_managed vs locally managed devices */
+	struct snps_femto_v2_device_ops {
+		int (*resume_resource)(struct qcom_snps_hsphy *hsphy);
+		int (*suspend_resource)(struct qcom_snps_hsphy *hsphy);
+	} snps_femto_v2_device_ops;
+
 };
 
+static void hsphy_fw_managed_domain_remove(struct qcom_snps_hsphy *hsphy)
+{
+	dev_pm_domain_detach_list(hsphy->pd_list);
+}
+
+static int hsphy_fw_managed_domain_init(struct qcom_snps_hsphy *hsphy)
+{
+	struct device *dev = hsphy->dev;
+	struct dev_pm_domain_attach_data pd_data = {
+		.pd_flags	= PD_FLAG_NO_DEV_LINK,
+		.pd_names	= (const char*[]) { "usb_transfer", "usb_core" },
+		.num_pd_names	= 2,
+	};
+	int ret = 0;
+
+	if (!dev->pm_domain) {
+		ret = dev_pm_domain_attach_list(dev, &pd_data, &hsphy->pd_list);
+		if (ret < 0) {
+			dev_err(dev, "domain attach failed %d)\n", ret);
+			return ret;
+		}
+
+		hsphy->genpd_transfer = hsphy->pd_list->pd_devs[DOMAIN_GENPD_TRANSFER];
+		hsphy->genpd_core = hsphy->pd_list->pd_devs[DOMAIN_GENPD_CORE];
+
+		dev_dbg(dev, "domains attached successfully\n");
+	} else {
+		dev_dbg(dev, "domain attach fail\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int qcom_snps_hsphy_clk_init(struct qcom_snps_hsphy *hsphy)
 {
 	struct device *dev = hsphy->dev;
@@ -316,27 +368,27 @@ static const struct override_param ls_fs_output_impedance_sc7280[] = {
 	{ 1310, 0 },
 };
 
-static const struct override_param_map sc7280_snps_7nm_phy[] = {
+static const struct snps_femto_v2_priv_data sc7280_snps_7nm_phy[] = {
 	{
 		"qcom,hs-disconnect-bp",
 		hs_disconnect_sc7280,
 		ARRAY_SIZE(hs_disconnect_sc7280),
 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0,
-		HS_DISCONNECT_MASK
+		HS_DISCONNECT_MASK,
 	},
 	{
 		"qcom,squelch-detector-bp",
 		squelch_det_threshold_sc7280,
 		ARRAY_SIZE(squelch_det_threshold_sc7280),
 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0,
-		SQUELCH_DETECTOR_MASK
+		SQUELCH_DETECTOR_MASK,
 	},
 	{
 		"qcom,hs-amplitude-bp",
 		hs_amplitude_sc7280,
 		ARRAY_SIZE(hs_amplitude_sc7280),
 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1,
-		HS_AMPLITUDE_MASK
+		HS_AMPLITUDE_MASK,
 	},
 	{
 		"qcom,pre-emphasis-duration-bp",
@@ -357,14 +409,14 @@ static const struct override_param_map sc7280_snps_7nm_phy[] = {
 		hs_rise_fall_time_sc7280,
 		ARRAY_SIZE(hs_rise_fall_time_sc7280),
 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2,
-		HS_RISE_FALL_MASK
+		HS_RISE_FALL_MASK,
 	},
 	{
 		"qcom,hs-crossover-voltage-microvolt",
 		hs_crossover_voltage_sc7280,
 		ARRAY_SIZE(hs_crossover_voltage_sc7280),
 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2,
-		HS_CROSSOVER_VOLTAGE_MASK
+		HS_CROSSOVER_VOLTAGE_MASK,
 	},
 	{
 		"qcom,hs-output-impedance-micro-ohms",
@@ -383,12 +435,31 @@ static const struct override_param_map sc7280_snps_7nm_phy[] = {
 	{},
 };
 
-static int qcom_snps_hsphy_init(struct phy *phy)
+static int fw_managed_hsphy_init(struct qcom_snps_hsphy *hsphy)
 {
-	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
-	int ret, i;
+	int ret = 0;
 
-	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
+	ret = pm_runtime_get_sync(hsphy->genpd_core);
+	if (ret < 0)
+		dev_err(hsphy->dev, "Failed to enable fw managed resources");
+
+	return ret;
+}
+
+static int fw_managed_hsphy_exit(struct qcom_snps_hsphy *hsphy)
+{
+	int ret = 0;
+
+	ret = pm_runtime_put_sync(hsphy->genpd_core);
+	if (ret < 0)
+		dev_err(hsphy->dev, "Failed to disable fw managed resources");
+
+	return 0;
+}
+
+static int locally_managed_hsphy_init(struct qcom_snps_hsphy *hsphy)
+{
+	int ret;
 
 	ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
 	if (ret)
@@ -396,13 +467,13 @@ static int qcom_snps_hsphy_init(struct phy *phy)
 
 	ret = clk_bulk_prepare_enable(hsphy->num_clks, hsphy->clks);
 	if (ret) {
-		dev_err(&phy->dev, "failed to enable clocks, %d\n", ret);
+		dev_err(hsphy->dev, "failed to enable clocks, %d\n", ret);
 		goto poweroff_phy;
 	}
 
 	ret = reset_control_assert(hsphy->phy_reset);
 	if (ret) {
-		dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
+		dev_err(hsphy->dev, "failed to assert phy_reset, %d\n", ret);
 		goto disable_clks;
 	}
 
@@ -410,10 +481,42 @@ static int qcom_snps_hsphy_init(struct phy *phy)
 
 	ret = reset_control_deassert(hsphy->phy_reset);
 	if (ret) {
-		dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
+		dev_err(hsphy->dev, "failed to de-assert phy_reset, %d\n", ret);
 		goto disable_clks;
 	}
 
+	return 0;
+
+disable_clks:
+	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
+poweroff_phy:
+	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
+
+	return ret;
+}
+
+static int locally_managed_hsphy_exit(struct qcom_snps_hsphy *hsphy)
+{
+	reset_control_assert(hsphy->phy_reset);
+	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
+	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
+
+	return 0;
+}
+
+static int qcom_snps_hsphy_init(struct phy *phy)
+{
+	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
+	int ret, i;
+
+	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
+
+	ret = hsphy->snps_femto_v2_device_ops.resume_resource(hsphy);
+	if (ret) {
+		dev_err(&phy->dev, "Error resumeing hsphy resources %d\n", ret);
+		return ret;
+	}
+
 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
@@ -467,22 +570,19 @@ static int qcom_snps_hsphy_init(struct phy *phy)
 	hsphy->phy_initialized = true;
 
 	return 0;
-
-disable_clks:
-	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
-poweroff_phy:
-	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
-
-	return ret;
 }
 
 static int qcom_snps_hsphy_exit(struct phy *phy)
 {
 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
+	int ret = 0;
+
+	ret = hsphy->snps_femto_v2_device_ops.suspend_resource(hsphy);
+	if (ret) {
+		dev_err(&phy->dev, "Error suspending hsphy resources %d\n", ret);
+		return ret;
+	}
 
-	reset_control_assert(hsphy->phy_reset);
-	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
-	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
 	hsphy->phy_initialized = false;
 
 	return 0;
@@ -497,7 +597,8 @@ static const struct phy_ops qcom_snps_hsphy_gen_ops = {
 
 static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
 	{ .compatible	= "qcom,sm8150-usb-hs-phy", },
-	{ .compatible	= "qcom,usb-snps-hs-5nm-phy", },
+	{ .compatible	= "qcom,sa8775p-usb-hs-phy", },
+	{ .compatible	= "qcom,sc8280xp-usb-hs-phy", },
 	{
 		.compatible	= "qcom,usb-snps-hs-7nm-phy",
 		.data		= &sc7280_snps_7nm_phy,
@@ -513,7 +614,7 @@ static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
 };
 
 static void qcom_snps_hsphy_override_param_update_val(
-			const struct override_param_map map,
+			const struct snps_femto_v2_priv_data map,
 			s32 dt_val, struct phy_override_seq *seq_entry)
 {
 	int i;
@@ -541,7 +642,7 @@ static void qcom_snps_hsphy_read_override_param_seq(struct device *dev)
 	s32 val;
 	int ret, i;
 	struct qcom_snps_hsphy *hsphy;
-	const struct override_param_map *cfg = of_device_get_match_data(dev);
+	const struct snps_femto_v2_priv_data *cfg = of_device_get_match_data(dev);
 
 	if (!cfg)
 		return;
@@ -580,24 +681,39 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
 	if (IS_ERR(hsphy->base))
 		return PTR_ERR(hsphy->base);
 
-	ret = qcom_snps_hsphy_clk_init(hsphy);
-	if (ret)
-		return dev_err_probe(dev, ret, "failed to initialize clocks\n");
 
-	hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
-	if (IS_ERR(hsphy->phy_reset)) {
-		dev_err(dev, "failed to get phy core reset\n");
-		return PTR_ERR(hsphy->phy_reset);
-	}
+	hsphy->fw_managed  = device_property_read_bool(dev, "hsphy,fw-managed");
+	if (hsphy->fw_managed) {
+		ret = hsphy_fw_managed_domain_init(hsphy);
+		if (ret) {
+			dev_err(dev, "Failed to init domains. Bail out");
+			return ret;
+		}
 
-	num = ARRAY_SIZE(hsphy->vregs);
-	for (i = 0; i < num; i++)
-		hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
+		hsphy->snps_femto_v2_device_ops.resume_resource = fw_managed_hsphy_init;
+		hsphy->snps_femto_v2_device_ops.suspend_resource = fw_managed_hsphy_exit;
+	} else {
+		ret = qcom_snps_hsphy_clk_init(hsphy);
+		if (ret)
+			return dev_err_probe(dev, ret, "failed to initialize clocks\n");
 
-	ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
-	if (ret)
-		return dev_err_probe(dev, ret,
-				     "failed to get regulator supplies\n");
+		hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+		if (IS_ERR(hsphy->phy_reset)) {
+			dev_err(dev, "failed to get phy core reset\n");
+			return PTR_ERR(hsphy->phy_reset);
+		}
+
+		num = ARRAY_SIZE(hsphy->vregs);
+		for (i = 0; i < num; i++)
+			hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
+
+		ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to get regulator supplies\n");
+		hsphy->snps_femto_v2_device_ops.resume_resource = locally_managed_hsphy_init;
+		hsphy->snps_femto_v2_device_ops.suspend_resource = locally_managed_hsphy_exit;
+	}
 
 	pm_runtime_set_active(dev);
 	pm_runtime_enable(dev);
@@ -609,6 +725,8 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
 
 	generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
 	if (IS_ERR(generic_phy)) {
+		if (hsphy->fw_managed)
+			hsphy_fw_managed_domain_remove(hsphy);
 		ret = PTR_ERR(generic_phy);
 		dev_err(dev, "failed to create phy, %d\n", ret);
 		return ret;
@@ -628,8 +746,19 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)
 	return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static void qcom_snps_hsphy_remove(struct platform_device *pdev)
+{
+	struct qcom_snps_hsphy *hsphy = platform_get_drvdata(pdev);
+
+	if (hsphy->fw_managed) {
+		pm_runtime_put_sync(hsphy->genpd_core);
+		hsphy_fw_managed_domain_remove(hsphy);
+	}
+}
+
 static struct platform_driver qcom_snps_hsphy_driver = {
 	.probe		= qcom_snps_hsphy_probe,
+	.remove_new	= qcom_snps_hsphy_remove,
 	.driver = {
 		.name	= "qcom-snps-hs-femto-v2-phy",
 		.pm = &qcom_snps_hsphy_pm_ops,
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index dbd6a5b..aea11d0 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -22,6 +22,8 @@
 #include <linux/iopoll.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_domain.h>
 #include "core.h"
 
 /* USB QSCRATCH Hardware registers */
@@ -53,6 +55,9 @@
 #define APPS_USB_AVG_BW 0
 #define APPS_USB_PEAK_BW MBps_to_icc(40)
 
+#define DOMAIN_GENPD_TRANSFER			0
+#define DOMAIN_GENPD_CORE			1
+
 struct dwc3_acpi_pdata {
 	u32			qscratch_base_offset;
 	u32			qscratch_base_size;
@@ -91,8 +96,54 @@ struct dwc3_qcom {
 	bool			pm_suspended;
 	struct icc_path		*icc_path_ddr;
 	struct icc_path		*icc_path_apps;
+
+	struct dev_pm_domain_list *pd_list;
+	struct device *genpd_core;
+	struct device *genpd_transfer;
+
+	bool			fw_managed;
+	/* separate resource management for fw_managed vs locally managed devices */
+	struct qcom_dwc3_device_ops {
+		int (*resume_resource)(struct dwc3_qcom *qcom);
+		void (*suspend_resource)(struct dwc3_qcom *qcom);
+		void (*exit_resource)(struct dwc3_qcom *qcom);
+	} qcom_dwc3_device_ops;
 };
 
+static void dwc3_qcom_fw_managed_domain_remove(struct dwc3_qcom *qcom)
+{
+	dev_pm_domain_detach_list(qcom->pd_list);
+}
+
+static int dwc3_qcom_fw_managed_domain_init(struct dwc3_qcom *qcom)
+{
+	struct device *dev = qcom->dev;
+	struct dev_pm_domain_attach_data pd_data = {
+		.pd_flags	= PD_FLAG_NO_DEV_LINK,
+		.pd_names	= (const char*[]) { "usb_transfer", "usb_core" },
+		.num_pd_names	= 2,
+	};
+	int ret = 0;
+
+	if (!dev->pm_domain) {
+		ret = dev_pm_domain_attach_list(dev, &pd_data, &qcom->pd_list);
+		if (ret < 0) {
+			dev_err(dev, "domain attach failed %d)\n", ret);
+			return ret;
+		}
+
+		qcom->genpd_transfer = qcom->pd_list->pd_devs[DOMAIN_GENPD_TRANSFER];
+		qcom->genpd_core = qcom->pd_list->pd_devs[DOMAIN_GENPD_CORE];
+
+		dev_dbg(dev, "domains attached successfully\n");
+	} else {
+		dev_dbg(dev, "domain attach fail\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
 {
 	u32 reg;
@@ -417,10 +468,87 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
 	dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
 }
 
+static void locally_managed_exit_resource(struct dwc3_qcom *qcom)
+{
+	int i;
+
+	for (i = qcom->num_clocks - 1; i >= 0; i--) {
+		clk_disable_unprepare(qcom->clks[i]);
+		clk_put(qcom->clks[i]);
+	}
+	qcom->num_clocks = 0;
+
+	dwc3_qcom_interconnect_exit(qcom);
+	reset_control_assert(qcom->resets);
+}
+
+static void fw_managed_exit_resource(struct dwc3_qcom *qcom)
+{
+	int ret = 0;
+
+	ret = pm_runtime_put_sync(qcom->genpd_core);
+
+	if (ret < 0)
+		dev_err(qcom->dev, "Failed to disable fw managed resources");
+
+	dwc3_qcom_fw_managed_domain_remove(qcom);
+}
+
+static int locally_managed_resume_resource(struct dwc3_qcom *qcom)
+{
+	int ret, i;
+
+	for (i = 0; i < qcom->num_clocks; i++) {
+		ret = clk_prepare_enable(qcom->clks[i]);
+		if (ret < 0) {
+			while (--i >= 0)
+				clk_disable_unprepare(qcom->clks[i]);
+			return ret;
+		}
+	}
+
+	ret = dwc3_qcom_interconnect_enable(qcom);
+	if (ret)
+		dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
+
+	return 0;
+}
+
+static int fw_managed_resume_resource(struct dwc3_qcom *qcom)
+{
+	int ret = 0;
+
+	ret = pm_runtime_get_sync(qcom->genpd_transfer);
+	if (ret < 0)
+		dev_err(qcom->dev, "Failed to enable fw managed resources");
+
+	return ret;
+}
+
+static void locally_managed_suspend_resource(struct dwc3_qcom *qcom)
+{
+	int i, ret;
+
+	for (i = qcom->num_clocks - 1; i >= 0; i--)
+		clk_disable_unprepare(qcom->clks[i]);
+
+	ret = dwc3_qcom_interconnect_disable(qcom);
+	if (ret)
+		dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
+}
+
+static void fw_managed_suspend_resource(struct dwc3_qcom *qcom)
+{
+	int ret = 0;
+
+	ret = pm_runtime_put_sync(qcom->genpd_transfer);
+	if (ret < 0)
+		dev_err(qcom->dev, "Failed to disable fw managed resources");
+}
+
 static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
 {
 	u32 val;
-	int i, ret;
 
 	if (qcom->is_suspended)
 		return 0;
@@ -429,12 +557,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
 	if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
 		dev_err(qcom->dev, "HS-PHY not in L2\n");
 
-	for (i = qcom->num_clocks - 1; i >= 0; i--)
-		clk_disable_unprepare(qcom->clks[i]);
-
-	ret = dwc3_qcom_interconnect_disable(qcom);
-	if (ret)
-		dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
+	qcom->qcom_dwc3_device_ops.suspend_resource(qcom);
 
 	/*
 	 * The role is stable during suspend as role switching is done from a
@@ -453,7 +576,6 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
 static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
 {
 	int ret;
-	int i;
 
 	if (!qcom->is_suspended)
 		return 0;
@@ -461,18 +583,9 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
 	if (dwc3_qcom_is_host(qcom) && wakeup)
 		dwc3_qcom_disable_interrupts(qcom);
 
-	for (i = 0; i < qcom->num_clocks; i++) {
-		ret = clk_prepare_enable(qcom->clks[i]);
-		if (ret < 0) {
-			while (--i >= 0)
-				clk_disable_unprepare(qcom->clks[i]);
-			return ret;
-		}
-	}
-
-	ret = dwc3_qcom_interconnect_enable(qcom);
-	if (ret)
-		dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
+	ret = qcom->qcom_dwc3_device_ops.resume_resource(qcom);
+	if (ret < 0)
+		return ret;
 
 	/* Clear existing events from PHY related to L2 in/out */
 	dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
@@ -833,30 +946,54 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 		}
 	}
 
-	qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
-	if (IS_ERR(qcom->resets)) {
-		return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
-				     "failed to get resets\n");
-	}
+	qcom->fw_managed  = device_property_read_bool(dev, "qcom,fw-managed");
+	if (qcom->fw_managed) {
+		ret = dwc3_qcom_fw_managed_domain_init(qcom);
+		if (ret) {
+			dev_err(dev, "Failed to init domains. Bail out\n");
+			return ret;
+		}
+		ret = pm_runtime_resume_and_get(qcom->genpd_core);
+		if (ret < 0) {
+			dev_err(qcom->dev, "Failed to enable %s", __func__);
+			dwc3_qcom_fw_managed_domain_remove(qcom);
+			return ret;
+		}
 
-	ret = reset_control_assert(qcom->resets);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
-		return ret;
-	}
+		qcom->qcom_dwc3_device_ops.resume_resource = fw_managed_resume_resource;
+		qcom->qcom_dwc3_device_ops.exit_resource = fw_managed_exit_resource;
+		qcom->qcom_dwc3_device_ops.suspend_resource = fw_managed_suspend_resource;
+	} else {
+		qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
+		if (IS_ERR(qcom->resets)) {
+			return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
+					     "failed to get resets\n");
+		}
 
-	usleep_range(10, 1000);
+		ret = reset_control_assert(qcom->resets);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
+			return ret;
+		}
 
-	ret = reset_control_deassert(qcom->resets);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
-		goto reset_assert;
-	}
+		usleep_range(10, 1000);
 
-	ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
-	if (ret) {
-		dev_err_probe(dev, ret, "failed to get clocks\n");
-		goto reset_assert;
+		ret = reset_control_deassert(qcom->resets);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
+			goto reset_assert;
+		}
+
+		ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
+		if (ret) {
+			dev_err_probe(dev, ret, "failed to get clocks\n");
+			goto reset_assert;
+		}
+
+		//Map the functions here for suspend resume
+		qcom->qcom_dwc3_device_ops.resume_resource = locally_managed_resume_resource;
+		qcom->qcom_dwc3_device_ops.exit_resource = locally_managed_exit_resource;
+		qcom->qcom_dwc3_device_ops.suspend_resource = locally_managed_suspend_resource;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -916,9 +1053,11 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 		goto free_urs;
 	}
 
-	ret = dwc3_qcom_interconnect_init(qcom);
-	if (ret)
-		goto depopulate;
+	if (!qcom->fw_managed) {
+		ret = dwc3_qcom_interconnect_init(qcom);
+		if (ret)
+			goto depopulate;
+	}
 
 	qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
 
@@ -928,8 +1067,12 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 
 	/* register extcon to override sw_vbus on Vbus change later */
 	ret = dwc3_qcom_register_extcon(qcom);
-	if (ret)
-		goto interconnect_exit;
+	if (ret) {
+		if (!qcom->fw_managed)
+			goto interconnect_exit;
+		else
+			goto depopulate;
+	}
 
 	wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
 	device_init_wakeup(&pdev->dev, wakeup_source);
@@ -956,13 +1099,19 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 	if (qcom->urs_usb)
 		dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
 clk_disable:
-	for (i = qcom->num_clocks - 1; i >= 0; i--) {
-		clk_disable_unprepare(qcom->clks[i]);
-		clk_put(qcom->clks[i]);
+	if (!qcom->fw_managed) {
+		for (i = qcom->num_clocks - 1; i >= 0; i--) {
+			clk_disable_unprepare(qcom->clks[i]);
+			clk_put(qcom->clks[i]);
+		}
 	}
 reset_assert:
-	reset_control_assert(qcom->resets);
-
+	if (qcom->fw_managed) {
+		pm_runtime_put_sync(qcom->genpd_core);
+		dwc3_qcom_fw_managed_domain_remove(qcom);
+	} else {
+		reset_control_assert(qcom->resets);
+	}
 	return ret;
 }
 
@@ -971,7 +1120,6 @@ static void dwc3_qcom_remove(struct platform_device *pdev)
 	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
 	struct device_node *np = pdev->dev.of_node;
 	struct device *dev = &pdev->dev;
-	int i;
 
 	if (np) {
 		of_platform_depopulate(&pdev->dev);
@@ -984,14 +1132,7 @@ static void dwc3_qcom_remove(struct platform_device *pdev)
 	if (qcom->urs_usb)
 		dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
 
-	for (i = qcom->num_clocks - 1; i >= 0; i--) {
-		clk_disable_unprepare(qcom->clks[i]);
-		clk_put(qcom->clks[i]);
-	}
-	qcom->num_clocks = 0;
-
-	dwc3_qcom_interconnect_exit(qcom);
-	reset_control_assert(qcom->resets);
+	qcom->qcom_dwc3_device_ops.exit_resource(qcom);
 
 	pm_runtime_allow(dev);
 	pm_runtime_disable(dev);
