xref: /linux/drivers/gpu/drm/sprd/sprd_dsi.c (revision 16b01df3)
11c66496bSKevin Tang // SPDX-License-Identifier: GPL-2.0
21c66496bSKevin Tang /*
31c66496bSKevin Tang  * Copyright (C) 2020 Unisoc Inc.
41c66496bSKevin Tang  */
51c66496bSKevin Tang 
61c66496bSKevin Tang #include <linux/component.h>
71c66496bSKevin Tang #include <linux/module.h>
8722d4f06SRob Herring #include <linux/of.h>
9722d4f06SRob Herring #include <linux/platform_device.h>
101c66496bSKevin Tang #include <video/mipi_display.h>
111c66496bSKevin Tang 
121c66496bSKevin Tang #include <drm/drm_atomic_helper.h>
131c66496bSKevin Tang #include <drm/drm_bridge.h>
141c66496bSKevin Tang #include <drm/drm_of.h>
151c66496bSKevin Tang #include <drm/drm_probe_helper.h>
161c66496bSKevin Tang 
171c66496bSKevin Tang #include "sprd_drm.h"
181c66496bSKevin Tang #include "sprd_dpu.h"
191c66496bSKevin Tang #include "sprd_dsi.h"
201c66496bSKevin Tang 
211c66496bSKevin Tang #define SOFT_RESET 0x04
221c66496bSKevin Tang #define MASK_PROTOCOL_INT 0x0C
231c66496bSKevin Tang #define MASK_INTERNAL_INT 0x14
241c66496bSKevin Tang #define DSI_MODE_CFG 0x18
251c66496bSKevin Tang 
261c66496bSKevin Tang #define VIRTUAL_CHANNEL_ID 0x1C
271c66496bSKevin Tang #define GEN_RX_VCID GENMASK(1, 0)
281c66496bSKevin Tang #define VIDEO_PKT_VCID GENMASK(3, 2)
291c66496bSKevin Tang 
301c66496bSKevin Tang #define DPI_VIDEO_FORMAT 0x20
311c66496bSKevin Tang #define DPI_VIDEO_MODE_FORMAT GENMASK(5, 0)
321c66496bSKevin Tang #define LOOSELY18_EN BIT(6)
331c66496bSKevin Tang 
341c66496bSKevin Tang #define VIDEO_PKT_CONFIG 0x24
351c66496bSKevin Tang #define VIDEO_PKT_SIZE GENMASK(15, 0)
361c66496bSKevin Tang #define VIDEO_LINE_CHUNK_NUM GENMASK(31, 16)
371c66496bSKevin Tang 
381c66496bSKevin Tang #define VIDEO_LINE_HBLK_TIME 0x28
391c66496bSKevin Tang #define VIDEO_LINE_HBP_TIME GENMASK(15, 0)
401c66496bSKevin Tang #define VIDEO_LINE_HSA_TIME GENMASK(31, 16)
411c66496bSKevin Tang 
421c66496bSKevin Tang #define VIDEO_LINE_TIME 0x2C
431c66496bSKevin Tang 
441c66496bSKevin Tang #define VIDEO_VBLK_LINES 0x30
451c66496bSKevin Tang #define VFP_LINES GENMASK(9, 0)
461c66496bSKevin Tang #define VBP_LINES GENMASK(19, 10)
471c66496bSKevin Tang #define VSA_LINES GENMASK(29, 20)
481c66496bSKevin Tang 
491c66496bSKevin Tang #define VIDEO_VACTIVE_LINES 0x34
501c66496bSKevin Tang 
511c66496bSKevin Tang #define VID_MODE_CFG 0x38
521c66496bSKevin Tang #define VID_MODE_TYPE GENMASK(1, 0)
531c66496bSKevin Tang #define LP_VSA_EN BIT(8)
541c66496bSKevin Tang #define LP_VBP_EN BIT(9)
551c66496bSKevin Tang #define LP_VFP_EN BIT(10)
561c66496bSKevin Tang #define LP_VACT_EN BIT(11)
571c66496bSKevin Tang #define LP_HBP_EN BIT(12)
581c66496bSKevin Tang #define LP_HFP_EN BIT(13)
591c66496bSKevin Tang #define FRAME_BTA_ACK_EN BIT(14)
601c66496bSKevin Tang 
611c66496bSKevin Tang #define TIMEOUT_CNT_CLK_CONFIG 0x40
621c66496bSKevin Tang #define HTX_TO_CONFIG 0x44
631c66496bSKevin Tang #define LRX_H_TO_CONFIG 0x48
641c66496bSKevin Tang 
651c66496bSKevin Tang #define TX_ESC_CLK_CONFIG 0x5C
661c66496bSKevin Tang 
671c66496bSKevin Tang #define CMD_MODE_CFG 0x68
681c66496bSKevin Tang #define TEAR_FX_EN BIT(0)
691c66496bSKevin Tang 
701c66496bSKevin Tang #define GEN_HDR 0x6C
711c66496bSKevin Tang #define GEN_DT GENMASK(5, 0)
721c66496bSKevin Tang #define GEN_VC GENMASK(7, 6)
731c66496bSKevin Tang 
741c66496bSKevin Tang #define GEN_PLD_DATA 0x70
751c66496bSKevin Tang 
761c66496bSKevin Tang #define PHY_CLK_LANE_LP_CTRL 0x74
771c66496bSKevin Tang #define PHY_CLKLANE_TX_REQ_HS BIT(0)
781c66496bSKevin Tang #define AUTO_CLKLANE_CTRL_EN BIT(1)
791c66496bSKevin Tang 
801c66496bSKevin Tang #define PHY_INTERFACE_CTRL 0x78
811c66496bSKevin Tang #define RF_PHY_SHUTDOWN BIT(0)
821c66496bSKevin Tang #define RF_PHY_RESET_N BIT(1)
831c66496bSKevin Tang #define RF_PHY_CLK_EN BIT(2)
841c66496bSKevin Tang 
851c66496bSKevin Tang #define CMD_MODE_STATUS 0x98
861c66496bSKevin Tang #define GEN_CMD_RDATA_FIFO_EMPTY BIT(1)
871c66496bSKevin Tang #define GEN_CMD_WDATA_FIFO_EMPTY BIT(3)
881c66496bSKevin Tang #define GEN_CMD_CMD_FIFO_EMPTY BIT(5)
891c66496bSKevin Tang #define GEN_CMD_RDCMD_DONE BIT(7)
901c66496bSKevin Tang 
911c66496bSKevin Tang #define PHY_STATUS 0x9C
921c66496bSKevin Tang #define PHY_LOCK BIT(1)
931c66496bSKevin Tang 
941c66496bSKevin Tang #define PHY_MIN_STOP_TIME 0xA0
951c66496bSKevin Tang #define PHY_LANE_NUM_CONFIG 0xA4
961c66496bSKevin Tang 
971c66496bSKevin Tang #define PHY_CLKLANE_TIME_CONFIG 0xA8
981c66496bSKevin Tang #define PHY_CLKLANE_LP_TO_HS_TIME GENMASK(15, 0)
991c66496bSKevin Tang #define PHY_CLKLANE_HS_TO_LP_TIME GENMASK(31, 16)
1001c66496bSKevin Tang 
1011c66496bSKevin Tang #define PHY_DATALANE_TIME_CONFIG 0xAC
1021c66496bSKevin Tang #define PHY_DATALANE_LP_TO_HS_TIME GENMASK(15, 0)
1031c66496bSKevin Tang #define PHY_DATALANE_HS_TO_LP_TIME GENMASK(31, 16)
1041c66496bSKevin Tang 
1051c66496bSKevin Tang #define MAX_READ_TIME 0xB0
1061c66496bSKevin Tang 
1071c66496bSKevin Tang #define RX_PKT_CHECK_CONFIG 0xB4
1081c66496bSKevin Tang #define RX_PKT_ECC_EN BIT(0)
1091c66496bSKevin Tang #define RX_PKT_CRC_EN BIT(1)
1101c66496bSKevin Tang 
1111c66496bSKevin Tang #define TA_EN 0xB8
1121c66496bSKevin Tang 
1131c66496bSKevin Tang #define EOTP_EN 0xBC
1141c66496bSKevin Tang #define TX_EOTP_EN BIT(0)
1151c66496bSKevin Tang #define RX_EOTP_EN BIT(1)
1161c66496bSKevin Tang 
1171c66496bSKevin Tang #define VIDEO_NULLPKT_SIZE 0xC0
1181c66496bSKevin Tang #define DCS_WM_PKT_SIZE 0xC4
1191c66496bSKevin Tang 
1201c66496bSKevin Tang #define VIDEO_SIG_DELAY_CONFIG 0xD0
1211c66496bSKevin Tang #define VIDEO_SIG_DELAY GENMASK(23, 0)
1221c66496bSKevin Tang 
1231c66496bSKevin Tang #define PHY_TST_CTRL0 0xF0
1241c66496bSKevin Tang #define PHY_TESTCLR BIT(0)
1251c66496bSKevin Tang #define PHY_TESTCLK BIT(1)
1261c66496bSKevin Tang 
1271c66496bSKevin Tang #define PHY_TST_CTRL1 0xF4
1281c66496bSKevin Tang #define PHY_TESTDIN GENMASK(7, 0)
1291c66496bSKevin Tang #define PHY_TESTDOUT GENMASK(15, 8)
1301c66496bSKevin Tang #define PHY_TESTEN BIT(16)
1311c66496bSKevin Tang 
1321c66496bSKevin Tang #define host_to_dsi(host) \
1331c66496bSKevin Tang 	container_of(host, struct sprd_dsi, host)
1341c66496bSKevin Tang 
1351c66496bSKevin Tang static inline u32
dsi_reg_rd(struct dsi_context * ctx,u32 offset,u32 mask,u32 shift)1361c66496bSKevin Tang dsi_reg_rd(struct dsi_context *ctx, u32 offset, u32 mask,
1371c66496bSKevin Tang 	   u32 shift)
1381c66496bSKevin Tang {
1391c66496bSKevin Tang 	return (readl(ctx->base + offset) & mask) >> shift;
1401c66496bSKevin Tang }
1411c66496bSKevin Tang 
1421c66496bSKevin Tang static inline void
dsi_reg_wr(struct dsi_context * ctx,u32 offset,u32 mask,u32 shift,u32 val)1431c66496bSKevin Tang dsi_reg_wr(struct dsi_context *ctx, u32 offset, u32 mask,
1441c66496bSKevin Tang 	   u32 shift, u32 val)
1451c66496bSKevin Tang {
1461c66496bSKevin Tang 	u32 ret;
1471c66496bSKevin Tang 
1481c66496bSKevin Tang 	ret = readl(ctx->base + offset);
1491c66496bSKevin Tang 	ret &= ~mask;
1501c66496bSKevin Tang 	ret |= (val << shift) & mask;
1511c66496bSKevin Tang 	writel(ret, ctx->base + offset);
1521c66496bSKevin Tang }
1531c66496bSKevin Tang 
1541c66496bSKevin Tang static inline void
dsi_reg_up(struct dsi_context * ctx,u32 offset,u32 mask,u32 val)1551c66496bSKevin Tang dsi_reg_up(struct dsi_context *ctx, u32 offset, u32 mask,
1561c66496bSKevin Tang 	   u32 val)
1571c66496bSKevin Tang {
1581c66496bSKevin Tang 	u32 ret = readl(ctx->base + offset);
1591c66496bSKevin Tang 
1601c66496bSKevin Tang 	writel((ret & ~mask) | (val & mask), ctx->base + offset);
1611c66496bSKevin Tang }
1621c66496bSKevin Tang 
regmap_tst_io_write(void * context,u32 reg,u32 val)1631c66496bSKevin Tang static int regmap_tst_io_write(void *context, u32 reg, u32 val)
1641c66496bSKevin Tang {
1651c66496bSKevin Tang 	struct sprd_dsi *dsi = context;
1661c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
1671c66496bSKevin Tang 
1681c66496bSKevin Tang 	if (val > 0xff || reg > 0xff)
1691c66496bSKevin Tang 		return -EINVAL;
1701c66496bSKevin Tang 
1711c66496bSKevin Tang 	drm_dbg(dsi->drm, "reg = 0x%02x, val = 0x%02x\n", reg, val);
1721c66496bSKevin Tang 
1731c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, PHY_TESTEN);
1741c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, reg);
1751c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
1761c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
1771c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, 0);
1781c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, val);
1791c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
1801c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
1811c66496bSKevin Tang 
1821c66496bSKevin Tang 	return 0;
1831c66496bSKevin Tang }
1841c66496bSKevin Tang 
regmap_tst_io_read(void * context,u32 reg,u32 * val)1851c66496bSKevin Tang static int regmap_tst_io_read(void *context, u32 reg, u32 *val)
1861c66496bSKevin Tang {
1871c66496bSKevin Tang 	struct sprd_dsi *dsi = context;
1881c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
1891c66496bSKevin Tang 	int ret;
1901c66496bSKevin Tang 
1911c66496bSKevin Tang 	if (reg > 0xff)
1921c66496bSKevin Tang 		return -EINVAL;
1931c66496bSKevin Tang 
1941c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, PHY_TESTEN);
1951c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_TST_CTRL1, PHY_TESTDIN, 0, reg);
1961c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, PHY_TESTCLK);
1971c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLK, 0);
1981c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL1, PHY_TESTEN, 0);
1991c66496bSKevin Tang 
2001c66496bSKevin Tang 	udelay(1);
2011c66496bSKevin Tang 
2021c66496bSKevin Tang 	ret = dsi_reg_rd(ctx, PHY_TST_CTRL1, PHY_TESTDOUT, 8);
2031c66496bSKevin Tang 	if (ret < 0)
2041c66496bSKevin Tang 		return ret;
2051c66496bSKevin Tang 
2061c66496bSKevin Tang 	*val = ret;
2071c66496bSKevin Tang 
2081c66496bSKevin Tang 	drm_dbg(dsi->drm, "reg = 0x%02x, val = 0x%02x\n", reg, *val);
2091c66496bSKevin Tang 	return 0;
2101c66496bSKevin Tang }
2111c66496bSKevin Tang 
2121c66496bSKevin Tang static struct regmap_bus regmap_tst_io = {
2131c66496bSKevin Tang 	.reg_write = regmap_tst_io_write,
2141c66496bSKevin Tang 	.reg_read = regmap_tst_io_read,
2151c66496bSKevin Tang };
2161c66496bSKevin Tang 
2171c66496bSKevin Tang static const struct regmap_config byte_config = {
2181c66496bSKevin Tang 	.reg_bits = 8,
2191c66496bSKevin Tang 	.val_bits = 8,
2201c66496bSKevin Tang };
2211c66496bSKevin Tang 
dphy_wait_pll_locked(struct dsi_context * ctx)2221c66496bSKevin Tang static int dphy_wait_pll_locked(struct dsi_context *ctx)
2231c66496bSKevin Tang {
2241c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
2251c66496bSKevin Tang 	int i;
2261c66496bSKevin Tang 
2271c66496bSKevin Tang 	for (i = 0; i < 50000; i++) {
2281c66496bSKevin Tang 		if (dsi_reg_rd(ctx, PHY_STATUS, PHY_LOCK, 1))
2291c66496bSKevin Tang 			return 0;
2301c66496bSKevin Tang 		udelay(3);
2311c66496bSKevin Tang 	}
2321c66496bSKevin Tang 
2331c66496bSKevin Tang 	drm_err(dsi->drm, "dphy pll can not be locked\n");
2341c66496bSKevin Tang 	return -ETIMEDOUT;
2351c66496bSKevin Tang }
2361c66496bSKevin Tang 
dsi_wait_tx_payload_fifo_empty(struct dsi_context * ctx)2371c66496bSKevin Tang static int dsi_wait_tx_payload_fifo_empty(struct dsi_context *ctx)
2381c66496bSKevin Tang {
2391c66496bSKevin Tang 	int i;
2401c66496bSKevin Tang 
2411c66496bSKevin Tang 	for (i = 0; i < 5000; i++) {
2421c66496bSKevin Tang 		if (dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_WDATA_FIFO_EMPTY, 3))
2431c66496bSKevin Tang 			return 0;
2441c66496bSKevin Tang 		udelay(1);
2451c66496bSKevin Tang 	}
2461c66496bSKevin Tang 
2471c66496bSKevin Tang 	return -ETIMEDOUT;
2481c66496bSKevin Tang }
2491c66496bSKevin Tang 
dsi_wait_tx_cmd_fifo_empty(struct dsi_context * ctx)2501c66496bSKevin Tang static int dsi_wait_tx_cmd_fifo_empty(struct dsi_context *ctx)
2511c66496bSKevin Tang {
2521c66496bSKevin Tang 	int i;
2531c66496bSKevin Tang 
2541c66496bSKevin Tang 	for (i = 0; i < 5000; i++) {
2551c66496bSKevin Tang 		if (dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_CMD_FIFO_EMPTY, 5))
2561c66496bSKevin Tang 			return 0;
2571c66496bSKevin Tang 		udelay(1);
2581c66496bSKevin Tang 	}
2591c66496bSKevin Tang 
2601c66496bSKevin Tang 	return -ETIMEDOUT;
2611c66496bSKevin Tang }
2621c66496bSKevin Tang 
dsi_wait_rd_resp_completed(struct dsi_context * ctx)2631c66496bSKevin Tang static int dsi_wait_rd_resp_completed(struct dsi_context *ctx)
2641c66496bSKevin Tang {
2651c66496bSKevin Tang 	int i;
2661c66496bSKevin Tang 
2671c66496bSKevin Tang 	for (i = 0; i < 10000; i++) {
2681c66496bSKevin Tang 		if (dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_RDCMD_DONE, 7))
2691c66496bSKevin Tang 			return 0;
2701c66496bSKevin Tang 		udelay(10);
2711c66496bSKevin Tang 	}
2721c66496bSKevin Tang 
2731c66496bSKevin Tang 	return -ETIMEDOUT;
2741c66496bSKevin Tang }
2751c66496bSKevin Tang 
calc_bytes_per_pixel_x100(int coding)2761c66496bSKevin Tang static u16 calc_bytes_per_pixel_x100(int coding)
2771c66496bSKevin Tang {
2781c66496bSKevin Tang 	u16 bpp_x100;
2791c66496bSKevin Tang 
2801c66496bSKevin Tang 	switch (coding) {
2811c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG1:
2821c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG2:
2831c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG3:
2841c66496bSKevin Tang 		bpp_x100 = 200;
2851c66496bSKevin Tang 		break;
2861c66496bSKevin Tang 	case COLOR_CODE_18BIT_CONFIG1:
2871c66496bSKevin Tang 	case COLOR_CODE_18BIT_CONFIG2:
2881c66496bSKevin Tang 		bpp_x100 = 225;
2891c66496bSKevin Tang 		break;
2901c66496bSKevin Tang 	case COLOR_CODE_24BIT:
2911c66496bSKevin Tang 		bpp_x100 = 300;
2921c66496bSKevin Tang 		break;
2931c66496bSKevin Tang 	case COLOR_CODE_COMPRESSTION:
2941c66496bSKevin Tang 		bpp_x100 = 100;
2951c66496bSKevin Tang 		break;
2961c66496bSKevin Tang 	case COLOR_CODE_20BIT_YCC422_LOOSELY:
2971c66496bSKevin Tang 		bpp_x100 = 250;
2981c66496bSKevin Tang 		break;
2991c66496bSKevin Tang 	case COLOR_CODE_24BIT_YCC422:
3001c66496bSKevin Tang 		bpp_x100 = 300;
3011c66496bSKevin Tang 		break;
3021c66496bSKevin Tang 	case COLOR_CODE_16BIT_YCC422:
3031c66496bSKevin Tang 		bpp_x100 = 200;
3041c66496bSKevin Tang 		break;
3051c66496bSKevin Tang 	case COLOR_CODE_30BIT:
3061c66496bSKevin Tang 		bpp_x100 = 375;
3071c66496bSKevin Tang 		break;
3081c66496bSKevin Tang 	case COLOR_CODE_36BIT:
3091c66496bSKevin Tang 		bpp_x100 = 450;
3101c66496bSKevin Tang 		break;
3111c66496bSKevin Tang 	case COLOR_CODE_12BIT_YCC420:
3121c66496bSKevin Tang 		bpp_x100 = 150;
3131c66496bSKevin Tang 		break;
3141c66496bSKevin Tang 	default:
3151c66496bSKevin Tang 		DRM_ERROR("invalid color coding");
3161c66496bSKevin Tang 		bpp_x100 = 0;
3171c66496bSKevin Tang 		break;
3181c66496bSKevin Tang 	}
3191c66496bSKevin Tang 
3201c66496bSKevin Tang 	return bpp_x100;
3211c66496bSKevin Tang }
3221c66496bSKevin Tang 
calc_video_size_step(int coding)3231c66496bSKevin Tang static u8 calc_video_size_step(int coding)
3241c66496bSKevin Tang {
3251c66496bSKevin Tang 	u8 video_size_step;
3261c66496bSKevin Tang 
3271c66496bSKevin Tang 	switch (coding) {
3281c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG1:
3291c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG2:
3301c66496bSKevin Tang 	case COLOR_CODE_16BIT_CONFIG3:
3311c66496bSKevin Tang 	case COLOR_CODE_18BIT_CONFIG1:
3321c66496bSKevin Tang 	case COLOR_CODE_18BIT_CONFIG2:
3331c66496bSKevin Tang 	case COLOR_CODE_24BIT:
3341c66496bSKevin Tang 	case COLOR_CODE_COMPRESSTION:
3351c66496bSKevin Tang 		return video_size_step = 1;
3361c66496bSKevin Tang 	case COLOR_CODE_20BIT_YCC422_LOOSELY:
3371c66496bSKevin Tang 	case COLOR_CODE_24BIT_YCC422:
3381c66496bSKevin Tang 	case COLOR_CODE_16BIT_YCC422:
3391c66496bSKevin Tang 	case COLOR_CODE_30BIT:
3401c66496bSKevin Tang 	case COLOR_CODE_36BIT:
3411c66496bSKevin Tang 	case COLOR_CODE_12BIT_YCC420:
3421c66496bSKevin Tang 		return video_size_step = 2;
3431c66496bSKevin Tang 	default:
3441c66496bSKevin Tang 		DRM_ERROR("invalid color coding");
3451c66496bSKevin Tang 		return 0;
3461c66496bSKevin Tang 	}
3471c66496bSKevin Tang }
3481c66496bSKevin Tang 
round_video_size(int coding,u16 video_size)3491c66496bSKevin Tang static u16 round_video_size(int coding, u16 video_size)
3501c66496bSKevin Tang {
3511c66496bSKevin Tang 	switch (coding) {
3521c66496bSKevin Tang 	case COLOR_CODE_16BIT_YCC422:
3531c66496bSKevin Tang 	case COLOR_CODE_24BIT_YCC422:
3541c66496bSKevin Tang 	case COLOR_CODE_20BIT_YCC422_LOOSELY:
3551c66496bSKevin Tang 	case COLOR_CODE_12BIT_YCC420:
3561c66496bSKevin Tang 		/* round up active H pixels to a multiple of 2 */
3571c66496bSKevin Tang 		if ((video_size % 2) != 0)
3581c66496bSKevin Tang 			video_size += 1;
3591c66496bSKevin Tang 		break;
3601c66496bSKevin Tang 	default:
3611c66496bSKevin Tang 		break;
3621c66496bSKevin Tang 	}
3631c66496bSKevin Tang 
3641c66496bSKevin Tang 	return video_size;
3651c66496bSKevin Tang }
3661c66496bSKevin Tang 
3671c66496bSKevin Tang #define SPRD_MIPI_DSI_FMT_DSC 0xff
fmt_to_coding(u32 fmt)3681c66496bSKevin Tang static u32 fmt_to_coding(u32 fmt)
3691c66496bSKevin Tang {
3701c66496bSKevin Tang 	switch (fmt) {
3711c66496bSKevin Tang 	case MIPI_DSI_FMT_RGB565:
3721c66496bSKevin Tang 		return COLOR_CODE_16BIT_CONFIG1;
3731c66496bSKevin Tang 	case MIPI_DSI_FMT_RGB666:
3741c66496bSKevin Tang 	case MIPI_DSI_FMT_RGB666_PACKED:
3751c66496bSKevin Tang 		return COLOR_CODE_18BIT_CONFIG1;
3761c66496bSKevin Tang 	case MIPI_DSI_FMT_RGB888:
3771c66496bSKevin Tang 		return COLOR_CODE_24BIT;
3781c66496bSKevin Tang 	case SPRD_MIPI_DSI_FMT_DSC:
3791c66496bSKevin Tang 		return COLOR_CODE_COMPRESSTION;
3801c66496bSKevin Tang 	default:
3811c66496bSKevin Tang 		DRM_ERROR("Unsupported format (%d)\n", fmt);
3821c66496bSKevin Tang 		return COLOR_CODE_24BIT;
3831c66496bSKevin Tang 	}
3841c66496bSKevin Tang }
3851c66496bSKevin Tang 
3861c66496bSKevin Tang #define ns_to_cycle(ns, byte_clk) \
3871c66496bSKevin Tang 	DIV_ROUND_UP((ns) * (byte_clk), 1000000)
3881c66496bSKevin Tang 
sprd_dsi_init(struct dsi_context * ctx)3891c66496bSKevin Tang static void sprd_dsi_init(struct dsi_context *ctx)
3901c66496bSKevin Tang {
3911c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
3921c66496bSKevin Tang 	u32 byte_clk = dsi->slave->hs_rate / 8;
3931c66496bSKevin Tang 	u16 data_hs2lp, data_lp2hs, clk_hs2lp, clk_lp2hs;
3941c66496bSKevin Tang 	u16 max_rd_time;
3951c66496bSKevin Tang 	int div;
3961c66496bSKevin Tang 
3971c66496bSKevin Tang 	writel(0, ctx->base + SOFT_RESET);
3981c66496bSKevin Tang 	writel(0xffffffff, ctx->base + MASK_PROTOCOL_INT);
3991c66496bSKevin Tang 	writel(0xffffffff, ctx->base + MASK_INTERNAL_INT);
4001c66496bSKevin Tang 	writel(1, ctx->base + DSI_MODE_CFG);
4011c66496bSKevin Tang 	dsi_reg_up(ctx, EOTP_EN, RX_EOTP_EN, 0);
4021c66496bSKevin Tang 	dsi_reg_up(ctx, EOTP_EN, TX_EOTP_EN, 0);
4031c66496bSKevin Tang 	dsi_reg_up(ctx, RX_PKT_CHECK_CONFIG, RX_PKT_ECC_EN, RX_PKT_ECC_EN);
4041c66496bSKevin Tang 	dsi_reg_up(ctx, RX_PKT_CHECK_CONFIG, RX_PKT_CRC_EN, RX_PKT_CRC_EN);
4051c66496bSKevin Tang 	writel(1, ctx->base + TA_EN);
4061c66496bSKevin Tang 	dsi_reg_up(ctx, VIRTUAL_CHANNEL_ID, VIDEO_PKT_VCID, 0);
4071c66496bSKevin Tang 	dsi_reg_up(ctx, VIRTUAL_CHANNEL_ID, GEN_RX_VCID, 0);
4081c66496bSKevin Tang 
4091c66496bSKevin Tang 	div = DIV_ROUND_UP(byte_clk, dsi->slave->lp_rate);
4101c66496bSKevin Tang 	writel(div, ctx->base + TX_ESC_CLK_CONFIG);
4111c66496bSKevin Tang 
4121c66496bSKevin Tang 	max_rd_time = ns_to_cycle(ctx->max_rd_time, byte_clk);
4131c66496bSKevin Tang 	writel(max_rd_time, ctx->base + MAX_READ_TIME);
4141c66496bSKevin Tang 
4151c66496bSKevin Tang 	data_hs2lp = ns_to_cycle(ctx->data_hs2lp, byte_clk);
4161c66496bSKevin Tang 	data_lp2hs = ns_to_cycle(ctx->data_lp2hs, byte_clk);
4171c66496bSKevin Tang 	clk_hs2lp = ns_to_cycle(ctx->clk_hs2lp, byte_clk);
4181c66496bSKevin Tang 	clk_lp2hs = ns_to_cycle(ctx->clk_lp2hs, byte_clk);
4191c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_DATALANE_TIME_CONFIG,
4201c66496bSKevin Tang 		   PHY_DATALANE_HS_TO_LP_TIME, 16, data_hs2lp);
4211c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_DATALANE_TIME_CONFIG,
4221c66496bSKevin Tang 		   PHY_DATALANE_LP_TO_HS_TIME, 0, data_lp2hs);
4231c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_CLKLANE_TIME_CONFIG,
4241c66496bSKevin Tang 		   PHY_CLKLANE_HS_TO_LP_TIME, 16, clk_hs2lp);
4251c66496bSKevin Tang 	dsi_reg_wr(ctx, PHY_CLKLANE_TIME_CONFIG,
4261c66496bSKevin Tang 		   PHY_CLKLANE_LP_TO_HS_TIME, 0, clk_lp2hs);
4271c66496bSKevin Tang 
4281c66496bSKevin Tang 	writel(1, ctx->base + SOFT_RESET);
4291c66496bSKevin Tang }
4301c66496bSKevin Tang 
4311c66496bSKevin Tang /*
4321c66496bSKevin Tang  * Free up resources and shutdown host controller and PHY
4331c66496bSKevin Tang  */
sprd_dsi_fini(struct dsi_context * ctx)4341c66496bSKevin Tang static void sprd_dsi_fini(struct dsi_context *ctx)
4351c66496bSKevin Tang {
4361c66496bSKevin Tang 	writel(0xffffffff, ctx->base + MASK_PROTOCOL_INT);
4371c66496bSKevin Tang 	writel(0xffffffff, ctx->base + MASK_INTERNAL_INT);
4381c66496bSKevin Tang 	writel(0, ctx->base + SOFT_RESET);
4391c66496bSKevin Tang }
4401c66496bSKevin Tang 
4411c66496bSKevin Tang /*
4421c66496bSKevin Tang  * If not in burst mode, it will compute the video and null packet sizes
4431c66496bSKevin Tang  * according to necessity.
4441c66496bSKevin Tang  * Configure timers for data lanes and/or clock lane to return to LP when
4451c66496bSKevin Tang  * bandwidth is not filled by data.
4461c66496bSKevin Tang  */
sprd_dsi_dpi_video(struct dsi_context * ctx)4471c66496bSKevin Tang static int sprd_dsi_dpi_video(struct dsi_context *ctx)
4481c66496bSKevin Tang {
4491c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
4501c66496bSKevin Tang 	struct videomode *vm = &ctx->vm;
4511c66496bSKevin Tang 	u32 byte_clk = dsi->slave->hs_rate / 8;
4521c66496bSKevin Tang 	u16 bpp_x100;
4531c66496bSKevin Tang 	u16 video_size;
4541c66496bSKevin Tang 	u32 ratio_x1000;
4551c66496bSKevin Tang 	u16 null_pkt_size = 0;
4561c66496bSKevin Tang 	u8 video_size_step;
4571c66496bSKevin Tang 	u32 hs_to;
4581c66496bSKevin Tang 	u32 total_bytes;
4591c66496bSKevin Tang 	u32 bytes_per_chunk;
4601c66496bSKevin Tang 	u32 chunks = 0;
4611c66496bSKevin Tang 	u32 bytes_left = 0;
4621c66496bSKevin Tang 	u32 chunk_overhead;
4631c66496bSKevin Tang 	const u8 pkt_header = 6;
4641c66496bSKevin Tang 	u8 coding;
4651c66496bSKevin Tang 	int div;
4661c66496bSKevin Tang 	u16 hline;
4671c66496bSKevin Tang 	u16 byte_cycle;
4681c66496bSKevin Tang 
4691c66496bSKevin Tang 	coding = fmt_to_coding(dsi->slave->format);
4701c66496bSKevin Tang 	video_size = round_video_size(coding, vm->hactive);
4711c66496bSKevin Tang 	bpp_x100 = calc_bytes_per_pixel_x100(coding);
4721c66496bSKevin Tang 	video_size_step = calc_video_size_step(coding);
4731c66496bSKevin Tang 	ratio_x1000 = byte_clk * 1000 / (vm->pixelclock / 1000);
4741c66496bSKevin Tang 	hline = vm->hactive + vm->hsync_len + vm->hfront_porch +
4751c66496bSKevin Tang 		vm->hback_porch;
4761c66496bSKevin Tang 
4771c66496bSKevin Tang 	writel(0, ctx->base + SOFT_RESET);
4781c66496bSKevin Tang 	dsi_reg_wr(ctx, VID_MODE_CFG, FRAME_BTA_ACK_EN, 15, ctx->frame_ack_en);
4791c66496bSKevin Tang 	dsi_reg_wr(ctx, DPI_VIDEO_FORMAT, DPI_VIDEO_MODE_FORMAT, 0, coding);
4801c66496bSKevin Tang 	dsi_reg_wr(ctx, VID_MODE_CFG, VID_MODE_TYPE, 0, ctx->burst_mode);
4811c66496bSKevin Tang 	byte_cycle = 95 * hline * ratio_x1000 / 100000;
4821c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_SIG_DELAY_CONFIG, VIDEO_SIG_DELAY, 0, byte_cycle);
4831c66496bSKevin Tang 	byte_cycle = hline * ratio_x1000 / 1000;
4841c66496bSKevin Tang 	writel(byte_cycle, ctx->base + VIDEO_LINE_TIME);
4851c66496bSKevin Tang 	byte_cycle = vm->hsync_len * ratio_x1000 / 1000;
4861c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_LINE_HBLK_TIME, VIDEO_LINE_HSA_TIME, 16, byte_cycle);
4871c66496bSKevin Tang 	byte_cycle = vm->hback_porch * ratio_x1000 / 1000;
4881c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_LINE_HBLK_TIME, VIDEO_LINE_HBP_TIME, 0, byte_cycle);
4891c66496bSKevin Tang 	writel(vm->vactive, ctx->base + VIDEO_VACTIVE_LINES);
4901c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_VBLK_LINES, VFP_LINES, 0, vm->vfront_porch);
4911c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_VBLK_LINES, VBP_LINES, 10, vm->vback_porch);
4921c66496bSKevin Tang 	dsi_reg_wr(ctx, VIDEO_VBLK_LINES, VSA_LINES, 20, vm->vsync_len);
4931c66496bSKevin Tang 	dsi_reg_up(ctx, VID_MODE_CFG, LP_HBP_EN | LP_HFP_EN | LP_VACT_EN |
4941c66496bSKevin Tang 			LP_VFP_EN | LP_VBP_EN | LP_VSA_EN, LP_HBP_EN | LP_HFP_EN |
4951c66496bSKevin Tang 			LP_VACT_EN | LP_VFP_EN | LP_VBP_EN | LP_VSA_EN);
4961c66496bSKevin Tang 
4971c66496bSKevin Tang 	hs_to = (hline * vm->vactive) + (2 * bpp_x100) / 100;
4981c66496bSKevin Tang 	for (div = 0x80; (div < hs_to) && (div > 2); div--) {
4991c66496bSKevin Tang 		if ((hs_to % div) == 0) {
5001c66496bSKevin Tang 			writel(div, ctx->base + TIMEOUT_CNT_CLK_CONFIG);
5011c66496bSKevin Tang 			writel(hs_to / div, ctx->base + LRX_H_TO_CONFIG);
5021c66496bSKevin Tang 			writel(hs_to / div, ctx->base + HTX_TO_CONFIG);
5031c66496bSKevin Tang 			break;
5041c66496bSKevin Tang 		}
5051c66496bSKevin Tang 	}
5061c66496bSKevin Tang 
5071c66496bSKevin Tang 	if (ctx->burst_mode == VIDEO_BURST_WITH_SYNC_PULSES) {
5081c66496bSKevin Tang 		dsi_reg_wr(ctx, VIDEO_PKT_CONFIG, VIDEO_PKT_SIZE, 0, video_size);
5091c66496bSKevin Tang 		writel(0, ctx->base + VIDEO_NULLPKT_SIZE);
5101c66496bSKevin Tang 		dsi_reg_up(ctx, VIDEO_PKT_CONFIG, VIDEO_LINE_CHUNK_NUM, 0);
5111c66496bSKevin Tang 	} else {
5121c66496bSKevin Tang 		/* non burst transmission */
5131c66496bSKevin Tang 		null_pkt_size = 0;
5141c66496bSKevin Tang 
5151c66496bSKevin Tang 		/* bytes to be sent - first as one chunk */
5161c66496bSKevin Tang 		bytes_per_chunk = vm->hactive * bpp_x100 / 100 + pkt_header;
5171c66496bSKevin Tang 
5181c66496bSKevin Tang 		/* hline total bytes from the DPI interface */
5191c66496bSKevin Tang 		total_bytes = (vm->hactive + vm->hfront_porch) *
5201c66496bSKevin Tang 				ratio_x1000 / dsi->slave->lanes / 1000;
5211c66496bSKevin Tang 
5221c66496bSKevin Tang 		/* check if the pixels actually fit on the DSI link */
5231c66496bSKevin Tang 		if (total_bytes < bytes_per_chunk) {
5241c66496bSKevin Tang 			drm_err(dsi->drm, "current resolution can not be set\n");
5251c66496bSKevin Tang 			return -EINVAL;
5261c66496bSKevin Tang 		}
5271c66496bSKevin Tang 
5281c66496bSKevin Tang 		chunk_overhead = total_bytes - bytes_per_chunk;
5291c66496bSKevin Tang 
5301c66496bSKevin Tang 		/* overhead higher than 1 -> enable multi packets */
5311c66496bSKevin Tang 		if (chunk_overhead > 1) {
5321c66496bSKevin Tang 			/* multi packets */
5331c66496bSKevin Tang 			for (video_size = video_size_step;
5341c66496bSKevin Tang 			     video_size < vm->hactive;
5351c66496bSKevin Tang 			     video_size += video_size_step) {
5361c66496bSKevin Tang 				if (vm->hactive * 1000 / video_size % 1000)
5371c66496bSKevin Tang 					continue;
5381c66496bSKevin Tang 
5391c66496bSKevin Tang 				chunks = vm->hactive / video_size;
5401c66496bSKevin Tang 				bytes_per_chunk = bpp_x100 * video_size / 100
5411c66496bSKevin Tang 						  + pkt_header;
5421c66496bSKevin Tang 				if (total_bytes >= (bytes_per_chunk * chunks)) {
5431c66496bSKevin Tang 					bytes_left = total_bytes -
5441c66496bSKevin Tang 						     bytes_per_chunk * chunks;
5451c66496bSKevin Tang 					break;
5461c66496bSKevin Tang 				}
5471c66496bSKevin Tang 			}
5481c66496bSKevin Tang 
5491c66496bSKevin Tang 			/* prevent overflow (unsigned - unsigned) */
5501c66496bSKevin Tang 			if (bytes_left > (pkt_header * chunks)) {
5511c66496bSKevin Tang 				null_pkt_size = (bytes_left -
5521c66496bSKevin Tang 						pkt_header * chunks) / chunks;
5531c66496bSKevin Tang 				/* avoid register overflow */
5541c66496bSKevin Tang 				if (null_pkt_size > 1023)
5551c66496bSKevin Tang 					null_pkt_size = 1023;
5561c66496bSKevin Tang 			}
5571c66496bSKevin Tang 
5581c66496bSKevin Tang 		} else {
5591c66496bSKevin Tang 			/* single packet */
5601c66496bSKevin Tang 			chunks = 1;
5611c66496bSKevin Tang 
5621c66496bSKevin Tang 			/* must be a multiple of 4 except 18 loosely */
5631c66496bSKevin Tang 			for (video_size = vm->hactive;
5641c66496bSKevin Tang 			    (video_size % video_size_step) != 0;
5651c66496bSKevin Tang 			     video_size++)
5661c66496bSKevin Tang 				;
5671c66496bSKevin Tang 		}
5681c66496bSKevin Tang 
5691c66496bSKevin Tang 		dsi_reg_wr(ctx, VIDEO_PKT_CONFIG, VIDEO_PKT_SIZE, 0, video_size);
5701c66496bSKevin Tang 		writel(null_pkt_size, ctx->base + VIDEO_NULLPKT_SIZE);
5711c66496bSKevin Tang 		dsi_reg_wr(ctx, VIDEO_PKT_CONFIG, VIDEO_LINE_CHUNK_NUM, 16, chunks);
5721c66496bSKevin Tang 	}
5731c66496bSKevin Tang 
5741c66496bSKevin Tang 	writel(ctx->int0_mask, ctx->base + MASK_PROTOCOL_INT);
5751c66496bSKevin Tang 	writel(ctx->int1_mask, ctx->base + MASK_INTERNAL_INT);
5761c66496bSKevin Tang 	writel(1, ctx->base + SOFT_RESET);
5771c66496bSKevin Tang 
5781c66496bSKevin Tang 	return 0;
5791c66496bSKevin Tang }
5801c66496bSKevin Tang 
sprd_dsi_edpi_video(struct dsi_context * ctx)5811c66496bSKevin Tang static void sprd_dsi_edpi_video(struct dsi_context *ctx)
5821c66496bSKevin Tang {
5831c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
5841c66496bSKevin Tang 	const u32 fifo_depth = 1096;
5851c66496bSKevin Tang 	const u32 word_length = 4;
5861c66496bSKevin Tang 	u32 hactive = ctx->vm.hactive;
5871c66496bSKevin Tang 	u32 bpp_x100;
5881c66496bSKevin Tang 	u32 max_fifo_len;
5891c66496bSKevin Tang 	u8 coding;
5901c66496bSKevin Tang 
5911c66496bSKevin Tang 	coding = fmt_to_coding(dsi->slave->format);
5921c66496bSKevin Tang 	bpp_x100 = calc_bytes_per_pixel_x100(coding);
5931c66496bSKevin Tang 	max_fifo_len = word_length * fifo_depth * 100 / bpp_x100;
5941c66496bSKevin Tang 
5951c66496bSKevin Tang 	writel(0, ctx->base + SOFT_RESET);
5961c66496bSKevin Tang 	dsi_reg_wr(ctx, DPI_VIDEO_FORMAT, DPI_VIDEO_MODE_FORMAT, 0, coding);
5971c66496bSKevin Tang 	dsi_reg_wr(ctx, CMD_MODE_CFG, TEAR_FX_EN, 0, ctx->te_ack_en);
5981c66496bSKevin Tang 
5991c66496bSKevin Tang 	if (max_fifo_len > hactive)
6001c66496bSKevin Tang 		writel(hactive, ctx->base + DCS_WM_PKT_SIZE);
6011c66496bSKevin Tang 	else
6021c66496bSKevin Tang 		writel(max_fifo_len, ctx->base + DCS_WM_PKT_SIZE);
6031c66496bSKevin Tang 
6041c66496bSKevin Tang 	writel(ctx->int0_mask, ctx->base + MASK_PROTOCOL_INT);
6051c66496bSKevin Tang 	writel(ctx->int1_mask, ctx->base + MASK_INTERNAL_INT);
6061c66496bSKevin Tang 	writel(1, ctx->base + SOFT_RESET);
6071c66496bSKevin Tang }
6081c66496bSKevin Tang 
6091c66496bSKevin Tang /*
6101c66496bSKevin Tang  * Send a packet on the generic interface,
6111c66496bSKevin Tang  * this function has an active delay to wait for the buffer to clear.
6121c66496bSKevin Tang  * The delay is limited to:
6131c66496bSKevin Tang  * (param_length / 4) x DSIH_FIFO_ACTIVE_WAIT x register access time
6141c66496bSKevin Tang  * the controller restricts the sending of.
6151c66496bSKevin Tang  *
6161c66496bSKevin Tang  * This function will not be able to send Null and Blanking packets due to
6171c66496bSKevin Tang  * controller restriction
6181c66496bSKevin Tang  */
sprd_dsi_wr_pkt(struct dsi_context * ctx,u8 vc,u8 type,const u8 * param,u16 len)6191c66496bSKevin Tang static int sprd_dsi_wr_pkt(struct dsi_context *ctx, u8 vc, u8 type,
6201c66496bSKevin Tang 			   const u8 *param, u16 len)
6211c66496bSKevin Tang {
6221c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
6231c66496bSKevin Tang 	u8 wc_lsbyte, wc_msbyte;
6241c66496bSKevin Tang 	u32 payload;
6251c66496bSKevin Tang 	int i, j, ret;
6261c66496bSKevin Tang 
6271c66496bSKevin Tang 	if (vc > 3)
6281c66496bSKevin Tang 		return -EINVAL;
6291c66496bSKevin Tang 
6301c66496bSKevin Tang 	/* 1st: for long packet, must config payload first */
6311c66496bSKevin Tang 	ret = dsi_wait_tx_payload_fifo_empty(ctx);
6321c66496bSKevin Tang 	if (ret) {
6331c66496bSKevin Tang 		drm_err(dsi->drm, "tx payload fifo is not empty\n");
6341c66496bSKevin Tang 		return ret;
6351c66496bSKevin Tang 	}
6361c66496bSKevin Tang 
6371c66496bSKevin Tang 	if (len > 2) {
6381c66496bSKevin Tang 		for (i = 0, j = 0; i < len; i += j) {
6391c66496bSKevin Tang 			payload = 0;
6401c66496bSKevin Tang 			for (j = 0; (j < 4) && ((j + i) < (len)); j++)
6411c66496bSKevin Tang 				payload |= param[i + j] << (j * 8);
6421c66496bSKevin Tang 
6431c66496bSKevin Tang 			writel(payload, ctx->base + GEN_PLD_DATA);
6441c66496bSKevin Tang 		}
6451c66496bSKevin Tang 		wc_lsbyte = len & 0xff;
6461c66496bSKevin Tang 		wc_msbyte = len >> 8;
6471c66496bSKevin Tang 	} else {
6481c66496bSKevin Tang 		wc_lsbyte = (len > 0) ? param[0] : 0;
6491c66496bSKevin Tang 		wc_msbyte = (len > 1) ? param[1] : 0;
6501c66496bSKevin Tang 	}
6511c66496bSKevin Tang 
6521c66496bSKevin Tang 	/* 2nd: then set packet header */
6531c66496bSKevin Tang 	ret = dsi_wait_tx_cmd_fifo_empty(ctx);
6541c66496bSKevin Tang 	if (ret) {
6551c66496bSKevin Tang 		drm_err(dsi->drm, "tx cmd fifo is not empty\n");
6561c66496bSKevin Tang 		return ret;
6571c66496bSKevin Tang 	}
6581c66496bSKevin Tang 
6591c66496bSKevin Tang 	writel(type | (vc << 6) | (wc_lsbyte << 8) | (wc_msbyte << 16),
6601c66496bSKevin Tang 	       ctx->base + GEN_HDR);
6611c66496bSKevin Tang 
6621c66496bSKevin Tang 	return 0;
6631c66496bSKevin Tang }
6641c66496bSKevin Tang 
6651c66496bSKevin Tang /*
6661c66496bSKevin Tang  * Send READ packet to peripheral using the generic interface,
6671c66496bSKevin Tang  * this will force command mode and stop video mode (because of BTA).
6681c66496bSKevin Tang  *
6691c66496bSKevin Tang  * This function has an active delay to wait for the buffer to clear,
6701c66496bSKevin Tang  * the delay is limited to 2 x DSIH_FIFO_ACTIVE_WAIT
6711c66496bSKevin Tang  * (waiting for command buffer, and waiting for receiving)
6721c66496bSKevin Tang  * @note this function will enable BTA
6731c66496bSKevin Tang  */
sprd_dsi_rd_pkt(struct dsi_context * ctx,u8 vc,u8 type,u8 msb_byte,u8 lsb_byte,u8 * buffer,u8 bytes_to_read)6741c66496bSKevin Tang static int sprd_dsi_rd_pkt(struct dsi_context *ctx, u8 vc, u8 type,
6751c66496bSKevin Tang 			   u8 msb_byte, u8 lsb_byte,
6761c66496bSKevin Tang 			   u8 *buffer, u8 bytes_to_read)
6771c66496bSKevin Tang {
6781c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
6791c66496bSKevin Tang 	int i, ret;
6801c66496bSKevin Tang 	int count = 0;
6811c66496bSKevin Tang 	u32 temp;
6821c66496bSKevin Tang 
6831c66496bSKevin Tang 	if (vc > 3)
6841c66496bSKevin Tang 		return -EINVAL;
6851c66496bSKevin Tang 
6861c66496bSKevin Tang 	/* 1st: send read command to peripheral */
6871c66496bSKevin Tang 	ret = dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_CMD_FIFO_EMPTY, 5);
6881c66496bSKevin Tang 	if (!ret)
6891c66496bSKevin Tang 		return -EIO;
6901c66496bSKevin Tang 
6911c66496bSKevin Tang 	writel(type | (vc << 6) | (lsb_byte << 8) | (msb_byte << 16),
6921c66496bSKevin Tang 	       ctx->base + GEN_HDR);
6931c66496bSKevin Tang 
6941c66496bSKevin Tang 	/* 2nd: wait peripheral response completed */
6951c66496bSKevin Tang 	ret = dsi_wait_rd_resp_completed(ctx);
6961c66496bSKevin Tang 	if (ret) {
6971c66496bSKevin Tang 		drm_err(dsi->drm, "wait read response time out\n");
6981c66496bSKevin Tang 		return ret;
6991c66496bSKevin Tang 	}
7001c66496bSKevin Tang 
7011c66496bSKevin Tang 	/* 3rd: get data from rx payload fifo */
7021c66496bSKevin Tang 	ret = dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_RDATA_FIFO_EMPTY, 1);
7031c66496bSKevin Tang 	if (ret) {
7041c66496bSKevin Tang 		drm_err(dsi->drm, "rx payload fifo empty\n");
7051c66496bSKevin Tang 		return -EIO;
7061c66496bSKevin Tang 	}
7071c66496bSKevin Tang 
7081c66496bSKevin Tang 	for (i = 0; i < 100; i++) {
7091c66496bSKevin Tang 		temp = readl(ctx->base + GEN_PLD_DATA);
7101c66496bSKevin Tang 
7111c66496bSKevin Tang 		if (count < bytes_to_read)
7121c66496bSKevin Tang 			buffer[count++] = temp & 0xff;
7131c66496bSKevin Tang 		if (count < bytes_to_read)
7141c66496bSKevin Tang 			buffer[count++] = (temp >> 8) & 0xff;
7151c66496bSKevin Tang 		if (count < bytes_to_read)
7161c66496bSKevin Tang 			buffer[count++] = (temp >> 16) & 0xff;
7171c66496bSKevin Tang 		if (count < bytes_to_read)
7181c66496bSKevin Tang 			buffer[count++] = (temp >> 24) & 0xff;
7191c66496bSKevin Tang 
7201c66496bSKevin Tang 		ret = dsi_reg_rd(ctx, CMD_MODE_STATUS, GEN_CMD_RDATA_FIFO_EMPTY, 1);
7211c66496bSKevin Tang 		if (ret)
7221c66496bSKevin Tang 			return count;
7231c66496bSKevin Tang 	}
7241c66496bSKevin Tang 
7251c66496bSKevin Tang 	return 0;
7261c66496bSKevin Tang }
7271c66496bSKevin Tang 
sprd_dsi_set_work_mode(struct dsi_context * ctx,u8 mode)7281c66496bSKevin Tang static void sprd_dsi_set_work_mode(struct dsi_context *ctx, u8 mode)
7291c66496bSKevin Tang {
7301c66496bSKevin Tang 	if (mode == DSI_MODE_CMD)
7311c66496bSKevin Tang 		writel(1, ctx->base + DSI_MODE_CFG);
7321c66496bSKevin Tang 	else
7331c66496bSKevin Tang 		writel(0, ctx->base + DSI_MODE_CFG);
7341c66496bSKevin Tang }
7351c66496bSKevin Tang 
sprd_dsi_state_reset(struct dsi_context * ctx)7361c66496bSKevin Tang static void sprd_dsi_state_reset(struct dsi_context *ctx)
7371c66496bSKevin Tang {
7381c66496bSKevin Tang 	writel(0, ctx->base + SOFT_RESET);
7391c66496bSKevin Tang 	udelay(100);
7401c66496bSKevin Tang 	writel(1, ctx->base + SOFT_RESET);
7411c66496bSKevin Tang }
7421c66496bSKevin Tang 
sprd_dphy_init(struct dsi_context * ctx)7431c66496bSKevin Tang static int sprd_dphy_init(struct dsi_context *ctx)
7441c66496bSKevin Tang {
7451c66496bSKevin Tang 	struct sprd_dsi *dsi = container_of(ctx, struct sprd_dsi, ctx);
7461c66496bSKevin Tang 	int ret;
7471c66496bSKevin Tang 
7481c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, 0);
7491c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_SHUTDOWN, 0);
7501c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_CLK_EN, 0);
7511c66496bSKevin Tang 
7521c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLR, 0);
7531c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLR, PHY_TESTCLR);
7541c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_TST_CTRL0, PHY_TESTCLR, 0);
7551c66496bSKevin Tang 
7561c66496bSKevin Tang 	dphy_pll_config(ctx);
7571c66496bSKevin Tang 	dphy_timing_config(ctx);
7581c66496bSKevin Tang 
7591c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_SHUTDOWN, RF_PHY_SHUTDOWN);
7601c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, RF_PHY_RESET_N);
7611c66496bSKevin Tang 	writel(0x1C, ctx->base + PHY_MIN_STOP_TIME);
7621c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_CLK_EN, RF_PHY_CLK_EN);
7631c66496bSKevin Tang 	writel(dsi->slave->lanes - 1, ctx->base + PHY_LANE_NUM_CONFIG);
7641c66496bSKevin Tang 
7651c66496bSKevin Tang 	ret = dphy_wait_pll_locked(ctx);
7661c66496bSKevin Tang 	if (ret) {
7671c66496bSKevin Tang 		drm_err(dsi->drm, "dphy initial failed\n");
7681c66496bSKevin Tang 		return ret;
7691c66496bSKevin Tang 	}
7701c66496bSKevin Tang 
7711c66496bSKevin Tang 	return 0;
7721c66496bSKevin Tang }
7731c66496bSKevin Tang 
sprd_dphy_fini(struct dsi_context * ctx)7741c66496bSKevin Tang static void sprd_dphy_fini(struct dsi_context *ctx)
7751c66496bSKevin Tang {
7761c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, 0);
7771c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_SHUTDOWN, 0);
7781c66496bSKevin Tang 	dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, RF_PHY_RESET_N);
7791c66496bSKevin Tang }
7801c66496bSKevin Tang 
sprd_dsi_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adj_mode)7811c66496bSKevin Tang static void sprd_dsi_encoder_mode_set(struct drm_encoder *encoder,
7821c66496bSKevin Tang 				      struct drm_display_mode *mode,
7831c66496bSKevin Tang 				 struct drm_display_mode *adj_mode)
7841c66496bSKevin Tang {
7851c66496bSKevin Tang 	struct sprd_dsi *dsi = encoder_to_dsi(encoder);
7861c66496bSKevin Tang 
7871c66496bSKevin Tang 	drm_display_mode_to_videomode(adj_mode, &dsi->ctx.vm);
7881c66496bSKevin Tang }
7891c66496bSKevin Tang 
sprd_dsi_encoder_enable(struct drm_encoder * encoder)7901c66496bSKevin Tang static void sprd_dsi_encoder_enable(struct drm_encoder *encoder)
7911c66496bSKevin Tang {
7921c66496bSKevin Tang 	struct sprd_dsi *dsi = encoder_to_dsi(encoder);
7931c66496bSKevin Tang 	struct sprd_dpu *dpu = to_sprd_crtc(encoder->crtc);
7941c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
7951c66496bSKevin Tang 
7961c66496bSKevin Tang 	if (ctx->enabled) {
7971c66496bSKevin Tang 		drm_warn(dsi->drm, "dsi is initialized\n");
7981c66496bSKevin Tang 		return;
7991c66496bSKevin Tang 	}
8001c66496bSKevin Tang 
8011c66496bSKevin Tang 	sprd_dsi_init(ctx);
8021c66496bSKevin Tang 	if (ctx->work_mode == DSI_MODE_VIDEO)
8031c66496bSKevin Tang 		sprd_dsi_dpi_video(ctx);
8041c66496bSKevin Tang 	else
8051c66496bSKevin Tang 		sprd_dsi_edpi_video(ctx);
8061c66496bSKevin Tang 
8071c66496bSKevin Tang 	sprd_dphy_init(ctx);
8081c66496bSKevin Tang 
8091c66496bSKevin Tang 	sprd_dsi_set_work_mode(ctx, ctx->work_mode);
8101c66496bSKevin Tang 	sprd_dsi_state_reset(ctx);
8111c66496bSKevin Tang 
8121c66496bSKevin Tang 	if (dsi->slave->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
8131c66496bSKevin Tang 		dsi_reg_up(ctx, PHY_CLK_LANE_LP_CTRL, AUTO_CLKLANE_CTRL_EN,
8141c66496bSKevin Tang 			   AUTO_CLKLANE_CTRL_EN);
8151c66496bSKevin Tang 	} else {
8161c66496bSKevin Tang 		dsi_reg_up(ctx, PHY_CLK_LANE_LP_CTRL, RF_PHY_CLK_EN, RF_PHY_CLK_EN);
8171c66496bSKevin Tang 		dsi_reg_up(ctx, PHY_CLK_LANE_LP_CTRL, PHY_CLKLANE_TX_REQ_HS,
8181c66496bSKevin Tang 			   PHY_CLKLANE_TX_REQ_HS);
8191c66496bSKevin Tang 		dphy_wait_pll_locked(ctx);
8201c66496bSKevin Tang 	}
8211c66496bSKevin Tang 
8221c66496bSKevin Tang 	sprd_dpu_run(dpu);
8231c66496bSKevin Tang 
8241c66496bSKevin Tang 	ctx->enabled = true;
8251c66496bSKevin Tang }
8261c66496bSKevin Tang 
sprd_dsi_encoder_disable(struct drm_encoder * encoder)8271c66496bSKevin Tang static void sprd_dsi_encoder_disable(struct drm_encoder *encoder)
8281c66496bSKevin Tang {
8291c66496bSKevin Tang 	struct sprd_dsi *dsi = encoder_to_dsi(encoder);
8301c66496bSKevin Tang 	struct sprd_dpu *dpu = to_sprd_crtc(encoder->crtc);
8311c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
8321c66496bSKevin Tang 
8331c66496bSKevin Tang 	if (!ctx->enabled) {
8341c66496bSKevin Tang 		drm_warn(dsi->drm, "dsi isn't initialized\n");
8351c66496bSKevin Tang 		return;
8361c66496bSKevin Tang 	}
8371c66496bSKevin Tang 
8381c66496bSKevin Tang 	sprd_dpu_stop(dpu);
8391c66496bSKevin Tang 	sprd_dphy_fini(ctx);
8401c66496bSKevin Tang 	sprd_dsi_fini(ctx);
8411c66496bSKevin Tang 
8421c66496bSKevin Tang 	ctx->enabled = false;
8431c66496bSKevin Tang }
8441c66496bSKevin Tang 
8451c66496bSKevin Tang static const struct drm_encoder_helper_funcs sprd_encoder_helper_funcs = {
8461c66496bSKevin Tang 	.mode_set	= sprd_dsi_encoder_mode_set,
8471c66496bSKevin Tang 	.enable		= sprd_dsi_encoder_enable,
8481c66496bSKevin Tang 	.disable	= sprd_dsi_encoder_disable
8491c66496bSKevin Tang };
8501c66496bSKevin Tang 
8511c66496bSKevin Tang static const struct drm_encoder_funcs sprd_encoder_funcs = {
8521c66496bSKevin Tang 	.destroy = drm_encoder_cleanup,
8531c66496bSKevin Tang };
8541c66496bSKevin Tang 
sprd_dsi_encoder_init(struct sprd_dsi * dsi,struct device * dev)8551c66496bSKevin Tang static int sprd_dsi_encoder_init(struct sprd_dsi *dsi,
8561c66496bSKevin Tang 				 struct device *dev)
8571c66496bSKevin Tang {
8581c66496bSKevin Tang 	struct drm_encoder *encoder = &dsi->encoder;
8591c66496bSKevin Tang 	u32 crtc_mask;
8601c66496bSKevin Tang 	int ret;
8611c66496bSKevin Tang 
8621c66496bSKevin Tang 	crtc_mask = drm_of_find_possible_crtcs(dsi->drm, dev->of_node);
8631c66496bSKevin Tang 	if (!crtc_mask) {
8641c66496bSKevin Tang 		drm_err(dsi->drm, "failed to find crtc mask\n");
8651c66496bSKevin Tang 		return -EINVAL;
8661c66496bSKevin Tang 	}
8671c66496bSKevin Tang 
8681c66496bSKevin Tang 	drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask);
8691c66496bSKevin Tang 
8701c66496bSKevin Tang 	encoder->possible_crtcs = crtc_mask;
8711c66496bSKevin Tang 	ret = drm_encoder_init(dsi->drm, encoder, &sprd_encoder_funcs,
8721c66496bSKevin Tang 			       DRM_MODE_ENCODER_DSI, NULL);
8731c66496bSKevin Tang 	if (ret) {
8741c66496bSKevin Tang 		drm_err(dsi->drm, "failed to init dsi encoder\n");
8751c66496bSKevin Tang 		return ret;
8761c66496bSKevin Tang 	}
8771c66496bSKevin Tang 
8781c66496bSKevin Tang 	drm_encoder_helper_add(encoder, &sprd_encoder_helper_funcs);
8791c66496bSKevin Tang 
8801c66496bSKevin Tang 	return 0;
8811c66496bSKevin Tang }
8821c66496bSKevin Tang 
sprd_dsi_bridge_init(struct sprd_dsi * dsi,struct device * dev)8831c66496bSKevin Tang static int sprd_dsi_bridge_init(struct sprd_dsi *dsi,
8841c66496bSKevin Tang 				struct device *dev)
8851c66496bSKevin Tang {
8861c66496bSKevin Tang 	int ret;
8871c66496bSKevin Tang 
8881c66496bSKevin Tang 	dsi->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
8891c66496bSKevin Tang 	if (IS_ERR(dsi->panel_bridge))
8901c66496bSKevin Tang 		return PTR_ERR(dsi->panel_bridge);
8911c66496bSKevin Tang 
8921c66496bSKevin Tang 	ret = drm_bridge_attach(&dsi->encoder, dsi->panel_bridge, NULL, 0);
8931c66496bSKevin Tang 	if (ret)
8941c66496bSKevin Tang 		return ret;
8951c66496bSKevin Tang 
8961c66496bSKevin Tang 	return 0;
8971c66496bSKevin Tang }
8981c66496bSKevin Tang 
sprd_dsi_context_init(struct sprd_dsi * dsi,struct device * dev)8991c66496bSKevin Tang static int sprd_dsi_context_init(struct sprd_dsi *dsi,
9001c66496bSKevin Tang 				 struct device *dev)
9011c66496bSKevin Tang {
9021c66496bSKevin Tang 	struct platform_device *pdev = to_platform_device(dev);
9031c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
9041c66496bSKevin Tang 	struct resource *res;
9051c66496bSKevin Tang 
9061c66496bSKevin Tang 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
90773792e6eSKevin Tang 	if (!res) {
90873792e6eSKevin Tang 		dev_err(dev, "failed to get I/O resource\n");
90973792e6eSKevin Tang 		return -EINVAL;
91073792e6eSKevin Tang 	}
91173792e6eSKevin Tang 
9121c66496bSKevin Tang 	ctx->base = devm_ioremap(dev, res->start, resource_size(res));
9131c66496bSKevin Tang 	if (!ctx->base) {
9141c66496bSKevin Tang 		drm_err(dsi->drm, "failed to map dsi host registers\n");
9151c66496bSKevin Tang 		return -ENXIO;
9161c66496bSKevin Tang 	}
9171c66496bSKevin Tang 
9181c66496bSKevin Tang 	ctx->regmap = devm_regmap_init(dev, &regmap_tst_io, dsi, &byte_config);
9191c66496bSKevin Tang 	if (IS_ERR(ctx->regmap)) {
9201c66496bSKevin Tang 		drm_err(dsi->drm, "dphy regmap init failed\n");
9211c66496bSKevin Tang 		return PTR_ERR(ctx->regmap);
9221c66496bSKevin Tang 	}
9231c66496bSKevin Tang 
9241c66496bSKevin Tang 	ctx->data_hs2lp = 120;
9251c66496bSKevin Tang 	ctx->data_lp2hs = 500;
9261c66496bSKevin Tang 	ctx->clk_hs2lp = 4;
9271c66496bSKevin Tang 	ctx->clk_lp2hs = 15;
9281c66496bSKevin Tang 	ctx->max_rd_time = 6000;
9291c66496bSKevin Tang 	ctx->int0_mask = 0xffffffff;
9301c66496bSKevin Tang 	ctx->int1_mask = 0xffffffff;
9311c66496bSKevin Tang 	ctx->enabled = true;
9321c66496bSKevin Tang 
9331c66496bSKevin Tang 	return 0;
9341c66496bSKevin Tang }
9351c66496bSKevin Tang 
sprd_dsi_bind(struct device * dev,struct device * master,void * data)9361c66496bSKevin Tang static int sprd_dsi_bind(struct device *dev, struct device *master, void *data)
9371c66496bSKevin Tang {
9381c66496bSKevin Tang 	struct drm_device *drm = data;
9391c66496bSKevin Tang 	struct sprd_dsi *dsi = dev_get_drvdata(dev);
9401c66496bSKevin Tang 	int ret;
9411c66496bSKevin Tang 
9421c66496bSKevin Tang 	dsi->drm = drm;
9431c66496bSKevin Tang 
9441c66496bSKevin Tang 	ret = sprd_dsi_encoder_init(dsi, dev);
9451c66496bSKevin Tang 	if (ret)
9461c66496bSKevin Tang 		return ret;
9471c66496bSKevin Tang 
9481c66496bSKevin Tang 	ret = sprd_dsi_bridge_init(dsi, dev);
9491c66496bSKevin Tang 	if (ret)
9501c66496bSKevin Tang 		return ret;
9511c66496bSKevin Tang 
9521c66496bSKevin Tang 	ret = sprd_dsi_context_init(dsi, dev);
9531c66496bSKevin Tang 	if (ret)
9541c66496bSKevin Tang 		return ret;
9551c66496bSKevin Tang 
9561c66496bSKevin Tang 	return 0;
9571c66496bSKevin Tang }
9581c66496bSKevin Tang 
sprd_dsi_unbind(struct device * dev,struct device * master,void * data)9591c66496bSKevin Tang static void sprd_dsi_unbind(struct device *dev,
9601c66496bSKevin Tang 			    struct device *master, void *data)
9611c66496bSKevin Tang {
9621c66496bSKevin Tang 	struct sprd_dsi *dsi = dev_get_drvdata(dev);
9631c66496bSKevin Tang 
9641c66496bSKevin Tang 	drm_of_panel_bridge_remove(dev->of_node, 1, 0);
9651c66496bSKevin Tang 
9661c66496bSKevin Tang 	drm_encoder_cleanup(&dsi->encoder);
9671c66496bSKevin Tang }
9681c66496bSKevin Tang 
9691c66496bSKevin Tang static const struct component_ops dsi_component_ops = {
9701c66496bSKevin Tang 	.bind	= sprd_dsi_bind,
9711c66496bSKevin Tang 	.unbind	= sprd_dsi_unbind,
9721c66496bSKevin Tang };
9731c66496bSKevin Tang 
sprd_dsi_host_attach(struct mipi_dsi_host * host,struct mipi_dsi_device * slave)9741c66496bSKevin Tang static int sprd_dsi_host_attach(struct mipi_dsi_host *host,
9751c66496bSKevin Tang 				struct mipi_dsi_device *slave)
9761c66496bSKevin Tang {
9771c66496bSKevin Tang 	struct sprd_dsi *dsi = host_to_dsi(host);
9781c66496bSKevin Tang 	struct dsi_context *ctx = &dsi->ctx;
9791c66496bSKevin Tang 
9801c66496bSKevin Tang 	dsi->slave = slave;
9811c66496bSKevin Tang 
9821c66496bSKevin Tang 	if (slave->mode_flags & MIPI_DSI_MODE_VIDEO)
9831c66496bSKevin Tang 		ctx->work_mode = DSI_MODE_VIDEO;
9841c66496bSKevin Tang 	else
9851c66496bSKevin Tang 		ctx->work_mode = DSI_MODE_CMD;
9861c66496bSKevin Tang 
9871c66496bSKevin Tang 	if (slave->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
9881c66496bSKevin Tang 		ctx->burst_mode = VIDEO_BURST_WITH_SYNC_PULSES;
9891c66496bSKevin Tang 	else if (slave->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
9901c66496bSKevin Tang 		ctx->burst_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES;
9911c66496bSKevin Tang 	else
9921c66496bSKevin Tang 		ctx->burst_mode = VIDEO_NON_BURST_WITH_SYNC_EVENTS;
9931c66496bSKevin Tang 
9941c66496bSKevin Tang 	return component_add(host->dev, &dsi_component_ops);
9951c66496bSKevin Tang }
9961c66496bSKevin Tang 
sprd_dsi_host_detach(struct mipi_dsi_host * host,struct mipi_dsi_device * slave)9971c66496bSKevin Tang static int sprd_dsi_host_detach(struct mipi_dsi_host *host,
9981c66496bSKevin Tang 				struct mipi_dsi_device *slave)
9991c66496bSKevin Tang {
10001c66496bSKevin Tang 	component_del(host->dev, &dsi_component_ops);
10011c66496bSKevin Tang 
10021c66496bSKevin Tang 	return 0;
10031c66496bSKevin Tang }
10041c66496bSKevin Tang 
sprd_dsi_host_transfer(struct mipi_dsi_host * host,const struct mipi_dsi_msg * msg)10051c66496bSKevin Tang static ssize_t sprd_dsi_host_transfer(struct mipi_dsi_host *host,
10061c66496bSKevin Tang 				      const struct mipi_dsi_msg *msg)
10071c66496bSKevin Tang {
10081c66496bSKevin Tang 	struct sprd_dsi *dsi = host_to_dsi(host);
10091c66496bSKevin Tang 	const u8 *tx_buf = msg->tx_buf;
10101c66496bSKevin Tang 
10111c66496bSKevin Tang 	if (msg->rx_buf && msg->rx_len) {
10121c66496bSKevin Tang 		u8 lsb = (msg->tx_len > 0) ? tx_buf[0] : 0;
10131c66496bSKevin Tang 		u8 msb = (msg->tx_len > 1) ? tx_buf[1] : 0;
10141c66496bSKevin Tang 
10151c66496bSKevin Tang 		return sprd_dsi_rd_pkt(&dsi->ctx, msg->channel, msg->type,
10161c66496bSKevin Tang 				msb, lsb, msg->rx_buf, msg->rx_len);
10171c66496bSKevin Tang 	}
10181c66496bSKevin Tang 
10191c66496bSKevin Tang 	if (msg->tx_buf && msg->tx_len)
10201c66496bSKevin Tang 		return sprd_dsi_wr_pkt(&dsi->ctx, msg->channel, msg->type,
10211c66496bSKevin Tang 					tx_buf, msg->tx_len);
10221c66496bSKevin Tang 
10231c66496bSKevin Tang 	return 0;
10241c66496bSKevin Tang }
10251c66496bSKevin Tang 
10261c66496bSKevin Tang static const struct mipi_dsi_host_ops sprd_dsi_host_ops = {
10271c66496bSKevin Tang 	.attach = sprd_dsi_host_attach,
10281c66496bSKevin Tang 	.detach = sprd_dsi_host_detach,
10291c66496bSKevin Tang 	.transfer = sprd_dsi_host_transfer,
10301c66496bSKevin Tang };
10311c66496bSKevin Tang 
10321c66496bSKevin Tang static const struct of_device_id dsi_match_table[] = {
10331c66496bSKevin Tang 	{ .compatible = "sprd,sharkl3-dsi-host" },
10341c66496bSKevin Tang 	{ /* sentinel */ },
10351c66496bSKevin Tang };
10361c66496bSKevin Tang 
sprd_dsi_probe(struct platform_device * pdev)10371c66496bSKevin Tang static int sprd_dsi_probe(struct platform_device *pdev)
10381c66496bSKevin Tang {
10391c66496bSKevin Tang 	struct device *dev = &pdev->dev;
10401c66496bSKevin Tang 	struct sprd_dsi *dsi;
10411c66496bSKevin Tang 
10421c66496bSKevin Tang 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
10431c66496bSKevin Tang 	if (!dsi)
10441c66496bSKevin Tang 		return -ENOMEM;
10451c66496bSKevin Tang 
10461c66496bSKevin Tang 	dev_set_drvdata(dev, dsi);
10471c66496bSKevin Tang 
10481c66496bSKevin Tang 	dsi->host.ops = &sprd_dsi_host_ops;
10491c66496bSKevin Tang 	dsi->host.dev = dev;
10501c66496bSKevin Tang 
10511c66496bSKevin Tang 	return mipi_dsi_host_register(&dsi->host);
10521c66496bSKevin Tang }
10531c66496bSKevin Tang 
sprd_dsi_remove(struct platform_device * pdev)1054*16b01df3SUwe Kleine-König static void sprd_dsi_remove(struct platform_device *pdev)
10551c66496bSKevin Tang {
10561c66496bSKevin Tang 	struct sprd_dsi *dsi = dev_get_drvdata(&pdev->dev);
10571c66496bSKevin Tang 
10581c66496bSKevin Tang 	mipi_dsi_host_unregister(&dsi->host);
10591c66496bSKevin Tang }
10601c66496bSKevin Tang 
10611c66496bSKevin Tang struct platform_driver sprd_dsi_driver = {
10621c66496bSKevin Tang 	.probe = sprd_dsi_probe,
1063*16b01df3SUwe Kleine-König 	.remove_new = sprd_dsi_remove,
10641c66496bSKevin Tang 	.driver = {
10651c66496bSKevin Tang 		.name = "sprd-dsi-drv",
10661c66496bSKevin Tang 		.of_match_table = dsi_match_table,
10671c66496bSKevin Tang 	},
10681c66496bSKevin Tang };
10691c66496bSKevin Tang 
10701c66496bSKevin Tang MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
10711c66496bSKevin Tang MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
10721c66496bSKevin Tang MODULE_DESCRIPTION("Unisoc MIPI DSI HOST Controller Driver");
10731c66496bSKevin Tang MODULE_LICENSE("GPL v2");
1074