[RK3399][Android7.1] 调试笔记 --- TC358775在uboot中的显示驱动patch

Platform: RK3399
OS: Android 7.1
Kernel: v4.4.83

二话不说,直接贴Patch.

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 432e3ff..934608f 100755
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -46,7 +46,7 @@ obj-$(CONFIG_ROCKCHIP_DISPLAY) += rockchip_display.o rockchip_crtc.o \
 			rockchip_phy.o
 obj-$(CONFIG_ROCKCHIP_VOP) += rockchip_vop.o rockchip_vop_reg.o
 obj-$(CONFIG_ROCKCHIP_MIPI_DSI)	+= rockchip_mipi_dsi.o
-obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += rockchip-dw-mipi-dsi.o rockchip-inno-mipi-dphy.o
+obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += rockchip_dsi.o rockchip-inno-mipi-dphy.o
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += rockchip_analogix_dp.o rockchip_analogix_dp_reg.o
 obj-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o
 obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi/
diff --git a/drivers/video/rockchip_connector.c b/drivers/video/rockchip_connector.c
index c09045c..1a86ef2 100644
--- a/drivers/video/rockchip_connector.c
+++ b/drivers/video/rockchip_connector.c
@@ -22,21 +22,21 @@
 static const struct rockchip_connector g_connector[] = {
 #ifdef CONFIG_ROCKCHIP_DW_MIPI_DSI
 	{
-	 .compatible = "rockchip,rk3288-mipi-dsi",
-	 .funcs = &rockchip_dw_mipi_dsi_funcs,
-	 .data = &rk3288_mipi_dsi_drv_data,
-	},{
-	 .compatible = "rockchip,rk3366-mipi-dsi",
-	 .funcs = &rockchip_dw_mipi_dsi_funcs,
-	 .data = &rk3366_mipi_dsi_drv_data,
-	},{
-	 .compatible = "rockchip,rk3368-mipi-dsi",
-	 .funcs = &rockchip_dw_mipi_dsi_funcs,
-	 .data = &rk3368_mipi_dsi_drv_data,
-	},{
-	 .compatible = "rockchip,rk3399-mipi-dsi",
-	 .funcs = &rockchip_dw_mipi_dsi_funcs,
-	 .data = &rk3399_mipi_dsi_drv_data,
+	 .compatible = "rockchip,rk3288-dsi",
+	 .funcs = &rockchip_dsi_connector_funcs,
+	 .data = &rk3288_dsi_soc_data,
+	}, {
+	 .compatible = "rockchip,rk3366-dsi",
+	 .funcs = &rockchip_dsi_connector_funcs,
+	 .data = &rk3366_dsi_soc_data,
+	}, {
+	 .compatible = "rockchip,rk3368-dsi",
+	 .funcs = &rockchip_dsi_connector_funcs,
+	 .data = &rk3368_dsi_soc_data,
+	}, {
+	 .compatible = "rockchip,rk3399-dsi",
+	 .funcs = &rockchip_dsi_connector_funcs,
+	 .data = &rk3399_dsi_soc_data,
 	},
 #endif
 #ifdef CONFIG_ROCKCHIP_ANALOGIX_DP
diff --git a/drivers/video/rockchip_connector.h b/drivers/video/rockchip_connector.h
index eb6c9f2..4bf3197 100644
--- a/drivers/video/rockchip_connector.h
+++ b/drivers/video/rockchip_connector.h
@@ -68,12 +68,12 @@ const struct rockchip_connector *
 rockchip_get_connector(const void *blob, int connector_node);
 
 #ifdef CONFIG_ROCKCHIP_DW_MIPI_DSI
-struct dw_mipi_dsi_plat_data;
-extern const struct rockchip_connector_funcs rockchip_dw_mipi_dsi_funcs;
-extern const struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data;
-extern const struct dw_mipi_dsi_plat_data rk3366_mipi_dsi_drv_data;
-extern const struct dw_mipi_dsi_plat_data rk3368_mipi_dsi_drv_data;
-extern const struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data;
+struct rockchip_dsi_soc_data;
+extern const struct rockchip_connector_funcs rockchip_dsi_connector_funcs;
+extern const struct rockchip_dsi_soc_data rk3288_dsi_soc_data;
+extern const struct rockchip_dsi_soc_data rk3366_dsi_soc_data;
+extern const struct rockchip_dsi_soc_data rk3368_dsi_soc_data;
+extern const struct rockchip_dsi_soc_data rk3399_dsi_soc_data;
 #endif
 #ifdef CONFIG_ROCKCHIP_ANALOGIX_DP
 struct rockchip_dp_chip_data;
diff --git a/drivers/video/rockchip_dsi.c b/drivers/video/rockchip_dsi.c
new file mode 100644
index 0000000..e76017d
--- /dev/null
+++ b/drivers/video/rockchip_dsi.c
@@ -0,0 +1,1643 @@
+/*
+ * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "rockchip_display.h"
+#include "rockchip_crtc.h"
+#include "rockchip_connector.h"
+#include "rockchip_phy.h"
+#include "rockchip_mipi_dsi.h"
+
+#define GRF_DESC(r, h, l)     ((r << 16) | (h << 8) | (l))
+
+#define IS_DSI0(dsi)	((dsi)->id == 0)
+#define IS_DSI1(dsi)	((dsi)->id == 1)
+
+/* DWC MIPI DSI Host Controller Register and Field Descriptions */
+#define DSI_VERSION			0x000
+#define DSI_PWR_UP			0x004
+#define RESET				0
+#define POWER_UP			BIT(0)
+#define DSI_CLKMGR_CFG			0x008
+#define TO_CLK_DIVIDSION_MASK		GENMASK(15, 8)
+#define TO_CLK_DIVIDSION(x)		UPDATE(x, 15, 8)
+#define TX_ESC_CLK_DIVIDSION_MASK	GENMASK(7, 0)
+#define TX_ESC_CLK_DIVIDSION(x)		UPDATE(x, 7, 0)
+#define DSI_DPI_VCID			0x00c
+#define DPI_VCID(x)			UPDATE(x, 1, 0)
+#define DSI_DPI_COLOR_CODING		0x010
+#define LOOSELY18_EN(x)			UPDATE(x, 8, 8)
+#define DPI_COLOR_CODING(x)		UPDATE(x, 3, 0)
+#define DSI_DPI_CFG_POL			0x014
+#define COLORM_ACTIVE_LOW		BIT(4)
+#define SHUTD_ACTIVE_LOW		BIT(3)
+#define HSYNC_ACTIVE_LOW		BIT(2)
+#define VSYNC_ACTIVE_LOW		BIT(1)
+#define DATAEN_ACTIVE_LOW		BIT(0)
+#define DSI_DPI_LP_CMD_TIM		0x018
+#define DSI_PCKHDL_CFG			0x02c
+#define CRC_RX_EN			BIT(4)
+#define ECC_RX_EN			BIT(3)
+#define BTA_EN				BIT(2)
+#define EOTP_RX_EN			BIT(1)
+#define EOTP_TX_EN_MASK			BIT(0)
+#define EOTP_TX_EN			BIT(0)
+#define DSI_GEN_VCID			0x030
+#define GEN_VCID_RX(x)			UPDATE(x, 1, 0)
+#define DSI_MODE_CFG			0x034
+#define COMMAND_MODE			BIT(0)
+#define VIDEO_MODE			0
+#define DSI_VID_MODE_CFG		0x038
+#define VPG_ORIENTATION(x)		UPDATE(x, 24, 24)
+#define VPG_MODE(x)			UPDATE(x, 20, 20)
+#define VPG_EN				BIT(16)
+#define LP_CMD_EN			BIT(15)
+#define FRAME_BTA_ACK_EN(x)		BIT(14)
+#define LP_HFP_EN			BIT(13)
+#define LP_HBP_EN			BIT(12)
+#define LP_VACT_EN			BIT(11)
+#define LP_VFP_EN			BIT(10)
+#define LP_VBP_EN			BIT(9)
+#define LP_VSA_EN			BIT(8)
+#define VID_MODE_TYPE(x)		UPDATE(x, 1, 0)
+#define NON_BURST_MODE_SYNC_PULSE	0
+#define NON_BURST_MODE_SYNC_EVENT	1
+#define BURST_MODE			2
+#define DSI_VID_PKT_SIZE		0x03c
+#define VID_PKT_SIZE(x)			UPDATE(x, 13, 0)
+#define DSI_VID_NUM_CHUMKS		0x040
+#define DSI_VID_NULL_PKT_SIZE		0x044
+#define DSI_VID_HSA_TIME		0x048
+#define VID_HSA_TIME(x)			UPDATE(x, 11, 0)
+#define DSI_VID_HBP_TIME		0x04c
+#define VID_HBP_TIME(x)			UPDATE(x, 11, 0)
+#define DSI_VID_HLINE_TIME		0x050
+#define VID_HLINE_TIME(x)		UPDATE(x, 14, 0)
+#define DSI_VID_VSA_LINES		0x054
+#define VSA_LINES(x)			UPDATE(x, 9, 0)
+#define DSI_VID_VBP_LINES		0x058
+#define VBP_LINES(x)			UPDATE(x, 9, 0)
+#define DSI_VID_VFP_LINES		0x05c
+#define VFP_LINES(x)			UPDATE(x, 9, 0)
+#define DSI_VID_VACTIVE_LINES		0x060
+#define V_ACTIVE_LINES(x)		UPDATE(x, 13, 0)
+#define DSI_CMD_MODE_CFG		0x068
+#define CMD_XFER_TYPE_MASK		0x010F7F00
+#define CMD_XFER_TYPE_LP		0x010F7F00
+#define CMD_XFER_TYPE_HS		0
+#define ACK_RQST_EN_MASK		BIT(1)
+#define ACK_RQST_EN			BIT(1)
+#define TEAR_FX_EN_MASK			BIT(0)
+#define TEAR_FX_EN			BIT(0)
+#define DSI_GEN_HDR			0x06c
+#define DSI_GEN_PLD_DATA		0x070
+#define DSI_CMD_PKT_STATUS		0x074
+#define GEN_RD_CMD_BUSY			BIT(6)
+#define GEN_PLD_R_FULL			BIT(5)
+#define GEN_PLD_R_EMPTY			BIT(4)
+#define GEN_PLD_W_FULL			BIT(3)
+#define GEN_PLD_W_EMPTY			BIT(2)
+#define GEN_CMD_FULL			BIT(1)
+#define GEN_CMD_EMPTY			BIT(0)
+#define DSI_TO_CNT_CFG			0x078
+#define HSTX_TO_CNT(x)			UPDATE(x, 31, 16)
+#define LPRX_TO_CNT(x)			UPDATE(x, 15, 0)
+#define DSI_HS_RD_TO_CNT		0x07c
+#define DSI_LP_RD_TO_CNT		0x080
+#define DSI_HS_WR_TO_CNT		0x084
+#define DSI_LP_WR_TO_CNT		0x088
+#define DSI_BTA_TO_CNT			0x08c
+#define DSI_LPCLK_CTRL			0x094
+#define AUTO_CLKLANE_CTRL_MASK		BIT(1)
+#define AUTO_CLKLANE_CTRL		BIT(1)
+#define PHY_TXREQUESTCLKHS_MASK		BIT(0)
+#define PHY_TXREQUESTCLKHS		BIT(0)
+#define DSI_PHY_TMR_LPCLK_CFG		0x098
+#define PHY_CLKHS2LP_TIME(x)		UPDATE(x, 25, 16)
+#define PHY_CLKLP2HS_TIME(x)		UPDATE(x, 9, 0)
+#define DSI_PHY_TMR_CFG			0x09c
+#define PHY_HS2LP_TIME(x)		UPDATE(x, 31, 24)
+#define PHY_LP2HS_TIME(x)		UPDATE(x, 23, 16)
+#define MAX_RD_TIME(x)			UPDATE(x, 14, 0)
+#define DSI_PHY_RSTZ			0x0a0
+#define PHY_ENABLECLK_MASK		BIT(2)
+#define PHY_ENABLECLK			BIT(2)
+#define PHY_RSTZ_MASK			BIT(1)
+#define PHY_RSTZ			BIT(1)
+#define PHY_SHUTDOWNZ_MASK		BIT(0)
+#define PHY_SHUTDOWNZ			BIT(0)
+#define DSI_PHY_IF_CFG			0x0a4
+#define PHY_STOP_WAIT_TIME(x)		UPDATE(x, 15, 8)
+#define N_LANES(x)			UPDATE(x, 1, 0)
+#define DSI_PHY_STATUS			0x0b0
+#define PHY_ULPSACTIVENOT3LANE		BIT(12)
+#define PHY_STOPSTATE3LANE		BIT(11)
+#define PHY_ULPSACTIVENOT2LANE		BIT(10)
+#define PHY_STOPSTATE2LANE		BIT(9)
+#define PHY_ULPSACTIVENOT1LANE		BIT(8)
+#define PHY_STOPSTATE1LANE		BIT(7)
+#define PHY_ULPSACTIVENOT0LANE		BIT(5)
+#define PHY_STOPSTATE0LANE		BIT(4)
+#define PHY_ULPSACTIVENOTCLK		BIT(3)
+#define PHY_STOPSTATECLKLANE		BIT(2)
+#define PHY_DIRECTION			BIT(1)
+#define PHY_LOCK			BIT(0)
+#define PHY_STOPSTATELANE		(PHY_STOPSTATE0LANE | \
+					 PHY_STOPSTATECLKLANE)
+#define DSI_PHY_TST_CTRL0		0x0b4
+#define PHY_TESTCLK_MASK		BIT(1)
+#define PHY_TESTCLK			BIT(1)
+#define PHY_TESTCLR_MASK		BIT(0)
+#define PHY_TESTCLR			BIT(0)
+#define DSI_PHY_TST_CTRL1		0x0b8
+#define PHY_TESTEN_MASK			BIT(16)
+#define PHY_TESTEN			BIT(16)
+#define PHY_TESTDOUT_SHIFT		8
+#define PHY_TESTDIN_MASK		GENMASK(7, 0)
+#define PHY_TESTDIN(x)			UPDATE(x, 7, 0)
+#define DSI_INT_ST0			0x0bc
+#define DSI_INT_ST1			0x0c0
+#define DSI_INT_MSK0			0x0c4
+#define DSI_INT_MSK1			0x0c8
+
+/* PLL Bias Current Selector/Filter Capacitance Control/VCO Control */
+#define VCO_RANGE_PROGRAM_EN	BIT(7)
+#define VCO_RANGE_CTRL(x)	UPDATE(x, 5, 3)
+#define VCO_INTER_CAP_CTRL(x)	UPDATE(x, 2, 1)
+/* PLL CP Control / PLL Lock Bypass for Initialization and for ULP */
+#define CP_CURRENT(x)		UPDATE(x, 3, 0)
+/* PLL LPF and CP Control */
+#define CP_PROGRAM_EN		BIT(7)
+#define LPF_PROGRAM_EN		BIT(6)
+#define LPF_RESISTORS(x)	UPDATE(x, 5, 0)
+/* PLL Input Divider Ratio */
+#define INPUT_DIV(x)		UPDATE(x, 6, 0)
+/* PLL Loop Divider Ratio */
+#define LOW_PROGRAM_EN		0
+#define HIGH_PROGRAM_EN		BIT(7)
+#define LOOP_DIV_4_0(x)		UPDATE(x, 4, 0)
+#define LOOP_DIV_8_5(x)		UPDATE(x, 3, 0)
+/* PLL Input and Loop Divider Ratios Control */
+#define LOOP_DIV_PROGRAM_EN	BIT(5)
+#define INPUT_DIV_PROGRAM_EN	BIT(4)
+/* Bandgap and Bias Control */
+#define OVERRIDE_ENBALE		BIT(6)
+#define BIAS_BLOCK_POWER_ON	BIT(2)
+#define BANDGAP_POWER_ON	BIT(0)
+/* AFE/BIAS/Bandgap Analog Programmability */
+#define ANA_CIR_1500_MBPS_EN	BIT(4)
+#define BIASEXTR_INTER_RES(x)	UPDATE(x, 2, 0)
+#define BANDGAP_REF_VOL(x)	UPDATE(x, 2, 0)
+/* HS operating frequency range selection */
+#define HSFREQRANGE(x)		UPDATE(x, 6, 1)
+
+enum {
+	PIXEL_COLOR_CODING_16BIT_1,
+	PIXEL_COLOR_CODING_16BIT_2,
+	PIXEL_COLOR_CODING_16BIT_3,
+	PIXEL_COLOR_CODING_18BIT_1,
+	PIXEL_COLOR_CODING_18BIT_2,
+	PIXEL_COLOR_CODING_24BIT,
+};
+
+enum grf_index {
+	DPIUPDATECFG,
+	DPISHUTDN,
+	DPICOLORM,
+	VOPSEL,
+	TURNREQUEST,
+	TURNDISABLE,
+	FORCETXSTOPMODE,
+	FORCERXMODE,
+	ENABLE_N,
+	MASTERSLAVEZ,
+	ENABLECLK,
+	BASEDIR,
+	NUM_GRF_DESC,
+};
+
+struct mipi_dphy {
+	/* Non-SNPS PHY */
+	const struct rockchip_phy *phy;
+
+	/* SNPS PHY */
+	struct {
+		u8 prediv;	/* PLL Input Divider Ratio */
+		u16 fbdiv;	/* PLL Loop Divider Ratio */
+		u8 vcorange;	/* VCO Range Selection */
+		u8 icpctrl;	/* Charge Pump Current Control */
+		u8 lpfctrl;	/* Loop Filter Zero Control */
+		u8 vcocap;	/* VCO Internal Capacitance Control */
+	} pll;
+};
+
+struct rockchip_dsi_soc_data {
+	unsigned int min_bit_rate_per_lane;
+	unsigned int max_bit_rate_per_lane;
+	const u32 **grf_descs;
+};
+
+struct rockchip_dsi {
+	const void *blob;
+	int node;
+	u32 regs;
+	int id;
+
+	struct mipi_dphy dphy;
+	unsigned int lane_mbps;
+	unsigned int channel;
+	unsigned int lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+
+	struct rockchip_dsi *master;
+	struct rockchip_dsi *slave;
+
+	/* for external bridge support */
+	struct fdt_gpio_state enable_gpio;
+	struct fdt_gpio_state reset_gpio;
+
+	const u32 *desc;
+	const struct rockchip_dsi_soc_data *soc_data;
+};
+
+/* Table 5-1 Frequency Ranges */
+static const struct {
+	unsigned long maxfreq;
+	u8 hsfreqrange;
+} hsfreqrange_table[] = {
+	{  90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
+	{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
+	{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
+	{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
+	{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
+	{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
+	{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
+	{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
+	{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
+	{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
+};
+
+/* Table 6-4 PLL CP and LPF Control Bits */
+static const struct {
+	unsigned long maxfreq;
+	u8 vcorange;
+	u8 icpctrl;
+	u8 lpfctrl;
+	u8 vcocap;
+} pll_cfg_table[] = {
+	{ 110, 0x0, 0x1, 0x02, 0x0},
+	{ 150, 0x0, 0x1, 0x01, 0x0},
+	{ 200, 0x0, 0x9, 0x02, 0x0},
+	{ 250, 0x1, 0x2, 0x02, 0x0},
+	{ 300, 0x1, 0x9, 0x04, 0x0},
+	{ 400, 0x2, 0x1, 0x01, 0x0},
+	{ 500, 0x2, 0x6, 0x04, 0x0},
+	{ 600, 0x3, 0x6, 0x08, 0x0},
+	{ 700, 0x3, 0x6, 0x04, 0x0},
+	{ 900, 0x4, 0x6, 0x04, 0x0},
+	{1100, 0x5, 0xb, 0x10, 0x0},
+	{1300, 0x6, 0xb, 0x08, 0x0},
+	{1500, 0x7, 0xb, 0x08, 0x0},
+};
+
+#define HSTT(_maxfreq, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp)	\
+{	\
+	.maxfreq = _maxfreq,	\
+	.clk_lane = {	\
+		.lp2hs = _c_lp2hs,	\
+		.hs2lp = _c_hs2lp,	\
+	},	\
+	.data_lane = {	\
+		.lp2hs = _d_lp2hs,	\
+		.hs2lp = _d_hs2lp,	\
+	},	\
+}
+
+/* Table A-3 High-Speed Transition Times */
+static const struct {
+	unsigned int maxfreq;
+	struct {
+		u16 lp2hs;
+		u16 hs2lp;
+	} clk_lane;
+	struct {
+		u8 lp2hs;
+		u8 hs2lp;
+	} data_lane;
+} hstt_table[] = {
+	HSTT(  90,  32, 20,  26, 13), HSTT( 100,  35, 23,  28, 14),
+	HSTT( 110,  32, 22,  26, 13), HSTT( 130,  31, 20,  27, 13),
+	HSTT( 140,  33, 22,  26, 14), HSTT( 150,  33, 21,  26, 14),
+	HSTT( 170,  32, 20,  27, 13), HSTT( 180,  36, 23,  30, 15),
+	HSTT( 200,  40, 22,  33, 15), HSTT( 220,  40, 22,  33, 15),
+	HSTT( 240,  44, 24,  36, 16), HSTT( 250,  48, 24,  38, 17),
+	HSTT( 270,  48, 24,  38, 17), HSTT( 300,  50, 27,  41, 18),
+	HSTT( 330,  56, 28,  45, 18), HSTT( 360,  59, 28,  48, 19),
+	HSTT( 400,  61, 30,  50, 20), HSTT( 450,  67, 31,  55, 21),
+	HSTT( 500,  73, 31,  59, 22), HSTT( 550,  79, 36,  63, 24),
+	HSTT( 600,  83, 37,  68, 25), HSTT( 650,  90, 38,  73, 27),
+	HSTT( 700,  95, 40,  77, 28), HSTT( 750, 102, 40,  84, 28),
+	HSTT( 800, 106, 42,  87, 30), HSTT( 850, 113, 44,  93, 31),
+	HSTT( 900, 118, 47,  98, 32), HSTT( 950, 124, 47, 102, 34),
+	HSTT(1000, 130, 49, 107, 35), HSTT(1050, 135, 51, 111, 37),
+	HSTT(1100, 139, 51, 114, 38), HSTT(1150, 146, 54, 120, 40),
+	HSTT(1200, 153, 57, 125, 41), HSTT(1250, 158, 58, 130, 42),
+	HSTT(1300, 163, 58, 135, 44), HSTT(1350, 168, 60, 140, 45),
+	HSTT(1400, 172, 64, 144, 47), HSTT(1450, 176, 65, 148, 48),
+	HSTT(1500, 181, 66, 153, 50)
+};
+
+static inline void dsi_write(struct rockchip_dsi *dsi, u32 reg, u32 val)
+{
+	writel(val, dsi->regs + reg);
+}
+
+static inline u32 dsi_read(struct rockchip_dsi *dsi, u32 reg)
+{
+	return readl(dsi->regs + reg);
+}
+
+static inline void dsi_update_bits(struct rockchip_dsi *dsi, u32 reg,
+				   u32 mask, u32 val)
+{
+	u32 tmp, orig;
+
+	orig = dsi_read(dsi, reg);
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+	dsi_write(dsi, reg, tmp);
+}
+
+static void grf_write(struct rockchip_dsi *dsi, enum grf_index index, u32 val)
+{
+	const u32 desc = dsi->desc[index];
+	u16 reg;
+	u8 h, l;
+
+	if (!desc)
+		return;
+
+	reg = (desc >> 16) & 0xffff;
+	h = (desc >> 8) & 0xff;
+	l = desc & 0xff;
+
+	writel(HIWORD_UPDATE(val, h, l), RKIO_GRF_PHYS + reg);
+}
+
+static u8 get_hsfreqrange(unsigned long freq)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hsfreqrange_table); i++)
+		if (freq < hsfreqrange_table[i].maxfreq)
+			return hsfreqrange_table[i].hsfreqrange;
+
+	return hsfreqrange_table[i-1].hsfreqrange;
+}
+
+static inline int get_bpp(enum mipi_dsi_pixel_format fmt)
+{
+	switch (fmt) {
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return 18;
+	case MIPI_DSI_FMT_RGB565:
+		return 16;
+	case MIPI_DSI_FMT_RGB666:
+	case MIPI_DSI_FMT_RGB888:
+	default:
+		return 24;
+	}
+}
+
+static inline void ppi_txrequestclkhs_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS_MASK,
+			PHY_TXREQUESTCLKHS);
+	udelay(1);
+}
+
+static inline void ppi_txrequestclkhs_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS_MASK, 0);
+	udelay(1);
+}
+
+static int ppi_wait_stopstatelane_assert(struct rockchip_dsi *dsi)
+{
+	u32 v, m = PHY_STOPSTATELANE;
+
+	return readl_poll_timeout(dsi->regs + DSI_PHY_STATUS,
+				  v, (v & m) == m, 1, USEC_PER_MSEC);
+}
+
+static inline void ppi_turnrequest_deassert(struct rockchip_dsi *dsi)
+{
+	grf_write(dsi, TURNREQUEST, 0);
+}
+
+static inline void ppi_turnrequest_assert(struct rockchip_dsi *dsi)
+{
+	grf_write(dsi, TURNREQUEST, 1);
+}
+
+static inline void ppi_request_deassert(struct rockchip_dsi *dsi)
+{
+	grf_write(dsi, TURNREQUEST, 0);
+	grf_write(dsi, TURNDISABLE, 0);
+	grf_write(dsi, FORCETXSTOPMODE, 0);
+	grf_write(dsi, FORCERXMODE, 0);
+}
+
+static inline void ppi_basedir_deassert(struct rockchip_dsi *dsi)
+{
+	grf_write(dsi, BASEDIR, 0);
+}
+
+static inline void genif_vcid_init(struct rockchip_dsi *dsi, u8 vcid)
+{
+	dsi_write(dsi, DSI_GEN_VCID, GEN_VCID_RX(vcid));
+}
+
+static int genif_wait_w_pld_fifo_not_full(struct rockchip_dsi *dsi)
+{
+	u32 v, m = GEN_PLD_W_FULL;
+
+	return readl_poll_timeout(dsi->regs + DSI_CMD_PKT_STATUS,
+				  v, !(v & m), 1, USEC_PER_MSEC);
+}
+
+static int genif_wait_cmd_fifo_not_full(struct rockchip_dsi *dsi)
+{
+	u32 v, m = GEN_CMD_FULL;
+
+	return readl_poll_timeout(dsi->regs + DSI_CMD_PKT_STATUS,
+				  v, !(v & m), 1, USEC_PER_MSEC);
+}
+
+static int genif_wait_w_fifo_is_empty(struct rockchip_dsi *dsi)
+{
+	u32 v, m = GEN_PLD_W_EMPTY | GEN_CMD_EMPTY;
+
+	return readl_poll_timeout(dsi->regs + DSI_CMD_PKT_STATUS,
+				  v, (v & m) == m, 1, USEC_PER_MSEC);
+}
+
+static int genif_wait_rd_cmd_not_busy(struct rockchip_dsi *dsi)
+{
+	u32 v, m = GEN_RD_CMD_BUSY;
+
+	return readl_poll_timeout(dsi->regs + DSI_CMD_PKT_STATUS,
+				  v, !(v & m), 1, USEC_PER_MSEC);
+}
+
+static int genif_wait_r_pld_fifo_not_empty(struct rockchip_dsi *dsi)
+{
+	u32 v, m = GEN_PLD_R_EMPTY;
+
+	return readl_poll_timeout(dsi->regs + DSI_CMD_PKT_STATUS,
+				  v, !(v & m), 1, USEC_PER_MSEC);
+}
+
+static inline void testif_testclk_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK_MASK, PHY_TESTCLK);
+	udelay(1);
+}
+
+static inline void testif_testclk_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK_MASK, 0);
+	udelay(1);
+}
+
+static inline void testif_testclr_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR_MASK, PHY_TESTCLR);
+	udelay(1);
+}
+
+static inline void testif_testclr_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR_MASK, 0);
+	udelay(1);
+}
+
+static inline void testif_testen_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN_MASK, PHY_TESTEN);
+	udelay(1);
+}
+
+static inline void testif_testen_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN_MASK, 0);
+	udelay(1);
+}
+
+static inline void testif_set_data(struct rockchip_dsi *dsi, u8 data)
+{
+	dsi_update_bits(dsi, DSI_PHY_TST_CTRL1, PHY_TESTDIN_MASK,
+			PHY_TESTDIN(data));
+	udelay(1);
+}
+
+static inline u8 testif_get_data(struct rockchip_dsi *dsi)
+{
+	return dsi_read(dsi, DSI_PHY_TST_CTRL1) >> PHY_TESTDOUT_SHIFT;
+}
+
+static void testif_test_code_write(struct rockchip_dsi *dsi, u8 test_code)
+{
+	testif_testclk_assert(dsi);
+	testif_set_data(dsi, test_code);
+	testif_testen_assert(dsi);
+	testif_testclk_deassert(dsi);
+	testif_testen_deassert(dsi);
+}
+
+static void testif_test_data_write(struct rockchip_dsi *dsi, u8 test_data)
+{
+	testif_testclk_deassert(dsi);
+	testif_set_data(dsi, test_data);
+	testif_testclk_assert(dsi);
+}
+
+static void testif_write(struct rockchip_dsi *dsi, u8 test_code, u8 test_data)
+{
+	testif_test_code_write(dsi, test_code);
+	testif_test_data_write(dsi, test_data);
+}
+
+static inline u8 testif_read(struct rockchip_dsi *dsi, u8 test_code)
+{
+	testif_test_code_write(dsi, test_code);
+
+	return testif_get_data(dsi);
+}
+
+static inline void mipi_dphy_enableclk_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_ENABLECLK_MASK, PHY_ENABLECLK);
+	udelay(1);
+}
+
+static inline void mipi_dphy_enableclk_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_ENABLECLK_MASK, 0);
+	udelay(1);
+}
+
+static inline void mipi_dphy_shutdownz_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_SHUTDOWNZ_MASK, 0);
+	udelay(1);
+}
+
+static inline void mipi_dphy_shutdownz_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_SHUTDOWNZ_MASK, PHY_SHUTDOWNZ);
+	udelay(1);
+}
+
+static inline void mipi_dphy_rstz_assert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_RSTZ_MASK, 0);
+	udelay(1);
+}
+
+static inline void mipi_dphy_rstz_deassert(struct rockchip_dsi *dsi)
+{
+	dsi_update_bits(dsi, DSI_PHY_RSTZ, PHY_RSTZ_MASK, PHY_RSTZ);
+	udelay(1);
+}
+
+static void mipi_dphy_hstt_config(struct rockchip_dsi *dsi)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hstt_table); i++)
+		if (dsi->lane_mbps < hstt_table[i].maxfreq)
+			break;
+
+	if (i == ARRAY_SIZE(hstt_table))
+		--i;
+
+	dsi_write(dsi, DSI_PHY_TMR_CFG,
+		  PHY_HS2LP_TIME(hstt_table[i].data_lane.hs2lp) |
+		  PHY_LP2HS_TIME(hstt_table[i].data_lane.lp2hs) |
+		  MAX_RD_TIME(0x7fff));
+	dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG,
+		  PHY_CLKHS2LP_TIME(hstt_table[i].clk_lane.hs2lp) |
+		  PHY_CLKLP2HS_TIME(hstt_table[i].clk_lane.lp2hs));
+}
+
+static inline void mipi_dphy_if_config(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_PHY_IF_CFG, N_LANES(dsi->lanes - 1) |
+		  PHY_STOP_WAIT_TIME(0x20));
+}
+
+static inline void mipi_dphy_masterslavez_assert(struct rockchip_dsi *dsi)
+{
+	grf_write(dsi, MASTERSLAVEZ, 1);
+}
+
+static inline void mipi_dphy_enable_n_assert(struct rockchip_dsi *dsi,
+					     unsigned int lanes)
+{
+	u32 map[] = {0x1, 0x3, 0x7, 0xf};
+
+	grf_write(dsi, ENABLE_N, map[lanes - 1]);
+}
+
+static void mipi_dphy_pll_get_param(struct mipi_dphy *dphy, unsigned long freq)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pll_cfg_table); i++)
+		if (freq < pll_cfg_table[i].maxfreq)
+			break;
+
+	dphy->pll.vcorange = pll_cfg_table[i].vcorange;
+	dphy->pll.icpctrl = pll_cfg_table[i].icpctrl;
+	dphy->pll.lpfctrl = pll_cfg_table[i].lpfctrl;
+	dphy->pll.vcocap = pll_cfg_table[i].vcocap;
+}
+
+static void mipi_dphy_pll_configure(struct rockchip_dsi *dsi)
+{
+	struct mipi_dphy *dphy = &dsi->dphy;
+	u8 n;
+	u16 m;
+	u8 test_code, test_data;
+
+	mipi_dphy_pll_get_param(dphy, dsi->lane_mbps);
+
+	/* make the previously configured N and M factors effective */
+	test_code = 0x19;
+	test_data = LOOP_DIV_PROGRAM_EN | INPUT_DIV_PROGRAM_EN;
+	testif_write(dsi, test_code, test_data);
+
+	
+
+	/* PLL Input Divider Ratio */
+	n = dphy->pll.prediv - 1;
+	test_code = 0x17;
+	test_data = INPUT_DIV(n);
+	testif_write(dsi, test_code, test_data);
+	/* PLL Loop Divider Ratio */
+	m = dphy->pll.fbdiv - 1;
+	test_code = 0x18;
+	test_data = LOOP_DIV_4_0(m) | LOW_PROGRAM_EN;
+	testif_write(dsi, test_code, test_data);
+	test_code = 0x18;
+	test_data = LOOP_DIV_8_5(m >> 5) | HIGH_PROGRAM_EN;
+	testif_write(dsi, test_code, test_data);
+
+	/* VCO Control (vcorange and vcocap) */
+	test_code = 0x10;
+	test_data = VCO_RANGE_PROGRAM_EN | VCO_RANGE_CTRL(dphy->pll.vcorange) |
+		    VCO_INTER_CAP_CTRL(dphy->pll.vcocap);
+	testif_write(dsi, test_code, test_data);
+	/* PLL Control (icpctrl) */
+	test_code = 0x11;
+	test_data = CP_CURRENT(dphy->pll.icpctrl);
+	testif_write(dsi, test_code, test_data);
+	/* PLL Control (lpfctrl) */
+	test_code = 0x12;
+	test_data = CP_PROGRAM_EN | LPF_PROGRAM_EN |
+		    LPF_RESISTORS(dphy->pll.lpfctrl);
+	testif_write(dsi, test_code, test_data);
+}
+
+static void mipi_dphy_configure(struct rockchip_dsi *dsi)
+{
+	u8 hsfreqrange;
+	u8 test_code, test_data;
+
+	/* HS frequency range selection */
+	hsfreqrange = get_hsfreqrange(dsi->lane_mbps);
+	test_code = 0x44;
+	test_data = HSFREQRANGE(hsfreqrange);
+	testif_write(dsi, test_code, test_data);
+
+	if (IS_DSI0(dsi))
+		mipi_dphy_pll_configure(dsi);
+
+	/* AFE/BIAS/Bandgap Analog Programmability */
+	test_code = 0x22;
+	test_data = LOW_PROGRAM_EN | BIASEXTR_INTER_RES(0x3);
+	testif_write(dsi, test_code, test_data);
+	test_code = 0x22;
+	test_data = HIGH_PROGRAM_EN | BANDGAP_REF_VOL(0x3);
+	if (dsi->lane_mbps > 1000)
+		test_data |= ANA_CIR_1500_MBPS_EN;
+	testif_write(dsi, test_code, test_data);
+}
+
+static void mipi_dphy_power_off(struct display_state *state,
+				struct rockchip_dsi *dsi)
+{
+	if (dsi->dphy.phy)
+		rockchip_phy_power_off(state);
+}
+
+static int mipi_dphy_power_on(struct display_state *state,
+			      struct rockchip_dsi *dsi)
+{
+	u32 status;
+	int ret;
+
+	mipi_dphy_shutdownz_deassert(dsi);
+	mipi_dphy_rstz_deassert(dsi);
+	mdelay(2);
+
+	if (dsi->dphy.phy)
+		rockchip_phy_power_on(state);
+
+	ret = readl_poll_timeout(dsi->regs + DSI_PHY_STATUS, status,
+				 status & PHY_LOCK, 50, USEC_PER_MSEC);
+	if (ret < 0) {
+		printf("PHY is not locked\n");
+		return ret;
+	}
+
+	udelay(200);
+
+	ret = ppi_wait_stopstatelane_assert(dsi);
+	if (ret) {
+		printf("lane module is not in stop state\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mipi_dphy_init(struct rockchip_dsi *dsi)
+{
+	mipi_dphy_shutdownz_assert(dsi);
+	mipi_dphy_rstz_assert(dsi);
+	testif_testclr_assert(dsi);
+	udelay(1);
+
+	mipi_dphy_masterslavez_assert(dsi);
+	ppi_basedir_deassert(dsi);
+	ppi_request_deassert(dsi);
+	udelay(1);
+
+	testif_testclr_deassert(dsi);
+
+	if (!dsi->dphy.phy)
+		mipi_dphy_configure(dsi);
+
+	mipi_dphy_enable_n_assert(dsi, dsi->lanes);
+	mipi_dphy_enableclk_assert(dsi);
+}
+
+static unsigned long mipi_dphy_pll_round_rate(unsigned long fin,
+					      unsigned long fout,
+					      u8 *prediv, u16 *fbdiv)
+{
+	unsigned long best_freq = 0;
+	unsigned long fvco_min, fvco_max;
+	u8 min_prediv, max_prediv;
+	u8 _prediv, best_prediv = 0;
+	u16 _fbdiv, best_fbdiv = 0;
+	u32 min_delta = 0xffffffff;
+
+	fin /= USEC_PER_SEC;
+	fout /= USEC_PER_SEC;
+
+	min_prediv = DIV_ROUND_UP(fin, 40);
+	max_prediv = fin / 5;
+	fvco_min = 80;
+	fvco_max = 1500;
+
+	for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
+		u32 tmp;
+		u32 delta;
+
+		_fbdiv = fout * _prediv / fin;
+		if (_fbdiv < 12 || _fbdiv > 1000)
+			continue;
+
+		if (_fbdiv % 2)
+			++_fbdiv;
+
+		tmp = _fbdiv * fin / _prediv;
+		if (tmp < fvco_min || tmp > fvco_max)
+			continue;
+
+		delta = abs(fout - tmp);
+		if (delta < min_delta) {
+			best_prediv = _prediv;
+			best_fbdiv = _fbdiv;
+			min_delta = delta;
+			best_freq = tmp;
+		}
+	}
+
+	if (best_freq) {
+		*prediv = best_prediv;
+		*fbdiv = best_fbdiv;
+	}
+
+	return best_freq * USEC_PER_SEC;
+}
+
+static inline void dsi_host_power_up(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_PWR_UP, POWER_UP);
+}
+
+static inline void dsi_host_reset(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_PWR_UP, RESET);
+}
+
+static inline void dsi_host_set_vid_mode(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_MODE_CFG, VIDEO_MODE);
+}
+
+static inline void dsi_host_set_cmd_mode(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_MODE_CFG, COMMAND_MODE);
+}
+
+static inline void dsi_host_err_to_timer_init(struct rockchip_dsi *dsi)
+{
+
+	dsi_update_bits(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION_MASK,
+			TO_CLK_DIVIDSION(10));
+	dsi_write(dsi, DSI_TO_CNT_CFG, 0xffffffff);
+}
+
+static inline void dsi_host_escclk_init(struct rockchip_dsi *dsi)
+{
+	u32 lanebyteclk = dsi->lane_mbps >> 3;
+	u32 esc_clk_div;
+
+	esc_clk_div = DIV_ROUND_UP(lanebyteclk, 20);
+
+	dsi_update_bits(dsi, DSI_CLKMGR_CFG, TX_ESC_CLK_DIVIDSION_MASK,
+			TX_ESC_CLK_DIVIDSION(esc_clk_div));
+}
+
+static inline void dsi_host_interrupt_init(struct rockchip_dsi *dsi)
+{
+	dsi_read(dsi, DSI_INT_ST0);
+	dsi_read(dsi, DSI_INT_ST1);
+	dsi_write(dsi, DSI_INT_MSK0, 0);
+	dsi_write(dsi, DSI_INT_MSK1, 0);
+}
+
+static inline void dsi_host_presp_to_counter_init(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_BTA_TO_CNT, 0);
+	dsi_write(dsi, DSI_LP_WR_TO_CNT, 0);
+	dsi_write(dsi, DSI_HS_WR_TO_CNT, 0);
+	dsi_write(dsi, DSI_LP_RD_TO_CNT, 0);
+	dsi_write(dsi, DSI_HS_RD_TO_CNT, 0);
+}
+
+static inline void dsi_host_pkthdl_init(struct rockchip_dsi *dsi)
+{
+	dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN);
+}
+
+static int dsi_host_read_from_fifo(struct rockchip_dsi *dsi,
+				   const struct mipi_dsi_msg *msg)
+{
+	u8 *payload = msg->rx_buf;
+	u16 length;
+	u32 val;
+	int ret;
+
+	ret = genif_wait_rd_cmd_not_busy(dsi);
+	if (ret) {
+		printf("entire response is not stored in the FIFO\n");
+		return ret;
+	}
+
+	/* Receive payload */
+	for (length = msg->rx_len; length; length -= 4) {
+		ret = genif_wait_r_pld_fifo_not_empty(dsi);
+		if (ret) {
+			printf("%s: read payload FIFO is empty\n", __func__);
+			return ret;
+		}
+
+		val = dsi_read(dsi, DSI_GEN_PLD_DATA);
+
+		switch (length) {
+		case 3:
+			payload[2] = (val >> 16) & 0xff;
+			/* Fall through */
+		case 2:
+			payload[1] = (val >> 8) & 0xff;
+			/* Fall through */
+		case 1:
+			payload[0] = val & 0xff;
+			return 0;
+		}
+
+		payload[0] = (val >>  0) & 0xff;
+		payload[1] = (val >>  8) & 0xff;
+		payload[2] = (val >> 16) & 0xff;
+		payload[3] = (val >> 24) & 0xff;
+		payload += 4;
+	}
+
+	return 0;
+}
+
+static void dsi_host_vid_mode_timing_config(struct rockchip_dsi *dsi,
+					    struct drm_display_mode *mode)
+
+{
+	unsigned int lanebyteclk = dsi->lane_mbps >> 3;
+	unsigned long dpipclk = mode->clock / MSEC_PER_SEC;
+	u32 htotal, hactive, hsa, hbp;
+	u32 vactive, vsa, vfp, vbp;
+	u32 hsa_time, hbp_time, hline_time;
+
+	vactive = mode->vdisplay;
+	vsa = mode->vsync_end - mode->vsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+
+	dsi_write(dsi, DSI_VID_VACTIVE_LINES, V_ACTIVE_LINES(vactive));
+	dsi_write(dsi, DSI_VID_VSA_LINES, VSA_LINES(vsa));
+	dsi_write(dsi, DSI_VID_VFP_LINES, VFP_LINES(vfp));
+	dsi_write(dsi, DSI_VID_VBP_LINES, VBP_LINES(vbp));
+
+	htotal = mode->htotal;
+	hactive = mode->hdisplay;
+	hsa = mode->hsync_end - mode->hsync_start;
+	hbp = mode->htotal - mode->hsync_end;
+
+	hline_time = DIV_ROUND_CLOSEST(htotal * lanebyteclk, dpipclk);
+	dsi_write(dsi, DSI_VID_HLINE_TIME, VID_HLINE_TIME(hline_time));
+	hsa_time = DIV_ROUND_CLOSEST(hsa * lanebyteclk, dpipclk);
+	dsi_write(dsi, DSI_VID_HSA_TIME, VID_HSA_TIME(hsa_time));
+	hbp_time = DIV_ROUND_CLOSEST(hbp * lanebyteclk, dpipclk);
+	dsi_write(dsi, DSI_VID_HBP_TIME, VID_HBP_TIME(hbp_time));
+
+	if (dsi->slave || dsi->master)
+		dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(hactive / 2));
+	else
+		dsi_write(dsi, DSI_VID_PKT_SIZE, VID_PKT_SIZE(hactive));
+}
+
+static void dsi_host_vid_mode_config(struct rockchip_dsi *dsi,
+				     struct drm_display_mode *mode)
+{
+	u32 val;
+	int prop;
+
+	dsi_host_vid_mode_timing_config(dsi, mode);
+
+	val = LP_VACT_EN | LP_VFP_EN | LP_VBP_EN | LP_VSA_EN;
+
+	if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP))
+		val |= LP_HFP_EN;
+	if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP))
+		val |= LP_HBP_EN;
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+		val |= VID_MODE_TYPE(BURST_MODE);
+	else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+		val |= VID_MODE_TYPE(NON_BURST_MODE_SYNC_PULSE);
+	else
+		val |= VID_MODE_TYPE(NON_BURST_MODE_SYNC_EVENT);
+
+	prop = fdtdec_get_int(dsi->blob, dsi->node, "snps,vpg-orientation", -1);
+	if (prop >= 0)
+		val |= VPG_ORIENTATION(prop) | VPG_EN;
+
+	prop = fdtdec_get_int(dsi->blob, dsi->node, "snps,vpg-mode", -1);
+	if (prop >= 0)
+		val |= VPG_MODE(prop) | VPG_EN;
+
+	dsi_write(dsi, DSI_VID_MODE_CFG, val);
+
+	if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+		dsi_update_bits(dsi, DSI_LPCLK_CTRL, AUTO_CLKLANE_CTRL_MASK,
+				AUTO_CLKLANE_CTRL);
+
+	if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET))
+		dsi_update_bits(dsi, DSI_PCKHDL_CFG, EOTP_TX_EN_MASK,
+				EOTP_TX_EN);
+}
+
+static void dsi_host_init(struct rockchip_dsi *dsi)
+{
+	dsi_host_presp_to_counter_init(dsi);
+	dsi_host_err_to_timer_init(dsi);
+	dsi_host_escclk_init(dsi);
+	dsi_host_set_cmd_mode(dsi);
+	dsi_host_pkthdl_init(dsi);
+	genif_vcid_init(dsi, dsi->channel);
+	dsi_host_interrupt_init(dsi);
+}
+
+static void dpi_color_coding_config(struct rockchip_dsi *dsi,
+				    enum mipi_dsi_pixel_format format)
+{
+	u8 color_coding;
+	bool loosely18_en = false;
+	u32 val;
+
+	switch (format) {
+	case MIPI_DSI_FMT_RGB666:
+		color_coding = PIXEL_COLOR_CODING_18BIT_2;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		color_coding = PIXEL_COLOR_CODING_18BIT_1;
+		loosely18_en = true;
+		break;
+	case MIPI_DSI_FMT_RGB565:
+		color_coding = PIXEL_COLOR_CODING_16BIT_1;
+		break;
+	case MIPI_DSI_FMT_RGB888:
+	default:
+		color_coding = PIXEL_COLOR_CODING_24BIT;
+		break;
+	}
+
+	val = LOOSELY18_EN(loosely18_en) | DPI_COLOR_CODING(color_coding);
+	dsi_write(dsi, DSI_DPI_COLOR_CODING, val);
+}
+
+static inline void dpi_vcid_config(struct rockchip_dsi *dsi, u8 vcid)
+{
+	dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(vcid));
+}
+
+static void dpi_pol_config(struct rockchip_dsi *dsi,
+			   struct drm_display_mode *mode)
+{
+	u32 val = 0;
+
+	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		val |= VSYNC_ACTIVE_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		val |= HSYNC_ACTIVE_LOW;
+	if (mode->flags & DRM_MODE_FLAG_NCSYNC)
+		val |= DATAEN_ACTIVE_LOW;
+
+	dsi_write(dsi, DSI_DPI_CFG_POL, val);
+}
+
+static void dpi_config(struct rockchip_dsi *dsi, struct drm_display_mode *mode)
+{
+	dpi_color_coding_config(dsi, dsi->format);
+	dpi_pol_config(dsi, mode);
+	dpi_vcid_config(dsi, dsi->channel);
+}
+
+static ssize_t rockchip_dsi_connector_transfer(struct display_state *state,
+					       const struct mipi_dsi_msg *msg)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+	struct mipi_dsi_packet packet;
+	u32 val;
+	int ret;
+
+	ret = mipi_dsi_create_packet(&packet, msg);
+	if (ret) {
+		printf("failed to create packet\n");
+		return ret;
+	}
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_LPM) {
+		val = CMD_XFER_TYPE_LP;
+	} else {
+		val = CMD_XFER_TYPE_HS;
+		ppi_txrequestclkhs_assert(dsi);
+	}
+
+	dsi_update_bits(dsi, DSI_CMD_MODE_CFG, CMD_XFER_TYPE_MASK, val);
+
+	while (packet.payload_length >= 4) {
+		ret = genif_wait_w_pld_fifo_not_full(dsi);
+		if (ret) {
+			printf("%s: write payload FIFO is full\n", __func__);
+			return ret;
+		}
+		val = get_unaligned_le32(packet.payload);
+		dsi_write(dsi, DSI_GEN_PLD_DATA, val);
+		packet.payload += 4;
+		packet.payload_length -= 4;
+	}
+
+	val = 0;
+	switch (packet.payload_length) {
+	case 3:
+		val |= packet.payload[2] << 16;
+		/* Fall through */
+	case 2:
+		val |= packet.payload[1] << 8;
+		/* Fall through */
+	case 1:
+		val |= packet.payload[0];
+		dsi_write(dsi, DSI_GEN_PLD_DATA, val);
+		break;
+	}
+
+	ret = genif_wait_cmd_fifo_not_full(dsi);
+	if (ret) {
+		printf("%s: command FIFO is full\n", __func__);
+		return ret;
+	}
+
+	val = get_unaligned_le32(packet.header);
+	dsi_write(dsi, DSI_GEN_HDR, val);
+
+	ret = genif_wait_w_fifo_is_empty(dsi);
+	if (ret) {
+		printf("%s: write payload FIFO is not empty\n", __func__);
+		return ret;
+	}
+
+	if (msg->rx_len) {
+		ppi_turnrequest_assert(dsi);
+		ret = dsi_host_read_from_fifo(dsi, msg);
+		if (ret)
+			return ret;
+		ppi_turnrequest_deassert(dsi);
+	}
+
+	return 0;
+}
+
+static void rockchip_dsi_vop_routing(struct rockchip_dsi *dsi, int pipe)
+{
+	grf_write(dsi, VOPSEL, pipe);
+	if (dsi->slave)
+		grf_write(dsi->slave, VOPSEL, pipe);
+}
+
+static void rockchip_dsi_external_bridge_parse_dt(struct rockchip_dsi *dsi)
+{
+	fdtdec_decode_gpio(dsi->blob, dsi->node, "enable-gpios",
+			   &dsi->enable_gpio);
+	fdtdec_decode_gpio(dsi->blob, dsi->node, "reset-gpios",
+			   &dsi->reset_gpio);
+}
+
+static void rockchip_dsi_external_bridge_power_off(struct rockchip_dsi *dsi)
+{
+	struct fdt_gpio_state *enable_gpio = &dsi->enable_gpio;
+	struct fdt_gpio_state *reset_gpio = &dsi->reset_gpio;
+
+	gpio_direction_output(enable_gpio->gpio, 0);
+	gpio_direction_output(reset_gpio->gpio, 0);
+}
+
+static void rockchip_dsi_external_bridge_power_on(struct rockchip_dsi *dsi)
+{
+	struct fdt_gpio_state *enable_gpio = &dsi->enable_gpio;
+	struct fdt_gpio_state *reset_gpio = &dsi->reset_gpio;
+
+	gpio_direction_output(enable_gpio->gpio, 1);
+	udelay(1000);
+	gpio_direction_output(reset_gpio->gpio, 1);
+	udelay(1000);
+	gpio_direction_output(reset_gpio->gpio, 0);
+	udelay(1000);
+	gpio_direction_output(reset_gpio->gpio, 1);
+}
+
+static void rockchip_dsi_enable(struct rockchip_dsi *dsi)
+{
+	dsi_host_reset(dsi);
+	dsi_host_set_vid_mode(dsi);
+	dsi_host_power_up(dsi);
+
+	if (dsi->slave)
+		rockchip_dsi_enable(dsi->slave);
+}
+
+static int rockchip_dsi_connector_enable(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+
+	rockchip_dsi_enable(dsi);
+
+	return 0;
+}
+
+static void rockchip_dsi_post_disable(struct display_state *state,
+				      struct rockchip_dsi *dsi)
+{
+	mipi_dphy_power_off(state, dsi);
+	dsi_host_reset(dsi);
+	ppi_txrequestclkhs_deassert(dsi);
+	rockchip_dsi_external_bridge_power_off(dsi);
+
+	if (dsi->slave)
+		rockchip_dsi_post_disable(state, dsi->slave);
+}
+
+static void rockchip_dsi_connector_unprepare(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+
+	rockchip_dsi_post_disable(state, dsi);
+}
+
+static void rockchip_dsi_disable(struct rockchip_dsi *dsi)
+{
+	dsi_host_set_cmd_mode(dsi);
+
+	if (dsi->slave)
+		rockchip_dsi_disable(dsi->slave);
+}
+
+static int rockchip_dsi_connector_disable(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+
+	rockchip_dsi_disable(dsi);
+
+	return 0;
+}
+
+static unsigned long rockchip_dsi_calc_link_bandwidth(struct rockchip_dsi *dsi,
+						struct drm_display_mode *mode)
+{
+	unsigned int min_freq = dsi->soc_data->min_bit_rate_per_lane;
+	unsigned int max_freq = dsi->soc_data->max_bit_rate_per_lane;
+	unsigned long fpclk, req_freq, tmp;
+	unsigned int lanes;
+	int bpp;
+
+	bpp = get_bpp(dsi->format);
+	lanes = dsi->slave ? dsi->lanes * 2 : dsi->lanes;
+	fpclk = mode->clock / 1000;
+
+	tmp = fpclk * bpp * 12 / 10 / lanes;
+	if (tmp < min_freq || tmp > max_freq)
+		req_freq = max_freq;
+	else
+		req_freq = tmp;
+
+	return req_freq * USEC_PER_SEC;
+}
+
+static unsigned long mipi_dphy_set_pll(struct rockchip_dsi *dsi,
+				       unsigned long rate)
+{
+	struct mipi_dphy *dphy = &dsi->dphy;
+	unsigned long fin, fout;
+	u8 prediv = 0;
+	u16 fbdiv = 0;
+
+	fin = 24000000;
+	fout = mipi_dphy_pll_round_rate(fin, rate, &prediv, &fbdiv);
+
+	dphy->pll.prediv = prediv;
+	dphy->pll.fbdiv = fbdiv;
+
+	printf("fin=%lu, prediv=%u, fbdiv=%u, fout=%lu\n",
+	      fin, dphy->pll.prediv, dphy->pll.fbdiv, fout);
+
+	return fout;
+}
+
+static void rockchip_dsi_compute_transmission_timing(struct display_state *state,
+						     struct rockchip_dsi *dsi,
+						     struct drm_display_mode *mode)
+{
+	unsigned long bw, rate;
+	int val;
+
+	/* XXX: optional override of the desired bandwidth */
+	val = fdtdec_get_int(dsi->blob, dsi->node, "snps,bit-rate-per-lane", -1);
+	if (val > 0)
+		bw = val;
+	else
+		bw = rockchip_dsi_calc_link_bandwidth(dsi, mode);
+
+	if (dsi->dphy.phy)
+		rate = rockchip_phy_set_pll(state, bw);
+	else
+		rate = mipi_dphy_set_pll(dsi, bw);
+
+	dsi->lane_mbps = rate / USEC_PER_SEC;
+	if (dsi->slave)
+		dsi->slave->lane_mbps = dsi->lane_mbps;
+
+	printf("final DSI-Link bandwidth: %u Mbps x %d\n",
+	       dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
+}
+
+static void rockchip_dsi_pre_enable(struct display_state *state,
+				    struct rockchip_dsi *dsi,
+				    struct drm_display_mode *mode)
+{
+	rockchip_dsi_external_bridge_power_on(dsi);
+	dsi_host_reset(dsi);
+	dsi_host_init(dsi);
+	mipi_dphy_init(dsi);
+	mipi_dphy_hstt_config(dsi);
+	mipi_dphy_if_config(dsi);
+	dpi_config(dsi, mode);
+	dsi_host_vid_mode_config(dsi, mode);
+	ppi_txrequestclkhs_assert(dsi);
+	mipi_dphy_power_on(state, dsi);
+	dsi_host_power_up(dsi);
+
+	if (dsi->slave)
+		rockchip_dsi_pre_enable(state, dsi->slave, mode);
+}
+
+static int rockchip_dsi_connector_prepare(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+	struct drm_display_mode *mode = &conn_state->mode;
+	struct crtc_state *crtc_state = &state->crtc_state;
+
+	rockchip_dsi_compute_transmission_timing(state, dsi, mode);
+	rockchip_dsi_vop_routing(dsi, crtc_state->crtc_id);
+
+	rockchip_dsi_pre_enable(state, dsi, mode);
+
+	return 0;
+}
+
+static int rockchip_dsi_dual_channel_probe(struct rockchip_dsi *master)
+{
+	int phandle, node;
+	struct rockchip_dsi *slave;
+
+	phandle = fdt_getprop_u32_default_node(master->blob, master->node, 0,
+					       "rockchip,dual-channel", -1);
+	if (phandle < 0)
+		return 0;
+
+	node = fdt_node_offset_by_phandle(master->blob, phandle);
+	if (node < 0) {
+		printf("failed to find dsi slave node\n");
+		return -ENODEV;
+	}
+
+	if (!fdt_device_is_available(master->blob, node)) {
+		printf("dsi slave node is not available\n");
+		return -ENODEV;
+	}
+
+	slave = malloc(sizeof(*slave));
+	if (!slave)
+		return -ENOMEM;
+
+	memset(slave, 0, sizeof(*slave));
+
+	master->lanes /= 2;
+	master->slave = slave;
+	slave->master = master;
+
+	slave->blob = master->blob;
+	slave->node = node;
+	slave->regs = fdtdec_get_addr_size_auto_noparent(slave->blob, node,
+							 "reg", 0, NULL);
+	slave->soc_data = master->soc_data;
+	slave->dphy.phy = master->dphy.phy;
+	slave->id = 1;
+	slave->desc = slave->soc_data->grf_descs[slave->id];
+	slave->lanes = master->lanes;
+	slave->format = master->format;
+	slave->mode_flags = master->mode_flags;
+	slave->channel = master->channel;
+
+	return 0;
+}
+
+static int rockchip_dsi_parse_dt(struct rockchip_dsi *dsi)
+{
+	int panel_node;
+
+	panel_node = fdt_subnode_offset(dsi->blob, dsi->node, "panel");
+	if (panel_node < 0) {
+		printf("failed to find panel node\n");
+		return -ENODEV;
+	}
+
+#define FDT_GET_INT(val, name) \
+	val = fdtdec_get_int(dsi->blob, panel_node, name, -1); \
+	if (val < 0) { \
+		printf("Can't get %s\n", name); \
+		return -1; \
+	}
+
+	FDT_GET_INT(dsi->lanes, "dsi,lanes");
+	FDT_GET_INT(dsi->format, "dsi,format");
+	FDT_GET_INT(dsi->mode_flags, "dsi,flags");
+	FDT_GET_INT(dsi->channel, "reg");
+
+	return 0;
+}
+
+static int rockchip_dsi_connector_init(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	const struct rockchip_connector *connector = conn_state->connector;
+	const struct rockchip_dsi_soc_data *data = connector->data;
+	int node = conn_state->node;
+	struct rockchip_dsi *dsi;
+	static int id = 0;
+	int ret;
+
+	dsi = malloc(sizeof(*dsi));
+	if (!dsi)
+		return -ENOMEM;
+
+	memset(dsi, 0, sizeof(*dsi));
+
+	dsi->blob = state->blob;
+	dsi->node = node;
+	dsi->regs = fdtdec_get_addr_size_auto_noparent(dsi->blob, dsi->node,
+						       "reg", 0, NULL);
+	dsi->soc_data = data;
+	dsi->dphy.phy = conn_state->phy;
+	dsi->id = id++;
+	dsi->desc = dsi->soc_data->grf_descs[dsi->id];
+
+	ret = rockchip_dsi_parse_dt(dsi);
+	if (ret) {
+		printf("%s: failed to parse DT\n", __func__);
+		return ret;
+	}
+
+	rockchip_dsi_external_bridge_parse_dt(dsi);
+
+	ret = rockchip_dsi_dual_channel_probe(dsi);
+	if (ret)
+		return ret;
+
+	conn_state->private = dsi;
+	conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
+	conn_state->type = DRM_MODE_CONNECTOR_DSI;
+
+	if (dsi->slave)
+		conn_state->output_type |= ROCKCHIP_OUTPUT_DSI_DUAL_CHANNEL;
+
+	if (IS_DSI1(dsi))
+		conn_state->output_type |= ROCKCHIP_OUTPUT_DSI_DUAL_LINK;
+
+	return 0;
+}
+
+static void rockchip_dsi_connector_deinit(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_dsi *dsi = conn_state->private;
+
+	free(dsi->slave);
+	free(dsi);
+}
+
+static const u32 rk3288_dsi0_grf_descs[NUM_GRF_DESC] = {
+	[DPICOLORM]	  = GRF_DESC(0x025c,  8, 8),
+	[DPISHUTDN]	  = GRF_DESC(0x025c,  7, 7),
+	[VOPSEL]	  = GRF_DESC(0x025c,  6, 6),
+	[FORCETXSTOPMODE] = GRF_DESC(0x0264, 11, 8),
+	[FORCERXMODE]	  = GRF_DESC(0x0264,  7, 4),
+	[TURNDISABLE]	  = GRF_DESC(0x0264,  3, 0),
+	[TURNREQUEST]	  = GRF_DESC(0x03a4, 10, 8),
+	[DPIUPDATECFG]	  = GRF_DESC(0x03a8,  0, 0),
+};
+
+static const u32 rk3288_dsi1_grf_descs[NUM_GRF_DESC] = {
+	[DPICOLORM]	  = GRF_DESC(0x025c, 11, 11),
+	[DPISHUTDN]	  = GRF_DESC(0x025c, 10, 10),
+	[VOPSEL]	  = GRF_DESC(0x025c,  9,  9),
+	[ENABLE_N]	  = GRF_DESC(0x0268, 15, 12),
+	[FORCETXSTOPMODE] = GRF_DESC(0x0268, 11,  8),
+	[FORCERXMODE]	  = GRF_DESC(0x0268,  7,  4),
+	[TURNDISABLE]	  = GRF_DESC(0x0268,  3,  0),
+	[BASEDIR]	  = GRF_DESC(0x027c, 15, 15),
+	[MASTERSLAVEZ]	  = GRF_DESC(0x027c, 14, 14),
+	[ENABLECLK]	  = GRF_DESC(0x027c, 12, 12),
+	[TURNREQUEST]	  = GRF_DESC(0x03a4,  7,  4),
+	[DPIUPDATECFG]	  = GRF_DESC(0x03a8,  1,  1),
+};
+
+static const u32 *rk3288_dsi_grf_descs[] = {
+	rk3288_dsi0_grf_descs,
+	rk3288_dsi1_grf_descs,
+};
+
+const struct rockchip_dsi_soc_data rk3288_dsi_soc_data = {
+	.min_bit_rate_per_lane = 80,
+	.max_bit_rate_per_lane = 1500,
+	.grf_descs = rk3288_dsi_grf_descs,
+};
+
+static const u32 rk3366_dsi0_grf_descs[NUM_GRF_DESC] = {
+	[VOPSEL]	  = GRF_DESC(0x0400,  2, 2),
+	[DPIUPDATECFG]	  = GRF_DESC(0x0410,  9, 9),
+	[DPICOLORM]	  = GRF_DESC(0x0410,  3, 3),
+	[DPISHUTDN]	  = GRF_DESC(0x0410,  2, 2),
+	[FORCETXSTOPMODE] = GRF_DESC(0x0414, 10, 7),
+	[FORCERXMODE]	  = GRF_DESC(0x0414,  6, 6),
+	[TURNDISABLE]	  = GRF_DESC(0x0414,  5, 5),
+};
+
+static const u32 *rk3366_dsi_grf_descs[] = {
+	rk3366_dsi0_grf_descs,
+};
+
+const struct rockchip_dsi_soc_data rk3366_dsi_soc_data = {
+	.min_bit_rate_per_lane = 80,
+	.max_bit_rate_per_lane = 1000,
+	.grf_descs = rk3366_dsi_grf_descs,
+};
+
+static const u32 rk3368_dsi0_grf_descs[NUM_GRF_DESC] = {
+	[DPIUPDATECFG]	  = GRF_DESC(0x0418,  7, 7),
+	[DPICOLORM]	  = GRF_DESC(0x0418,  3, 3),
+	[DPISHUTDN]	  = GRF_DESC(0x0418,  2, 2),
+	[FORCETXSTOPMODE] = GRF_DESC(0x041c, 10, 7),
+	[FORCERXMODE]	  = GRF_DESC(0x041c,  6, 6),
+	[TURNDISABLE]	  = GRF_DESC(0x041c,  5, 5),
+};
+
+static const u32 *rk3368_dsi_grf_descs[] = {
+	rk3368_dsi0_grf_descs,
+};
+
+const struct rockchip_dsi_soc_data rk3368_dsi_soc_data = {
+	.min_bit_rate_per_lane = 80,
+	.max_bit_rate_per_lane = 1000,
+	.grf_descs = rk3368_dsi_grf_descs,
+};
+
+static const u32 rk3399_dsi0_grf_descs[NUM_GRF_DESC] = {
+	[DPIUPDATECFG]	  = GRF_DESC(0x6224, 15, 15),
+	[DPISHUTDN]	  = GRF_DESC(0x6224, 14, 14),
+	[DPICOLORM]	  = GRF_DESC(0x6224, 13, 13),
+	[VOPSEL]	  = GRF_DESC(0x6250,  0,  0),
+	[TURNREQUEST]	  = GRF_DESC(0x6258, 15, 12),
+	[TURNDISABLE]	  = GRF_DESC(0x6258, 11,  8),
+	[FORCETXSTOPMODE] = GRF_DESC(0x6258,  7,  4),
+	[FORCERXMODE]	  = GRF_DESC(0x6258,  3,  0),
+};
+
+static const u32 rk3399_dsi1_grf_descs[NUM_GRF_DESC] = {
+	[VOPSEL]	  = GRF_DESC(0x6250,  4,  4),
+	[DPIUPDATECFG]	  = GRF_DESC(0x6250,  3,  3),
+	[DPISHUTDN]	  = GRF_DESC(0x6250,  2,  2),
+	[DPICOLORM]	  = GRF_DESC(0x6250,  1,  1),
+	[TURNDISABLE]	  = GRF_DESC(0x625c, 15, 12),
+	[FORCETXSTOPMODE] = GRF_DESC(0x625c, 11,  8),
+	[FORCERXMODE]	  = GRF_DESC(0x625c,  7,  4),
+	[ENABLE_N]	  = GRF_DESC(0x625c,  3,  0),
+	[MASTERSLAVEZ]	  = GRF_DESC(0x6260,  7,  7),
+	[ENABLECLK]	  = GRF_DESC(0x6260,  6,  6),
+	[BASEDIR]	  = GRF_DESC(0x6260,  5,  5),
+	[TURNREQUEST]	  = GRF_DESC(0x6260,  3,  0),
+};
+
+static const u32 *rk3399_dsi_grf_descs[] = {
+	rk3399_dsi0_grf_descs,
+	rk3399_dsi1_grf_descs,
+};
+
+const struct rockchip_dsi_soc_data rk3399_dsi_soc_data = {
+	.min_bit_rate_per_lane = 80,
+	.max_bit_rate_per_lane = 1500,
+	.grf_descs = rk3399_dsi_grf_descs,
+};
+
+const struct rockchip_connector_funcs rockchip_dsi_connector_funcs = {
+	.init = rockchip_dsi_connector_init,
+	.deinit = rockchip_dsi_connector_deinit,
+	.prepare = rockchip_dsi_connector_prepare,
+	.unprepare = rockchip_dsi_connector_unprepare,
+	.enable = rockchip_dsi_connector_enable,
+	.disable = rockchip_dsi_connector_disable,
+	.transfer = rockchip_dsi_connector_transfer,
+};
diff --git a/drivers/video/rockchip_vop.c b/drivers/video/rockchip_vop.c
index 49170a6..373cee4 100644
--- a/drivers/video/rockchip_vop.c
+++ b/drivers/video/rockchip_vop.c
@@ -123,7 +123,7 @@ static int rockchip_vop_init(struct display_state *state)
 	if (conn_state->type == DRM_MODE_CONNECTOR_HDMIA)
 		rkclk_lcdc_dclk_pll_sel(crtc_state->crtc_id, 0);
 	else
-		rkclk_lcdc_dclk_pll_sel(crtc_state->crtc_id, 1);
+		rkclk_lcdc_dclk_pll_sel(crtc_state->crtc_id, crtc_state->crtc_id);
 #endif
 
 	/* Set aclk hclk and dclk */

你可能感兴趣的:(RK3399,子类__Display)