From be6cccb49b858e6c8ef77e032c6eded318b08bdf Mon Sep 17 00:00:00 2001
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Date: Wed, 30 Aug 2023 04:00:41 +0300
Subject: [PATCH 4/4] clk: qcom: mmcc-msm8996: force enable the GFX3D_CLK_SRC
 when toggling GX

Forcebly keep GFX3D_CLK_SRC when toggling the GPU_GX GDSC.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 kernel/drivers/clk/qcom/common.c       | 18 +++++++++++
 kernel/drivers/clk/qcom/gdsc.c         | 42 +++++++++++++++++++-------
 kernel/drivers/clk/qcom/gdsc.h         |  3 ++
 kernel/drivers/clk/qcom/mmcc-msm8996.c |  1 +
 4 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/kernel/drivers/clk/qcom/common.c b/kernel/drivers/clk/qcom/common.c
index 2af04fc4abfa..0815f32f4862 100644
--- a/kernel/drivers/clk/qcom/common.c
+++ b/kernel/drivers/clk/qcom/common.c
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/regmap.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/reset-controller.h>
 #include <linux/of.h>
@@ -305,6 +306,23 @@ int qcom_cc_really_probe(struct platform_device *pdev,
 	if (ret)
 		return ret;
 
+	if (desc->gdscs) {
+		for (i = 0; i < scd->num; i++) {
+			struct clk_regmap *rclk;
+
+			if (!scd->scs[i]->force_clk)
+				continue;
+
+			rclk = rclks[scd->scs[i]->force_clk];
+			if (!rclk)
+				continue;
+
+			scd->scs[i]->clk = devm_clk_hw_get_clk(dev,
+							       &rclk->hw,
+							       scd->scs[i]->pd.name);
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(qcom_cc_really_probe);
diff --git a/kernel/drivers/clk/qcom/gdsc.c b/kernel/drivers/clk/qcom/gdsc.c
index 6c4349336b0c..210057f5b9c1 100644
--- a/kernel/drivers/clk/qcom/gdsc.c
+++ b/kernel/drivers/clk/qcom/gdsc.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/export.h>
@@ -270,6 +271,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 	struct gdsc *sc = domain_to_gdsc(domain);
 	int ret;
 
+	if (sc->clk)
+		clk_prepare_enable(sc->clk);
+
 	if (sc->off_on_delay && sc->last_off) {
 		ktime_t end = ktime_add_us(sc->last_off, sc->off_on_delay);
 		s64 remain = ktime_us_delta(end, ktime_get());
@@ -278,8 +282,10 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 			gdsc_enable_delay(remain);
 	}
 
-	if (sc->pwrsts == PWRSTS_ON)
-		return gdsc_deassert_reset(sc);
+	if (sc->pwrsts == PWRSTS_ON) {
+		ret = gdsc_deassert_reset(sc);
+		goto out;
+	}
 
 	if (sc->flags & SW_RESET) {
 		gdsc_assert_reset(sc);
@@ -295,7 +301,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 
 	ret = gdsc_toggle_logic(sc, GDSC_ON);
 	if (ret)
-		return ret;
+		goto out;
 
 	if (sc->pwrsts & PWRSTS_OFF)
 		gdsc_force_mem_on(sc);
@@ -313,7 +319,7 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 	if (sc->flags & HW_CTRL) {
 		ret = gdsc_hwctrl(sc, true);
 		if (ret)
-			return ret;
+			goto out;
 		/*
 		 * Wait for the GDSC to go through a power down and
 		 * up cycle.  In case a firmware ends up polling status
@@ -328,7 +334,12 @@ static int gdsc_enable(struct generic_pm_domain *domain)
 	if (sc->flags & RETAIN_FF_ENABLE)
 		gdsc_retain_ff_on(sc);
 
-	return 0;
+	ret = 0;
+
+out:
+	clk_disable_unprepare(sc->clk);
+
+	return ret;
 }
 
 static int gdsc_disable(struct generic_pm_domain *domain)
@@ -336,14 +347,19 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 	struct gdsc *sc = domain_to_gdsc(domain);
 	int ret;
 
-	if (sc->pwrsts == PWRSTS_ON)
-		return gdsc_assert_reset(sc);
+	if (sc->clk)
+		clk_prepare_enable(sc->clk);
+
+	if (sc->pwrsts == PWRSTS_ON) {
+		ret = gdsc_assert_reset(sc);
+		goto out;
+	}
 
 	/* Turn off HW trigger mode if supported */
 	if (sc->flags & HW_CTRL) {
 		ret = gdsc_hwctrl(sc, false);
 		if (ret < 0)
-			return ret;
+			goto out;
 		/*
 		 * Wait for the GDSC to go through a power down and
 		 * up cycle.  In case we end up polling status
@@ -354,7 +370,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 
 		ret = gdsc_poll_status(sc, GDSC_ON);
 		if (ret)
-			return ret;
+			goto out;
 	}
 
 	if (sc->pwrsts & PWRSTS_OFF)
@@ -362,7 +378,7 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 
 	ret = gdsc_toggle_logic(sc, GDSC_OFF);
 	if (ret)
-		return ret;
+		goto out;
 
 	if (sc->flags & CLAMP_IO)
 		gdsc_assert_clamp_io(sc);
@@ -370,7 +386,11 @@ static int gdsc_disable(struct generic_pm_domain *domain)
 	if (sc->off_on_delay)
 		sc->last_off = ktime_get();
 
-	return 0;
+out:
+	if (sc->clk)
+		clk_disable_unprepare(sc->clk);
+
+	return ret;
 }
 
 static int gdsc_init(struct gdsc *sc)
diff --git a/kernel/drivers/clk/qcom/gdsc.h b/kernel/drivers/clk/qcom/gdsc.h
index 196b6d22a069..66f0b463f268 100644
--- a/kernel/drivers/clk/qcom/gdsc.h
+++ b/kernel/drivers/clk/qcom/gdsc.h
@@ -67,6 +67,9 @@ struct gdsc {
 
 	u64				off_on_delay;
 	ktime_t				last_off;
+
+	unsigned int			force_clk;
+	struct clk			*clk;
 };
 
 struct gdsc_desc {
diff --git a/kernel/drivers/clk/qcom/mmcc-msm8996.c b/kernel/drivers/clk/qcom/mmcc-msm8996.c
index 985fa34ca23c..224c7e48abf6 100644
--- a/kernel/drivers/clk/qcom/mmcc-msm8996.c
+++ b/kernel/drivers/clk/qcom/mmcc-msm8996.c
@@ -3075,6 +3075,7 @@ static struct gdsc gpu_gx_gdsc = {
 	.flags = CLAMP_IO,
 	.supply = "vdd-gfx",
 	.off_on_delay = 250 * 1000,
+	.force_clk = GFX3D_CLK_SRC + 1,
 };
 
 static struct clk_regmap *mmcc_msm8996_clocks[] = {
-- 
2.39.2

