1234353Sdim// SPDX-License-Identifier: GPL-2.0+
2193323Sed/*
3193323Sed * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
4193323Sed * Copyright (C) STMicroelectronics SA 2017
5193323Sed *
6193323Sed * Modified by Philippe Cornu <philippe.cornu@st.com>
7193323Sed * This generic Synopsys DesignWare MIPI DSI host driver is based on the
8193323Sed * Rockchip version from rockchip/dw-mipi-dsi.c with phy & bridge APIs.
9193323Sed */
10193323Sed
11193323Sed#include <linux/clk.h>
12193323Sed#include <linux/component.h>
13193323Sed#include <linux/debugfs.h>
14218893Sdim#include <linux/iopoll.h>
15218893Sdim#include <linux/math64.h>
16218893Sdim#include <linux/media-bus-format.h>
17218893Sdim#include <linux/module.h>
18218893Sdim#include <linux/platform_device.h>
19193323Sed#include <linux/pm_runtime.h>
20218893Sdim#include <linux/reset.h>
21218893Sdim
22218893Sdim#include <video/mipi_display.h>
23218893Sdim
24218893Sdim#include <drm/bridge/dw_mipi_dsi.h>
25218893Sdim#include <drm/drm_atomic_helper.h>
26218893Sdim#include <drm/drm_bridge.h>
27218893Sdim#include <drm/drm_connector.h>
28193323Sed#include <drm/drm_crtc.h>
29218893Sdim#include <drm/drm_mipi_dsi.h>
30193323Sed#include <drm/drm_modes.h>
31198892Srdivacky#include <drm/drm_of.h>
32198892Srdivacky#include <drm/drm_print.h>
33198892Srdivacky
34226633Sdim#define HWVER_131			0x31333100	/* IP version 1.31 */
35226633Sdim
36226633Sdim#define DSI_VERSION			0x00
37226633Sdim#define VERSION				GENMASK(31, 8)
38226633Sdim
39226633Sdim#define DSI_PWR_UP			0x04
40198892Srdivacky#define RESET				0
41198892Srdivacky#define POWERUP				BIT(0)
42226633Sdim
43226633Sdim#define DSI_CLKMGR_CFG			0x08
44226633Sdim#define TO_CLK_DIVISION(div)		(((div) & 0xff) << 8)
45226633Sdim#define TX_ESC_CLK_DIVISION(div)	((div) & 0xff)
46226633Sdim
47226633Sdim#define DSI_DPI_VCID			0x0c
48226633Sdim#define DPI_VCID(vcid)			((vcid) & 0x3)
49226633Sdim
50198892Srdivacky#define DSI_DPI_COLOR_CODING		0x10
51198892Srdivacky#define LOOSELY18_EN			BIT(8)
52198892Srdivacky#define DPI_COLOR_CODING_16BIT_1	0x0
53198892Srdivacky#define DPI_COLOR_CODING_16BIT_2	0x1
54226633Sdim#define DPI_COLOR_CODING_16BIT_3	0x2
55226633Sdim#define DPI_COLOR_CODING_18BIT_1	0x3
56226633Sdim#define DPI_COLOR_CODING_18BIT_2	0x4
57226633Sdim#define DPI_COLOR_CODING_24BIT		0x5
58226633Sdim
59226633Sdim#define DSI_DPI_CFG_POL			0x14
60226633Sdim#define COLORM_ACTIVE_LOW		BIT(4)
61226633Sdim#define SHUTD_ACTIVE_LOW		BIT(3)
62198892Srdivacky#define HSYNC_ACTIVE_LOW		BIT(2)
63198892Srdivacky#define VSYNC_ACTIVE_LOW		BIT(1)
64239462Sdim#define DATAEN_ACTIVE_LOW		BIT(0)
65239462Sdim
66239462Sdim#define DSI_DPI_LP_CMD_TIM		0x18
67239462Sdim#define OUTVACT_LPCMD_TIME(p)		(((p) & 0xff) << 16)
68239462Sdim#define INVACT_LPCMD_TIME(p)		((p) & 0xff)
69239462Sdim
70239462Sdim#define DSI_DBI_VCID			0x1c
71239462Sdim#define DSI_DBI_CFG			0x20
72239462Sdim#define DSI_DBI_PARTITIONING_EN		0x24
73234353Sdim#define DSI_DBI_CMDSIZE			0x28
74234353Sdim
75234353Sdim#define DSI_PCKHDL_CFG			0x2c
76234353Sdim#define CRC_RX_EN			BIT(4)
77234353Sdim#define ECC_RX_EN			BIT(3)
78234353Sdim#define BTA_EN				BIT(2)
79234353Sdim#define EOTP_RX_EN			BIT(1)
80234353Sdim#define EOTP_TX_EN			BIT(0)
81234353Sdim
82234353Sdim#define DSI_GEN_VCID			0x30
83198892Srdivacky
84234353Sdim#define DSI_MODE_CFG			0x34
85234353Sdim#define ENABLE_VIDEO_MODE		0
86234353Sdim#define ENABLE_CMD_MODE			BIT(0)
87234353Sdim
88234353Sdim#define DSI_VID_MODE_CFG		0x38
89234353Sdim#define ENABLE_LOW_POWER		(0x3f << 8)
90198892Srdivacky#define ENABLE_LOW_POWER_MASK		(0x3f << 8)
91193323Sed#define VID_MODE_TYPE_NON_BURST_SYNC_PULSES	0x0
92193323Sed#define VID_MODE_TYPE_NON_BURST_SYNC_EVENTS	0x1
93193323Sed#define VID_MODE_TYPE_BURST			0x2
94204642Srdivacky#define VID_MODE_TYPE_MASK			0x3
95193323Sed#define ENABLE_LOW_POWER_CMD		BIT(15)
96218893Sdim#define VID_MODE_VPG_ENABLE		BIT(16)
97234353Sdim#define VID_MODE_VPG_MODE		BIT(20)
98239462Sdim#define VID_MODE_VPG_HORIZONTAL		BIT(24)
99193323Sed
100218893Sdim#define DSI_VID_PKT_SIZE		0x3c
101234353Sdim#define VID_PKT_SIZE(p)			((p) & 0x3fff)
102218893Sdim
103218893Sdim#define DSI_VID_NUM_CHUNKS		0x40
104218893Sdim#define VID_NUM_CHUNKS(c)		((c) & 0x1fff)
105218893Sdim
106218893Sdim#define DSI_VID_NULL_SIZE		0x44
107193323Sed#define VID_NULL_SIZE(b)		((b) & 0x1fff)
108218893Sdim
109193323Sed#define DSI_VID_HSA_TIME		0x48
110218893Sdim#define DSI_VID_HBP_TIME		0x4c
111234353Sdim#define DSI_VID_HLINE_TIME		0x50
112239462Sdim#define DSI_VID_VSA_LINES		0x54
113218893Sdim#define DSI_VID_VBP_LINES		0x58
114218893Sdim#define DSI_VID_VFP_LINES		0x5c
115234353Sdim#define DSI_VID_VACTIVE_LINES		0x60
116218893Sdim#define DSI_EDPI_CMD_SIZE		0x64
117218893Sdim
118218893Sdim#define DSI_CMD_MODE_CFG		0x68
119218893Sdim#define MAX_RD_PKT_SIZE_LP		BIT(24)
120218893Sdim#define DCS_LW_TX_LP			BIT(19)
121218893Sdim#define DCS_SR_0P_TX_LP			BIT(18)
122193323Sed#define DCS_SW_1P_TX_LP			BIT(17)
123193323Sed#define DCS_SW_0P_TX_LP			BIT(16)
124193323Sed#define GEN_LW_TX_LP			BIT(14)
125193323Sed#define GEN_SR_2P_TX_LP			BIT(13)
126218893Sdim#define GEN_SR_1P_TX_LP			BIT(12)
127218893Sdim#define GEN_SR_0P_TX_LP			BIT(11)
128218893Sdim#define GEN_SW_2P_TX_LP			BIT(10)
129218893Sdim#define GEN_SW_1P_TX_LP			BIT(9)
130218893Sdim#define GEN_SW_0P_TX_LP			BIT(8)
131218893Sdim#define ACK_RQST_EN			BIT(1)
132218893Sdim#define TEAR_FX_EN			BIT(0)
133218893Sdim
134218893Sdim#define CMD_MODE_ALL_LP			(MAX_RD_PKT_SIZE_LP | \
135218893Sdim					 DCS_LW_TX_LP | \
136218893Sdim					 DCS_SR_0P_TX_LP | \
137218893Sdim					 DCS_SW_1P_TX_LP | \
138224145Sdim					 DCS_SW_0P_TX_LP | \
139224145Sdim					 GEN_LW_TX_LP | \
140218893Sdim					 GEN_SR_2P_TX_LP | \
141218893Sdim					 GEN_SR_1P_TX_LP | \
142218893Sdim					 GEN_SR_0P_TX_LP | \
143218893Sdim					 GEN_SW_2P_TX_LP | \
144218893Sdim					 GEN_SW_1P_TX_LP | \
145218893Sdim					 GEN_SW_0P_TX_LP)
146218893Sdim
147224145Sdim#define DSI_GEN_HDR			0x6c
148224145Sdim#define DSI_GEN_PLD_DATA		0x70
149218893Sdim
150218893Sdim#define DSI_CMD_PKT_STATUS		0x74
151218893Sdim#define GEN_RD_CMD_BUSY			BIT(6)
152218893Sdim#define GEN_PLD_R_FULL			BIT(5)
153218893Sdim#define GEN_PLD_R_EMPTY			BIT(4)
154218893Sdim#define GEN_PLD_W_FULL			BIT(3)
155193323Sed#define GEN_PLD_W_EMPTY			BIT(2)
156218893Sdim#define GEN_CMD_FULL			BIT(1)
157218893Sdim#define GEN_CMD_EMPTY			BIT(0)
158218893Sdim
159218893Sdim#define DSI_TO_CNT_CFG			0x78
160218893Sdim#define HSTX_TO_CNT(p)			(((p) & 0xffff) << 16)
161218893Sdim#define LPRX_TO_CNT(p)			((p) & 0xffff)
162218893Sdim
163218893Sdim#define DSI_HS_RD_TO_CNT		0x7c
164205218Srdivacky#define DSI_LP_RD_TO_CNT		0x80
165218893Sdim#define DSI_HS_WR_TO_CNT		0x84
166218893Sdim#define DSI_LP_WR_TO_CNT		0x88
167218893Sdim#define DSI_BTA_TO_CNT			0x8c
168218893Sdim
169218893Sdim#define DSI_LPCLK_CTRL			0x94
170224145Sdim#define AUTO_CLKLANE_CTRL		BIT(1)
171224145Sdim#define PHY_TXREQUESTCLKHS		BIT(0)
172218893Sdim
173218893Sdim#define DSI_PHY_TMR_LPCLK_CFG		0x98
174218893Sdim#define PHY_CLKHS2LP_TIME(lbcc)		(((lbcc) & 0x3ff) << 16)
175218893Sdim#define PHY_CLKLP2HS_TIME(lbcc)		((lbcc) & 0x3ff)
176218893Sdim
177205218Srdivacky#define DSI_PHY_TMR_CFG			0x9c
178218893Sdim#define PHY_HS2LP_TIME(lbcc)		(((lbcc) & 0xff) << 24)
179218893Sdim#define PHY_LP2HS_TIME(lbcc)		(((lbcc) & 0xff) << 16)
180218893Sdim#define MAX_RD_TIME(lbcc)		((lbcc) & 0x7fff)
181218893Sdim#define PHY_HS2LP_TIME_V131(lbcc)	(((lbcc) & 0x3ff) << 16)
182218893Sdim#define PHY_LP2HS_TIME_V131(lbcc)	((lbcc) & 0x3ff)
183224145Sdim
184224145Sdim#define DSI_PHY_RSTZ			0xa0
185218893Sdim#define PHY_DISFORCEPLL			0
186218893Sdim#define PHY_ENFORCEPLL			BIT(3)
187218893Sdim#define PHY_DISABLECLK			0
188218893Sdim#define PHY_ENABLECLK			BIT(2)
189218893Sdim#define PHY_RSTZ			0
190193323Sed#define PHY_UNRSTZ			BIT(1)
191218893Sdim#define PHY_SHUTDOWNZ			0
192218893Sdim#define PHY_UNSHUTDOWNZ			BIT(0)
193218893Sdim
194218893Sdim#define DSI_PHY_IF_CFG			0xa4
195193323Sed#define PHY_STOP_WAIT_TIME(cycle)	(((cycle) & 0xff) << 8)
196205218Srdivacky#define N_LANES(n)			(((n) - 1) & 0x3)
197218893Sdim
198205218Srdivacky#define DSI_PHY_ULPS_CTRL		0xa8
199218893Sdim#define DSI_PHY_TX_TRIGGERS		0xac
200218893Sdim
201193323Sed#define DSI_PHY_STATUS			0xb0
202218893Sdim#define PHY_STOP_STATE_CLK_LANE		BIT(2)
203218893Sdim#define PHY_LOCK			BIT(0)
204218893Sdim
205218893Sdim#define DSI_PHY_TST_CTRL0		0xb4
206218893Sdim#define PHY_TESTCLK			BIT(1)
207218893Sdim#define PHY_UNTESTCLK			0
208218893Sdim#define PHY_TESTCLR			BIT(0)
209218893Sdim#define PHY_UNTESTCLR			0
210224145Sdim
211224145Sdim#define DSI_PHY_TST_CTRL1		0xb8
212224145Sdim#define PHY_TESTEN			BIT(16)
213224145Sdim#define PHY_UNTESTEN			0
214224145Sdim#define PHY_TESTDOUT(n)			(((n) & 0xff) << 8)
215224145Sdim#define PHY_TESTDIN(n)			((n) & 0xff)
216224145Sdim
217224145Sdim#define DSI_INT_ST0			0xbc
218234353Sdim#define DSI_INT_ST1			0xc0
219234353Sdim#define DSI_INT_MSK0			0xc4
220234353Sdim#define DSI_INT_MSK1			0xc8
221234353Sdim
222234353Sdim#define DSI_PHY_TMR_RD_CFG		0xf4
223234353Sdim#define MAX_RD_TIME_V131(lbcc)		((lbcc) & 0x7fff)
224234353Sdim
225234353Sdim#define PHY_STATUS_TIMEOUT_US		10000
226224145Sdim#define CMD_PKT_STATUS_TIMEOUT_US	20000
227263508Sdim
228263508Sdim#ifdef CONFIG_DEBUG_FS
229263508Sdim#define VPG_DEFS(name, dsi) \
230263508Sdim	((void __force *)&((*dsi).vpg_defs.name))
231263508Sdim
232263508Sdim#define REGISTER(name, mask, dsi) \
233263508Sdim	{ #name, VPG_DEFS(name, dsi), mask, dsi }
234263508Sdim
235263508Sdimstruct debugfs_entries {
236263508Sdim	const char				*name;
237263508Sdim	bool					*reg;
238263508Sdim	u32					mask;
239263508Sdim	struct dw_mipi_dsi			*dsi;
240263508Sdim};
241263508Sdim#endif /* CONFIG_DEBUG_FS */
242263508Sdim
243263508Sdimstruct dw_mipi_dsi {
244263508Sdim	struct drm_bridge bridge;
245263508Sdim	struct mipi_dsi_host dsi_host;
246263508Sdim	struct drm_bridge *panel_bridge;
247263508Sdim	struct device *dev;
248263508Sdim	void __iomem *base;
249263508Sdim
250263508Sdim	struct clk *pclk;
251263508Sdim
252263508Sdim	unsigned int lane_mbps; /* per lane */
253263508Sdim	u32 channel;
254193323Sed	u32 lanes;
255263508Sdim	u32 format;
256263508Sdim	unsigned long mode_flags;
257263508Sdim
258193323Sed#ifdef CONFIG_DEBUG_FS
259193323Sed	struct dentry *debugfs;
260193323Sed	struct debugfs_entries *debugfs_vpg;
261193323Sed	struct {
262239462Sdim		bool vpg;
263218893Sdim		bool vpg_horizontal;
264218893Sdim		bool vpg_ber_pattern;
265218893Sdim	} vpg_defs;
266218893Sdim#endif /* CONFIG_DEBUG_FS */
267193323Sed
268239462Sdim	struct dw_mipi_dsi *master; /* dual-dsi master ptr */
269218893Sdim	struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
270218893Sdim
271218893Sdim	struct drm_display_mode mode;
272218893Sdim	const struct dw_mipi_dsi_plat_data *plat_data;
273219077Sdim};
274219077Sdim
275219077Sdim/*
276218893Sdim * Check if either a link to a master or slave is present
277193323Sed */
278239462Sdimstatic inline bool dw_mipi_is_dual_mode(struct dw_mipi_dsi *dsi)
279218893Sdim{
280218893Sdim	return dsi->slave || dsi->master;
281218893Sdim}
282218893Sdim
283193323Sed/*
284239462Sdim * The controller should generate 2 frames before
285218893Sdim * preparing the peripheral.
286218893Sdim */
287218893Sdimstatic void dw_mipi_dsi_wait_for_two_frames(const struct drm_display_mode *mode)
288218893Sdim{
289219077Sdim	int refresh, two_frames;
290219077Sdim
291219077Sdim	refresh = drm_mode_vrefresh(mode);
292198090Srdivacky	two_frames = DIV_ROUND_UP(MSEC_PER_SEC, refresh) * 2;
293193323Sed	msleep(two_frames);
294239462Sdim}
295218893Sdim
296218893Sdimstatic inline struct dw_mipi_dsi *host_to_dsi(struct mipi_dsi_host *host)
297218893Sdim{
298218893Sdim	return container_of(host, struct dw_mipi_dsi, dsi_host);
299193323Sed}
300239462Sdim
301218893Sdimstatic inline struct dw_mipi_dsi *bridge_to_dsi(struct drm_bridge *bridge)
302218893Sdim{
303218893Sdim	return container_of(bridge, struct dw_mipi_dsi, bridge);
304218893Sdim}
305193323Sed
306239462Sdimstatic inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
307218893Sdim{
308218893Sdim	writel(val, dsi->base + reg);
309218893Sdim}
310218893Sdim
311193323Sedstatic inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
312239462Sdim{
313218893Sdim	return readl(dsi->base + reg);
314218893Sdim}
315218893Sdim
316218893Sdimstatic int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
317219077Sdim				   struct mipi_dsi_device *device)
318219077Sdim{
319219077Sdim	struct dw_mipi_dsi *dsi = host_to_dsi(host);
320218893Sdim	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
321199481Srdivacky	struct drm_bridge *bridge;
322218893Sdim	int ret;
323218893Sdim
324218893Sdim	if (device->lanes > dsi->plat_data->max_data_lanes) {
325218893Sdim		dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
326193323Sed			device->lanes);
327218893Sdim		return -EINVAL;
328218893Sdim	}
329218893Sdim
330218893Sdim	dsi->lanes = device->lanes;
331219077Sdim	dsi->channel = device->channel;
332219077Sdim	dsi->format = device->format;
333219077Sdim	dsi->mode_flags = device->mode_flags;
334218893Sdim
335193323Sed	bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
336263508Sdim	if (IS_ERR(bridge))
337263508Sdim		return PTR_ERR(bridge);
338263508Sdim
339263508Sdim	bridge->pre_enable_prev_first = true;
340263508Sdim	dsi->panel_bridge = bridge;
341263508Sdim
342263508Sdim	drm_bridge_add(&dsi->bridge);
343263508Sdim
344263508Sdim	if (pdata->host_ops && pdata->host_ops->attach) {
345263508Sdim		ret = pdata->host_ops->attach(pdata->priv_data, device);
346263508Sdim		if (ret < 0)
347263508Sdim			return ret;
348263508Sdim	}
349263508Sdim
350263508Sdim	return 0;
351263508Sdim}
352263508Sdim
353263508Sdimstatic int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
354263508Sdim				   struct mipi_dsi_device *device)
355263508Sdim{
356263508Sdim	struct dw_mipi_dsi *dsi = host_to_dsi(host);
357263508Sdim	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
358263508Sdim	int ret;
359263508Sdim
360263508Sdim	if (pdata->host_ops && pdata->host_ops->detach) {
361263508Sdim		ret = pdata->host_ops->detach(pdata->priv_data, device);
362263508Sdim		if (ret < 0)
363263508Sdim			return ret;
364263508Sdim	}
365263508Sdim
366263508Sdim	drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
367263508Sdim
368263508Sdim	drm_bridge_remove(&dsi->bridge);
369263508Sdim
370263508Sdim	return 0;
371263508Sdim}
372263508Sdim
373263508Sdimstatic void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
374263508Sdim				   const struct mipi_dsi_msg *msg)
375263508Sdim{
376263508Sdim	bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM;
377263508Sdim	u32 val = 0;
378193323Sed
379204961Srdivacky	/*
380263508Sdim	 * TODO dw drv improvements
381263508Sdim	 * largest packet sizes during hfp or during vsa/vpb/vfp
382193323Sed	 * should be computed according to byte lane, lane number and only
383199481Srdivacky	 * if sending lp cmds in high speed is enable (PHY_TXREQUESTCLKHS)
384193323Sed	 */
385218893Sdim	dsi_write(dsi, DSI_DPI_LP_CMD_TIM, OUTVACT_LPCMD_TIME(16)
386234353Sdim		  | INVACT_LPCMD_TIME(4));
387218893Sdim
388218893Sdim	if (msg->flags & MIPI_DSI_MSG_REQ_ACK)
389218893Sdim		val |= ACK_RQST_EN;
390218893Sdim	if (lpm)
391193323Sed		val |= CMD_MODE_ALL_LP;
392218893Sdim
393218893Sdim	dsi_write(dsi, DSI_CMD_MODE_CFG, val);
394218893Sdim
395218893Sdim	val = dsi_read(dsi, DSI_VID_MODE_CFG);
396219077Sdim	if (lpm)
397219077Sdim		val |= ENABLE_LOW_POWER_CMD;
398219077Sdim	else
399218893Sdim		val &= ~ENABLE_LOW_POWER_CMD;
400193323Sed	dsi_write(dsi, DSI_VID_MODE_CFG, val);
401218893Sdim}
402218893Sdim
403218893Sdimstatic int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val)
404218893Sdim{
405218893Sdim	int ret;
406193323Sed	u32 val, mask;
407218893Sdim
408218893Sdim	ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
409218893Sdim				 val, !(val & GEN_CMD_FULL), 1000,
410218893Sdim				 CMD_PKT_STATUS_TIMEOUT_US);
411219077Sdim	if (ret) {
412219077Sdim		dev_err(dsi->dev, "failed to get available command FIFO\n");
413219077Sdim		return ret;
414218893Sdim	}
415234353Sdim
416218893Sdim	dsi_write(dsi, DSI_GEN_HDR, hdr_val);
417193323Sed
418193323Sed	mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
419193323Sed	ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
420193323Sed				 val, (val & mask) == mask,
421218893Sdim				 1000, CMD_PKT_STATUS_TIMEOUT_US);
422218893Sdim	if (ret) {
423218893Sdim		dev_err(dsi->dev, "failed to write command FIFO\n");
424218893Sdim		return ret;
425193323Sed	}
426218893Sdim
427218893Sdim	return 0;
428218893Sdim}
429218893Sdim
430219077Sdimstatic int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi,
431219077Sdim			     const struct mipi_dsi_packet *packet)
432219077Sdim{
433218893Sdim	const u8 *tx_buf = packet->payload;
434193323Sed	int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret;
435234353Sdim	__le32 word;
436218893Sdim	u32 val;
437218893Sdim
438218893Sdim	while (len) {
439218893Sdim		if (len < pld_data_bytes) {
440218893Sdim			word = 0;
441218893Sdim			memcpy(&word, tx_buf, len);
442218893Sdim			dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word));
443193323Sed			len = 0;
444218893Sdim		} else {
445218893Sdim			memcpy(&word, tx_buf, pld_data_bytes);
446218893Sdim			dsi_write(dsi, DSI_GEN_PLD_DATA, le32_to_cpu(word));
447218893Sdim			tx_buf += pld_data_bytes;
448218893Sdim			len -= pld_data_bytes;
449218893Sdim		}
450203954Srdivacky
451219077Sdim		ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
452219077Sdim					 val, !(val & GEN_PLD_W_FULL), 1000,
453219077Sdim					 CMD_PKT_STATUS_TIMEOUT_US);
454218893Sdim		if (ret) {
455203954Srdivacky			dev_err(dsi->dev,
456218893Sdim				"failed to get available write payload FIFO\n");
457218893Sdim			return ret;
458218893Sdim		}
459218893Sdim	}
460218893Sdim
461218893Sdim	word = 0;
462218893Sdim	memcpy(&word, packet->header, sizeof(packet->header));
463198090Srdivacky	return dw_mipi_dsi_gen_pkt_hdr_write(dsi, le32_to_cpu(word));
464193323Sed}
465218893Sdim
466218893Sdimstatic int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi,
467218893Sdim			    const struct mipi_dsi_msg *msg)
468218893Sdim{
469218893Sdim	int i, j, ret, len = msg->rx_len;
470218893Sdim	u8 *buf = msg->rx_buf;
471193323Sed	u32 val;
472219077Sdim
473219077Sdim	/* Wait end of the read operation */
474219077Sdim	ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
475218893Sdim				 val, !(val & GEN_RD_CMD_BUSY),
476234353Sdim				 1000, CMD_PKT_STATUS_TIMEOUT_US);
477218893Sdim	if (ret) {
478218893Sdim		dev_err(dsi->dev, "Timeout during read operation\n");
479218893Sdim		return ret;
480218893Sdim	}
481218893Sdim
482218893Sdim	for (i = 0; i < len; i += 4) {
483218893Sdim		/* Read fifo must not be empty before all bytes are read */
484218893Sdim		ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
485218893Sdim					 val, !(val & GEN_PLD_R_EMPTY),
486218893Sdim					 1000, CMD_PKT_STATUS_TIMEOUT_US);
487218893Sdim		if (ret) {
488218893Sdim			dev_err(dsi->dev, "Read payload FIFO is empty\n");
489218893Sdim			return ret;
490218893Sdim		}
491218893Sdim
492218893Sdim		val = dsi_read(dsi, DSI_GEN_PLD_DATA);
493193323Sed		for (j = 0; j < 4 && j + i < len; j++)
494218893Sdim			buf[i + j] = val >> (8 * j);
495218893Sdim	}
496218893Sdim
497218893Sdim	return ret;
498218893Sdim}
499218893Sdim
500218893Sdimstatic ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
501218893Sdim					 const struct mipi_dsi_msg *msg)
502218893Sdim{
503218893Sdim	struct dw_mipi_dsi *dsi = host_to_dsi(host);
504218893Sdim	struct mipi_dsi_packet packet;
505218893Sdim	int ret, nb_bytes;
506218893Sdim
507193323Sed	ret = mipi_dsi_create_packet(&packet, msg);
508193323Sed	if (ret) {
509193323Sed		dev_err(dsi->dev, "failed to create packet: %d\n", ret);
510203954Srdivacky		return ret;
511203954Srdivacky	}
512263508Sdim
513263508Sdim	dw_mipi_message_config(dsi, msg);
514193323Sed	if (dsi->slave)
515193323Sed		dw_mipi_message_config(dsi->slave, msg);
516263508Sdim
517203954Srdivacky	ret = dw_mipi_dsi_write(dsi, &packet);
518218893Sdim	if (ret)
519239462Sdim		return ret;
520226633Sdim	if (dsi->slave) {
521205407Srdivacky		ret = dw_mipi_dsi_write(dsi->slave, &packet);
522203954Srdivacky		if (ret)
523239462Sdim			return ret;
524239462Sdim	}
525239462Sdim
526239462Sdim	if (msg->rx_buf && msg->rx_len) {
527243830Sdim		ret = dw_mipi_dsi_read(dsi, msg);
528243830Sdim		if (ret)
529205407Srdivacky			return ret;
530243830Sdim		nb_bytes = msg->rx_len;
531243830Sdim	} else {
532205407Srdivacky		nb_bytes = packet.size;
533239462Sdim	}
534226633Sdim
535203954Srdivacky	return nb_bytes;
536203954Srdivacky}
537239462Sdim
538226633Sdimstatic const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
539203954Srdivacky	.attach = dw_mipi_dsi_host_attach,
540203954Srdivacky	.detach = dw_mipi_dsi_host_detach,
541263508Sdim	.transfer = dw_mipi_dsi_host_transfer,
542263508Sdim};
543263508Sdim
544263508Sdimstatic u32 *
545263508Sdimdw_mipi_dsi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
546263508Sdim					     struct drm_bridge_state *bridge_state,
547263508Sdim					     struct drm_crtc_state *crtc_state,
548263508Sdim					     struct drm_connector_state *conn_state,
549263508Sdim					     u32 output_fmt,
550263508Sdim					     unsigned int *num_input_fmts)
551263508Sdim{
552263508Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
553263508Sdim	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
554263508Sdim	u32 *input_fmts;
555263508Sdim
556263508Sdim	if (pdata->get_input_bus_fmts)
557263508Sdim		return pdata->get_input_bus_fmts(pdata->priv_data,
558263508Sdim						 bridge, bridge_state,
559263508Sdim						 crtc_state, conn_state,
560263508Sdim						 output_fmt, num_input_fmts);
561263508Sdim
562263508Sdim	/* Fall back to MEDIA_BUS_FMT_FIXED as the only input format. */
563263508Sdim	input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
564263508Sdim	if (!input_fmts)
565263508Sdim		return NULL;
566263508Sdim	input_fmts[0] = MEDIA_BUS_FMT_FIXED;
567263508Sdim	*num_input_fmts = 1;
568263508Sdim
569263508Sdim	return input_fmts;
570263508Sdim}
571263508Sdim
572263508Sdimstatic int dw_mipi_dsi_bridge_atomic_check(struct drm_bridge *bridge,
573263508Sdim					   struct drm_bridge_state *bridge_state,
574263508Sdim					   struct drm_crtc_state *crtc_state,
575263508Sdim					   struct drm_connector_state *conn_state)
576263508Sdim{
577263508Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
578263508Sdim	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
579263508Sdim	bool ret;
580263508Sdim
581263508Sdim	bridge_state->input_bus_cfg.flags =
582263508Sdim		DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE;
583263508Sdim
584263508Sdim	if (pdata->mode_fixup) {
585263508Sdim		ret = pdata->mode_fixup(pdata->priv_data, &crtc_state->mode,
586263508Sdim					&crtc_state->adjusted_mode);
587263508Sdim		if (!ret) {
588263508Sdim			DRM_DEBUG_DRIVER("failed to fixup mode " DRM_MODE_FMT "\n",
589263508Sdim					 DRM_MODE_ARG(&crtc_state->mode));
590263508Sdim			return -EINVAL;
591263508Sdim		}
592263508Sdim	}
593263508Sdim
594263508Sdim	return 0;
595263508Sdim}
596263508Sdim
597263508Sdimstatic void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
598263508Sdim{
599263508Sdim	u32 val;
600263508Sdim
601263508Sdim	/*
602263508Sdim	 * TODO dw drv improvements
603263508Sdim	 * enabling low power is panel-dependent, we should use the
604263508Sdim	 * panel configuration here...
605263508Sdim	 */
606263508Sdim	val = ENABLE_LOW_POWER;
607263508Sdim
608263508Sdim	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
609263508Sdim		val |= VID_MODE_TYPE_BURST;
610263508Sdim	else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
611263508Sdim		val |= VID_MODE_TYPE_NON_BURST_SYNC_PULSES;
612263508Sdim	else
613263508Sdim		val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
614263508Sdim
615263508Sdim#ifdef CONFIG_DEBUG_FS
616263508Sdim	if (dsi->vpg_defs.vpg) {
617263508Sdim		val |= VID_MODE_VPG_ENABLE;
618263508Sdim		val |= dsi->vpg_defs.vpg_horizontal ?
619263508Sdim		       VID_MODE_VPG_HORIZONTAL : 0;
620263508Sdim		val |= dsi->vpg_defs.vpg_ber_pattern ? VID_MODE_VPG_MODE : 0;
621263508Sdim	}
622263508Sdim#endif /* CONFIG_DEBUG_FS */
623263508Sdim
624263508Sdim	dsi_write(dsi, DSI_VID_MODE_CFG, val);
625263508Sdim}
626263508Sdim
627263508Sdimstatic void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
628263508Sdim				 unsigned long mode_flags)
629263508Sdim{
630263508Sdim	u32 val;
631263508Sdim
632263508Sdim	dsi_write(dsi, DSI_PWR_UP, RESET);
633263508Sdim
634263508Sdim	if (mode_flags & MIPI_DSI_MODE_VIDEO) {
635263508Sdim		dsi_write(dsi, DSI_MODE_CFG, ENABLE_VIDEO_MODE);
636263508Sdim		dw_mipi_dsi_video_mode_config(dsi);
637263508Sdim	} else {
638263508Sdim		dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
639263508Sdim	}
640263508Sdim
641263508Sdim	val = PHY_TXREQUESTCLKHS;
642263508Sdim	if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
643263508Sdim		val |= AUTO_CLKLANE_CTRL;
644263508Sdim	dsi_write(dsi, DSI_LPCLK_CTRL, val);
645263508Sdim
646218893Sdim	dsi_write(dsi, DSI_PWR_UP, POWERUP);
647218893Sdim}
648218893Sdim
649218893Sdimstatic void dw_mipi_dsi_disable(struct dw_mipi_dsi *dsi)
650193323Sed{
651218893Sdim	dsi_write(dsi, DSI_PWR_UP, RESET);
652218893Sdim	dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
653218893Sdim}
654218893Sdim
655219077Sdimstatic void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi)
656219077Sdim{
657219077Sdim	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
658218893Sdim	unsigned int esc_rate; /* in MHz */
659193323Sed	u32 esc_clk_division;
660263508Sdim	int ret;
661263508Sdim
662263508Sdim	/*
663263508Sdim	 * The maximum permitted escape clock is 20MHz and it is derived from
664263508Sdim	 * lanebyteclk, which is running at "lane_mbps / 8".
665263508Sdim	 */
666263508Sdim	if (phy_ops->get_esc_clk_rate) {
667263508Sdim		ret = phy_ops->get_esc_clk_rate(dsi->plat_data->priv_data,
668263508Sdim						&esc_rate);
669263508Sdim		if (ret)
670263508Sdim			DRM_DEBUG_DRIVER("Phy get_esc_clk_rate() failed\n");
671263508Sdim	} else
672263508Sdim		esc_rate = 20; /* Default to 20MHz */
673263508Sdim
674263508Sdim	/*
675263508Sdim	 * We want :
676263508Sdim	 *     (lane_mbps >> 3) / esc_clk_division < X
677263508Sdim	 * which is:
678263508Sdim	 *     (lane_mbps >> 3) / X > esc_clk_division
679263508Sdim	 */
680263508Sdim	esc_clk_division = (dsi->lane_mbps >> 3) / esc_rate + 1;
681263508Sdim
682263508Sdim	dsi_write(dsi, DSI_PWR_UP, RESET);
683263508Sdim
684263508Sdim	/*
685263508Sdim	 * TODO dw drv improvements
686263508Sdim	 * timeout clock division should be computed with the
687263508Sdim	 * high speed transmission counter timeout and byte lane...
688263508Sdim	 */
689263508Sdim	dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVISION(0) |
690263508Sdim		  TX_ESC_CLK_DIVISION(esc_clk_division));
691263508Sdim}
692263508Sdim
693263508Sdimstatic void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi,
694263508Sdim				   const struct drm_display_mode *mode)
695263508Sdim{
696263508Sdim	u32 val = 0, color = 0;
697263508Sdim
698263508Sdim	switch (dsi->format) {
699263508Sdim	case MIPI_DSI_FMT_RGB888:
700263508Sdim		color = DPI_COLOR_CODING_24BIT;
701263508Sdim		break;
702263508Sdim	case MIPI_DSI_FMT_RGB666:
703263508Sdim		color = DPI_COLOR_CODING_18BIT_2 | LOOSELY18_EN;
704263508Sdim		break;
705263508Sdim	case MIPI_DSI_FMT_RGB666_PACKED:
706263508Sdim		color = DPI_COLOR_CODING_18BIT_1;
707263508Sdim		break;
708263508Sdim	case MIPI_DSI_FMT_RGB565:
709263508Sdim		color = DPI_COLOR_CODING_16BIT_1;
710263508Sdim		break;
711263508Sdim	}
712263508Sdim
713263508Sdim	if (mode->flags & DRM_MODE_FLAG_NVSYNC)
714263508Sdim		val |= VSYNC_ACTIVE_LOW;
715263508Sdim	if (mode->flags & DRM_MODE_FLAG_NHSYNC)
716263508Sdim		val |= HSYNC_ACTIVE_LOW;
717218893Sdim
718218893Sdim	dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel));
719218893Sdim	dsi_write(dsi, DSI_DPI_COLOR_CODING, color);
720218893Sdim	dsi_write(dsi, DSI_DPI_CFG_POL, val);
721193323Sed}
722218893Sdim
723218893Sdimstatic void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi)
724218893Sdim{
725218893Sdim	dsi_write(dsi, DSI_PCKHDL_CFG, CRC_RX_EN | ECC_RX_EN | BTA_EN);
726193323Sed}
727218893Sdim
728218893Sdimstatic void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi,
729218893Sdim					    const struct drm_display_mode *mode)
730218893Sdim{
731193323Sed	/*
732218893Sdim	 * TODO dw drv improvements
733218893Sdim	 * only burst mode is supported here. For non-burst video modes,
734218893Sdim	 * we should compute DSI_VID_PKT_SIZE, DSI_VCCR.NUMC &
735218893Sdim	 * DSI_VNPCR.NPSIZE... especially because this driver supports
736193323Sed	 * non-burst video modes, see dw_mipi_dsi_video_mode_config()...
737193323Sed	 */
738193323Sed
739193323Sed	dsi_write(dsi, DSI_VID_PKT_SIZE,
740193323Sed		       dw_mipi_is_dual_mode(dsi) ?
741218893Sdim				VID_PKT_SIZE(mode->hdisplay / 2) :
742218893Sdim				VID_PKT_SIZE(mode->hdisplay));
743218893Sdim}
744218893Sdim
745218893Sdimstatic void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi)
746218893Sdim{
747218893Sdim	/*
748193323Sed	 * TODO dw drv improvements
749218893Sdim	 * compute high speed transmission counter timeout according
750218893Sdim	 * to the timeout clock division (TO_CLK_DIVISION) and byte lane...
751218893Sdim	 */
752218893Sdim	dsi_write(dsi, DSI_TO_CNT_CFG, HSTX_TO_CNT(0) | LPRX_TO_CNT(0));
753193323Sed	/*
754218893Sdim	 * TODO dw drv improvements
755218893Sdim	 * the Bus-Turn-Around Timeout Counter should be computed
756221345Sdim	 * according to byte lane...
757221345Sdim	 */
758221345Sdim	dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00);
759221345Sdim	dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE);
760218893Sdim}
761218893Sdim
762243830Sdimstatic const u32 minimum_lbccs[] = {10, 5, 4, 3};
763218893Sdim
764218893Sdimstatic inline u32 dw_mipi_dsi_get_minimum_lbcc(struct dw_mipi_dsi *dsi)
765218893Sdim{
766243830Sdim	return minimum_lbccs[dsi->lanes - 1];
767243830Sdim}
768218893Sdim
769218893Sdim/* Get lane byte clock cycles. */
770218893Sdimstatic u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
771218893Sdim					   const struct drm_display_mode *mode,
772218893Sdim					   u32 hcomponent)
773218893Sdim{
774218893Sdim	u32 frac, lbcc, minimum_lbcc;
775218893Sdim	int bpp;
776218893Sdim
777218893Sdim	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
778218893Sdim		/* lbcc based on lane_mbps */
779221345Sdim		lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
780221345Sdim	} else {
781221345Sdim		/* lbcc based on pixel clock rate */
782221345Sdim		bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
783218893Sdim		if (bpp < 0) {
784218893Sdim			dev_err(dsi->dev, "failed to get bpp\n");
785208599Srdivacky			return 0;
786199481Srdivacky		}
787218893Sdim
788218893Sdim		lbcc = div_u64((u64)hcomponent * mode->clock * bpp, dsi->lanes * 8);
789203954Srdivacky	}
790218893Sdim
791218893Sdim	frac = lbcc % mode->clock;
792218893Sdim	lbcc = lbcc / mode->clock;
793218893Sdim	if (frac)
794218893Sdim		lbcc++;
795218893Sdim
796218893Sdim	minimum_lbcc = dw_mipi_dsi_get_minimum_lbcc(dsi);
797218893Sdim
798218893Sdim	if (lbcc < minimum_lbcc)
799218893Sdim		lbcc = minimum_lbcc;
800218893Sdim
801203954Srdivacky	return lbcc;
802221345Sdim}
803221345Sdim
804221345Sdimstatic void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi,
805221345Sdim					  const struct drm_display_mode *mode)
806203954Srdivacky{
807193323Sed	u32 htotal, hsa, hbp, lbcc;
808203954Srdivacky
809226633Sdim	htotal = mode->htotal;
810226633Sdim	hsa = mode->hsync_end - mode->hsync_start;
811203954Srdivacky	hbp = mode->htotal - mode->hsync_end;
812226633Sdim
813226633Sdim	/*
814226633Sdim	 * TODO dw drv improvements
815226633Sdim	 * computations below may be improved...
816226633Sdim	 */
817239462Sdim	lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, htotal);
818239462Sdim	dsi_write(dsi, DSI_VID_HLINE_TIME, lbcc);
819226633Sdim
820226633Sdim	lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hsa);
821226633Sdim	dsi_write(dsi, DSI_VID_HSA_TIME, lbcc);
822203954Srdivacky
823221345Sdim	lbcc = dw_mipi_dsi_get_hcomponent_lbcc(dsi, mode, hbp);
824221345Sdim	dsi_write(dsi, DSI_VID_HBP_TIME, lbcc);
825221345Sdim}
826221345Sdim
827226633Sdimstatic void dw_mipi_dsi_vertical_timing_config(struct dw_mipi_dsi *dsi,
828203954Srdivacky					const struct drm_display_mode *mode)
829208599Srdivacky{
830203954Srdivacky	u32 vactive, vsa, vfp, vbp;
831193323Sed
832193323Sed	vactive = mode->vdisplay;
833193323Sed	vsa = mode->vsync_end - mode->vsync_start;
834199481Srdivacky	vfp = mode->vsync_start - mode->vdisplay;
835218893Sdim	vbp = mode->vtotal - mode->vsync_end;
836218893Sdim
837218893Sdim	dsi_write(dsi, DSI_VID_VACTIVE_LINES, vactive);
838218893Sdim	dsi_write(dsi, DSI_VID_VSA_LINES, vsa);
839218893Sdim	dsi_write(dsi, DSI_VID_VFP_LINES, vfp);
840218893Sdim	dsi_write(dsi, DSI_VID_VBP_LINES, vbp);
841218893Sdim}
842218893Sdim
843218893Sdimstatic void dw_mipi_dsi_dphy_timing_config(struct dw_mipi_dsi *dsi)
844218893Sdim{
845218893Sdim	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
846218893Sdim	struct dw_mipi_dsi_dphy_timing timing;
847218893Sdim	u32 hw_version;
848218893Sdim	int ret;
849218893Sdim
850221345Sdim	ret = phy_ops->get_timing(dsi->plat_data->priv_data,
851221345Sdim				  dsi->lane_mbps, &timing);
852221345Sdim	if (ret)
853221345Sdim		DRM_DEV_ERROR(dsi->dev, "Retrieving phy timings failed\n");
854203954Srdivacky
855193323Sed	/*
856208599Srdivacky	 * TODO dw drv improvements
857203954Srdivacky	 * data & clock lane timers should be computed according to panel
858203954Srdivacky	 * blankings and to the automatic clock lane control mode...
859207618Srdivacky	 * note: DSI_PHY_TMR_CFG.MAX_RD_TIME should be in line with
860203954Srdivacky	 * DSI_CMD_MODE_CFG.MAX_RD_PKT_SIZE_LP (see CMD_MODE_ALL_LP)
861226633Sdim	 */
862226633Sdim
863226633Sdim	hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
864226633Sdim
865226633Sdim	if (hw_version >= HWVER_131) {
866226633Sdim		dsi_write(dsi, DSI_PHY_TMR_CFG,
867239462Sdim			  PHY_HS2LP_TIME_V131(timing.data_hs2lp) |
868239462Sdim			  PHY_LP2HS_TIME_V131(timing.data_lp2hs));
869226633Sdim		dsi_write(dsi, DSI_PHY_TMR_RD_CFG, MAX_RD_TIME_V131(10000));
870226633Sdim	} else {
871226633Sdim		dsi_write(dsi, DSI_PHY_TMR_CFG,
872203954Srdivacky			  PHY_HS2LP_TIME(timing.data_hs2lp) |
873221345Sdim			  PHY_LP2HS_TIME(timing.data_lp2hs) |
874221345Sdim			  MAX_RD_TIME(10000));
875221345Sdim	}
876221345Sdim
877226633Sdim	dsi_write(dsi, DSI_PHY_TMR_LPCLK_CFG,
878226633Sdim		  PHY_CLKHS2LP_TIME(timing.clk_hs2lp) |
879203954Srdivacky		  PHY_CLKLP2HS_TIME(timing.clk_lp2hs));
880203954Srdivacky}
881193323Sed
882193323Sedstatic void dw_mipi_dsi_dphy_interface_config(struct dw_mipi_dsi *dsi)
883193323Sed{
884218893Sdim	/*
885193323Sed	 * TODO dw drv improvements
886218893Sdim	 * stop wait time should be the maximum between host dsi
887193323Sed	 * and panel stop wait times
888193323Sed	 */
889218893Sdim	dsi_write(dsi, DSI_PHY_IF_CFG, PHY_STOP_WAIT_TIME(0x20) |
890193323Sed		  N_LANES(dsi->lanes));
891218893Sdim}
892218893Sdim
893218893Sdimstatic void dw_mipi_dsi_dphy_init(struct dw_mipi_dsi *dsi)
894218893Sdim{
895218893Sdim	/* Clear PHY state */
896218893Sdim	dsi_write(dsi, DSI_PHY_RSTZ, PHY_DISFORCEPLL | PHY_DISABLECLK
897218893Sdim		  | PHY_RSTZ | PHY_SHUTDOWNZ);
898218893Sdim	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
899218893Sdim	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLR);
900193323Sed	dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLR);
901218893Sdim}
902218893Sdim
903218893Sdimstatic void dw_mipi_dsi_dphy_enable(struct dw_mipi_dsi *dsi)
904218893Sdim{
905218893Sdim	u32 val;
906263508Sdim	int ret;
907263508Sdim
908218893Sdim	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
909218893Sdim		  PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
910218893Sdim
911218893Sdim	ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS, val,
912218893Sdim				 val & PHY_LOCK, 1000, PHY_STATUS_TIMEOUT_US);
913218893Sdim	if (ret)
914218893Sdim		DRM_DEBUG_DRIVER("failed to wait phy lock state\n");
915218893Sdim
916218893Sdim	ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
917218893Sdim				 val, val & PHY_STOP_STATE_CLK_LANE, 1000,
918218893Sdim				 PHY_STATUS_TIMEOUT_US);
919218893Sdim	if (ret)
920218893Sdim		DRM_DEBUG_DRIVER("failed to wait phy clk lane stop state\n");
921218893Sdim}
922218893Sdim
923218893Sdimstatic void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
924218893Sdim{
925218893Sdim	dsi_read(dsi, DSI_INT_ST0);
926218893Sdim	dsi_read(dsi, DSI_INT_ST1);
927218893Sdim	dsi_write(dsi, DSI_INT_MSK0, 0);
928218893Sdim	dsi_write(dsi, DSI_INT_MSK1, 0);
929218893Sdim}
930203954Srdivacky
931193323Sedstatic void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge,
932193323Sed						   struct drm_bridge_state *old_bridge_state)
933218893Sdim{
934218893Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
935218893Sdim	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
936218893Sdim
937203954Srdivacky	/*
938218893Sdim	 * Switch to command mode before panel-bridge post_disable &
939219077Sdim	 * panel unprepare.
940219077Sdim	 * Note: panel-bridge disable & panel disable has been called
941219077Sdim	 * before by the drm framework.
942193323Sed	 */
943193323Sed	dw_mipi_dsi_set_mode(dsi, 0);
944218893Sdim
945218893Sdim	if (phy_ops->power_off)
946218893Sdim		phy_ops->power_off(dsi->plat_data->priv_data);
947218893Sdim
948203954Srdivacky	if (dsi->slave) {
949203954Srdivacky		dw_mipi_dsi_disable(dsi->slave);
950193323Sed		clk_disable_unprepare(dsi->slave->pclk);
951218893Sdim		pm_runtime_put(dsi->slave->dev);
952218893Sdim	}
953218893Sdim	dw_mipi_dsi_disable(dsi);
954218893Sdim
955203954Srdivacky	clk_disable_unprepare(dsi->pclk);
956218893Sdim	pm_runtime_put(dsi->dev);
957219077Sdim}
958219077Sdim
959219077Sdimstatic unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
960203954Srdivacky{
961193323Sed	/* this instance is the slave, so add the master's lanes */
962218893Sdim	if (dsi->master)
963218893Sdim		return dsi->master->lanes + dsi->lanes;
964218893Sdim
965218893Sdim	/* this instance is the master, so add the slave's lanes */
966218893Sdim	if (dsi->slave)
967218893Sdim		return dsi->lanes + dsi->slave->lanes;
968218893Sdim
969218893Sdim	/* single-dsi, so no other instance to consider */
970218893Sdim	return dsi->lanes;
971218893Sdim}
972218893Sdim
973218893Sdimstatic void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
974218893Sdim				 const struct drm_display_mode *adjusted_mode)
975218893Sdim{
976218893Sdim	const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
977218893Sdim	void *priv_data = dsi->plat_data->priv_data;
978218893Sdim	int ret;
979263508Sdim	u32 lanes = dw_mipi_dsi_get_lanes(dsi);
980263508Sdim
981218893Sdim	clk_prepare_enable(dsi->pclk);
982218893Sdim
983218893Sdim	ret = phy_ops->get_lane_mbps(priv_data, adjusted_mode, dsi->mode_flags,
984218893Sdim				     lanes, dsi->format, &dsi->lane_mbps);
985218893Sdim	if (ret)
986218893Sdim		DRM_DEBUG_DRIVER("Phy get_lane_mbps() failed\n");
987218893Sdim
988218893Sdim	pm_runtime_get_sync(dsi->dev);
989218893Sdim	dw_mipi_dsi_init(dsi);
990218893Sdim	dw_mipi_dsi_dpi_config(dsi, adjusted_mode);
991218893Sdim	dw_mipi_dsi_packet_handler_config(dsi);
992218893Sdim	dw_mipi_dsi_video_mode_config(dsi);
993218893Sdim	dw_mipi_dsi_video_packet_config(dsi, adjusted_mode);
994218893Sdim	dw_mipi_dsi_command_mode_config(dsi);
995218893Sdim	dw_mipi_dsi_line_timer_config(dsi, adjusted_mode);
996218893Sdim	dw_mipi_dsi_vertical_timing_config(dsi, adjusted_mode);
997218893Sdim
998218893Sdim	dw_mipi_dsi_dphy_init(dsi);
999218893Sdim	dw_mipi_dsi_dphy_timing_config(dsi);
1000193323Sed	dw_mipi_dsi_dphy_interface_config(dsi);
1001218893Sdim
1002218893Sdim	dw_mipi_dsi_clear_err(dsi);
1003218893Sdim
1004218893Sdim	ret = phy_ops->init(priv_data);
1005193323Sed	if (ret)
1006193323Sed		DRM_DEBUG_DRIVER("Phy init() failed\n");
1007193323Sed
1008218893Sdim	dw_mipi_dsi_dphy_enable(dsi);
1009218893Sdim
1010218893Sdim	dw_mipi_dsi_wait_for_two_frames(adjusted_mode);
1011218893Sdim
1012193323Sed	/* Switch to cmd mode for panel-bridge pre_enable & panel prepare */
1013218893Sdim	dw_mipi_dsi_set_mode(dsi, 0);
1014219077Sdim
1015219077Sdim	if (phy_ops->power_on)
1016219077Sdim		phy_ops->power_on(dsi->plat_data->priv_data);
1017193323Sed}
1018193323Sed
1019218893Sdimstatic void dw_mipi_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
1020218893Sdim						 struct drm_bridge_state *old_bridge_state)
1021218893Sdim{
1022218893Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
1023193323Sed
1024193323Sed	/* Power up the dsi ctl into a command mode */
1025193323Sed	dw_mipi_dsi_mode_set(dsi, &dsi->mode);
1026218893Sdim	if (dsi->slave)
1027218893Sdim		dw_mipi_dsi_mode_set(dsi->slave, &dsi->mode);
1028218893Sdim}
1029218893Sdim
1030193323Sedstatic void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
1031218893Sdim					const struct drm_display_mode *mode,
1032219077Sdim					const struct drm_display_mode *adjusted_mode)
1033219077Sdim{
1034219077Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
1035193323Sed
1036193323Sed	/* Store the display mode for later use in pre_enable callback */
1037203954Srdivacky	drm_mode_copy(&dsi->mode, adjusted_mode);
1038212904Sdim}
1039218893Sdim
1040218893Sdimstatic void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
1041218893Sdim					     struct drm_bridge_state *old_bridge_state)
1042218893Sdim{
1043218893Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
1044203954Srdivacky
1045203954Srdivacky	/* Switch to video mode for panel-bridge enable & panel enable */
1046203954Srdivacky	dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
1047218893Sdim	if (dsi->slave)
1048218893Sdim		dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
1049218893Sdim}
1050218893Sdim
1051203954Srdivackystatic enum drm_mode_status
1052203954Srdivackydw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
1053203954Srdivacky			      const struct drm_display_info *info,
1054218893Sdim			      const struct drm_display_mode *mode)
1055218893Sdim{
1056218893Sdim	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
1057218893Sdim	const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data;
1058203954Srdivacky	enum drm_mode_status mode_status = MODE_OK;
1059203954Srdivacky
1060203954Srdivacky	if (pdata->mode_valid)
1061218893Sdim		mode_status = pdata->mode_valid(pdata->priv_data, mode,
1062218893Sdim						dsi->mode_flags,
1063218893Sdim						dw_mipi_dsi_get_lanes(dsi),
1064218893Sdim						dsi->format);
1065203954Srdivacky
1066203954Srdivacky	return mode_status;
1067212904Sdim}
1068203954Srdivacky
1069203954Srdivackystatic int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
1070203954Srdivacky				     enum drm_bridge_attach_flags flags)
1071203954Srdivacky{
1072203954Srdivacky	struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
1073203954Srdivacky
1074203954Srdivacky	if (!bridge->encoder) {
1075203954Srdivacky		DRM_ERROR("Parent encoder object not found\n");
1076234353Sdim		return -ENODEV;
1077203954Srdivacky	}
1078203954Srdivacky
1079203954Srdivacky	/* Set the encoder type as caller does not know it */
1080234353Sdim	bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
1081239462Sdim
1082239462Sdim	/* Attach the panel-bridge to the dsi bridge */
1083239462Sdim	return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
1084263508Sdim				 flags);
1085263508Sdim}
1086234353Sdim
1087234353Sdimstatic const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
1088234353Sdim	.atomic_duplicate_state	= drm_atomic_helper_bridge_duplicate_state,
1089234353Sdim	.atomic_destroy_state	= drm_atomic_helper_bridge_destroy_state,
1090234353Sdim	.atomic_get_input_bus_fmts = dw_mipi_dsi_bridge_atomic_get_input_bus_fmts,
1091234353Sdim	.atomic_check		= dw_mipi_dsi_bridge_atomic_check,
1092234353Sdim	.atomic_reset		= drm_atomic_helper_bridge_reset,
1093239462Sdim	.atomic_pre_enable	= dw_mipi_dsi_bridge_atomic_pre_enable,
1094239462Sdim	.atomic_enable		= dw_mipi_dsi_bridge_atomic_enable,
1095239462Sdim	.atomic_post_disable	= dw_mipi_dsi_bridge_post_atomic_disable,
1096263508Sdim	.mode_set		= dw_mipi_dsi_bridge_mode_set,
1097263508Sdim	.mode_valid		= dw_mipi_dsi_bridge_mode_valid,
1098234353Sdim	.attach			= dw_mipi_dsi_bridge_attach,
1099234353Sdim};
1100234353Sdim
1101234353Sdim#ifdef CONFIG_DEBUG_FS
1102263508Sdim
1103263508Sdimstatic int dw_mipi_dsi_debugfs_write(void *data, u64 val)
1104234353Sdim{
1105234353Sdim	struct debugfs_entries *vpg = data;
1106234353Sdim	struct dw_mipi_dsi *dsi;
1107234353Sdim	u32 mode_cfg;
1108234353Sdim
1109219077Sdim	if (!vpg)
1110219077Sdim		return -ENODEV;
1111219077Sdim
1112218893Sdim	dsi = vpg->dsi;
1113203954Srdivacky
1114234353Sdim	*vpg->reg = (bool)val;
1115234353Sdim
1116234353Sdim	mode_cfg = dsi_read(dsi, DSI_VID_MODE_CFG);
1117219077Sdim
1118219077Sdim	if (*vpg->reg)
1119219077Sdim		mode_cfg |= vpg->mask;
1120218893Sdim	else
1121203954Srdivacky		mode_cfg &= ~vpg->mask;
1122234353Sdim
1123234353Sdim	dsi_write(dsi, DSI_VID_MODE_CFG, mode_cfg);
1124234353Sdim
1125219077Sdim	return 0;
1126219077Sdim}
1127219077Sdim
1128218893Sdimstatic int dw_mipi_dsi_debugfs_show(void *data, u64 *val)
1129203954Srdivacky{
1130234353Sdim	struct debugfs_entries *vpg = data;
1131234353Sdim
1132234353Sdim	if (!vpg)
1133219077Sdim		return -ENODEV;
1134219077Sdim
1135219077Sdim	*val = *vpg->reg;
1136218893Sdim
1137203954Srdivacky	return 0;
1138234353Sdim}
1139234353Sdim
1140234353SdimDEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_mipi_dsi_debugfs_show,
1141203954Srdivacky			 dw_mipi_dsi_debugfs_write, "%llu\n");
1142234353Sdim
1143234353Sdimstatic void debugfs_create_files(void *data)
1144234353Sdim{
1145203954Srdivacky	struct dw_mipi_dsi *dsi = data;
1146234353Sdim	struct debugfs_entries debugfs[] = {
1147234353Sdim		REGISTER(vpg, VID_MODE_VPG_ENABLE, dsi),
1148234353Sdim		REGISTER(vpg_horizontal, VID_MODE_VPG_HORIZONTAL, dsi),
1149203954Srdivacky		REGISTER(vpg_ber_pattern, VID_MODE_VPG_MODE, dsi),
1150234353Sdim	};
1151234353Sdim	int i;
1152234353Sdim
1153203954Srdivacky	dsi->debugfs_vpg = kmemdup(debugfs, sizeof(debugfs), GFP_KERNEL);
1154203954Srdivacky	if (!dsi->debugfs_vpg)
1155203954Srdivacky		return;
1156234353Sdim
1157234353Sdim	for (i = 0; i < ARRAY_SIZE(debugfs); i++)
1158234353Sdim		debugfs_create_file(dsi->debugfs_vpg[i].name, 0644,
1159219077Sdim				    dsi->debugfs, &dsi->debugfs_vpg[i],
1160219077Sdim				    &fops_x32);
1161219077Sdim}
1162218893Sdim
1163203954Srdivackystatic void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi)
1164234353Sdim{
1165234353Sdim	dsi->debugfs = debugfs_create_dir(dev_name(dsi->dev), NULL);
1166234353Sdim	if (IS_ERR(dsi->debugfs)) {
1167219077Sdim		dev_err(dsi->dev, "failed to create debugfs root\n");
1168219077Sdim		return;
1169219077Sdim	}
1170218893Sdim
1171203954Srdivacky	debugfs_create_files(dsi);
1172234353Sdim}
1173234353Sdim
1174234353Sdimstatic void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi)
1175219077Sdim{
1176219077Sdim	debugfs_remove_recursive(dsi->debugfs);
1177219077Sdim	kfree(dsi->debugfs_vpg);
1178218893Sdim}
1179203954Srdivacky
1180234353Sdim#else
1181234353Sdim
1182234353Sdimstatic void dw_mipi_dsi_debugfs_init(struct dw_mipi_dsi *dsi) { }
1183219077Sdimstatic void dw_mipi_dsi_debugfs_remove(struct dw_mipi_dsi *dsi) { }
1184219077Sdim
1185219077Sdim#endif /* CONFIG_DEBUG_FS */
1186218893Sdim
1187203954Srdivackystatic struct dw_mipi_dsi *
1188234353Sdim__dw_mipi_dsi_probe(struct platform_device *pdev,
1189234353Sdim		    const struct dw_mipi_dsi_plat_data *plat_data)
1190234353Sdim{
1191203954Srdivacky	struct device *dev = &pdev->dev;
1192234353Sdim	struct reset_control *apb_rst;
1193234353Sdim	struct dw_mipi_dsi *dsi;
1194234353Sdim	int ret;
1195203954Srdivacky
1196234353Sdim	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
1197234353Sdim	if (!dsi)
1198234353Sdim		return ERR_PTR(-ENOMEM);
1199203954Srdivacky
1200234353Sdim	dsi->dev = dev;
1201234353Sdim	dsi->plat_data = plat_data;
1202234353Sdim
1203203954Srdivacky	if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps ||
1204234353Sdim	    !plat_data->phy_ops->get_timing) {
1205203954Srdivacky		DRM_ERROR("Phy not properly configured\n");
1206193323Sed		return ERR_PTR(-ENODEV);
1207224145Sdim	}
1208193323Sed
1209193323Sed	if (!plat_data->base) {
1210218893Sdim		dsi->base = devm_platform_ioremap_resource(pdev, 0);
1211218893Sdim		if (IS_ERR(dsi->base))
1212218893Sdim			return ERR_PTR(-ENODEV);
1213218893Sdim
1214218893Sdim	} else {
1215218893Sdim		dsi->base = plat_data->base;
1216263508Sdim	}
1217193323Sed
1218203954Srdivacky	dsi->pclk = devm_clk_get(dev, "pclk");
1219218893Sdim	if (IS_ERR(dsi->pclk)) {
1220218893Sdim		ret = PTR_ERR(dsi->pclk);
1221218893Sdim		dev_err(dev, "Unable to get pclk: %d\n", ret);
1222218893Sdim		return ERR_PTR(ret);
1223218893Sdim	}
1224234353Sdim
1225219077Sdim	/*
1226219077Sdim	 * Note that the reset was not defined in the initial device tree, so
1227219077Sdim	 * we have to be prepared for it not being found.
1228218893Sdim	 */
1229193323Sed	apb_rst = devm_reset_control_get_optional_exclusive(dev, "apb");
1230218893Sdim	if (IS_ERR(apb_rst)) {
1231218893Sdim		ret = PTR_ERR(apb_rst);
1232263508Sdim
1233218893Sdim		if (ret != -EPROBE_DEFER)
1234218893Sdim			dev_err(dev, "Unable to get reset control: %d\n", ret);
1235234353Sdim
1236193323Sed		return ERR_PTR(ret);
1237218893Sdim	}
1238218893Sdim
1239218893Sdim	if (apb_rst) {
1240218893Sdim		ret = clk_prepare_enable(dsi->pclk);
1241218893Sdim		if (ret) {
1242218893Sdim			dev_err(dev, "%s: Failed to enable pclk\n", __func__);
1243263508Sdim			return ERR_PTR(ret);
1244193323Sed		}
1245203954Srdivacky
1246218893Sdim		reset_control_assert(apb_rst);
1247218893Sdim		usleep_range(10, 20);
1248218893Sdim		reset_control_deassert(apb_rst);
1249218893Sdim
1250218893Sdim		clk_disable_unprepare(dsi->pclk);
1251234353Sdim	}
1252219077Sdim
1253219077Sdim	dw_mipi_dsi_debugfs_init(dsi);
1254219077Sdim	pm_runtime_enable(dev);
1255218893Sdim
1256193323Sed	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
1257218893Sdim	dsi->dsi_host.dev = dev;
1258218893Sdim	ret = mipi_dsi_host_register(&dsi->dsi_host);
1259263508Sdim	if (ret) {
1260218893Sdim		dev_err(dev, "Failed to register MIPI host: %d\n", ret);
1261218893Sdim		pm_runtime_disable(dev);
1262234353Sdim		dw_mipi_dsi_debugfs_remove(dsi);
1263198090Srdivacky		return ERR_PTR(ret);
1264218893Sdim	}
1265218893Sdim
1266218893Sdim	dsi->bridge.driver_private = dsi;
1267218893Sdim	dsi->bridge.funcs = &dw_mipi_dsi_bridge_funcs;
1268218893Sdim	dsi->bridge.of_node = pdev->dev.of_node;
1269218893Sdim
1270263508Sdim	return dsi;
1271193323Sed}
1272203954Srdivacky
1273218893Sdimstatic void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
1274218893Sdim{
1275218893Sdim	mipi_dsi_host_unregister(&dsi->dsi_host);
1276218893Sdim
1277218893Sdim	pm_runtime_disable(dsi->dev);
1278234353Sdim	dw_mipi_dsi_debugfs_remove(dsi);
1279219077Sdim}
1280219077Sdim
1281219077Sdimvoid dw_mipi_dsi_set_slave(struct dw_mipi_dsi *dsi, struct dw_mipi_dsi *slave)
1282218893Sdim{
1283193323Sed	/* introduce controllers to each other */
1284218893Sdim	dsi->slave = slave;
1285218893Sdim	dsi->slave->master = dsi;
1286263508Sdim
1287218893Sdim	/* migrate settings for already attached displays */
1288218893Sdim	dsi->slave->lanes = dsi->lanes;
1289234353Sdim	dsi->slave->channel = dsi->channel;
1290218893Sdim	dsi->slave->format = dsi->format;
1291218893Sdim	dsi->slave->mode_flags = dsi->mode_flags;
1292218893Sdim}
1293218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_set_slave);
1294218893Sdim
1295218893Sdimstruct drm_bridge *dw_mipi_dsi_get_bridge(struct dw_mipi_dsi *dsi)
1296218893Sdim{
1297263508Sdim	return &dsi->bridge;
1298218893Sdim}
1299218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_get_bridge);
1300218893Sdim
1301218893Sdim/*
1302218893Sdim * Probe/remove API, used from platforms based on the DRM bridge API.
1303218893Sdim */
1304234353Sdimstruct dw_mipi_dsi *
1305219077Sdimdw_mipi_dsi_probe(struct platform_device *pdev,
1306219077Sdim		  const struct dw_mipi_dsi_plat_data *plat_data)
1307219077Sdim{
1308218893Sdim	return __dw_mipi_dsi_probe(pdev, plat_data);
1309218893Sdim}
1310218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_probe);
1311218893Sdim
1312263508Sdimvoid dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi)
1313218893Sdim{
1314218893Sdim	__dw_mipi_dsi_remove(dsi);
1315234353Sdim}
1316218893SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_remove);
1317234353Sdim
1318234353Sdim/*
1319234353Sdim * Bind/unbind API, used from platforms based on the component framework.
1320234353Sdim */
1321234353Sdimint dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder)
1322234353Sdim{
1323234353Sdim	return drm_bridge_attach(encoder, &dsi->bridge, NULL, 0);
1324234353Sdim}
1325234353SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_bind);
1326263508Sdim
1327218893Sdimvoid dw_mipi_dsi_unbind(struct dw_mipi_dsi *dsi)
1328234353Sdim{
1329234353Sdim}
1330234353SdimEXPORT_SYMBOL_GPL(dw_mipi_dsi_unbind);
1331234353Sdim
1332234353SdimMODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
1333234353SdimMODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
1334234353SdimMODULE_DESCRIPTION("DW MIPI DSI host controller driver");
1335234353SdimMODULE_LICENSE("GPL");
1336234353SdimMODULE_ALIAS("platform:dw-mipi-dsi");
1337234353Sdim