xref: /linux/drivers/gpu/drm/tegra/dsi.c (revision b7e1e969c887c897947fdc3754fe9b0c24acb155)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2dec72739SThierry Reding /*
3dec72739SThierry Reding  * Copyright (C) 2013 NVIDIA Corporation
4dec72739SThierry Reding  */
5dec72739SThierry Reding 
6dec72739SThierry Reding #include <linux/clk.h>
7dec72739SThierry Reding #include <linux/debugfs.h>
8eb1df694SSam Ravnborg #include <linux/delay.h>
9dec72739SThierry Reding #include <linux/host1x.h>
10dec72739SThierry Reding #include <linux/module.h>
11dec72739SThierry Reding #include <linux/of.h>
12e94236cdSThierry Reding #include <linux/of_platform.h>
13dec72739SThierry Reding #include <linux/platform_device.h>
14ef8187d7SThierry Reding #include <linux/pm_runtime.h>
15eb1df694SSam Ravnborg #include <linux/regulator/consumer.h>
16dec72739SThierry Reding #include <linux/reset.h>
17dec72739SThierry Reding 
18eb1df694SSam Ravnborg #include <video/mipi_display.h>
193b077afbSThierry Reding 
204aa3df71SThierry Reding #include <drm/drm_atomic_helper.h>
21eb1df694SSam Ravnborg #include <drm/drm_debugfs.h>
22eb1df694SSam Ravnborg #include <drm/drm_file.h>
23dec72739SThierry Reding #include <drm/drm_mipi_dsi.h>
24dec72739SThierry Reding #include <drm/drm_panel.h>
254d0e95e0SThomas Zimmermann #include <drm/drm_simple_kms_helper.h>
26dec72739SThierry Reding 
27dec72739SThierry Reding #include "dc.h"
28dec72739SThierry Reding #include "drm.h"
29dec72739SThierry Reding #include "dsi.h"
30dec72739SThierry Reding #include "mipi-phy.h"
3175af8fa7SThierry Reding #include "trace.h"
32dec72739SThierry Reding 
33ebd14afeSThierry Reding struct tegra_dsi_state {
34ebd14afeSThierry Reding 	struct drm_connector_state base;
35ebd14afeSThierry Reding 
36ebd14afeSThierry Reding 	struct mipi_dphy_timing timing;
37ebd14afeSThierry Reding 	unsigned long period;
38ebd14afeSThierry Reding 
39ebd14afeSThierry Reding 	unsigned int vrefresh;
40ebd14afeSThierry Reding 	unsigned int lanes;
41ebd14afeSThierry Reding 	unsigned long pclk;
42ebd14afeSThierry Reding 	unsigned long bclk;
43ebd14afeSThierry Reding 
44ebd14afeSThierry Reding 	enum tegra_dsi_format format;
45ebd14afeSThierry Reding 	unsigned int mul;
46ebd14afeSThierry Reding 	unsigned int div;
47ebd14afeSThierry Reding };
48ebd14afeSThierry Reding 
49ebd14afeSThierry Reding static inline struct tegra_dsi_state *
to_dsi_state(struct drm_connector_state * state)50ebd14afeSThierry Reding to_dsi_state(struct drm_connector_state *state)
51ebd14afeSThierry Reding {
52ebd14afeSThierry Reding 	return container_of(state, struct tegra_dsi_state, base);
53ebd14afeSThierry Reding }
54ebd14afeSThierry Reding 
55dec72739SThierry Reding struct tegra_dsi {
56dec72739SThierry Reding 	struct host1x_client client;
57dec72739SThierry Reding 	struct tegra_output output;
58dec72739SThierry Reding 	struct device *dev;
59dec72739SThierry Reding 
60dec72739SThierry Reding 	void __iomem *regs;
61dec72739SThierry Reding 
62dec72739SThierry Reding 	struct reset_control *rst;
63dec72739SThierry Reding 	struct clk *clk_parent;
64dec72739SThierry Reding 	struct clk *clk_lp;
65dec72739SThierry Reding 	struct clk *clk;
66dec72739SThierry Reding 
67dec72739SThierry Reding 	struct drm_info_list *debugfs_files;
68dec72739SThierry Reding 
6917297a28SThierry Reding 	unsigned long flags;
70dec72739SThierry Reding 	enum mipi_dsi_pixel_format format;
71dec72739SThierry Reding 	unsigned int lanes;
72dec72739SThierry Reding 
73dec72739SThierry Reding 	struct tegra_mipi_device *mipi;
74dec72739SThierry Reding 	struct mipi_dsi_host host;
753b077afbSThierry Reding 
763b077afbSThierry Reding 	struct regulator *vdd;
77976cebc3SThierry Reding 
78976cebc3SThierry Reding 	unsigned int video_fifo_depth;
79976cebc3SThierry Reding 	unsigned int host_fifo_depth;
80e94236cdSThierry Reding 
81e94236cdSThierry Reding 	/* for ganged-mode support */
82e94236cdSThierry Reding 	struct tegra_dsi *master;
83e94236cdSThierry Reding 	struct tegra_dsi *slave;
84dec72739SThierry Reding };
85dec72739SThierry Reding 
86dec72739SThierry Reding static inline struct tegra_dsi *
host1x_client_to_dsi(struct host1x_client * client)87dec72739SThierry Reding host1x_client_to_dsi(struct host1x_client *client)
88dec72739SThierry Reding {
89dec72739SThierry Reding 	return container_of(client, struct tegra_dsi, client);
90dec72739SThierry Reding }
91dec72739SThierry Reding 
host_to_tegra(struct mipi_dsi_host * host)92dec72739SThierry Reding static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
93dec72739SThierry Reding {
94dec72739SThierry Reding 	return container_of(host, struct tegra_dsi, host);
95dec72739SThierry Reding }
96dec72739SThierry Reding 
to_dsi(struct tegra_output * output)97dec72739SThierry Reding static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
98dec72739SThierry Reding {
99dec72739SThierry Reding 	return container_of(output, struct tegra_dsi, output);
100dec72739SThierry Reding }
101dec72739SThierry Reding 
tegra_dsi_get_state(struct tegra_dsi * dsi)102ebd14afeSThierry Reding static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
103ebd14afeSThierry Reding {
104ebd14afeSThierry Reding 	return to_dsi_state(dsi->output.connector.state);
105ebd14afeSThierry Reding }
106ebd14afeSThierry Reding 
tegra_dsi_readl(struct tegra_dsi * dsi,unsigned int offset)10712831076SThierry Reding static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned int offset)
108dec72739SThierry Reding {
10975af8fa7SThierry Reding 	u32 value = readl(dsi->regs + (offset << 2));
11075af8fa7SThierry Reding 
11175af8fa7SThierry Reding 	trace_dsi_readl(dsi->dev, offset, value);
11275af8fa7SThierry Reding 
11375af8fa7SThierry Reding 	return value;
114dec72739SThierry Reding }
115dec72739SThierry Reding 
tegra_dsi_writel(struct tegra_dsi * dsi,u32 value,unsigned int offset)1169c0b4ca1SThierry Reding static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
11712831076SThierry Reding 				    unsigned int offset)
118dec72739SThierry Reding {
11975af8fa7SThierry Reding 	trace_dsi_writel(dsi->dev, offset, value);
12012831076SThierry Reding 	writel(value, dsi->regs + (offset << 2));
121dec72739SThierry Reding }
122dec72739SThierry Reding 
123a40051c0SThierry Reding #define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name }
124a40051c0SThierry Reding 
125a40051c0SThierry Reding static const struct debugfs_reg32 tegra_dsi_regs[] = {
126a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT),
127a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT_CONTROL),
128a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT_ERROR),
129a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_CTXSW),
130a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_RD_DATA),
131a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_WR_DATA),
132a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_POWER_CONTROL),
133a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_ENABLE),
134a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_STATUS),
135a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_MASK),
136a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_HOST_CONTROL),
137a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_CONTROL),
138a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_SOL_DELAY),
139a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_MAX_THRESHOLD),
140a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TRIGGER),
141a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TX_CRC),
142a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_STATUS),
143a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_CONTROL),
144a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_0),
145a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_1),
146a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_2),
147a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_3),
148a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_4),
149a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_5),
150a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_6),
151a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_7),
152a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_0_LO),
153a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_0_HI),
154a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_1_LO),
155a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_1_HI),
156a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_2_LO),
157a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_2_HI),
158a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_3_LO),
159a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_3_HI),
160a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_4_LO),
161a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_4_HI),
162a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_5_LO),
163a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_5_HI),
164a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_DCS_CMDS),
165a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_0_1),
166a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_2_3),
167a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_4_5),
168a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_6_7),
169a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_0),
170a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_1),
171a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_2),
172a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_BTA_TIMING),
173a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TIMEOUT_0),
174a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TIMEOUT_1),
175a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TO_TALLY),
176a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_0),
177a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_CD),
178a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CD_STATUS),
179a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_VIDEO_MODE_CONTROL),
180a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_1),
181a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_2),
182a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_3),
183a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_4),
184a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL),
185a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_START),
186a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_SIZE),
187a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT),
188a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL),
189a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8),
190a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9),
191a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10),
192a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11),
193a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12),
194a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13),
195a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14),
196a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15),
197a40051c0SThierry Reding };
198a40051c0SThierry Reding 
tegra_dsi_show_regs(struct seq_file * s,void * data)199dec72739SThierry Reding static int tegra_dsi_show_regs(struct seq_file *s, void *data)
200dec72739SThierry Reding {
201dec72739SThierry Reding 	struct drm_info_node *node = s->private;
202dec72739SThierry Reding 	struct tegra_dsi *dsi = node->info_ent->data;
203171e2e6dSThierry Reding 	struct drm_crtc *crtc = dsi->output.encoder.crtc;
204171e2e6dSThierry Reding 	struct drm_device *drm = node->minor->dev;
205a40051c0SThierry Reding 	unsigned int i;
206171e2e6dSThierry Reding 	int err = 0;
207171e2e6dSThierry Reding 
208171e2e6dSThierry Reding 	drm_modeset_lock_all(drm);
209171e2e6dSThierry Reding 
210171e2e6dSThierry Reding 	if (!crtc || !crtc->state->active) {
211171e2e6dSThierry Reding 		err = -EBUSY;
212171e2e6dSThierry Reding 		goto unlock;
213171e2e6dSThierry Reding 	}
214dec72739SThierry Reding 
215a40051c0SThierry Reding 	for (i = 0; i < ARRAY_SIZE(tegra_dsi_regs); i++) {
216a40051c0SThierry Reding 		unsigned int offset = tegra_dsi_regs[i].offset;
217dec72739SThierry Reding 
218a40051c0SThierry Reding 		seq_printf(s, "%-32s %#05x %08x\n", tegra_dsi_regs[i].name,
219a40051c0SThierry Reding 			   offset, tegra_dsi_readl(dsi, offset));
220a40051c0SThierry Reding 	}
221dec72739SThierry Reding 
222171e2e6dSThierry Reding unlock:
223171e2e6dSThierry Reding 	drm_modeset_unlock_all(drm);
224171e2e6dSThierry Reding 	return err;
225dec72739SThierry Reding }
226dec72739SThierry Reding 
227dec72739SThierry Reding static struct drm_info_list debugfs_files[] = {
228dec72739SThierry Reding 	{ "regs", tegra_dsi_show_regs, 0, NULL },
229dec72739SThierry Reding };
230dec72739SThierry Reding 
tegra_dsi_late_register(struct drm_connector * connector)231a813d704SThierry Reding static int tegra_dsi_late_register(struct drm_connector *connector)
232dec72739SThierry Reding {
233a813d704SThierry Reding 	struct tegra_output *output = connector_to_output(connector);
234a813d704SThierry Reding 	unsigned int i, count = ARRAY_SIZE(debugfs_files);
235a813d704SThierry Reding 	struct drm_minor *minor = connector->dev->primary;
236a813d704SThierry Reding 	struct dentry *root = connector->debugfs_entry;
237a813d704SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
238dec72739SThierry Reding 
239dec72739SThierry Reding 	dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
240dec72739SThierry Reding 				     GFP_KERNEL);
241a813d704SThierry Reding 	if (!dsi->debugfs_files)
242a813d704SThierry Reding 		return -ENOMEM;
243dec72739SThierry Reding 
244a813d704SThierry Reding 	for (i = 0; i < count; i++)
245dec72739SThierry Reding 		dsi->debugfs_files[i].data = dsi;
246dec72739SThierry Reding 
247ad6d94f2SWambui Karuga 	drm_debugfs_create_files(dsi->debugfs_files, count, root, minor);
248dec72739SThierry Reding 
249dec72739SThierry Reding 	return 0;
250dec72739SThierry Reding }
251dec72739SThierry Reding 
tegra_dsi_early_unregister(struct drm_connector * connector)252a813d704SThierry Reding static void tegra_dsi_early_unregister(struct drm_connector *connector)
253dec72739SThierry Reding {
254a813d704SThierry Reding 	struct tegra_output *output = connector_to_output(connector);
255a813d704SThierry Reding 	unsigned int count = ARRAY_SIZE(debugfs_files);
256a813d704SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
257dec72739SThierry Reding 
258a813d704SThierry Reding 	drm_debugfs_remove_files(dsi->debugfs_files, count,
2598e455145SChristian König 				 connector->debugfs_entry,
260a813d704SThierry Reding 				 connector->dev->primary);
261dec72739SThierry Reding 	kfree(dsi->debugfs_files);
262dec72739SThierry Reding 	dsi->debugfs_files = NULL;
263dec72739SThierry Reding }
264dec72739SThierry Reding 
265dec72739SThierry Reding #define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
266dec72739SThierry Reding #define PKT_LEN0(len)	(((len) & 0x07) <<  0)
267dec72739SThierry Reding #define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
268dec72739SThierry Reding #define PKT_LEN1(len)	(((len) & 0x07) << 10)
269dec72739SThierry Reding #define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
270dec72739SThierry Reding #define PKT_LEN2(len)	(((len) & 0x07) << 20)
271dec72739SThierry Reding 
272dec72739SThierry Reding #define PKT_LP		(1 << 30)
273dec72739SThierry Reding #define NUM_PKT_SEQ	12
274dec72739SThierry Reding 
27517297a28SThierry Reding /*
27617297a28SThierry Reding  * non-burst mode with sync pulses
27717297a28SThierry Reding  */
27817297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
279dec72739SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
280dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
281dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
282dec72739SThierry Reding 	       PKT_LP,
283dec72739SThierry Reding 	[ 1] = 0,
284dec72739SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
285dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
286dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
287dec72739SThierry Reding 	       PKT_LP,
288dec72739SThierry Reding 	[ 3] = 0,
289dec72739SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
290dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
291dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
292dec72739SThierry Reding 	       PKT_LP,
293dec72739SThierry Reding 	[ 5] = 0,
294dec72739SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
295dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
296dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
297dec72739SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
298dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
299dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
300dec72739SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
301dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
302dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
303dec72739SThierry Reding 	       PKT_LP,
304dec72739SThierry Reding 	[ 9] = 0,
305dec72739SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
306dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
307dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
308dec72739SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
309dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
310dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
311dec72739SThierry Reding };
312dec72739SThierry Reding 
31317297a28SThierry Reding /*
31417297a28SThierry Reding  * non-burst mode with sync events
31517297a28SThierry Reding  */
31617297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
31717297a28SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
31817297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
31917297a28SThierry Reding 	       PKT_LP,
32017297a28SThierry Reding 	[ 1] = 0,
32117297a28SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
32217297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
32317297a28SThierry Reding 	       PKT_LP,
32417297a28SThierry Reding 	[ 3] = 0,
32517297a28SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
32617297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
32717297a28SThierry Reding 	       PKT_LP,
32817297a28SThierry Reding 	[ 5] = 0,
32917297a28SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
33017297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
33117297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
33217297a28SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
33317297a28SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
33417297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
33517297a28SThierry Reding 	       PKT_LP,
33617297a28SThierry Reding 	[ 9] = 0,
33717297a28SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
33817297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
33917297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
34017297a28SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
34117297a28SThierry Reding };
34217297a28SThierry Reding 
343337b443dSThierry Reding static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
344337b443dSThierry Reding 	[ 0] = 0,
345337b443dSThierry Reding 	[ 1] = 0,
346337b443dSThierry Reding 	[ 2] = 0,
347337b443dSThierry Reding 	[ 3] = 0,
348337b443dSThierry Reding 	[ 4] = 0,
349337b443dSThierry Reding 	[ 5] = 0,
350337b443dSThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
351337b443dSThierry Reding 	[ 7] = 0,
352337b443dSThierry Reding 	[ 8] = 0,
353337b443dSThierry Reding 	[ 9] = 0,
354337b443dSThierry Reding 	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
355337b443dSThierry Reding 	[11] = 0,
356337b443dSThierry Reding };
357337b443dSThierry Reding 
tegra_dsi_set_phy_timing(struct tegra_dsi * dsi,unsigned long period,const struct mipi_dphy_timing * timing)358ebd14afeSThierry Reding static void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
359ebd14afeSThierry Reding 				     unsigned long period,
360ebd14afeSThierry Reding 				     const struct mipi_dphy_timing *timing)
361dec72739SThierry Reding {
3629c0b4ca1SThierry Reding 	u32 value;
363dec72739SThierry Reding 
364ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
365ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
366ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
367ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hsprepare, period, 1);
368dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
369dec72739SThierry Reding 
370ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
371ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
372ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
373ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->lpx, period, 1);
374dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
375dec72739SThierry Reding 
376ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
377ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
378dec72739SThierry Reding 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
379dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
380dec72739SThierry Reding 
381ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
382ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
383ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->tago, period, 1);
384dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
385dec72739SThierry Reding 
3867e3bc3a9SSean Paul 	if (dsi->slave)
387ebd14afeSThierry Reding 		tegra_dsi_set_phy_timing(dsi->slave, period, timing);
388dec72739SThierry Reding }
389dec72739SThierry Reding 
tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,unsigned int * mulp,unsigned int * divp)390dec72739SThierry Reding static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
391dec72739SThierry Reding 				unsigned int *mulp, unsigned int *divp)
392dec72739SThierry Reding {
393dec72739SThierry Reding 	switch (format) {
394dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
395dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB888:
396dec72739SThierry Reding 		*mulp = 3;
397dec72739SThierry Reding 		*divp = 1;
398dec72739SThierry Reding 		break;
399dec72739SThierry Reding 
400dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB565:
401dec72739SThierry Reding 		*mulp = 2;
402dec72739SThierry Reding 		*divp = 1;
403dec72739SThierry Reding 		break;
404dec72739SThierry Reding 
405dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666:
406dec72739SThierry Reding 		*mulp = 9;
407dec72739SThierry Reding 		*divp = 4;
408dec72739SThierry Reding 		break;
409dec72739SThierry Reding 
410dec72739SThierry Reding 	default:
411dec72739SThierry Reding 		return -EINVAL;
412dec72739SThierry Reding 	}
413dec72739SThierry Reding 
414dec72739SThierry Reding 	return 0;
415dec72739SThierry Reding }
416dec72739SThierry Reding 
tegra_dsi_get_format(enum mipi_dsi_pixel_format format,enum tegra_dsi_format * fmt)417f7d6889bSThierry Reding static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
418f7d6889bSThierry Reding 				enum tegra_dsi_format *fmt)
419f7d6889bSThierry Reding {
420f7d6889bSThierry Reding 	switch (format) {
421f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB888:
422f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_24P;
423f7d6889bSThierry Reding 		break;
424f7d6889bSThierry Reding 
425f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666:
426f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18NP;
427f7d6889bSThierry Reding 		break;
428f7d6889bSThierry Reding 
429f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
430f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18P;
431f7d6889bSThierry Reding 		break;
432f7d6889bSThierry Reding 
433f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB565:
434f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_16P;
435f7d6889bSThierry Reding 		break;
436f7d6889bSThierry Reding 
437f7d6889bSThierry Reding 	default:
438f7d6889bSThierry Reding 		return -EINVAL;
439f7d6889bSThierry Reding 	}
440f7d6889bSThierry Reding 
441f7d6889bSThierry Reding 	return 0;
442f7d6889bSThierry Reding }
443f7d6889bSThierry Reding 
tegra_dsi_ganged_enable(struct tegra_dsi * dsi,unsigned int start,unsigned int size)444e94236cdSThierry Reding static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
445e94236cdSThierry Reding 				    unsigned int size)
446e94236cdSThierry Reding {
447e94236cdSThierry Reding 	u32 value;
448e94236cdSThierry Reding 
449e94236cdSThierry Reding 	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
450e94236cdSThierry Reding 	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
451e94236cdSThierry Reding 
452e94236cdSThierry Reding 	value = DSI_GANGED_MODE_CONTROL_ENABLE;
453e94236cdSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
454e94236cdSThierry Reding }
455e94236cdSThierry Reding 
tegra_dsi_enable(struct tegra_dsi * dsi)456563eff1fSThierry Reding static void tegra_dsi_enable(struct tegra_dsi *dsi)
457dec72739SThierry Reding {
458563eff1fSThierry Reding 	u32 value;
459dec72739SThierry Reding 
460563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
461563eff1fSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
462563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
463e94236cdSThierry Reding 
464e94236cdSThierry Reding 	if (dsi->slave)
465e94236cdSThierry Reding 		tegra_dsi_enable(dsi->slave);
466e94236cdSThierry Reding }
467e94236cdSThierry Reding 
tegra_dsi_get_lanes(struct tegra_dsi * dsi)468e94236cdSThierry Reding static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
469e94236cdSThierry Reding {
470e94236cdSThierry Reding 	if (dsi->master)
471e94236cdSThierry Reding 		return dsi->master->lanes + dsi->lanes;
472e94236cdSThierry Reding 
473e94236cdSThierry Reding 	if (dsi->slave)
474e94236cdSThierry Reding 		return dsi->lanes + dsi->slave->lanes;
475e94236cdSThierry Reding 
476e94236cdSThierry Reding 	return dsi->lanes;
477563eff1fSThierry Reding }
478563eff1fSThierry Reding 
tegra_dsi_configure(struct tegra_dsi * dsi,unsigned int pipe,const struct drm_display_mode * mode)479ebd14afeSThierry Reding static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
480563eff1fSThierry Reding 				const struct drm_display_mode *mode)
481563eff1fSThierry Reding {
482563eff1fSThierry Reding 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
483ebd14afeSThierry Reding 	struct tegra_dsi_state *state;
484563eff1fSThierry Reding 	const u32 *pkt_seq;
485563eff1fSThierry Reding 	u32 value;
486ebd14afeSThierry Reding 
487ebd14afeSThierry Reding 	/* XXX: pass in state into this function? */
488ebd14afeSThierry Reding 	if (dsi->master)
489ebd14afeSThierry Reding 		state = tegra_dsi_get_state(dsi->master);
490ebd14afeSThierry Reding 	else
491ebd14afeSThierry Reding 		state = tegra_dsi_get_state(dsi);
492ebd14afeSThierry Reding 
493ebd14afeSThierry Reding 	mul = state->mul;
494ebd14afeSThierry Reding 	div = state->div;
495334ae6b5SThierry Reding 
49617297a28SThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
49717297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
49817297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
499337b443dSThierry Reding 	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
50017297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
50117297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_events;
502337b443dSThierry Reding 	} else {
503337b443dSThierry Reding 		DRM_DEBUG_KMS("Command mode\n");
504337b443dSThierry Reding 		pkt_seq = pkt_seq_command_mode;
50517297a28SThierry Reding 	}
50617297a28SThierry Reding 
507ebd14afeSThierry Reding 	value = DSI_CONTROL_CHANNEL(0) |
508ebd14afeSThierry Reding 		DSI_CONTROL_FORMAT(state->format) |
509dec72739SThierry Reding 		DSI_CONTROL_LANES(dsi->lanes - 1) |
510563eff1fSThierry Reding 		DSI_CONTROL_SOURCE(pipe);
511dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
512dec72739SThierry Reding 
513976cebc3SThierry Reding 	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
514dec72739SThierry Reding 
515563eff1fSThierry Reding 	value = DSI_HOST_CONTROL_HS;
516dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
517dec72739SThierry Reding 
518dec72739SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
519563eff1fSThierry Reding 
5200c6b1e4bSAlexandre Courbot 	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
521dec72739SThierry Reding 		value |= DSI_CONTROL_HS_CLK_CTRL;
522563eff1fSThierry Reding 
523dec72739SThierry Reding 	value &= ~DSI_CONTROL_TX_TRIG(3);
524337b443dSThierry Reding 
525337b443dSThierry Reding 	/* enable DCS commands for command mode */
526337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
527dec72739SThierry Reding 		value &= ~DSI_CONTROL_DCS_ENABLE;
528337b443dSThierry Reding 	else
529337b443dSThierry Reding 		value |= DSI_CONTROL_DCS_ENABLE;
530337b443dSThierry Reding 
531dec72739SThierry Reding 	value |= DSI_CONTROL_VIDEO_ENABLE;
532dec72739SThierry Reding 	value &= ~DSI_CONTROL_HOST_ENABLE;
533dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
534dec72739SThierry Reding 
535dec72739SThierry Reding 	for (i = 0; i < NUM_PKT_SEQ; i++)
536dec72739SThierry Reding 		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
537dec72739SThierry Reding 
538337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
539dec72739SThierry Reding 		/* horizontal active pixels */
540dec72739SThierry Reding 		hact = mode->hdisplay * mul / div;
541dec72739SThierry Reding 
542dec72739SThierry Reding 		/* horizontal sync width */
543dec72739SThierry Reding 		hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
544dec72739SThierry Reding 
545dec72739SThierry Reding 		/* horizontal back porch */
546dec72739SThierry Reding 		hbp = (mode->htotal - mode->hsync_end) * mul / div;
547b8be0bdbSThierry Reding 
548b8be0bdbSThierry Reding 		if ((dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
549b8be0bdbSThierry Reding 			hbp += hsw;
550dec72739SThierry Reding 
551dec72739SThierry Reding 		/* horizontal front porch */
552dec72739SThierry Reding 		hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
553b8be0bdbSThierry Reding 
554b8be0bdbSThierry Reding 		/* subtract packet overhead */
555b8be0bdbSThierry Reding 		hsw -= 10;
556b8be0bdbSThierry Reding 		hbp -= 14;
557dec72739SThierry Reding 		hfp -= 8;
558dec72739SThierry Reding 
559dec72739SThierry Reding 		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
560dec72739SThierry Reding 		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
561dec72739SThierry Reding 		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
562dec72739SThierry Reding 		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
563dec72739SThierry Reding 
564563eff1fSThierry Reding 		/* set SOL delay (for non-burst mode only) */
565dec72739SThierry Reding 		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
566e94236cdSThierry Reding 
567e94236cdSThierry Reding 		/* TODO: implement ganged mode */
568337b443dSThierry Reding 	} else {
569337b443dSThierry Reding 		u16 bytes;
570337b443dSThierry Reding 
571e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
572e94236cdSThierry Reding 			/*
573e94236cdSThierry Reding 			 * For ganged mode, assume symmetric left-right mode.
574e94236cdSThierry Reding 			 */
575e94236cdSThierry Reding 			bytes = 1 + (mode->hdisplay / 2) * mul / div;
576e94236cdSThierry Reding 		} else {
577337b443dSThierry Reding 			/* 1 byte (DCS command) + pixel data */
578337b443dSThierry Reding 			bytes = 1 + mode->hdisplay * mul / div;
579e94236cdSThierry Reding 		}
580337b443dSThierry Reding 
581337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
582337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
583337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
584337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
585337b443dSThierry Reding 
586337b443dSThierry Reding 		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
587337b443dSThierry Reding 			MIPI_DCS_WRITE_MEMORY_CONTINUE;
588337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
589337b443dSThierry Reding 
590e94236cdSThierry Reding 		/* set SOL delay */
591e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
592e94236cdSThierry Reding 			unsigned long delay, bclk, bclk_ganged;
593ebd14afeSThierry Reding 			unsigned int lanes = state->lanes;
594e94236cdSThierry Reding 
595e94236cdSThierry Reding 			/* SOL to valid, valid to FIFO and FIFO write delay */
596e94236cdSThierry Reding 			delay = 4 + 4 + 2;
597e94236cdSThierry Reding 			delay = DIV_ROUND_UP(delay * mul, div * lanes);
598e94236cdSThierry Reding 			/* FIFO read delay */
599e94236cdSThierry Reding 			delay = delay + 6;
600e94236cdSThierry Reding 
601e94236cdSThierry Reding 			bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes);
602e94236cdSThierry Reding 			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
603e94236cdSThierry Reding 			value = bclk - bclk_ganged + delay + 20;
604e94236cdSThierry Reding 		} else {
605e94236cdSThierry Reding 			/* TODO: revisit for non-ganged mode */
606337b443dSThierry Reding 			value = 8 * mul / div;
607e94236cdSThierry Reding 		}
608337b443dSThierry Reding 
609337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
610337b443dSThierry Reding 	}
611dec72739SThierry Reding 
612e94236cdSThierry Reding 	if (dsi->slave) {
613ebd14afeSThierry Reding 		tegra_dsi_configure(dsi->slave, pipe, mode);
614e94236cdSThierry Reding 
615e94236cdSThierry Reding 		/*
616e94236cdSThierry Reding 		 * TODO: Support modes other than symmetrical left-right
617e94236cdSThierry Reding 		 * split.
618e94236cdSThierry Reding 		 */
619e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
620e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
621e94236cdSThierry Reding 					mode->hdisplay / 2);
622e94236cdSThierry Reding 	}
623563eff1fSThierry Reding }
624563eff1fSThierry Reding 
tegra_dsi_wait_idle(struct tegra_dsi * dsi,unsigned long timeout)625563eff1fSThierry Reding static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
626563eff1fSThierry Reding {
627563eff1fSThierry Reding 	u32 value;
628563eff1fSThierry Reding 
629563eff1fSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
630563eff1fSThierry Reding 
631563eff1fSThierry Reding 	while (time_before(jiffies, timeout)) {
632563eff1fSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_STATUS);
633563eff1fSThierry Reding 		if (value & DSI_STATUS_IDLE)
634563eff1fSThierry Reding 			return 0;
635563eff1fSThierry Reding 
636563eff1fSThierry Reding 		usleep_range(1000, 2000);
637563eff1fSThierry Reding 	}
638563eff1fSThierry Reding 
639563eff1fSThierry Reding 	return -ETIMEDOUT;
640563eff1fSThierry Reding }
641563eff1fSThierry Reding 
tegra_dsi_video_disable(struct tegra_dsi * dsi)642563eff1fSThierry Reding static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
643563eff1fSThierry Reding {
644563eff1fSThierry Reding 	u32 value;
645563eff1fSThierry Reding 
646563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
647563eff1fSThierry Reding 	value &= ~DSI_CONTROL_VIDEO_ENABLE;
648563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
649e94236cdSThierry Reding 
650e94236cdSThierry Reding 	if (dsi->slave)
651e94236cdSThierry Reding 		tegra_dsi_video_disable(dsi->slave);
652e94236cdSThierry Reding }
653e94236cdSThierry Reding 
tegra_dsi_ganged_disable(struct tegra_dsi * dsi)654e94236cdSThierry Reding static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
655e94236cdSThierry Reding {
656e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
657e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
658e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
659563eff1fSThierry Reding }
660563eff1fSThierry Reding 
tegra_dsi_pad_enable(struct tegra_dsi * dsi)661ef8187d7SThierry Reding static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
662ef8187d7SThierry Reding {
663ef8187d7SThierry Reding 	u32 value;
664ef8187d7SThierry Reding 
665ef8187d7SThierry Reding 	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
666ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
667ef8187d7SThierry Reding 
668ef8187d7SThierry Reding 	return 0;
669ef8187d7SThierry Reding }
670ef8187d7SThierry Reding 
tegra_dsi_pad_calibrate(struct tegra_dsi * dsi)671ef8187d7SThierry Reding static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
672ef8187d7SThierry Reding {
673ef8187d7SThierry Reding 	u32 value;
674b3f1b760SSowjanya Komatineni 	int err;
675ef8187d7SThierry Reding 
676ef8187d7SThierry Reding 	/*
677ef8187d7SThierry Reding 	 * XXX Is this still needed? The module reset is deasserted right
678ef8187d7SThierry Reding 	 * before this function is called.
679ef8187d7SThierry Reding 	 */
680ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
681ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
682ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
683ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
684ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
685ef8187d7SThierry Reding 
686ef8187d7SThierry Reding 	/* start calibration */
687ef8187d7SThierry Reding 	tegra_dsi_pad_enable(dsi);
688ef8187d7SThierry Reding 
689ef8187d7SThierry Reding 	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
690ef8187d7SThierry Reding 		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
691ef8187d7SThierry Reding 		DSI_PAD_OUT_CLK(0x0);
692ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
693ef8187d7SThierry Reding 
694ef8187d7SThierry Reding 	value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
695ef8187d7SThierry Reding 		DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
696ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
697ef8187d7SThierry Reding 
698cf5153e4SSowjanya Komatineni 	err = tegra_mipi_start_calibration(dsi->mipi);
699b3f1b760SSowjanya Komatineni 	if (err < 0)
700b3f1b760SSowjanya Komatineni 		return err;
701b3f1b760SSowjanya Komatineni 
702cf5153e4SSowjanya Komatineni 	return tegra_mipi_finish_calibration(dsi->mipi);
703ef8187d7SThierry Reding }
704ef8187d7SThierry Reding 
tegra_dsi_set_timeout(struct tegra_dsi * dsi,unsigned long bclk,unsigned int vrefresh)7055b901e78SThierry Reding static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
7065b901e78SThierry Reding 				  unsigned int vrefresh)
7075b901e78SThierry Reding {
7085b901e78SThierry Reding 	unsigned int timeout;
7095b901e78SThierry Reding 	u32 value;
7105b901e78SThierry Reding 
7115b901e78SThierry Reding 	/* one frame high-speed transmission timeout */
7125b901e78SThierry Reding 	timeout = (bclk / vrefresh) / 512;
7135b901e78SThierry Reding 	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
7145b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
7155b901e78SThierry Reding 
7165b901e78SThierry Reding 	/* 2 ms peripheral timeout for panel */
7175b901e78SThierry Reding 	timeout = 2 * bclk / 512 * 1000;
7185b901e78SThierry Reding 	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
7195b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
7205b901e78SThierry Reding 
7215b901e78SThierry Reding 	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
7225b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
7235b901e78SThierry Reding 
7245b901e78SThierry Reding 	if (dsi->slave)
7255b901e78SThierry Reding 		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
7265b901e78SThierry Reding }
7275b901e78SThierry Reding 
tegra_dsi_disable(struct tegra_dsi * dsi)728563eff1fSThierry Reding static void tegra_dsi_disable(struct tegra_dsi *dsi)
729563eff1fSThierry Reding {
730563eff1fSThierry Reding 	u32 value;
731563eff1fSThierry Reding 
732e94236cdSThierry Reding 	if (dsi->slave) {
733e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi->slave);
734e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi);
735e94236cdSThierry Reding 	}
736e94236cdSThierry Reding 
737563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
738563eff1fSThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
739563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
740563eff1fSThierry Reding 
741e94236cdSThierry Reding 	if (dsi->slave)
742e94236cdSThierry Reding 		tegra_dsi_disable(dsi->slave);
743e94236cdSThierry Reding 
744563eff1fSThierry Reding 	usleep_range(5000, 10000);
745563eff1fSThierry Reding }
746563eff1fSThierry Reding 
tegra_dsi_soft_reset(struct tegra_dsi * dsi)74792f0e073SThierry Reding static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
74892f0e073SThierry Reding {
74992f0e073SThierry Reding 	u32 value;
75092f0e073SThierry Reding 
75192f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
75292f0e073SThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
75392f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
75492f0e073SThierry Reding 
75592f0e073SThierry Reding 	usleep_range(300, 1000);
75692f0e073SThierry Reding 
75792f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
75892f0e073SThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
75992f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
76092f0e073SThierry Reding 
76192f0e073SThierry Reding 	usleep_range(300, 1000);
76292f0e073SThierry Reding 
76392f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_TRIGGER);
76492f0e073SThierry Reding 	if (value)
76592f0e073SThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
76692f0e073SThierry Reding 
76792f0e073SThierry Reding 	if (dsi->slave)
76892f0e073SThierry Reding 		tegra_dsi_soft_reset(dsi->slave);
76992f0e073SThierry Reding }
77092f0e073SThierry Reding 
tegra_dsi_connector_reset(struct drm_connector * connector)771ebd14afeSThierry Reding static void tegra_dsi_connector_reset(struct drm_connector *connector)
772ebd14afeSThierry Reding {
773280dc0e1SJon Hunter 	struct tegra_dsi_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
774ebd14afeSThierry Reding 
775280dc0e1SJon Hunter 	if (!state)
776280dc0e1SJon Hunter 		return;
777280dc0e1SJon Hunter 
778280dc0e1SJon Hunter 	if (connector->state) {
779280dc0e1SJon Hunter 		__drm_atomic_helper_connector_destroy_state(connector->state);
780ebd14afeSThierry Reding 		kfree(connector->state);
7815459a2adSMaarten Lankhorst 	}
782280dc0e1SJon Hunter 
783280dc0e1SJon Hunter 	__drm_atomic_helper_connector_reset(connector, &state->base);
784ebd14afeSThierry Reding }
785ebd14afeSThierry Reding 
786ebd14afeSThierry Reding static struct drm_connector_state *
tegra_dsi_connector_duplicate_state(struct drm_connector * connector)787ebd14afeSThierry Reding tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
788ebd14afeSThierry Reding {
789ebd14afeSThierry Reding 	struct tegra_dsi_state *state = to_dsi_state(connector->state);
790ebd14afeSThierry Reding 	struct tegra_dsi_state *copy;
791ebd14afeSThierry Reding 
792ebd14afeSThierry Reding 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
793ebd14afeSThierry Reding 	if (!copy)
794ebd14afeSThierry Reding 		return NULL;
795ebd14afeSThierry Reding 
796280dc0e1SJon Hunter 	__drm_atomic_helper_connector_duplicate_state(connector,
797280dc0e1SJon Hunter 						      &copy->base);
798280dc0e1SJon Hunter 
799ebd14afeSThierry Reding 	return &copy->base;
800ebd14afeSThierry Reding }
801ebd14afeSThierry Reding 
8025b901e78SThierry Reding static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
803ebd14afeSThierry Reding 	.reset = tegra_dsi_connector_reset,
8045b901e78SThierry Reding 	.detect = tegra_output_connector_detect,
8055b901e78SThierry Reding 	.fill_modes = drm_helper_probe_single_connector_modes,
8065b901e78SThierry Reding 	.destroy = tegra_output_connector_destroy,
807ebd14afeSThierry Reding 	.atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
8084aa3df71SThierry Reding 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
809a813d704SThierry Reding 	.late_register = tegra_dsi_late_register,
810a813d704SThierry Reding 	.early_unregister = tegra_dsi_early_unregister,
8115b901e78SThierry Reding };
8125b901e78SThierry Reding 
8135b901e78SThierry Reding static enum drm_mode_status
tegra_dsi_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)8145b901e78SThierry Reding tegra_dsi_connector_mode_valid(struct drm_connector *connector,
8155b901e78SThierry Reding 			       struct drm_display_mode *mode)
8165b901e78SThierry Reding {
8175b901e78SThierry Reding 	return MODE_OK;
8185b901e78SThierry Reding }
8195b901e78SThierry Reding 
8205b901e78SThierry Reding static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
8215b901e78SThierry Reding 	.get_modes = tegra_output_connector_get_modes,
8225b901e78SThierry Reding 	.mode_valid = tegra_dsi_connector_mode_valid,
8235b901e78SThierry Reding };
8245b901e78SThierry Reding 
tegra_dsi_unprepare(struct tegra_dsi * dsi)82587904c3eSThierry Reding static void tegra_dsi_unprepare(struct tegra_dsi *dsi)
82687904c3eSThierry Reding {
82787904c3eSThierry Reding 	int err;
82887904c3eSThierry Reding 
82987904c3eSThierry Reding 	if (dsi->slave)
83087904c3eSThierry Reding 		tegra_dsi_unprepare(dsi->slave);
83187904c3eSThierry Reding 
83287904c3eSThierry Reding 	err = tegra_mipi_disable(dsi->mipi);
83387904c3eSThierry Reding 	if (err < 0)
83487904c3eSThierry Reding 		dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n",
83587904c3eSThierry Reding 			err);
83687904c3eSThierry Reding 
837fd67e9c6SThierry Reding 	err = host1x_client_suspend(&dsi->client);
838fd67e9c6SThierry Reding 	if (err < 0)
839fd67e9c6SThierry Reding 		dev_err(dsi->dev, "failed to suspend: %d\n", err);
84087904c3eSThierry Reding }
84187904c3eSThierry Reding 
tegra_dsi_encoder_disable(struct drm_encoder * encoder)8425b901e78SThierry Reding static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
8435b901e78SThierry Reding {
8445b901e78SThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
8455b901e78SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
8465b901e78SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
8475b901e78SThierry Reding 	u32 value;
8485b901e78SThierry Reding 	int err;
8495b901e78SThierry Reding 
8505b901e78SThierry Reding 	if (output->panel)
8515b901e78SThierry Reding 		drm_panel_disable(output->panel);
8525b901e78SThierry Reding 
8535b901e78SThierry Reding 	tegra_dsi_video_disable(dsi);
8545b901e78SThierry Reding 
8555b901e78SThierry Reding 	/*
8565b901e78SThierry Reding 	 * The following accesses registers of the display controller, so make
8575b901e78SThierry Reding 	 * sure it's only executed when the output is attached to one.
8585b901e78SThierry Reding 	 */
8595b901e78SThierry Reding 	if (dc) {
8605b901e78SThierry Reding 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
8615b901e78SThierry Reding 		value &= ~DSI_ENABLE;
8625b901e78SThierry Reding 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
8635b901e78SThierry Reding 
8645b901e78SThierry Reding 		tegra_dc_commit(dc);
8655b901e78SThierry Reding 	}
8665b901e78SThierry Reding 
8675b901e78SThierry Reding 	err = tegra_dsi_wait_idle(dsi, 100);
8685b901e78SThierry Reding 	if (err < 0)
8695b901e78SThierry Reding 		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
8705b901e78SThierry Reding 
8715b901e78SThierry Reding 	tegra_dsi_soft_reset(dsi);
8725b901e78SThierry Reding 
8735b901e78SThierry Reding 	if (output->panel)
8745b901e78SThierry Reding 		drm_panel_unprepare(output->panel);
8755b901e78SThierry Reding 
8765b901e78SThierry Reding 	tegra_dsi_disable(dsi);
8775b901e78SThierry Reding 
87887904c3eSThierry Reding 	tegra_dsi_unprepare(dsi);
87987904c3eSThierry Reding }
88087904c3eSThierry Reding 
tegra_dsi_prepare(struct tegra_dsi * dsi)881fd67e9c6SThierry Reding static int tegra_dsi_prepare(struct tegra_dsi *dsi)
88287904c3eSThierry Reding {
88387904c3eSThierry Reding 	int err;
88487904c3eSThierry Reding 
885fd67e9c6SThierry Reding 	err = host1x_client_resume(&dsi->client);
886fd67e9c6SThierry Reding 	if (err < 0) {
887fd67e9c6SThierry Reding 		dev_err(dsi->dev, "failed to resume: %d\n", err);
888fd67e9c6SThierry Reding 		return err;
889fd67e9c6SThierry Reding 	}
89087904c3eSThierry Reding 
89187904c3eSThierry Reding 	err = tegra_mipi_enable(dsi->mipi);
89287904c3eSThierry Reding 	if (err < 0)
89387904c3eSThierry Reding 		dev_err(dsi->dev, "failed to enable MIPI calibration: %d\n",
89487904c3eSThierry Reding 			err);
89587904c3eSThierry Reding 
89687904c3eSThierry Reding 	err = tegra_dsi_pad_calibrate(dsi);
89787904c3eSThierry Reding 	if (err < 0)
89887904c3eSThierry Reding 		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
89987904c3eSThierry Reding 
90087904c3eSThierry Reding 	if (dsi->slave)
90187904c3eSThierry Reding 		tegra_dsi_prepare(dsi->slave);
902fd67e9c6SThierry Reding 
903fd67e9c6SThierry Reding 	return 0;
9045b901e78SThierry Reding }
9055b901e78SThierry Reding 
tegra_dsi_encoder_enable(struct drm_encoder * encoder)906171e2e6dSThierry Reding static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
907171e2e6dSThierry Reding {
908171e2e6dSThierry Reding 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
909171e2e6dSThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
910171e2e6dSThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
911171e2e6dSThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
912171e2e6dSThierry Reding 	struct tegra_dsi_state *state;
913171e2e6dSThierry Reding 	u32 value;
914fd67e9c6SThierry Reding 	int err;
915ef8187d7SThierry Reding 
916b22fd0b9SDiogo Ivo 	/* If the bootloader enabled DSI it needs to be disabled
917b22fd0b9SDiogo Ivo 	 * in order for the panel initialization commands to be
918b22fd0b9SDiogo Ivo 	 * properly sent.
919b22fd0b9SDiogo Ivo 	 */
920b22fd0b9SDiogo Ivo 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
921b22fd0b9SDiogo Ivo 
922b22fd0b9SDiogo Ivo 	if (value & DSI_POWER_CONTROL_ENABLE)
923b22fd0b9SDiogo Ivo 		tegra_dsi_disable(dsi);
924b22fd0b9SDiogo Ivo 
925fd67e9c6SThierry Reding 	err = tegra_dsi_prepare(dsi);
926fd67e9c6SThierry Reding 	if (err < 0) {
927fd67e9c6SThierry Reding 		dev_err(dsi->dev, "failed to prepare: %d\n", err);
928fd67e9c6SThierry Reding 		return;
929fd67e9c6SThierry Reding 	}
930171e2e6dSThierry Reding 
931171e2e6dSThierry Reding 	state = tegra_dsi_get_state(dsi);
932171e2e6dSThierry Reding 
933171e2e6dSThierry Reding 	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
934171e2e6dSThierry Reding 
935171e2e6dSThierry Reding 	/*
936171e2e6dSThierry Reding 	 * The D-PHY timing fields are expressed in byte-clock cycles, so
937171e2e6dSThierry Reding 	 * multiply the period by 8.
938171e2e6dSThierry Reding 	 */
939171e2e6dSThierry Reding 	tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
940171e2e6dSThierry Reding 
941171e2e6dSThierry Reding 	if (output->panel)
942171e2e6dSThierry Reding 		drm_panel_prepare(output->panel);
943171e2e6dSThierry Reding 
944171e2e6dSThierry Reding 	tegra_dsi_configure(dsi, dc->pipe, mode);
945171e2e6dSThierry Reding 
946171e2e6dSThierry Reding 	/* enable display controller */
947171e2e6dSThierry Reding 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
948171e2e6dSThierry Reding 	value |= DSI_ENABLE;
949171e2e6dSThierry Reding 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
950171e2e6dSThierry Reding 
951171e2e6dSThierry Reding 	tegra_dc_commit(dc);
952171e2e6dSThierry Reding 
953171e2e6dSThierry Reding 	/* enable DSI controller */
954171e2e6dSThierry Reding 	tegra_dsi_enable(dsi);
955171e2e6dSThierry Reding 
956171e2e6dSThierry Reding 	if (output->panel)
957171e2e6dSThierry Reding 		drm_panel_enable(output->panel);
958171e2e6dSThierry Reding }
959171e2e6dSThierry Reding 
960ebd14afeSThierry Reding static int
tegra_dsi_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)961ebd14afeSThierry Reding tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
962ebd14afeSThierry Reding 			       struct drm_crtc_state *crtc_state,
963ebd14afeSThierry Reding 			       struct drm_connector_state *conn_state)
964ebd14afeSThierry Reding {
965ebd14afeSThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
966ebd14afeSThierry Reding 	struct tegra_dsi_state *state = to_dsi_state(conn_state);
967ebd14afeSThierry Reding 	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
968ebd14afeSThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
969ebd14afeSThierry Reding 	unsigned int scdiv;
970ebd14afeSThierry Reding 	unsigned long plld;
971ebd14afeSThierry Reding 	int err;
972ebd14afeSThierry Reding 
973ebd14afeSThierry Reding 	state->pclk = crtc_state->mode.clock * 1000;
974ebd14afeSThierry Reding 
975ebd14afeSThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
976ebd14afeSThierry Reding 	if (err < 0)
977ebd14afeSThierry Reding 		return err;
978ebd14afeSThierry Reding 
979ebd14afeSThierry Reding 	state->lanes = tegra_dsi_get_lanes(dsi);
980ebd14afeSThierry Reding 
981ebd14afeSThierry Reding 	err = tegra_dsi_get_format(dsi->format, &state->format);
982ebd14afeSThierry Reding 	if (err < 0)
983ebd14afeSThierry Reding 		return err;
984ebd14afeSThierry Reding 
985ebd14afeSThierry Reding 	state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
986ebd14afeSThierry Reding 
987ebd14afeSThierry Reding 	/* compute byte clock */
988ebd14afeSThierry Reding 	state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
989ebd14afeSThierry Reding 
990ebd14afeSThierry Reding 	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
991ebd14afeSThierry Reding 		      state->lanes);
992ebd14afeSThierry Reding 	DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
993ebd14afeSThierry Reding 		      state->vrefresh);
994ebd14afeSThierry Reding 	DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
995ebd14afeSThierry Reding 
996ebd14afeSThierry Reding 	/*
997ebd14afeSThierry Reding 	 * Compute bit clock and round up to the next MHz.
998ebd14afeSThierry Reding 	 */
999ebd14afeSThierry Reding 	plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
1000ebd14afeSThierry Reding 	state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
1001ebd14afeSThierry Reding 
1002ebd14afeSThierry Reding 	err = mipi_dphy_timing_get_default(&state->timing, state->period);
1003ebd14afeSThierry Reding 	if (err < 0)
1004ebd14afeSThierry Reding 		return err;
1005ebd14afeSThierry Reding 
1006ebd14afeSThierry Reding 	err = mipi_dphy_timing_validate(&state->timing, state->period);
1007ebd14afeSThierry Reding 	if (err < 0) {
1008ebd14afeSThierry Reding 		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
1009ebd14afeSThierry Reding 		return err;
1010ebd14afeSThierry Reding 	}
1011ebd14afeSThierry Reding 
1012ebd14afeSThierry Reding 	/*
1013ebd14afeSThierry Reding 	 * We divide the frequency by two here, but we make up for that by
1014ebd14afeSThierry Reding 	 * setting the shift clock divider (further below) to half of the
1015ebd14afeSThierry Reding 	 * correct value.
1016ebd14afeSThierry Reding 	 */
1017ebd14afeSThierry Reding 	plld /= 2;
1018ebd14afeSThierry Reding 
1019ebd14afeSThierry Reding 	/*
1020ebd14afeSThierry Reding 	 * Derive pixel clock from bit clock using the shift clock divider.
1021ebd14afeSThierry Reding 	 * Note that this is only half of what we would expect, but we need
1022ebd14afeSThierry Reding 	 * that to make up for the fact that we divided the bit clock by a
1023ebd14afeSThierry Reding 	 * factor of two above.
1024ebd14afeSThierry Reding 	 *
1025ebd14afeSThierry Reding 	 * It's not clear exactly why this is necessary, but the display is
1026ebd14afeSThierry Reding 	 * not working properly otherwise. Perhaps the PLLs cannot generate
1027ebd14afeSThierry Reding 	 * frequencies sufficiently high.
1028ebd14afeSThierry Reding 	 */
1029ebd14afeSThierry Reding 	scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
1030ebd14afeSThierry Reding 
1031ebd14afeSThierry Reding 	err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
1032ebd14afeSThierry Reding 					 plld, scdiv);
1033ebd14afeSThierry Reding 	if (err < 0) {
1034ebd14afeSThierry Reding 		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
1035ebd14afeSThierry Reding 		return err;
1036ebd14afeSThierry Reding 	}
1037ebd14afeSThierry Reding 
1038ebd14afeSThierry Reding 	return err;
1039ebd14afeSThierry Reding }
1040ebd14afeSThierry Reding 
10415b901e78SThierry Reding static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
10425b901e78SThierry Reding 	.disable = tegra_dsi_encoder_disable,
1043171e2e6dSThierry Reding 	.enable = tegra_dsi_encoder_enable,
1044ebd14afeSThierry Reding 	.atomic_check = tegra_dsi_encoder_atomic_check,
1045dec72739SThierry Reding };
1046dec72739SThierry Reding 
tegra_dsi_init(struct host1x_client * client)1047dec72739SThierry Reding static int tegra_dsi_init(struct host1x_client *client)
1048dec72739SThierry Reding {
1049608f43adSThierry Reding 	struct drm_device *drm = dev_get_drvdata(client->host);
1050dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1051dec72739SThierry Reding 	int err;
1052dec72739SThierry Reding 
1053e94236cdSThierry Reding 	/* Gangsters must not register their own outputs. */
1054e94236cdSThierry Reding 	if (!dsi->master) {
1055dec72739SThierry Reding 		dsi->output.dev = client->dev;
1056dec72739SThierry Reding 
10575b901e78SThierry Reding 		drm_connector_init(drm, &dsi->output.connector,
10585b901e78SThierry Reding 				   &tegra_dsi_connector_funcs,
10595b901e78SThierry Reding 				   DRM_MODE_CONNECTOR_DSI);
10605b901e78SThierry Reding 		drm_connector_helper_add(&dsi->output.connector,
10615b901e78SThierry Reding 					 &tegra_dsi_connector_helper_funcs);
10625b901e78SThierry Reding 		dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
10635b901e78SThierry Reding 
10644d0e95e0SThomas Zimmermann 		drm_simple_encoder_init(drm, &dsi->output.encoder,
10654d0e95e0SThomas Zimmermann 					DRM_MODE_ENCODER_DSI);
10665b901e78SThierry Reding 		drm_encoder_helper_add(&dsi->output.encoder,
10675b901e78SThierry Reding 				       &tegra_dsi_encoder_helper_funcs);
10685b901e78SThierry Reding 
1069cde4c44dSDaniel Vetter 		drm_connector_attach_encoder(&dsi->output.connector,
10705b901e78SThierry Reding 						  &dsi->output.encoder);
10715b901e78SThierry Reding 		drm_connector_register(&dsi->output.connector);
10725b901e78SThierry Reding 
1073ea130b24SThierry Reding 		err = tegra_output_init(drm, &dsi->output);
1074ef8187d7SThierry Reding 		if (err < 0)
1075ef8187d7SThierry Reding 			dev_err(dsi->dev, "failed to initialize output: %d\n",
1076ea130b24SThierry Reding 				err);
1077ea130b24SThierry Reding 
10785b901e78SThierry Reding 		dsi->output.encoder.possible_crtcs = 0x3;
1079e94236cdSThierry Reding 	}
1080dec72739SThierry Reding 
1081dec72739SThierry Reding 	return 0;
1082dec72739SThierry Reding }
1083dec72739SThierry Reding 
tegra_dsi_exit(struct host1x_client * client)1084dec72739SThierry Reding static int tegra_dsi_exit(struct host1x_client *client)
1085dec72739SThierry Reding {
1086dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1087dec72739SThierry Reding 
10885b901e78SThierry Reding 	tegra_output_exit(&dsi->output);
1089201106d8SThierry Reding 
1090dec72739SThierry Reding 	return 0;
1091dec72739SThierry Reding }
1092dec72739SThierry Reding 
tegra_dsi_runtime_suspend(struct host1x_client * client)1093fd67e9c6SThierry Reding static int tegra_dsi_runtime_suspend(struct host1x_client *client)
1094fd67e9c6SThierry Reding {
1095fd67e9c6SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1096fd67e9c6SThierry Reding 	struct device *dev = client->dev;
1097fd67e9c6SThierry Reding 	int err;
1098fd67e9c6SThierry Reding 
1099fd67e9c6SThierry Reding 	if (dsi->rst) {
1100fd67e9c6SThierry Reding 		err = reset_control_assert(dsi->rst);
1101fd67e9c6SThierry Reding 		if (err < 0) {
1102fd67e9c6SThierry Reding 			dev_err(dev, "failed to assert reset: %d\n", err);
1103fd67e9c6SThierry Reding 			return err;
1104fd67e9c6SThierry Reding 		}
1105fd67e9c6SThierry Reding 	}
1106fd67e9c6SThierry Reding 
1107fd67e9c6SThierry Reding 	usleep_range(1000, 2000);
1108fd67e9c6SThierry Reding 
1109fd67e9c6SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1110fd67e9c6SThierry Reding 	clk_disable_unprepare(dsi->clk);
1111fd67e9c6SThierry Reding 
1112fd67e9c6SThierry Reding 	regulator_disable(dsi->vdd);
1113fd67e9c6SThierry Reding 	pm_runtime_put_sync(dev);
1114fd67e9c6SThierry Reding 
1115fd67e9c6SThierry Reding 	return 0;
1116fd67e9c6SThierry Reding }
1117fd67e9c6SThierry Reding 
tegra_dsi_runtime_resume(struct host1x_client * client)1118fd67e9c6SThierry Reding static int tegra_dsi_runtime_resume(struct host1x_client *client)
1119fd67e9c6SThierry Reding {
1120fd67e9c6SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1121fd67e9c6SThierry Reding 	struct device *dev = client->dev;
1122fd67e9c6SThierry Reding 	int err;
1123fd67e9c6SThierry Reding 
1124dcdfe271SQinglang Miao 	err = pm_runtime_resume_and_get(dev);
1125fd67e9c6SThierry Reding 	if (err < 0) {
1126fd67e9c6SThierry Reding 		dev_err(dev, "failed to get runtime PM: %d\n", err);
1127fd67e9c6SThierry Reding 		return err;
1128fd67e9c6SThierry Reding 	}
1129fd67e9c6SThierry Reding 
1130fd67e9c6SThierry Reding 	err = regulator_enable(dsi->vdd);
1131fd67e9c6SThierry Reding 	if (err < 0) {
1132fd67e9c6SThierry Reding 		dev_err(dev, "failed to enable VDD supply: %d\n", err);
1133fd67e9c6SThierry Reding 		goto put_rpm;
1134fd67e9c6SThierry Reding 	}
1135fd67e9c6SThierry Reding 
1136fd67e9c6SThierry Reding 	err = clk_prepare_enable(dsi->clk);
1137fd67e9c6SThierry Reding 	if (err < 0) {
1138fd67e9c6SThierry Reding 		dev_err(dev, "cannot enable DSI clock: %d\n", err);
1139fd67e9c6SThierry Reding 		goto disable_vdd;
1140fd67e9c6SThierry Reding 	}
1141fd67e9c6SThierry Reding 
1142fd67e9c6SThierry Reding 	err = clk_prepare_enable(dsi->clk_lp);
1143fd67e9c6SThierry Reding 	if (err < 0) {
1144fd67e9c6SThierry Reding 		dev_err(dev, "cannot enable low-power clock: %d\n", err);
1145fd67e9c6SThierry Reding 		goto disable_clk;
1146fd67e9c6SThierry Reding 	}
1147fd67e9c6SThierry Reding 
1148fd67e9c6SThierry Reding 	usleep_range(1000, 2000);
1149fd67e9c6SThierry Reding 
1150fd67e9c6SThierry Reding 	if (dsi->rst) {
1151fd67e9c6SThierry Reding 		err = reset_control_deassert(dsi->rst);
1152fd67e9c6SThierry Reding 		if (err < 0) {
1153fd67e9c6SThierry Reding 			dev_err(dev, "cannot assert reset: %d\n", err);
1154fd67e9c6SThierry Reding 			goto disable_clk_lp;
1155fd67e9c6SThierry Reding 		}
1156fd67e9c6SThierry Reding 	}
1157fd67e9c6SThierry Reding 
1158fd67e9c6SThierry Reding 	return 0;
1159fd67e9c6SThierry Reding 
1160fd67e9c6SThierry Reding disable_clk_lp:
1161fd67e9c6SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1162fd67e9c6SThierry Reding disable_clk:
1163fd67e9c6SThierry Reding 	clk_disable_unprepare(dsi->clk);
1164fd67e9c6SThierry Reding disable_vdd:
1165fd67e9c6SThierry Reding 	regulator_disable(dsi->vdd);
1166fd67e9c6SThierry Reding put_rpm:
1167fd67e9c6SThierry Reding 	pm_runtime_put_sync(dev);
1168fd67e9c6SThierry Reding 	return err;
1169fd67e9c6SThierry Reding }
1170fd67e9c6SThierry Reding 
1171dec72739SThierry Reding static const struct host1x_client_ops dsi_client_ops = {
1172dec72739SThierry Reding 	.init = tegra_dsi_init,
1173dec72739SThierry Reding 	.exit = tegra_dsi_exit,
1174fd67e9c6SThierry Reding 	.suspend = tegra_dsi_runtime_suspend,
1175fd67e9c6SThierry Reding 	.resume = tegra_dsi_runtime_resume,
1176dec72739SThierry Reding };
1177dec72739SThierry Reding 
tegra_dsi_setup_clocks(struct tegra_dsi * dsi)1178dec72739SThierry Reding static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
1179dec72739SThierry Reding {
1180dec72739SThierry Reding 	struct clk *parent;
1181dec72739SThierry Reding 	int err;
1182dec72739SThierry Reding 
1183dec72739SThierry Reding 	parent = clk_get_parent(dsi->clk);
1184dec72739SThierry Reding 	if (!parent)
1185dec72739SThierry Reding 		return -EINVAL;
1186dec72739SThierry Reding 
1187dec72739SThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1188dec72739SThierry Reding 	if (err < 0)
1189dec72739SThierry Reding 		return err;
1190dec72739SThierry Reding 
1191dec72739SThierry Reding 	return 0;
1192dec72739SThierry Reding }
1193dec72739SThierry Reding 
11940fffdf6cSThierry Reding static const char * const error_report[16] = {
11950fffdf6cSThierry Reding 	"SoT Error",
11960fffdf6cSThierry Reding 	"SoT Sync Error",
11970fffdf6cSThierry Reding 	"EoT Sync Error",
11980fffdf6cSThierry Reding 	"Escape Mode Entry Command Error",
11990fffdf6cSThierry Reding 	"Low-Power Transmit Sync Error",
12000fffdf6cSThierry Reding 	"Peripheral Timeout Error",
12010fffdf6cSThierry Reding 	"False Control Error",
12020fffdf6cSThierry Reding 	"Contention Detected",
12030fffdf6cSThierry Reding 	"ECC Error, single-bit",
12040fffdf6cSThierry Reding 	"ECC Error, multi-bit",
12050fffdf6cSThierry Reding 	"Checksum Error",
12060fffdf6cSThierry Reding 	"DSI Data Type Not Recognized",
12070fffdf6cSThierry Reding 	"DSI VC ID Invalid",
12080fffdf6cSThierry Reding 	"Invalid Transmission Length",
12090fffdf6cSThierry Reding 	"Reserved",
12100fffdf6cSThierry Reding 	"DSI Protocol Violation",
12110fffdf6cSThierry Reding };
12120fffdf6cSThierry Reding 
tegra_dsi_read_response(struct tegra_dsi * dsi,const struct mipi_dsi_msg * msg,size_t count)12130fffdf6cSThierry Reding static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
12140fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg,
12150fffdf6cSThierry Reding 				       size_t count)
12160fffdf6cSThierry Reding {
12170fffdf6cSThierry Reding 	u8 *rx = msg->rx_buf;
12180fffdf6cSThierry Reding 	unsigned int i, j, k;
12190fffdf6cSThierry Reding 	size_t size = 0;
12200fffdf6cSThierry Reding 	u16 errors;
12210fffdf6cSThierry Reding 	u32 value;
12220fffdf6cSThierry Reding 
12230fffdf6cSThierry Reding 	/* read and parse packet header */
12240fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12250fffdf6cSThierry Reding 
12260fffdf6cSThierry Reding 	switch (value & 0x3f) {
12270fffdf6cSThierry Reding 	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
12280fffdf6cSThierry Reding 		errors = (value >> 8) & 0xffff;
12290fffdf6cSThierry Reding 		dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
12300fffdf6cSThierry Reding 			errors);
12310fffdf6cSThierry Reding 		for (i = 0; i < ARRAY_SIZE(error_report); i++)
12320fffdf6cSThierry Reding 			if (errors & BIT(i))
12330fffdf6cSThierry Reding 				dev_dbg(dsi->dev, "  %2u: %s\n", i,
12340fffdf6cSThierry Reding 					error_report[i]);
12350fffdf6cSThierry Reding 		break;
12360fffdf6cSThierry Reding 
12370fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
12380fffdf6cSThierry Reding 		rx[0] = (value >> 8) & 0xff;
12390fffdf6cSThierry Reding 		size = 1;
12400fffdf6cSThierry Reding 		break;
12410fffdf6cSThierry Reding 
12420fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
12430fffdf6cSThierry Reding 		rx[0] = (value >>  8) & 0xff;
12440fffdf6cSThierry Reding 		rx[1] = (value >> 16) & 0xff;
12450fffdf6cSThierry Reding 		size = 2;
12460fffdf6cSThierry Reding 		break;
12470fffdf6cSThierry Reding 
12480fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
12490fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
12500fffdf6cSThierry Reding 		break;
12510fffdf6cSThierry Reding 
12520fffdf6cSThierry Reding 	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
12530fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
12540fffdf6cSThierry Reding 		break;
12550fffdf6cSThierry Reding 
12560fffdf6cSThierry Reding 	default:
12570fffdf6cSThierry Reding 		dev_err(dsi->dev, "unhandled response type: %02x\n",
12580fffdf6cSThierry Reding 			value & 0x3f);
12590fffdf6cSThierry Reding 		return -EPROTO;
12600fffdf6cSThierry Reding 	}
12610fffdf6cSThierry Reding 
12620fffdf6cSThierry Reding 	size = min(size, msg->rx_len);
12630fffdf6cSThierry Reding 
12640fffdf6cSThierry Reding 	if (msg->rx_buf && size > 0) {
12650fffdf6cSThierry Reding 		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
12660fffdf6cSThierry Reding 			u8 *rx = msg->rx_buf + j;
12670fffdf6cSThierry Reding 
12680fffdf6cSThierry Reding 			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12690fffdf6cSThierry Reding 
12700fffdf6cSThierry Reding 			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
12710fffdf6cSThierry Reding 				rx[j + k] = (value >> (k << 3)) & 0xff;
12720fffdf6cSThierry Reding 		}
12730fffdf6cSThierry Reding 	}
12740fffdf6cSThierry Reding 
12750fffdf6cSThierry Reding 	return size;
12760fffdf6cSThierry Reding }
12770fffdf6cSThierry Reding 
tegra_dsi_transmit(struct tegra_dsi * dsi,unsigned long timeout)12780fffdf6cSThierry Reding static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
12790fffdf6cSThierry Reding {
12800fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
12810fffdf6cSThierry Reding 
12820fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
12830fffdf6cSThierry Reding 
12840fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
12850fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
12860fffdf6cSThierry Reding 		if ((value & DSI_TRIGGER_HOST) == 0)
12870fffdf6cSThierry Reding 			return 0;
12880fffdf6cSThierry Reding 
12890fffdf6cSThierry Reding 		usleep_range(1000, 2000);
12900fffdf6cSThierry Reding 	}
12910fffdf6cSThierry Reding 
12920fffdf6cSThierry Reding 	DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
12930fffdf6cSThierry Reding 	return -ETIMEDOUT;
12940fffdf6cSThierry Reding }
12950fffdf6cSThierry Reding 
tegra_dsi_wait_for_response(struct tegra_dsi * dsi,unsigned long timeout)12960fffdf6cSThierry Reding static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
12970fffdf6cSThierry Reding 				       unsigned long timeout)
12980fffdf6cSThierry Reding {
12990fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(250);
13000fffdf6cSThierry Reding 
13010fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
13020fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
13030fffdf6cSThierry Reding 		u8 count = value & 0x1f;
13040fffdf6cSThierry Reding 
13050fffdf6cSThierry Reding 		if (count > 0)
13060fffdf6cSThierry Reding 			return count;
13070fffdf6cSThierry Reding 
13080fffdf6cSThierry Reding 		usleep_range(1000, 2000);
13090fffdf6cSThierry Reding 	}
13100fffdf6cSThierry Reding 
13110fffdf6cSThierry Reding 	DRM_DEBUG_KMS("peripheral returned no data\n");
13120fffdf6cSThierry Reding 	return -ETIMEDOUT;
13130fffdf6cSThierry Reding }
13140fffdf6cSThierry Reding 
tegra_dsi_writesl(struct tegra_dsi * dsi,unsigned long offset,const void * buffer,size_t size)13150fffdf6cSThierry Reding static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
13160fffdf6cSThierry Reding 			      const void *buffer, size_t size)
13170fffdf6cSThierry Reding {
13180fffdf6cSThierry Reding 	const u8 *buf = buffer;
13190fffdf6cSThierry Reding 	size_t i, j;
13200fffdf6cSThierry Reding 	u32 value;
13210fffdf6cSThierry Reding 
13220fffdf6cSThierry Reding 	for (j = 0; j < size; j += 4) {
13230fffdf6cSThierry Reding 		value = 0;
13240fffdf6cSThierry Reding 
13250fffdf6cSThierry Reding 		for (i = 0; i < 4 && j + i < size; i++)
13260fffdf6cSThierry Reding 			value |= buf[j + i] << (i << 3);
13270fffdf6cSThierry Reding 
13280fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_WR_DATA);
13290fffdf6cSThierry Reding 	}
13300fffdf6cSThierry Reding }
13310fffdf6cSThierry Reding 
tegra_dsi_host_transfer(struct mipi_dsi_host * host,const struct mipi_dsi_msg * msg)13320fffdf6cSThierry Reding static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
13330fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg)
13340fffdf6cSThierry Reding {
13350fffdf6cSThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
13360fffdf6cSThierry Reding 	struct mipi_dsi_packet packet;
13370fffdf6cSThierry Reding 	const u8 *header;
13380fffdf6cSThierry Reding 	size_t count;
13390fffdf6cSThierry Reding 	ssize_t err;
13400fffdf6cSThierry Reding 	u32 value;
13410fffdf6cSThierry Reding 
13420fffdf6cSThierry Reding 	err = mipi_dsi_create_packet(&packet, msg);
13430fffdf6cSThierry Reding 	if (err < 0)
13440fffdf6cSThierry Reding 		return err;
13450fffdf6cSThierry Reding 
13460fffdf6cSThierry Reding 	header = packet.header;
13470fffdf6cSThierry Reding 
13480fffdf6cSThierry Reding 	/* maximum FIFO depth is 1920 words */
13490fffdf6cSThierry Reding 	if (packet.size > dsi->video_fifo_depth * 4)
13500fffdf6cSThierry Reding 		return -ENOSPC;
13510fffdf6cSThierry Reding 
13520fffdf6cSThierry Reding 	/* reset underflow/overflow flags */
13530fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_STATUS);
13540fffdf6cSThierry Reding 	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
13550fffdf6cSThierry Reding 		value = DSI_HOST_CONTROL_FIFO_RESET;
13560fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13570fffdf6cSThierry Reding 		usleep_range(10, 20);
13580fffdf6cSThierry Reding 	}
13590fffdf6cSThierry Reding 
13600fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
13610fffdf6cSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
13620fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
13630fffdf6cSThierry Reding 
13640fffdf6cSThierry Reding 	usleep_range(5000, 10000);
13650fffdf6cSThierry Reding 
13660fffdf6cSThierry Reding 	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
13670fffdf6cSThierry Reding 		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
13680fffdf6cSThierry Reding 
13690fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
13700fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_HS;
13710fffdf6cSThierry Reding 
13720fffdf6cSThierry Reding 	/*
13730fffdf6cSThierry Reding 	 * The host FIFO has a maximum of 64 words, so larger transmissions
13740fffdf6cSThierry Reding 	 * need to use the video FIFO.
13750fffdf6cSThierry Reding 	 */
13760fffdf6cSThierry Reding 	if (packet.size > dsi->host_fifo_depth * 4)
13770fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_FIFO_SEL;
13780fffdf6cSThierry Reding 
13790fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13800fffdf6cSThierry Reding 
13810fffdf6cSThierry Reding 	/*
13820fffdf6cSThierry Reding 	 * For reads and messages with explicitly requested ACK, generate a
13830fffdf6cSThierry Reding 	 * BTA sequence after the transmission of the packet.
13840fffdf6cSThierry Reding 	 */
13850fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
13860fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
13870fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
13880fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_PKT_BTA;
13890fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
13900fffdf6cSThierry Reding 	}
13910fffdf6cSThierry Reding 
13920fffdf6cSThierry Reding 	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
13930fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
13940fffdf6cSThierry Reding 
13950fffdf6cSThierry Reding 	/* write packet header, ECC is generated by hardware */
13960fffdf6cSThierry Reding 	value = header[2] << 16 | header[1] << 8 | header[0];
13970fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
13980fffdf6cSThierry Reding 
13990fffdf6cSThierry Reding 	/* write payload (if any) */
14000fffdf6cSThierry Reding 	if (packet.payload_length > 0)
14010fffdf6cSThierry Reding 		tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
14020fffdf6cSThierry Reding 				  packet.payload_length);
14030fffdf6cSThierry Reding 
14040fffdf6cSThierry Reding 	err = tegra_dsi_transmit(dsi, 250);
14050fffdf6cSThierry Reding 	if (err < 0)
14060fffdf6cSThierry Reding 		return err;
14070fffdf6cSThierry Reding 
14080fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
14090fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
14100fffdf6cSThierry Reding 		err = tegra_dsi_wait_for_response(dsi, 250);
14110fffdf6cSThierry Reding 		if (err < 0)
14120fffdf6cSThierry Reding 			return err;
14130fffdf6cSThierry Reding 
14140fffdf6cSThierry Reding 		count = err;
14150fffdf6cSThierry Reding 
14160fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
14170fffdf6cSThierry Reding 		switch (value) {
14180fffdf6cSThierry Reding 		case 0x84:
14190fffdf6cSThierry Reding 			/*
14200fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ACK\n");
14210fffdf6cSThierry Reding 			*/
14220fffdf6cSThierry Reding 			break;
14230fffdf6cSThierry Reding 
14240fffdf6cSThierry Reding 		case 0x87:
14250fffdf6cSThierry Reding 			/*
14260fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ESCAPE\n");
14270fffdf6cSThierry Reding 			*/
14280fffdf6cSThierry Reding 			break;
14290fffdf6cSThierry Reding 
14300fffdf6cSThierry Reding 		default:
14310fffdf6cSThierry Reding 			dev_err(dsi->dev, "unknown status: %08x\n", value);
14320fffdf6cSThierry Reding 			break;
14330fffdf6cSThierry Reding 		}
14340fffdf6cSThierry Reding 
14350fffdf6cSThierry Reding 		if (count > 1) {
14360fffdf6cSThierry Reding 			err = tegra_dsi_read_response(dsi, msg, count);
14370fffdf6cSThierry Reding 			if (err < 0)
14380fffdf6cSThierry Reding 				dev_err(dsi->dev,
14390fffdf6cSThierry Reding 					"failed to parse response: %zd\n",
14400fffdf6cSThierry Reding 					err);
14410fffdf6cSThierry Reding 			else {
14420fffdf6cSThierry Reding 				/*
14430fffdf6cSThierry Reding 				 * For read commands, return the number of
14440fffdf6cSThierry Reding 				 * bytes returned by the peripheral.
14450fffdf6cSThierry Reding 				 */
14460fffdf6cSThierry Reding 				count = err;
14470fffdf6cSThierry Reding 			}
14480fffdf6cSThierry Reding 		}
14490fffdf6cSThierry Reding 	} else {
14500fffdf6cSThierry Reding 		/*
14510fffdf6cSThierry Reding 		 * For write commands, we have transmitted the 4-byte header
14520fffdf6cSThierry Reding 		 * plus the variable-length payload.
14530fffdf6cSThierry Reding 		 */
14540fffdf6cSThierry Reding 		count = 4 + packet.payload_length;
14550fffdf6cSThierry Reding 	}
14560fffdf6cSThierry Reding 
14570fffdf6cSThierry Reding 	return count;
14580fffdf6cSThierry Reding }
14590fffdf6cSThierry Reding 
tegra_dsi_ganged_setup(struct tegra_dsi * dsi)1460e94236cdSThierry Reding static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
1461e94236cdSThierry Reding {
1462e94236cdSThierry Reding 	struct clk *parent;
1463e94236cdSThierry Reding 	int err;
1464e94236cdSThierry Reding 
1465e94236cdSThierry Reding 	/* make sure both DSI controllers share the same PLL */
1466e94236cdSThierry Reding 	parent = clk_get_parent(dsi->slave->clk);
1467e94236cdSThierry Reding 	if (!parent)
1468e94236cdSThierry Reding 		return -EINVAL;
1469e94236cdSThierry Reding 
1470e94236cdSThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1471e94236cdSThierry Reding 	if (err < 0)
1472e94236cdSThierry Reding 		return err;
1473e94236cdSThierry Reding 
1474e94236cdSThierry Reding 	return 0;
1475e94236cdSThierry Reding }
1476e94236cdSThierry Reding 
tegra_dsi_host_attach(struct mipi_dsi_host * host,struct mipi_dsi_device * device)1477dec72739SThierry Reding static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
1478dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1479dec72739SThierry Reding {
1480dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1481dec72739SThierry Reding 
148217297a28SThierry Reding 	dsi->flags = device->mode_flags;
1483dec72739SThierry Reding 	dsi->format = device->format;
1484dec72739SThierry Reding 	dsi->lanes = device->lanes;
1485dec72739SThierry Reding 
1486e94236cdSThierry Reding 	if (dsi->slave) {
1487e94236cdSThierry Reding 		int err;
1488e94236cdSThierry Reding 
1489e94236cdSThierry Reding 		dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
1490e94236cdSThierry Reding 			dev_name(&device->dev));
1491e94236cdSThierry Reding 
1492e94236cdSThierry Reding 		err = tegra_dsi_ganged_setup(dsi);
1493e94236cdSThierry Reding 		if (err < 0) {
1494e94236cdSThierry Reding 			dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
1495e94236cdSThierry Reding 				err);
1496e94236cdSThierry Reding 			return err;
1497e94236cdSThierry Reding 		}
1498e94236cdSThierry Reding 	}
1499e94236cdSThierry Reding 
1500e94236cdSThierry Reding 	/*
1501e94236cdSThierry Reding 	 * Slaves don't have a panel associated with them, so they provide
1502e94236cdSThierry Reding 	 * merely the second channel.
1503e94236cdSThierry Reding 	 */
1504e94236cdSThierry Reding 	if (!dsi->master) {
1505e94236cdSThierry Reding 		struct tegra_output *output = &dsi->output;
1506e94236cdSThierry Reding 
1507dec72739SThierry Reding 		output->panel = of_drm_find_panel(device->dev.of_node);
15085fa8e4a2SBoris Brezillon 		if (IS_ERR(output->panel))
15095fa8e4a2SBoris Brezillon 			output->panel = NULL;
15105fa8e4a2SBoris Brezillon 
151187154ff8SJoe Perches 		if (output->panel && output->connector.dev)
1512dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1513dec72739SThierry Reding 	}
1514dec72739SThierry Reding 
1515dec72739SThierry Reding 	return 0;
1516dec72739SThierry Reding }
1517dec72739SThierry Reding 
tegra_dsi_host_detach(struct mipi_dsi_host * host,struct mipi_dsi_device * device)1518dec72739SThierry Reding static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
1519dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1520dec72739SThierry Reding {
1521dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1522dec72739SThierry Reding 	struct tegra_output *output = &dsi->output;
1523dec72739SThierry Reding 
1524dec72739SThierry Reding 	if (output->panel && &device->dev == output->panel->dev) {
1525ba3df979SThierry Reding 		output->panel = NULL;
1526ba3df979SThierry Reding 
1527dec72739SThierry Reding 		if (output->connector.dev)
1528dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1529dec72739SThierry Reding 	}
1530dec72739SThierry Reding 
1531dec72739SThierry Reding 	return 0;
1532dec72739SThierry Reding }
1533dec72739SThierry Reding 
1534dec72739SThierry Reding static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
1535dec72739SThierry Reding 	.attach = tegra_dsi_host_attach,
1536dec72739SThierry Reding 	.detach = tegra_dsi_host_detach,
15370fffdf6cSThierry Reding 	.transfer = tegra_dsi_host_transfer,
1538dec72739SThierry Reding };
1539dec72739SThierry Reding 
tegra_dsi_ganged_probe(struct tegra_dsi * dsi)1540e94236cdSThierry Reding static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
1541e94236cdSThierry Reding {
1542e94236cdSThierry Reding 	struct device_node *np;
1543e94236cdSThierry Reding 
1544e94236cdSThierry Reding 	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
1545e94236cdSThierry Reding 	if (np) {
1546e94236cdSThierry Reding 		struct platform_device *gangster = of_find_device_by_node(np);
1547afe6fcb9SChen Ni 		of_node_put(np);
1548afe6fcb9SChen Ni 		if (!gangster)
1549afe6fcb9SChen Ni 			return -EPROBE_DEFER;
1550e94236cdSThierry Reding 
1551e94236cdSThierry Reding 		dsi->slave = platform_get_drvdata(gangster);
1552e94236cdSThierry Reding 
1553221e3638SMiaoqian Lin 		if (!dsi->slave) {
1554221e3638SMiaoqian Lin 			put_device(&gangster->dev);
1555e94236cdSThierry Reding 			return -EPROBE_DEFER;
1556221e3638SMiaoqian Lin 		}
1557e94236cdSThierry Reding 
1558e94236cdSThierry Reding 		dsi->slave->master = dsi;
1559e94236cdSThierry Reding 	}
1560e94236cdSThierry Reding 
1561e94236cdSThierry Reding 	return 0;
1562e94236cdSThierry Reding }
1563e94236cdSThierry Reding 
tegra_dsi_probe(struct platform_device * pdev)1564dec72739SThierry Reding static int tegra_dsi_probe(struct platform_device *pdev)
1565dec72739SThierry Reding {
1566dec72739SThierry Reding 	struct tegra_dsi *dsi;
1567dec72739SThierry Reding 	struct resource *regs;
1568dec72739SThierry Reding 	int err;
1569dec72739SThierry Reding 
1570dec72739SThierry Reding 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
1571dec72739SThierry Reding 	if (!dsi)
1572dec72739SThierry Reding 		return -ENOMEM;
1573dec72739SThierry Reding 
1574dec72739SThierry Reding 	dsi->output.dev = dsi->dev = &pdev->dev;
1575976cebc3SThierry Reding 	dsi->video_fifo_depth = 1920;
1576976cebc3SThierry Reding 	dsi->host_fifo_depth = 64;
1577dec72739SThierry Reding 
1578e94236cdSThierry Reding 	err = tegra_dsi_ganged_probe(dsi);
1579e94236cdSThierry Reding 	if (err < 0)
1580e94236cdSThierry Reding 		return err;
1581e94236cdSThierry Reding 
1582dec72739SThierry Reding 	err = tegra_output_probe(&dsi->output);
1583dec72739SThierry Reding 	if (err < 0)
1584dec72739SThierry Reding 		return err;
1585dec72739SThierry Reding 
1586ba3df979SThierry Reding 	dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
1587ba3df979SThierry Reding 
1588dec72739SThierry Reding 	/*
1589dec72739SThierry Reding 	 * Assume these values by default. When a DSI peripheral driver
1590dec72739SThierry Reding 	 * attaches to the DSI host, the parameters will be taken from
1591dec72739SThierry Reding 	 * the attached device.
1592dec72739SThierry Reding 	 */
159317297a28SThierry Reding 	dsi->flags = MIPI_DSI_MODE_VIDEO;
1594dec72739SThierry Reding 	dsi->format = MIPI_DSI_FMT_RGB888;
1595dec72739SThierry Reding 	dsi->lanes = 4;
1596dec72739SThierry Reding 
159764230aa0SJon Hunter 	if (!pdev->dev.pm_domain) {
1598dec72739SThierry Reding 		dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
1599830c1dedSChristophe JAILLET 		if (IS_ERR(dsi->rst)) {
1600830c1dedSChristophe JAILLET 			err = PTR_ERR(dsi->rst);
1601830c1dedSChristophe JAILLET 			goto remove;
1602830c1dedSChristophe JAILLET 		}
160364230aa0SJon Hunter 	}
1604dec72739SThierry Reding 
1605dec72739SThierry Reding 	dsi->clk = devm_clk_get(&pdev->dev, NULL);
1606830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->clk)) {
1607830c1dedSChristophe JAILLET 		err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk),
1608fc75e4fcSCai Huoqing 				    "cannot get DSI clock\n");
1609830c1dedSChristophe JAILLET 		goto remove;
1610830c1dedSChristophe JAILLET 	}
1611dec72739SThierry Reding 
1612dec72739SThierry Reding 	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
1613830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->clk_lp)) {
1614830c1dedSChristophe JAILLET 		err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_lp),
1615fc75e4fcSCai Huoqing 				    "cannot get low-power clock\n");
1616830c1dedSChristophe JAILLET 		goto remove;
1617830c1dedSChristophe JAILLET 	}
1618dec72739SThierry Reding 
1619dec72739SThierry Reding 	dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
1620830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->clk_parent)) {
1621830c1dedSChristophe JAILLET 		err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->clk_parent),
1622fc75e4fcSCai Huoqing 				    "cannot get parent clock\n");
1623830c1dedSChristophe JAILLET 		goto remove;
1624830c1dedSChristophe JAILLET 	}
1625dec72739SThierry Reding 
16263b077afbSThierry Reding 	dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
1627830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->vdd)) {
1628830c1dedSChristophe JAILLET 		err = dev_err_probe(&pdev->dev, PTR_ERR(dsi->vdd),
1629fc75e4fcSCai Huoqing 				    "cannot get VDD supply\n");
1630830c1dedSChristophe JAILLET 		goto remove;
1631830c1dedSChristophe JAILLET 	}
16323b077afbSThierry Reding 
1633dec72739SThierry Reding 	err = tegra_dsi_setup_clocks(dsi);
1634dec72739SThierry Reding 	if (err < 0) {
1635dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot setup clocks\n");
1636830c1dedSChristophe JAILLET 		goto remove;
1637dec72739SThierry Reding 	}
1638dec72739SThierry Reding 
1639dec72739SThierry Reding 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1640dec72739SThierry Reding 	dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
1641830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->regs)) {
1642830c1dedSChristophe JAILLET 		err = PTR_ERR(dsi->regs);
1643830c1dedSChristophe JAILLET 		goto remove;
1644830c1dedSChristophe JAILLET 	}
1645dec72739SThierry Reding 
1646767598d4SSowjanya Komatineni 	dsi->mipi = tegra_mipi_request(&pdev->dev, pdev->dev.of_node);
1647830c1dedSChristophe JAILLET 	if (IS_ERR(dsi->mipi)) {
1648830c1dedSChristophe JAILLET 		err = PTR_ERR(dsi->mipi);
1649830c1dedSChristophe JAILLET 		goto remove;
1650830c1dedSChristophe JAILLET 	}
1651dec72739SThierry Reding 
1652dec72739SThierry Reding 	dsi->host.ops = &tegra_dsi_host_ops;
1653dec72739SThierry Reding 	dsi->host.dev = &pdev->dev;
1654dec72739SThierry Reding 
1655dec72739SThierry Reding 	err = mipi_dsi_host_register(&dsi->host);
1656dec72739SThierry Reding 	if (err < 0) {
1657dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
1658d2d0a9d2SThierry Reding 		goto mipi_free;
1659dec72739SThierry Reding 	}
1660dec72739SThierry Reding 
1661ef8187d7SThierry Reding 	platform_set_drvdata(pdev, dsi);
1662ef8187d7SThierry Reding 	pm_runtime_enable(&pdev->dev);
1663ef8187d7SThierry Reding 
1664dec72739SThierry Reding 	INIT_LIST_HEAD(&dsi->client.list);
1665dec72739SThierry Reding 	dsi->client.ops = &dsi_client_ops;
1666dec72739SThierry Reding 	dsi->client.dev = &pdev->dev;
1667dec72739SThierry Reding 
1668dec72739SThierry Reding 	err = host1x_client_register(&dsi->client);
1669dec72739SThierry Reding 	if (err < 0) {
1670dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1671dec72739SThierry Reding 			err);
1672d2d0a9d2SThierry Reding 		goto unregister;
1673dec72739SThierry Reding 	}
1674dec72739SThierry Reding 
1675dec72739SThierry Reding 	return 0;
1676d2d0a9d2SThierry Reding 
1677d2d0a9d2SThierry Reding unregister:
1678*5286a9fcSChristophe JAILLET 	pm_runtime_disable(&pdev->dev);
1679d2d0a9d2SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1680d2d0a9d2SThierry Reding mipi_free:
1681d2d0a9d2SThierry Reding 	tegra_mipi_free(dsi->mipi);
1682830c1dedSChristophe JAILLET remove:
1683830c1dedSChristophe JAILLET 	tegra_output_remove(&dsi->output);
1684d2d0a9d2SThierry Reding 	return err;
1685dec72739SThierry Reding }
1686dec72739SThierry Reding 
tegra_dsi_remove(struct platform_device * pdev)168750a2a987SUwe Kleine-König static void tegra_dsi_remove(struct platform_device *pdev)
1688dec72739SThierry Reding {
1689dec72739SThierry Reding 	struct tegra_dsi *dsi = platform_get_drvdata(pdev);
1690dec72739SThierry Reding 
1691ef8187d7SThierry Reding 	pm_runtime_disable(&pdev->dev);
1692ef8187d7SThierry Reding 
16931d83d1a2SUwe Kleine-König 	host1x_client_unregister(&dsi->client);
1694dec72739SThierry Reding 
1695328ec69eSThierry Reding 	tegra_output_remove(&dsi->output);
16965b901e78SThierry Reding 
1697dec72739SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1698dec72739SThierry Reding 	tegra_mipi_free(dsi->mipi);
1699ef8187d7SThierry Reding }
1700ef8187d7SThierry Reding 
1701dec72739SThierry Reding static const struct of_device_id tegra_dsi_of_match[] = {
1702ddfb406bSThierry Reding 	{ .compatible = "nvidia,tegra210-dsi", },
1703c06c7930SThierry Reding 	{ .compatible = "nvidia,tegra132-dsi", },
17047d338587SThierry Reding 	{ .compatible = "nvidia,tegra124-dsi", },
1705dec72739SThierry Reding 	{ .compatible = "nvidia,tegra114-dsi", },
1706dec72739SThierry Reding 	{ },
1707dec72739SThierry Reding };
1708ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
1709dec72739SThierry Reding 
1710dec72739SThierry Reding struct platform_driver tegra_dsi_driver = {
1711dec72739SThierry Reding 	.driver = {
1712dec72739SThierry Reding 		.name = "tegra-dsi",
1713dec72739SThierry Reding 		.of_match_table = tegra_dsi_of_match,
1714dec72739SThierry Reding 	},
1715dec72739SThierry Reding 	.probe = tegra_dsi_probe,
171650a2a987SUwe Kleine-König 	.remove_new = tegra_dsi_remove,
1717dec72739SThierry Reding };
1718