drm/msm/dsi-staging: add min data rate to use phy regulator

Add minimum per lane data rate to control if regulator is required
to turn on. Below the minimum rate, phy regulator is not required
and can be turned off. With regulator off, phy power is sourced
from mx domain.

Change-Id: I1d717a848825c74f3b3f8a352bcba1e2b0ba88e6
Signed-off-by: Alan Kwong <akwong@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index de5738e..21184ca 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -740,6 +740,17 @@
 			       display->name, name, rc);
 			goto error_remove_dir;
 		}
+
+		snprintf(name, ARRAY_SIZE(name),
+				"%s_regulator_min_datarate_bps", phy->name);
+		dump_file = debugfs_create_u32(name, 0600, dir,
+				&phy->regulator_min_datarate_bps);
+		if (IS_ERR_OR_NULL(dump_file)) {
+			rc = PTR_ERR(dump_file);
+			pr_err("[%s] debugfs create %s failed, rc=%d\n",
+			       display->name, name, rc);
+			goto error_remove_dir;
+		}
 	}
 
 	display->root = dir;
@@ -3006,6 +3017,20 @@
 		}
 	}
 
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+
+		if (!ctrl->phy || !ctrl->ctrl)
+			continue;
+
+		rc = dsi_phy_set_clk_freq(ctrl->phy, &ctrl->ctrl->clk_freq);
+		if (rc) {
+			pr_err("[%s] failed to set phy clk freq, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+	}
+
 	if (priv_info->phy_timing_len) {
 		for (i = 0; i < display->ctrl_count; i++) {
 			ctrl = &display->ctrl[i];
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 287afda..92064e1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -33,6 +33,8 @@
 
 #define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL"
 
+#define BITS_PER_BYTE	8
+
 struct dsi_phy_list_item {
 	struct msm_dsi_phy *phy;
 	struct list_head list;
@@ -294,6 +296,10 @@
 	phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node,
 			"qcom,panel-allow-phy-poweroff");
 
+	of_property_read_u32(pdev->dev.of_node,
+			"qcom,dsi-phy-regulator-min-datarate-bps",
+			&phy->regulator_min_datarate_bps);
+
 	return 0;
 err:
 	lane->count_per_lane = 0;
@@ -645,7 +651,8 @@
 			goto error;
 		}
 
-		if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
+		if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
+				dsi_phy->regulator_required) {
 			rc = dsi_pwr_enable_regulator(
 				&dsi_phy->pwr_info.phy_pwr, true);
 			if (rc) {
@@ -656,7 +663,8 @@
 			}
 		}
 	} else {
-		if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF) {
+		if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF &&
+				dsi_phy->regulator_required) {
 			rc = dsi_pwr_enable_regulator(
 				&dsi_phy->pwr_info.phy_pwr, false);
 			if (rc) {
@@ -910,6 +918,33 @@
 }
 
 /**
+ * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
+ * @phy:          DSI PHY handle
+ * @clk_freq:     link clock frequency
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
+		struct link_clk_freq *clk_freq)
+{
+	if (!phy || !clk_freq) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	phy->regulator_required = clk_freq->byte_clk_rate >
+		(phy->regulator_min_datarate_bps / BITS_PER_BYTE);
+
+	pr_debug("[%s] lane_datarate=%u min_datarate=%u required=%d\n",
+			phy->name,
+			clk_freq->byte_clk_rate * BITS_PER_BYTE,
+			phy->regulator_min_datarate_bps,
+			phy->regulator_required);
+
+	return 0;
+}
+
+/**
  * dsi_phy_set_timing_params() - timing parameters for the panel
  * @phy:          DSI PHY handle
  * @timing:       array holding timing params.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 09ed9d6..8f0c05f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -68,6 +68,8 @@
  * @data_lanes:        Number of data lanes used.
  * @dst_format:        Destination format.
  * @allow_phy_power_off: True if PHY is allowed to power off when idle
+ * @regulator_min_datarate_bps: Minimum per lane data rate to turn on regulator
+ * @regulator_required: True if phy regulator is required
  */
 struct msm_dsi_phy {
 	struct platform_device *pdev;
@@ -91,6 +93,8 @@
 	enum dsi_pixel_format dst_format;
 
 	bool allow_phy_power_off;
+	u32 regulator_min_datarate_bps;
+	bool regulator_required;
 };
 
 /**
@@ -212,6 +216,16 @@
 int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable);
 
 /**
+ * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
+ * @phy:          DSI PHY handle
+ * @clk_freq:     link clock frequency
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy,
+		struct link_clk_freq *clk_freq);
+
+/**
  * dsi_phy_set_timing_params() - timing parameters for the panel
  * @phy:          DSI PHY handle
  * @timing:       array holding timing params.