From: Huang Jiachai <hjc@rock-chips.com>
Date: Wed, 19 Apr 2017 12:29:29 +0000 (+0800)
Subject: drm/rockchip: lvds: add support rk3368 lvds
X-Git-Tag: release-20171130_firefly~4^2~728
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=07bac5e0b8728590a0921aa9d9e5bd4e5f8c8c3f;p=firefly-linux-kernel-4.4.55.git

drm/rockchip: lvds: add support rk3368 lvds

Change-Id: I288fd42d9591119fadcbede67ff74be52d594e02
Signed-off-by: Huang Jiachai <hjc@rock-chips.com>
---

diff --git a/Documentation/devicetree/bindings/video/rockchip-lvds.txt b/Documentation/devicetree/bindings/video/rockchip-lvds.txt
index 80529f429cc5..51f4864b8c21 100644
--- a/Documentation/devicetree/bindings/video/rockchip-lvds.txt
+++ b/Documentation/devicetree/bindings/video/rockchip-lvds.txt
@@ -2,10 +2,16 @@ Rockchip RK3288 LVDS interface
 ================================
 
 Required properties:
-- compatible: "rockchip,rk3288-lvds";
+- compatible: matching the soc type, one of
+	- "rockchip,rk3288-lvds";
+	- "rockchip,rk33xx-lvds";
 
 - reg: physical base address of the controller and length
 	of memory mapped region.
+- reg-names: the name to indicate register. example:
+	- "mipi_lvds_phy": lvds phy register, this's included in the MIPI phy module
+	- "mipi_lvds_ctl": lvds control register, this's included in the MIPI
+		controller module
 - clocks: must include clock specifiers corresponding to entries in the
 	clock-names property.
 - clock-names: must contain "pclk_lvds"
@@ -23,6 +29,11 @@ Required properties:
 - rockchip,output: should be "rgb", "lvds" or "duallvds",
 	This describes the output face.
 
+Optional properties
+- pinctrl-names: must contain a "default" entry.
+- pinctrl-0: pin control group to be used for this controller.
+- pinctrl-1: pin control group to be used for gpio.
+
 Required nodes:
 
 The lvds has two video ports as described by
@@ -34,6 +45,9 @@ Their connections are modeled using the OF graph bindings specified in
 - video port 1 for either a panel or subsequent encoder
 
 Example:
+
+For Rockchip RK3288:
+
 	lvds: lvds@ff96c000 {
 		compatible = "rockchip,rk3288-lvds";
 		rockchip,grf = <&grf>;
@@ -72,3 +86,24 @@ Example:
 			};
 		};
 	};
+
+For Rockchip RK3368:
+
+	lvds: lvds@ff968000 {
+		compatible = "rockchip,rk33xx-lvds";
+		reg = <0x0 0xff968000 0x0 0x4000>, <0x0 0xff9600a0 0x0 0x20>;
+		reg-names = "mipi_lvds_phy", "mipi_lvds_ctl";
+		clocks = <&cru PCLK_DPHYTX0>, <&cru PCLK_MIPI_DSI0>;
+		clock-names = "pclk_lvds", "pclk_lvds_ctl";
+		power-domains = <&power RK3368_PD_VIO>;
+		rockchip,grf = <&grf>;
+		pinctrl-names = "lcdc", "gpio";
+		pinctrl-0 = <&lcdc_lcdc>;
+		pinctrl-1 = <&lcdc_gpio>;
+
+		ports {
+
+		...
+
+		};
+	};
\ No newline at end of file
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index aa0c49a3b90d..cdf061b57262 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -43,21 +43,27 @@
 
 #define encoder_to_lvds(c) \
 		container_of(c, struct rockchip_lvds, encoder)
+#define LVDS_CHIP(lvds)	((lvds)->soc_data->chip_type)
 
 /*
  * @grf_offset: offset inside the grf regmap for setting the rockchip lvds
  */
 struct rockchip_lvds_soc_data {
+	int chip_type;
+	int grf_soc_con5;
 	int grf_soc_con6;
 	int grf_soc_con7;
+	int grf_soc_con15;
 };
 
 struct rockchip_lvds {
 	void *base;
 	struct device *dev;
 	void __iomem *regs;
+	void __iomem *regs_ctrl;
 	struct regmap *grf;
 	struct clk *pclk;
+	struct clk *pclk_ctrl;
 	const struct rockchip_lvds_soc_data *soc_data;
 
 	int output;
@@ -70,12 +76,38 @@ struct rockchip_lvds {
 
 	struct mutex suspend_lock;
 	int suspend;
+	struct dev_pin_info *pins;
 };
 
 static inline void lvds_writel(struct rockchip_lvds *lvds, u32 offset, u32 val)
 {
 	writel_relaxed(val, lvds->regs + offset);
-	writel_relaxed(val, lvds->regs + offset + 0x100);
+	if ((lvds->output == DISPLAY_OUTPUT_DUAL_LVDS) &&
+	    (LVDS_CHIP(lvds) == RK3288_LVDS))
+		writel_relaxed(val, lvds->regs + offset + 0x100);
+}
+
+static inline void lvds_msk_reg(struct rockchip_lvds *lvds, u32 offset,
+				u32 msk, u32 val)
+{
+	u32 temp;
+
+	temp = readl_relaxed(lvds->regs + offset) & (0xFF - (msk));
+	writel_relaxed(temp | ((val) & (msk)), lvds->regs + offset);
+}
+
+static inline void lvds_dsi_writel(struct rockchip_lvds *lvds,
+				   u32 offset, u32 val)
+{
+	writel_relaxed(val, lvds->regs_ctrl + offset);
+}
+
+static inline u32 lvds_phy_lockon(struct rockchip_lvds *lvds)
+{
+	u32 val = 0;
+
+	val = readl_relaxed(lvds->regs_ctrl + 0x10);
+	return (val & 0x01);
 }
 
 static inline int lvds_name_to_format(const char *s)
@@ -106,22 +138,8 @@ static inline int lvds_name_to_output(const char *s)
 	return -EINVAL;
 }
 
-static int rockchip_lvds_poweron(struct rockchip_lvds *lvds)
+static int rk3288_lvds_poweron(struct rockchip_lvds *lvds)
 {
-	int ret;
-
-	ret = clk_enable(lvds->pclk);
-	if (ret < 0) {
-		dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret);
-		return ret;
-	}
-
-	ret = pm_runtime_get_sync(lvds->dev);
-	if (ret < 0) {
-		dev_err(lvds->dev, "failed to get pm runtime: %d\n", ret);
-		return ret;
-	}
-
 	if (lvds->output == DISPLAY_OUTPUT_RGB) {
 		lvds_writel(lvds, RK3288_LVDS_CH0_REG0,
 			    RK3288_LVDS_CH0_REG0_TTL_EN |
@@ -197,22 +215,171 @@ static int rockchip_lvds_poweron(struct rockchip_lvds *lvds)
 	return 0;
 }
 
-static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds)
+static int rk3368_lvds_poweron(struct rockchip_lvds *lvds)
+{
+	u32 delay_times = 20;
+
+	if (lvds->output == DISPLAY_OUTPUT_LVDS) {
+		/* set VOCM 900 mv and V-DIFF 350 mv */
+		lvds_msk_reg(lvds, MIPIPHY_REGE4, m_VOCM | m_DIFF_V,
+			     v_VOCM(0) | v_DIFF_V(2));
+		/* power up lvds pll and ldo */
+		lvds_msk_reg(lvds, MIPIPHY_REG1,
+			     m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
+			     v_SYNC_RST(0) | v_LDO_PWR_DOWN(0) |
+			     v_PLL_PWR_DOWN(0));
+		/* enable lvds lane and power on pll */
+		lvds_writel(lvds, MIPIPHY_REGEB,
+			    v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) |
+			    v_LANE3_EN(1) | v_LANECLK_EN(1) | v_PLL_PWR_OFF(0));
+
+		/* enable lvds */
+		lvds_msk_reg(lvds, MIPIPHY_REGE3,
+			     m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
+			     v_MIPI_EN(0) | v_LVDS_EN(1) | v_TTL_EN(0));
+	} else {
+		lvds_msk_reg(lvds, MIPIPHY_REGE3,
+			     m_MIPI_EN | m_LVDS_EN | m_TTL_EN,
+			     v_MIPI_EN(0) | v_LVDS_EN(0) | v_TTL_EN(1));
+	}
+	/* delay for waitting pll lock on */
+	while (delay_times--) {
+		if (lvds_phy_lockon(lvds))
+			break;
+		udelay(100);
+	}
+
+	if (delay_times <= 0)
+		dev_err(lvds->dev, "wait phy lockon failed, please check hardware\n");
+
+	return 0;
+}
+
+static void rk3368_output_ttl(struct rockchip_lvds *lvds)
+{
+	u32 val = 0;
+
+	/* enable lane */
+	lvds_writel(lvds, MIPIPHY_REG0, 0x7f);
+	val = v_LANE0_EN(1) | v_LANE1_EN(1) | v_LANE2_EN(1) | v_LANE3_EN(1) |
+		v_LANECLK_EN(1) | v_PLL_PWR_OFF(1);
+	lvds_writel(lvds, MIPIPHY_REGEB, val);
+
+	/* set ttl mode and reset phy config */
+	val = v_LVDS_MODE_EN(0) | v_TTL_MODE_EN(1) | v_MIPI_MODE_EN(0) |
+		v_MSB_SEL(1) | v_DIG_INTER_RST(1);
+	lvds_writel(lvds, MIPIPHY_REGE0, val);
+
+	rk3368_lvds_poweron(lvds);
+}
+
+static void rk3368_output_lvds(struct rockchip_lvds *lvds)
+{
+	/* digital internal disable */
+	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(0));
+
+	/* set pll prediv and fbdiv */
+	lvds_writel(lvds, MIPIPHY_REG3, v_PREDIV(2) | v_FBDIV_MSB(0));
+	lvds_writel(lvds, MIPIPHY_REG4, v_FBDIV_LSB(28));
+
+	lvds_writel(lvds, MIPIPHY_REGE8, 0xfc);
+
+	/* set lvds mode and reset phy config */
+	lvds_msk_reg(lvds, MIPIPHY_REGE0,
+		     m_MSB_SEL | m_DIG_INTER_RST,
+		     v_MSB_SEL(1) | v_DIG_INTER_RST(1));
+
+	rk3368_lvds_poweron(lvds);
+	lvds_msk_reg(lvds, MIPIPHY_REGE1, m_DIG_INTER_EN, v_DIG_INTER_EN(1));
+}
+
+static int rk3368_lvds_output(struct rockchip_lvds *lvds)
+{
+	if (lvds->output == DISPLAY_OUTPUT_RGB)
+		rk3368_output_ttl(lvds);
+	else
+		rk3368_output_lvds(lvds);
+	return 0;
+}
+
+static int rockchip_lvds_poweron(struct rockchip_lvds *lvds)
 {
 	int ret;
 
-	ret = regmap_write(lvds->grf,
-			   lvds->soc_data->grf_soc_con7, 0xffff8000);
-	if (ret != 0)
-		dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
+	if (lvds->pclk) {
+		ret = clk_enable(lvds->pclk);
+		if (ret < 0) {
+			dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret);
+			return ret;
+		}
+	}
+	if (lvds->pclk_ctrl) {
+		ret = clk_enable(lvds->pclk_ctrl);
+		if (ret < 0) {
+			dev_err(lvds->dev, "failed to enable lvds pclk_ctrl %d\n", ret);
+			return ret;
+		}
+	}
 
-	writel(RK3288_LVDS_CFG_REG21_TX_DISABLE,
-	       lvds->regs + RK3288_LVDS_CFG_REG21);
-	writel(RK3288_LVDS_CFG_REGC_PLL_DISABLE,
-	       lvds->regs + RK3288_LVDS_CFG_REGC);
+	ret = pm_runtime_get_sync(lvds->dev);
+	if (ret < 0) {
+		dev_err(lvds->dev, "failed to get pm runtime: %d\n", ret);
+		return ret;
+	}
+	if (LVDS_CHIP(lvds) == RK3288_LVDS)
+		rk3288_lvds_poweron(lvds);
+	else if (LVDS_CHIP(lvds) == RK3368_LVDS)
+		rk3368_lvds_output(lvds);
+
+	return 0;
+}
+
+static void rockchip_lvds_poweroff(struct rockchip_lvds *lvds)
+{
+	int ret;
+	u32 val;
+
+	if (LVDS_CHIP(lvds) == RK3288_LVDS) {
+		ret = regmap_write(lvds->grf,
+				   lvds->soc_data->grf_soc_con7, 0xffff8000);
+		if (ret != 0)
+			dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
+
+		writel(RK3288_LVDS_CFG_REG21_TX_DISABLE,
+		       lvds->regs + RK3288_LVDS_CFG_REG21);
+		writel(RK3288_LVDS_CFG_REGC_PLL_DISABLE,
+		       lvds->regs + RK3288_LVDS_CFG_REGC);
+
+		pm_runtime_put(lvds->dev);
+		if (lvds->pclk)
+			clk_disable(lvds->pclk);
+	} else if (LVDS_CHIP(lvds) == RK3368_LVDS) {
+		val = v_RK3368_LVDSMODE_EN(0) | v_RK3368_MIPIPHY_TTL_EN(0);
+		ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
+		if (ret != 0) {
+			dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
+			return;
+		}
 
-	pm_runtime_put(lvds->dev);
-	clk_disable(lvds->pclk);
+		/* disable lvds lane and power off pll */
+		lvds_writel(lvds, MIPIPHY_REGEB,
+			    v_LANE0_EN(0) | v_LANE1_EN(0) | v_LANE2_EN(0) |
+			    v_LANE3_EN(0) | v_LANECLK_EN(0) | v_PLL_PWR_OFF(1));
+
+		/* power down lvds pll and bandgap */
+		lvds_msk_reg(lvds, MIPIPHY_REG1,
+			     m_SYNC_RST | m_LDO_PWR_DOWN | m_PLL_PWR_DOWN,
+			     v_SYNC_RST(1) | v_LDO_PWR_DOWN(1) | v_PLL_PWR_DOWN(1));
+
+		/* disable lvds */
+		lvds_msk_reg(lvds, MIPIPHY_REGE3, m_LVDS_EN | m_TTL_EN,
+			     v_LVDS_EN(0) | v_TTL_EN(0));
+		pm_runtime_put(lvds->dev);
+		if (lvds->pclk)
+			clk_disable(lvds->pclk);
+		if (lvds->pclk_ctrl)
+			clk_disable(lvds->pclk_ctrl);
+	}
 }
 
 static enum drm_connector_status
@@ -327,23 +494,70 @@ static void rockchip_lvds_encoder_mode_set(struct drm_encoder *encoder,
 	u32 val;
 	int ret;
 
-	val = lvds->format;
-	if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
-		val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
-	else if (lvds->output == DISPLAY_OUTPUT_LVDS)
-		val |= LVDS_CH0_EN;
-	else if (lvds->output == DISPLAY_OUTPUT_RGB)
-		val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
-
-	if (h_bp & 0x01)
-		val |= LVDS_START_PHASE_RST_1;
-
-	val |= (pin_dclk << 8) | (pin_hsync << 9);
-	val |= (0xffff << 16);
-	ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
-	if (ret != 0) {
-		dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
-		return;
+	if (LVDS_CHIP(lvds) == RK3288_LVDS) {
+		val = lvds->format;
+		if (lvds->output == DISPLAY_OUTPUT_DUAL_LVDS)
+			val |= LVDS_DUAL | LVDS_CH0_EN | LVDS_CH1_EN;
+		else if (lvds->output == DISPLAY_OUTPUT_LVDS)
+			val |= LVDS_CH0_EN;
+		else if (lvds->output == DISPLAY_OUTPUT_RGB)
+			val |= LVDS_TTL_EN | LVDS_CH0_EN | LVDS_CH1_EN;
+
+		if (h_bp & 0x01)
+			val |= LVDS_START_PHASE_RST_1;
+
+		val |= (pin_dclk << 8) | (pin_hsync << 9);
+		val |= (0xffff << 16);
+		ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con7, val);
+		if (ret != 0) {
+			dev_err(lvds->dev, "Could not write to GRF: %d\n", ret);
+			return;
+		}
+	} else if (LVDS_CHIP(lvds) == RK3368_LVDS) {
+		if (lvds->output == DISPLAY_OUTPUT_RGB) {
+			/* iomux to lcdc */
+			if (lvds->pins && !IS_ERR(lvds->pins->default_state))
+				pinctrl_select_state(lvds->pins->p,
+						     lvds->pins->default_state);
+
+			lvds_dsi_writel(lvds, 0x0, 0x4);/*set clock lane enable*/
+			/* enable lvds mode */
+			val = v_RK3368_LVDSMODE_EN(0) |
+				v_RK3368_MIPIPHY_TTL_EN(1) |
+				v_RK3368_MIPIPHY_LANE0_EN(1) |
+				v_RK3368_MIPIDPI_FORCEX_EN(1);
+			ret = regmap_write(lvds->grf,
+					   lvds->soc_data->grf_soc_con7, val);
+			if (ret != 0) {
+				dev_err(lvds->dev,
+					"Could not write to GRF: %d\n", ret);
+				return;
+			}
+			val = v_RK3368_FORCE_JETAG(0);
+			ret = regmap_write(lvds->grf,
+					   lvds->soc_data->grf_soc_con15, val);
+			if (ret != 0) {
+				dev_err(lvds->dev,
+					"Could not write to GRF: %d\n", ret);
+				return;
+			}
+		} else if (lvds->output == DISPLAY_OUTPUT_LVDS) {
+			/* enable lvds mode */
+			val = v_RK3368_LVDSMODE_EN(1) | v_RK3368_MIPIPHY_TTL_EN(0);
+			/* config lvds_format */
+			val |= v_RK3368_LVDS_OUTPUT_FORMAT(lvds->format);
+			/* LSB receive mode */
+			val |= v_RK3368_LVDS_MSBSEL(LVDS_MSB_D7);
+			val |= v_RK3368_MIPIPHY_LANE0_EN(1) |
+			       v_RK3368_MIPIDPI_FORCEX_EN(1);
+			ret = regmap_write(lvds->grf,
+					   lvds->soc_data->grf_soc_con7, val);
+			if (ret != 0) {
+				dev_err(lvds->dev,
+					"Could not write to GRF: %d\n", ret);
+				return;
+			}
+		}
 	}
 }
 
@@ -357,16 +571,17 @@ static int rockchip_lvds_set_vop_source(struct rockchip_lvds *lvds,
 	if (ret < 0)
 		return ret;
 
-	if (ret)
-		val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
-		      (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
-	else
-		val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
-
-	ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val);
-	if (ret < 0)
-		return ret;
+	if (LVDS_CHIP(lvds) == RK3288_LVDS) {
+		if (ret)
+			val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT |
+			      (RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16);
+		else
+			val = RK3288_LVDS_SOC_CON6_SEL_VOP_LIT << 16;
 
+		ret = regmap_write(lvds->grf, lvds->soc_data->grf_soc_con6, val);
+		if (ret < 0)
+			return ret;
+	}
 	return 0;
 }
 
@@ -419,15 +634,28 @@ static struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
 };
 
 static struct rockchip_lvds_soc_data rk3288_lvds_data = {
+	.chip_type = RK3288_LVDS,
 	.grf_soc_con6 = 0x025c,
 	.grf_soc_con7 = 0x0260,
 };
 
+static struct rockchip_lvds_soc_data rk33xx_lvds_data = {
+	.chip_type = RK3368_LVDS,
+	.grf_soc_con5  = 0x0414,
+	.grf_soc_con6  = 0x0418,
+	.grf_soc_con7  = 0x041c,
+	.grf_soc_con15 = 0x043c,
+};
+
 static const struct of_device_id rockchip_lvds_dt_ids[] = {
 	{
 		.compatible = "rockchip,rk3288-lvds",
 		.data = &rk3288_lvds_data
 	},
+	{
+		.compatible = "rockchip,rk33xx-lvds",
+		.data = &rk33xx_lvds_data
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, rockchip_lvds_dt_ids);
@@ -439,10 +667,71 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
 	struct drm_device *drm_dev = data;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	int ret;
-
+	struct device_node *panel_node, *port, *endpoint;
+	int ret, i;
+	const char *name;
 	lvds->drm_dev = drm_dev;
 
+	port = of_graph_get_port_by_id(dev->of_node, 1);
+	if (port) {
+		endpoint = of_get_child_by_name(port, "endpoint");
+		of_node_put(port);
+		if (!endpoint) {
+			dev_err(dev, "no output endpoint found\n");
+			return -EINVAL;
+		}
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		of_node_put(endpoint);
+		if (!panel_node) {
+			dev_err(dev, "no output node found\n");
+			return -EINVAL;
+		}
+		lvds->panel = of_drm_find_panel(panel_node);
+		if (!lvds->panel) {
+			DRM_ERROR("failed to find panel\n");
+			of_node_put(panel_node);
+			return -EPROBE_DEFER;
+		}
+
+		if (of_property_read_string(panel_node, "rockchip,output", &name))
+			/* default set it as output rgb */
+			lvds->output = DISPLAY_OUTPUT_RGB;
+		else
+			lvds->output = lvds_name_to_output(name);
+
+		if (lvds->output < 0) {
+			dev_err(dev, "invalid output type [%s]\n", name);
+			return lvds->output;
+		}
+
+		if (of_property_read_string(panel_node, "rockchip,data-mapping",
+					    &name))
+			/* default set it as format jeida */
+			lvds->format = LVDS_FORMAT_JEIDA;
+		else
+			lvds->format = lvds_name_to_format(name);
+
+		if (lvds->format < 0) {
+			dev_err(dev, "invalid data-mapping format [%s]\n", name);
+			return lvds->format;
+		}
+
+		if (of_property_read_u32(panel_node, "rockchip,data-width", &i)) {
+			lvds->format |= LVDS_24BIT;
+		} else {
+			if (i == 24) {
+				lvds->format |= LVDS_24BIT;
+			} else if (i == 18) {
+				lvds->format |= LVDS_18BIT;
+			} else {
+				dev_err(dev,
+					"rockchip-lvds unsupport data-width[%d]\n", i);
+				return -EINVAL;
+			}
+		}
+		of_node_put(panel_node);
+	}
+
 	encoder = &lvds->encoder;
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dev->of_node);
@@ -481,7 +770,7 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
 		DRM_ERROR("failed to attach connector and encoder\n");
 		goto err_free_connector;
 	}
-
+	lvds->connector.port = dev->of_node;
 	pm_runtime_enable(dev);
 
 	return 0;
@@ -517,11 +806,9 @@ static int rockchip_lvds_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rockchip_lvds *lvds;
-	struct device_node *output_node = NULL;
 	const struct of_device_id *match;
 	struct resource *res;
-	const char *name;
-	int i, ret;
+	int ret;
 
 	if (!dev->of_node)
 		return -ENODEV;
@@ -532,91 +819,95 @@ static int rockchip_lvds_probe(struct platform_device *pdev)
 
 	lvds->dev = dev;
 	lvds->suspend = true;
+	match = of_match_node(rockchip_lvds_dt_ids, dev->of_node);
+	lvds->soc_data = match->data;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	lvds->regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(lvds->regs))
-		return PTR_ERR(lvds->regs);
+	if (LVDS_CHIP(lvds) == RK3288_LVDS) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		lvds->regs = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(lvds->regs))
+			return PTR_ERR(lvds->regs);
+	} else if (LVDS_CHIP(lvds) == RK3368_LVDS) {
+		/* lvds regs on MIPIPHY_REG */
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   "mipi_lvds_phy");
+		lvds->regs = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(lvds->regs)) {
+			dev_err(&pdev->dev, "ioremap lvds phy reg failed\n");
+			return PTR_ERR(lvds->regs);
+		}
 
-	lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
-						    "rockchip,grf");
-	if (IS_ERR(lvds->grf)) {
-		dev_err(dev, "missing rockchip,grf property\n");
-		return PTR_ERR(lvds->grf);
+		/* pll lock on status reg that is MIPICTRL Register */
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						   "mipi_lvds_ctl");
+		lvds->regs_ctrl = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(lvds->regs_ctrl)) {
+			dev_err(&pdev->dev, "ioremap lvds ctl reg failed\n");
+			return PTR_ERR(lvds->regs_ctrl);
+		}
+		/* mipi ctrl clk for read lvds phy lock state */
+		lvds->pclk_ctrl = devm_clk_get(&pdev->dev, "pclk_lvds_ctl");
+		if (IS_ERR(lvds->pclk_ctrl)) {
+			dev_err(dev, "could not get pclk_ctrl\n");
+			lvds->pclk_ctrl = NULL;
+		}
+		lvds->pins = devm_kzalloc(lvds->dev, sizeof(*lvds->pins),
+					  GFP_KERNEL);
+		if (!lvds->pins)
+			return -ENOMEM;
+
+		lvds->pins->p = devm_pinctrl_get(lvds->dev);
+		if (IS_ERR(lvds->pins->p)) {
+			dev_info(lvds->dev, "no pinctrl handle\n");
+			devm_kfree(lvds->dev, lvds->pins);
+			lvds->pins = NULL;
+		} else {
+			lvds->pins->default_state =
+				pinctrl_lookup_state(lvds->pins->p, "lcdc");
+			if (IS_ERR(lvds->pins->default_state)) {
+				dev_info(lvds->dev, "no default pinctrl state\n");
+				devm_kfree(lvds->dev, lvds->pins);
+				lvds->pins = NULL;
+			}
+		}
 	}
-
 	lvds->pclk = devm_clk_get(&pdev->dev, "pclk_lvds");
 	if (IS_ERR(lvds->pclk)) {
 		dev_err(dev, "could not get pclk_lvds\n");
 		return PTR_ERR(lvds->pclk);
 	}
-
-	match = of_match_node(rockchip_lvds_dt_ids, dev->of_node);
-	lvds->soc_data = match->data;
+	lvds->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+						    "rockchip,grf");
+	if (IS_ERR(lvds->grf)) {
+		dev_err(dev, "missing rockchip,grf property\n");
+		return PTR_ERR(lvds->grf);
+	}
 
 	dev_set_drvdata(dev, lvds);
 	mutex_init(&lvds->suspend_lock);
 
-	if (of_property_read_string(dev->of_node, "rockchip,output", &name))
-		/* default set it as output rgb */
-		lvds->output = DISPLAY_OUTPUT_RGB;
-	else
-		lvds->output = lvds_name_to_output(name);
-
-	if (lvds->output < 0) {
-		dev_err(dev, "invalid output type [%s]\n", name);
-		return lvds->output;
-	}
-
-	if (of_property_read_string(dev->of_node, "rockchip,data-mapping",
-				    &name))
-		/* default set it as format jeida */
-		lvds->format = LVDS_FORMAT_JEIDA;
-	else
-		lvds->format = lvds_name_to_format(name);
-
-	if (lvds->format < 0) {
-		dev_err(dev, "invalid data-mapping format [%s]\n", name);
-		return lvds->format;
-	}
-
-	if (of_property_read_u32(dev->of_node, "rockchip,data-width", &i)) {
-		lvds->format |= LVDS_24BIT;
-	} else {
-		if (i == 24) {
-			lvds->format |= LVDS_24BIT;
-		} else if (i == 18) {
-			lvds->format |= LVDS_18BIT;
-		} else {
-			dev_err(&pdev->dev,
-				"rockchip-lvds unsupport data-width[%d]\n", i);
-			return -EINVAL;
+	if (lvds->pclk) {
+		ret = clk_prepare(lvds->pclk);
+		if (ret < 0) {
+			dev_err(dev, "failed to prepare pclk_lvds\n");
+			return ret;
 		}
 	}
-
-	output_node = of_parse_phandle(dev->of_node, "rockchip,panel", 0);
-	if (!output_node) {
-		DRM_ERROR("failed to find rockchip,panel dt node\n");
-		return -ENODEV;
-	}
-
-	lvds->panel = of_drm_find_panel(output_node);
-	of_node_put(output_node);
-	if (!lvds->panel) {
-		DRM_ERROR("failed to find panel\n");
-		return -EPROBE_DEFER;
+	if (lvds->pclk_ctrl) {
+		ret = clk_prepare(lvds->pclk_ctrl);
+		if (ret < 0) {
+			dev_err(dev, "failed to prepare pclk_ctrl lvds\n");
+			return ret;
+		}
 	}
-
-	ret = clk_prepare(lvds->pclk);
+	ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
 	if (ret < 0) {
-		dev_err(dev, "failed to prepare pclk_lvds\n");
-		return ret;
+		if (lvds->pclk)
+			clk_unprepare(lvds->pclk);
+		if (lvds->pclk_ctrl)
+			clk_unprepare(lvds->pclk_ctrl);
 	}
 
-	ret = component_add(&pdev->dev, &rockchip_lvds_component_ops);
-	if (ret < 0)
-		clk_unprepare(lvds->pclk);
-
 	return ret;
 }
 
@@ -625,8 +916,10 @@ static int rockchip_lvds_remove(struct platform_device *pdev)
 	struct rockchip_lvds *lvds = dev_get_drvdata(&pdev->dev);
 
 	component_del(&pdev->dev, &rockchip_lvds_component_ops);
-	clk_unprepare(lvds->pclk);
-
+	if (lvds->pclk)
+		clk_unprepare(lvds->pclk);
+	if (lvds->pclk_ctrl)
+		clk_unprepare(lvds->pclk_ctrl);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.h b/drivers/gpu/drm/rockchip/rockchip_lvds.h
index 5b79651cb725..803566b37955 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.h
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.h
@@ -105,4 +105,86 @@
 #define LVDS_FORMAT_VESA			(0 << 0)
 #define LVDS_FORMAT_JEIDA			(1 << 0)
 
+#define BITS(x, bit)		((x) << (bit))
+#define BITS_MASK(x, mask, bit)	BITS((x) & (mask), bit)
+#define BITS_EN(mask, bit)	BITS(mask, bit + 16)
+
+#define MIPIPHY_REG0		0x0000
+
+#define MIPIPHY_REG1		0x0004
+#define m_SYNC_RST		BIT(0)
+#define m_LDO_PWR_DOWN		BIT(1)
+#define m_PLL_PWR_DOWN		BIT(2)
+#define v_SYNC_RST(x)		BITS_MASK(x, 1, 0)
+#define v_LDO_PWR_DOWN(x)	BITS_MASK(x, 1, 1)
+#define v_PLL_PWR_DOWN(x)	BITS_MASK(x, 1, 2)
+
+#define MIPIPHY_REG3		0x000c
+#define m_PREDIV		GENMASK(4, 0)
+#define m_FBDIV_MSB		BIT(5)
+#define v_PREDIV(x)		BITS_MASK(x, 0x1f, 0)
+#define v_FBDIV_MSB(x)		BITS_MASK(x, 1, 5)
+
+#define MIPIPHY_REG4		0x0010
+#define v_FBDIV_LSB(x)		BITS_MASK(x, 0xff, 0)
+
+#define MIPIPHY_REGE0		0x0380
+#define m_MSB_SEL		BIT(0)
+#define m_DIG_INTER_RST		BIT(2)
+#define m_LVDS_MODE_EN		BIT(5)
+#define m_TTL_MODE_EN		BIT(6)
+#define m_MIPI_MODE_EN		BIT(7)
+#define v_MSB_SEL(x)		BITS_MASK(x, 1, 0)
+#define v_DIG_INTER_RST(x)	BITS_MASK(x, 1, 2)
+#define v_LVDS_MODE_EN(x)	BITS_MASK(x, 1, 5)
+#define v_TTL_MODE_EN(x)	BITS_MASK(x, 1, 6)
+#define v_MIPI_MODE_EN(x)	BITS_MASK(x, 1, 7)
+
+#define MIPIPHY_REGE1		0x0384
+#define m_DIG_INTER_EN		BIT(7)
+#define v_DIG_INTER_EN(x)	BITS_MASK(x, 1, 7)
+
+#define MIPIPHY_REGE3		0x038c
+#define m_MIPI_EN		BIT(0)
+#define m_LVDS_EN		BIT(1)
+#define m_TTL_EN		BIT(2)
+#define v_MIPI_EN(x)		BITS_MASK(x, 1, 0)
+#define v_LVDS_EN(x)		BITS_MASK(x, 1, 1)
+#define v_TTL_EN(x)		BITS_MASK(x, 1, 2)
+
+#define MIPIPHY_REGE4		0x0390
+#define m_VOCM			GENMASK(5, 4)
+#define m_DIFF_V		GENMASK(7, 6)
+
+#define v_VOCM(x)		BITS_MASK(x, 3, 4)
+#define v_DIFF_V(x)		BITS_MASK(x, 3, 6)
+
+#define MIPIPHY_REGE8		0x03a0
+
+#define MIPIPHY_REGEB		0x03ac
+#define v_PLL_PWR_OFF(x)	BITS_MASK(x, 1, 2)
+#define v_LANECLK_EN(x)		BITS_MASK(x, 1, 3)
+#define v_LANE3_EN(x)		BITS_MASK(x, 1, 4)
+#define v_LANE2_EN(x)		BITS_MASK(x, 1, 5)
+#define v_LANE1_EN(x)		BITS_MASK(x, 1, 6)
+#define v_LANE0_EN(x)		BITS_MASK(x, 1, 7)
+
+#define v_RK3368_LVDS_OUTPUT_FORMAT(x)	(BITS_MASK(x, 3, 13) | BITS_EN(3, 13))
+#define v_RK3368_LVDS_MSBSEL(x)		(BITS_MASK(x, 1, 11) | BITS_EN(1, 11))
+#define v_RK3368_LVDSMODE_EN(x)		(BITS_MASK(x, 1, 12) | BITS_EN(1, 12))
+#define v_RK3368_MIPIPHY_TTL_EN(x)	(BITS_MASK(x, 1, 15) | BITS_EN(1, 15))
+#define v_RK3368_MIPIPHY_LANE0_EN(x)	(BITS_MASK(x, 1, 5) | BITS_EN(1, 5))
+#define v_RK3368_MIPIDPI_FORCEX_EN(x)	(BITS_MASK(x, 1, 6) | BITS_EN(1, 6))
+#define v_RK3368_FORCE_JETAG(x)		(BITS_MASK(x, 1, 13) | BITS_EN(1, 13))
+
+enum {
+	LVDS_MSB_D0 = 0,
+	LVDS_MSB_D7,
+};
+
+enum rockchip_lvds_sub_devtype {
+	RK3288_LVDS,
+	RK3368_LVDS,
+};
+
 #endif /* _ROCKCHIP_LVDS_ */