From: WeiYong Bi <bivvy.bi@rock-chips.com>
Date: Tue, 14 Mar 2017 09:40:40 +0000 (+0800)
Subject: drm/rockchip/dsi: dw-mipi: Add support for RK3368 MIPI DSI Controller Host
X-Git-Tag: firefly_0821_release~304
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=6ee9b7d6fb3700952cad90988858fb560abdab76;p=firefly-linux-kernel-4.4.55.git

drm/rockchip/dsi: dw-mipi: Add support for RK3368 MIPI DSI Controller Host

Change-Id: I6c16b5a51451cdfc112a0bdefb44ad5a4b216c4f
Signed-off-by: WeiYong Bi <bivvy.bi@rock-chips.com>
---

diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 1ed91f92251b..dc4952e8a0e2 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -5,23 +5,30 @@ Required properties:
 - #address-cells: Should be <1>.
 - #size-cells: Should be <0>.
 - compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
+  or "rockchip,rk3368-mipi-dsi", "snps,dw-mipi-dsi".
   or "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
 - reg: Represent the physical address range of the controller.
 - interrupts: Represent the controller's interrupt to the CPU(s).
-- clocks, clock-names: Phandles to the controller's pll reference
-  clock(ref) and APB clock(pclk) as described in [1].
+- clocks, clock-names: Phandles to the controller's APB clock(pclk) as
+  described in [1].
 - rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
 - ports: contain a port node with endpoint definitions as defined in [2].
   For vopb,set the reg = <0> and set the reg = <1> for vopl.
 
 Optional properties
 - clocks, clock-names: phandle to the mipi dsi phy config clock, name should be
-  "phy_cfg".
+  "phy_cfg".phandle to the mipi dsi phy reference clock, name should be 'ref'.
+- phys: phandle to third party MIPI PHY node
+- phy-names: the string "mipi_dphy" when is found in a node, along with "phys"
+  attribute, provides phandle to MIPI PHY node
 
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/media/video-interfaces.txt
 
 Example:
+
+For Rockchip RK3288:
+
 	mipi_dsi: mipi@ff960000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
@@ -64,3 +71,35 @@ Example:
 			status = "okay";
 		};
 	};
+
+For Rockchip RK3368:
+
+mipi_dsi_host: mipi-dsi-host@ff960000 {
+	compatible = "rockchip,rk3368-mipi-dsi";
+	phys = <&mipi_dphy>;
+	phy-names = "mipi_dphy";
+	...
+
+	ports@1 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <1>;
+
+		mipi_in: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			mipi_in_vop: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&vop_out_mipi>;
+			};
+		};
+	};
+
+	dsi_panel: panel@0 {
+		compatible = "simple-panel-dsi";
+		reg = <0>;
+		dsi,lanes = <4>;
+		...
+	};
+};
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 98c7e1031196..0190bfb8bbf3 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -12,6 +12,7 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/phy/phy.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
@@ -280,6 +281,11 @@ struct dw_mipi_dsi_plat_data {
 	u32 grf_dsi0_mode;
 	u32 grf_dsi0_mode_reg;
 	unsigned int max_data_lanes;
+	u32 max_bit_rate_per_lane;
+	bool has_separate_phy;
+	bool has_phy_pclk;
+	bool has_phy_refclk;
+	bool has_vop_sel;
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
 };
@@ -288,6 +294,7 @@ struct dw_mipi_dsi {
 	struct drm_encoder encoder;
 	struct drm_connector connector;
 	struct mipi_dsi_host dsi_host;
+	struct phy *phy;
 	struct drm_panel *panel;
 	struct device *dev;
 	struct regmap *grf_regmap;
@@ -488,10 +495,11 @@ phy_init_end:
 
 static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
 {
+	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
 	unsigned int i, pre;
 	unsigned long mpclk, pllref, tmp;
 	unsigned int m = 1, n = 1, target_mbps = 1000;
-	unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
+	unsigned int max_mbps = pdata->max_bit_rate_per_lane / USEC_PER_SEC;
 	int bpp;
 
 	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
@@ -511,7 +519,12 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
 			dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
 	}
 
-	pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
+	if (pdata->has_phy_refclk)
+		pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk),
+				      USEC_PER_SEC);
+	else
+		pllref = DIV_ROUND_UP(12000000, USEC_PER_SEC);
+
 	tmp = pllref;
 
 	for (i = 1; i < 6; i++) {
@@ -543,8 +556,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 		return -EINVAL;
 	}
 
-	if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
-	    !(device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) {
+	if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) {
 		dev_err(dsi->dev, "device mode is unsupported\n");
 		return -EINVAL;
 	}
@@ -552,6 +564,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->lanes = device->lanes;
 	dsi->channel = device->channel;
 	dsi->format = device->format;
+
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
 	if (!dsi->panel) {
 		DRM_ERROR("failed to find panel\n");
@@ -832,8 +845,12 @@ static void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi)
 
 static void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
 {
-	dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x40)
-		  | PHY_LP2HS_TIME(0x40) | MAX_RD_TIME(10000));
+	/*
+	 * HS-PREPARE: 40ns + 4 * UI ~ 85ns + 6 * UI
+	 * HS-EXIT: 100ns
+	 */
+	dsi_write(dsi, DSI_PHY_TMR_CFG, PHY_HS2LP_TIME(0x14)
+		  | PHY_LP2HS_TIME(0x10) | MAX_RD_TIME(10000));
 
 	dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG, PHY_CLKHS2LP_TIME(0x40)
 		  | PHY_CLKLP2HS_TIME(0x40));
@@ -885,6 +902,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
 
 	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
 	dw_mipi_dsi_disable(dsi);
+	phy_power_off(dsi->phy);
 	pm_runtime_put(dsi->dev);
 	clk_disable_unprepare(dsi->pclk);
 }
@@ -915,6 +933,7 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 
 	pm_runtime_get_sync(dsi->dev);
 
+	phy_power_on(dsi->phy);
 	dw_mipi_dsi_init(dsi);
 	dw_mipi_dsi_dpi_config(dsi, &dsi->mode);
 	dw_mipi_dsi_packet_handler_config(dsi);
@@ -941,6 +960,9 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 
 	clk_disable_unprepare(dsi->pclk);
 
+	if (!pdata->has_vop_sel)
+		return;
+
 	if (mux)
 		val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
 	else
@@ -1114,6 +1136,10 @@ static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
 	.dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
 	.grf_switch_reg = RK3288_GRF_SOC_CON6,
 	.max_data_lanes = 4,
+	.max_bit_rate_per_lane = 1500000000,
+	.has_vop_sel = true,
+	.has_phy_refclk = true,
+	.has_phy_pclk = true,
 };
 
 static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
@@ -1123,6 +1149,16 @@ static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
 	.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
 	.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
 	.max_data_lanes = 4,
+	.max_bit_rate_per_lane = 1500000000,
+	.has_vop_sel = true,
+	.has_phy_refclk = true,
+	.has_phy_pclk = true,
+};
+
+static struct dw_mipi_dsi_plat_data rk3368_mipi_dsi_drv_data = {
+	.max_data_lanes = 4,
+	.max_bit_rate_per_lane = 1000000000,
+	.has_separate_phy = true,
 };
 
 static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
@@ -1132,6 +1168,9 @@ static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
 	},{
 	 .compatible = "rockchip,rk3399-mipi-dsi",
 	 .data = &rk3399_mipi_dsi_drv_data,
+	}, {
+	 .compatible = "rockchip,rk3368-mipi-dsi",
+	 .data = &rk3368_mipi_dsi_drv_data,
 	},
 	{ /* sentinel */ }
 };
@@ -1143,6 +1182,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *drm = data;
 	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
+	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
 	struct resource *res;
 	int ret;
 
@@ -1153,6 +1193,14 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	if (ret)
 		return ret;
 
+	if (pdata->has_separate_phy) {
+		dsi->phy = devm_phy_get(dev, "mipi_dphy");
+		if (IS_ERR(dsi->phy)) {
+			dev_err(dev, "failed to get mipi dphy\n");
+			return PTR_ERR(dsi->phy);
+		}
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
 		return -ENODEV;
@@ -1161,13 +1209,6 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 	if (IS_ERR(dsi->base))
 		return PTR_ERR(dsi->base);
 
-	dsi->pllref_clk = devm_clk_get(dev, "ref");
-	if (IS_ERR(dsi->pllref_clk)) {
-		ret = PTR_ERR(dsi->pllref_clk);
-		dev_err(dev, "Unable to get pll reference clock: %d\n", ret);
-		return ret;
-	}
-
 	dsi->pclk = devm_clk_get(dev, "pclk");
 	if (IS_ERR(dsi->pclk)) {
 		ret = PTR_ERR(dsi->pclk);
@@ -1175,9 +1216,20 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
-	dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
-	if (IS_ERR(dsi->phy_cfg_clk))
-		dev_dbg(dev, "have not phy_cfg_clk\n");
+	if (pdata->has_phy_refclk) {
+		dsi->pllref_clk = devm_clk_get(dev, "ref");
+		if (IS_ERR(dsi->pllref_clk)) {
+			ret = PTR_ERR(dsi->pllref_clk);
+			dev_err(dev, "failed to get pll ref clock: %d\n", ret);
+			return ret;
+		}
+	}
+
+	if (pdata->has_phy_pclk) {
+		dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+		if (IS_ERR(dsi->phy_cfg_clk))
+			dev_dbg(dev, "have not phy_cfg_clk\n");
+	}
 
 	ret = clk_prepare_enable(dsi->pllref_clk);
 	if (ret) {