clk: qcom: mdss: fix device crash on continuous splash disabled

TZ introduced a recent change which mandates the scm call
before accessing the pll registers. So, when continuous splash
is disabled in bootloader, the scm call is not made and it causes
device crash when the pll driver tries to access the registers.
This change makes it return with a disabled handoff clk from the
pll driver when continuous splash is disabled, thus not accessing
the pll registers at this point.

Change-Id: Ic487ef733f889d463d149ee347667cd8eb04084f
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index f748111..230aef3 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -54,8 +54,9 @@
 		cell-index = <0>;
 
 		reg = <0xfd922A00 0xD4>,
-		      <0xfd922900 0x64>;
-		reg-names = "pll_base", "dynamic_pll_base";
+		      <0xfd922900 0x64>,
+		      <0xfd8c2300 0x8>;
+		reg-names = "pll_base", "dynamic_pll_base", "gdsc_base";
 		gdsc-supply = <&gdsc_mdss>;
 		vddio-supply = <&pm8941_l12>;
 		vcca-supply = <&pm8941_l28>;
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c b/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
index dacbb7a..baf5431 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
@@ -268,6 +268,9 @@
 	int mux_mode, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -334,6 +337,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(clk->priv, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -391,6 +397,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -452,6 +461,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -919,6 +931,9 @@
 	int rc;
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -967,6 +982,9 @@
 	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-util.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-util.c
index 935935c..fd8d6cd 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-util.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-util.c
@@ -70,6 +70,9 @@
 	int mux_mode, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -147,6 +150,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -183,6 +189,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -219,6 +228,9 @@
 	int div = 0, rc;
 	struct mdss_pll_resources *dsi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(clk->priv, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -394,6 +406,9 @@
 	int rc;
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
@@ -509,6 +524,9 @@
 	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(dsi_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
 	rc = mdss_pll_resource_enable(dsi_pll_res, true);
 	if (rc) {
 		pr_err("Failed to enable mdss dsi pll resources\n");
diff --git a/drivers/clk/qcom/mdss/mdss-edp-pll-28hpm.c b/drivers/clk/qcom/mdss/mdss-edp-pll-28hpm.c
index 80d55a5..da3536d 100644
--- a/drivers/clk/qcom/mdss/mdss-edp-pll-28hpm.c
+++ b/drivers/clk/qcom/mdss/mdss-edp-pll-28hpm.c
@@ -306,6 +306,9 @@
 	u32 pll_status, div2;
 	int rc;
 
+	if (is_gdsc_disabled(edp_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(edp_pll_res, true);
 	if (rc) {
 		pr_err("edp pll resources not available\n");
@@ -399,6 +402,9 @@
 	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
 	struct mdss_pll_resources *edp_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(edp_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
 	if (mdss_pll_resource_enable(edp_pll_res, true)) {
 		pr_err("edp pll resources not available\n");
 		return ret;
@@ -509,6 +515,9 @@
 	int rc;
 	struct mdss_pll_resources *edp_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(edp_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(edp_pll_res, true);
 	if (rc) {
 		pr_err("edp pll resources not available\n");
diff --git a/drivers/clk/qcom/mdss/mdss-hdmi-pll-20nm.c b/drivers/clk/qcom/mdss/mdss-hdmi-pll-20nm.c
index e866735..742f639 100644
--- a/drivers/clk/qcom/mdss/mdss-hdmi-pll-20nm.c
+++ b/drivers/clk/qcom/mdss/mdss-hdmi-pll-20nm.c
@@ -775,6 +775,9 @@
 	struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c);
 	struct mdss_pll_resources *io = vco->priv;
 
+	if (is_gdsc_disabled(io))
+		return 0;
+
 	rc = mdss_pll_resource_enable(io, true);
 	if (rc) {
 		pr_err("pll resource can't be enabled\n");
@@ -844,6 +847,9 @@
 	struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c);
 	struct mdss_pll_resources *io = vco->priv;
 
+	if (is_gdsc_disabled(io))
+		return HANDOFF_DISABLED_CLK;
+
 	if (mdss_pll_resource_enable(io, true)) {
 		pr_err("pll resource can't be enabled\n");
 		return ret;
diff --git a/drivers/clk/qcom/mdss/mdss-hdmi-pll-28hpm.c b/drivers/clk/qcom/mdss/mdss-hdmi-pll-28hpm.c
index 95d7328..94fd4e5 100644
--- a/drivers/clk/qcom/mdss/mdss-hdmi-pll-28hpm.c
+++ b/drivers/clk/qcom/mdss/mdss-hdmi-pll-28hpm.c
@@ -767,6 +767,9 @@
 	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
 	struct mdss_pll_resources *hdmi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(hdmi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(hdmi_pll_res, true);
 	if (rc) {
 		pr_err("pll resource can't be enabled\n");
@@ -868,6 +871,9 @@
 	struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
 	struct mdss_pll_resources *hdmi_pll_res = vco->priv;
 
+	if (is_gdsc_disabled(hdmi_pll_res))
+		return HANDOFF_DISABLED_CLK;
+
 	if (mdss_pll_resource_enable(hdmi_pll_res, true)) {
 		pr_err("pll resource can't be enabled\n");
 		return ret;
@@ -994,6 +1000,9 @@
 	int mux_sel = 0;
 	struct mdss_pll_resources *hdmi_pll_res = clk->priv;
 
+	if (is_gdsc_disabled(hdmi_pll_res))
+		return 0;
+
 	rc = mdss_pll_resource_enable(hdmi_pll_res, true);
 	if (rc) {
 		pr_err("pll resource can't be enabled\n");
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 948f680..080bcff 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -208,6 +208,7 @@
 	struct resource *pll_base_reg;
 	struct resource *phy_base_reg;
 	struct resource *dynamic_pll_base_reg;
+	struct resource *gdsc_base_reg;
 	struct mdss_pll_resources *pll_res;
 
 	if (!pdev->dev.of_node) {
@@ -310,6 +311,21 @@
 		}
 	}
 
+	gdsc_base_reg = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "gdsc_base");
+	if (!gdsc_base_reg) {
+		pr_err("Unable to get the gdsc base resource\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+	pll_res->gdsc_base = ioremap(gdsc_base_reg->start,
+			resource_size(gdsc_base_reg));
+	if (!pll_res->gdsc_base) {
+		pr_err("Unable to remap gdsc base resources\n");
+		rc = -ENOMEM;
+		goto gdsc_io_error;
+	}
+
 	rc = mdss_pll_resource_init(pdev, pll_res);
 	if (rc) {
 		pr_err("Pll resource init failed rc=%d\n", rc);
@@ -327,6 +343,9 @@
 clock_register_error:
 	mdss_pll_resource_deinit(pdev, pll_res);
 res_init_error:
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
+gdsc_io_error:
 	if (pll_res->dyn_pll_base)
 		iounmap(pll_res->dyn_pll_base);
 dyn_pll_io_error:
@@ -357,6 +376,8 @@
 	mdss_pll_resource_deinit(pdev, pll_res);
 	if (pll_res->phy_base)
 		iounmap(pll_res->phy_base);
+	if (pll_res->gdsc_base)
+		iounmap(pll_res->gdsc_base);
 	mdss_pll_resource_release(pdev, pll_res);
 	iounmap(pll_res->pll_base);
 	devm_kfree(&pdev->dev, pll_res);
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 6092e33..14c0914 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -51,12 +51,13 @@
 	struct dss_module_power mp;
 
 	/*
-	 * dsi/edp/hmdi plls' base register, phy and dynamic refresh
+	 * dsi/edp/hmdi plls' base register, phy, gdsc and dynamic refresh
 	 * register mapping
 	 */
 	void __iomem	*pll_base;
 	void __iomem	*pll_1_base;
 	void __iomem	*phy_base;
+	void __iomem	*gdsc_base;
 	void __iomem	*dyn_pll_base;
 
 	/*
@@ -139,6 +140,17 @@
 	s64 pll_plllock_cmp3;
 };
 
+static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res)
+{
+	if (!pll_res->gdsc_base) {
+		WARN(1, "gdsc_base register is not defined\n");
+		return true;
+	}
+
+	return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
+		(!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
+}
+
 int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable);
 int mdss_pll_util_resource_init(struct platform_device *pdev,
 					struct mdss_pll_resources *pll_res);