xref: /linux/drivers/gpu/drm/tegra/dsi.c (revision 030611ecc5d8b1daf8de110600c8771de45d398d)
1dec72739SThierry Reding /*
2dec72739SThierry Reding  * Copyright (C) 2013 NVIDIA Corporation
3dec72739SThierry Reding  *
49a2ac2dcSThierry Reding  * This program is free software; you can redistribute it and/or modify
59a2ac2dcSThierry Reding  * it under the terms of the GNU General Public License version 2 as
69a2ac2dcSThierry Reding  * published by the Free Software Foundation.
7dec72739SThierry Reding  */
8dec72739SThierry Reding 
9dec72739SThierry Reding #include <linux/clk.h>
10dec72739SThierry Reding #include <linux/debugfs.h>
11dec72739SThierry Reding #include <linux/host1x.h>
12dec72739SThierry Reding #include <linux/module.h>
13dec72739SThierry Reding #include <linux/of.h>
14e94236cdSThierry Reding #include <linux/of_platform.h>
15dec72739SThierry Reding #include <linux/platform_device.h>
16dec72739SThierry Reding #include <linux/reset.h>
17dec72739SThierry Reding 
183b077afbSThierry Reding #include <linux/regulator/consumer.h>
193b077afbSThierry Reding 
20dec72739SThierry Reding #include <drm/drm_mipi_dsi.h>
21dec72739SThierry Reding #include <drm/drm_panel.h>
22dec72739SThierry Reding 
23dec72739SThierry Reding #include <video/mipi_display.h>
24dec72739SThierry Reding 
25dec72739SThierry Reding #include "dc.h"
26dec72739SThierry Reding #include "drm.h"
27dec72739SThierry Reding #include "dsi.h"
28dec72739SThierry Reding #include "mipi-phy.h"
29dec72739SThierry Reding 
30dec72739SThierry Reding struct tegra_dsi {
31dec72739SThierry Reding 	struct host1x_client client;
32dec72739SThierry Reding 	struct tegra_output output;
33dec72739SThierry Reding 	struct device *dev;
34dec72739SThierry Reding 
35dec72739SThierry Reding 	void __iomem *regs;
36dec72739SThierry Reding 
37dec72739SThierry Reding 	struct reset_control *rst;
38dec72739SThierry Reding 	struct clk *clk_parent;
39dec72739SThierry Reding 	struct clk *clk_lp;
40dec72739SThierry Reding 	struct clk *clk;
41dec72739SThierry Reding 
42dec72739SThierry Reding 	struct drm_info_list *debugfs_files;
43dec72739SThierry Reding 	struct drm_minor *minor;
44dec72739SThierry Reding 	struct dentry *debugfs;
45dec72739SThierry Reding 
4617297a28SThierry Reding 	unsigned long flags;
47dec72739SThierry Reding 	enum mipi_dsi_pixel_format format;
48dec72739SThierry Reding 	unsigned int lanes;
49dec72739SThierry Reding 
50dec72739SThierry Reding 	struct tegra_mipi_device *mipi;
51dec72739SThierry Reding 	struct mipi_dsi_host host;
523b077afbSThierry Reding 
533b077afbSThierry Reding 	struct regulator *vdd;
54334ae6b5SThierry Reding 	bool enabled;
55976cebc3SThierry Reding 
56976cebc3SThierry Reding 	unsigned int video_fifo_depth;
57976cebc3SThierry Reding 	unsigned int host_fifo_depth;
58e94236cdSThierry Reding 
59e94236cdSThierry Reding 	/* for ganged-mode support */
60e94236cdSThierry Reding 	struct tegra_dsi *master;
61e94236cdSThierry Reding 	struct tegra_dsi *slave;
62dec72739SThierry Reding };
63dec72739SThierry Reding 
64dec72739SThierry Reding static inline struct tegra_dsi *
65dec72739SThierry Reding host1x_client_to_dsi(struct host1x_client *client)
66dec72739SThierry Reding {
67dec72739SThierry Reding 	return container_of(client, struct tegra_dsi, client);
68dec72739SThierry Reding }
69dec72739SThierry Reding 
70dec72739SThierry Reding static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
71dec72739SThierry Reding {
72dec72739SThierry Reding 	return container_of(host, struct tegra_dsi, host);
73dec72739SThierry Reding }
74dec72739SThierry Reding 
75dec72739SThierry Reding static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
76dec72739SThierry Reding {
77dec72739SThierry Reding 	return container_of(output, struct tegra_dsi, output);
78dec72739SThierry Reding }
79dec72739SThierry Reding 
80dec72739SThierry Reding static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
81dec72739SThierry Reding 					    unsigned long reg)
82dec72739SThierry Reding {
83dec72739SThierry Reding 	return readl(dsi->regs + (reg << 2));
84dec72739SThierry Reding }
85dec72739SThierry Reding 
86dec72739SThierry Reding static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
87dec72739SThierry Reding 				    unsigned long reg)
88dec72739SThierry Reding {
89dec72739SThierry Reding 	writel(value, dsi->regs + (reg << 2));
90dec72739SThierry Reding }
91dec72739SThierry Reding 
92dec72739SThierry Reding static int tegra_dsi_show_regs(struct seq_file *s, void *data)
93dec72739SThierry Reding {
94dec72739SThierry Reding 	struct drm_info_node *node = s->private;
95dec72739SThierry Reding 	struct tegra_dsi *dsi = node->info_ent->data;
96dec72739SThierry Reding 
97dec72739SThierry Reding #define DUMP_REG(name)						\
98dec72739SThierry Reding 	seq_printf(s, "%-32s %#05x %08lx\n", #name, name,	\
99dec72739SThierry Reding 		   tegra_dsi_readl(dsi, name))
100dec72739SThierry Reding 
101dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT);
102dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT_CONTROL);
103dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT_ERROR);
104dec72739SThierry Reding 	DUMP_REG(DSI_CTXSW);
105dec72739SThierry Reding 	DUMP_REG(DSI_RD_DATA);
106dec72739SThierry Reding 	DUMP_REG(DSI_WR_DATA);
107dec72739SThierry Reding 	DUMP_REG(DSI_POWER_CONTROL);
108dec72739SThierry Reding 	DUMP_REG(DSI_INT_ENABLE);
109dec72739SThierry Reding 	DUMP_REG(DSI_INT_STATUS);
110dec72739SThierry Reding 	DUMP_REG(DSI_INT_MASK);
111dec72739SThierry Reding 	DUMP_REG(DSI_HOST_CONTROL);
112dec72739SThierry Reding 	DUMP_REG(DSI_CONTROL);
113dec72739SThierry Reding 	DUMP_REG(DSI_SOL_DELAY);
114dec72739SThierry Reding 	DUMP_REG(DSI_MAX_THRESHOLD);
115dec72739SThierry Reding 	DUMP_REG(DSI_TRIGGER);
116dec72739SThierry Reding 	DUMP_REG(DSI_TX_CRC);
117dec72739SThierry Reding 	DUMP_REG(DSI_STATUS);
118dec72739SThierry Reding 
119dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_CONTROL);
120dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_0);
121dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_1);
122dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_2);
123dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_3);
124dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_4);
125dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_5);
126dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_6);
127dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_7);
128dec72739SThierry Reding 
129dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_0_LO);
130dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_0_HI);
131dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_1_LO);
132dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_1_HI);
133dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_2_LO);
134dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_2_HI);
135dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_3_LO);
136dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_3_HI);
137dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_4_LO);
138dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_4_HI);
139dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_5_LO);
140dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_5_HI);
141dec72739SThierry Reding 
142dec72739SThierry Reding 	DUMP_REG(DSI_DCS_CMDS);
143dec72739SThierry Reding 
144dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_0_1);
145dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_2_3);
146dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_4_5);
147dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_6_7);
148dec72739SThierry Reding 
149dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_0);
150dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_1);
151dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_2);
152dec72739SThierry Reding 	DUMP_REG(DSI_BTA_TIMING);
153dec72739SThierry Reding 
154dec72739SThierry Reding 	DUMP_REG(DSI_TIMEOUT_0);
155dec72739SThierry Reding 	DUMP_REG(DSI_TIMEOUT_1);
156dec72739SThierry Reding 	DUMP_REG(DSI_TO_TALLY);
157dec72739SThierry Reding 
158dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_0);
159dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_CD);
160dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CD_STATUS);
161dec72739SThierry Reding 	DUMP_REG(DSI_VIDEO_MODE_CONTROL);
162dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_1);
163dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_2);
164dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_3);
165dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_4);
166dec72739SThierry Reding 
167dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_CONTROL);
168dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_START);
169dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_SIZE);
170dec72739SThierry Reding 
171dec72739SThierry Reding 	DUMP_REG(DSI_RAW_DATA_BYTE_COUNT);
172dec72739SThierry Reding 	DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL);
173dec72739SThierry Reding 
174dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_8);
175dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_9);
176dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_10);
177dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_11);
178dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_12);
179dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_13);
180dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_14);
181dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_15);
182dec72739SThierry Reding 
183dec72739SThierry Reding #undef DUMP_REG
184dec72739SThierry Reding 
185dec72739SThierry Reding 	return 0;
186dec72739SThierry Reding }
187dec72739SThierry Reding 
188dec72739SThierry Reding static struct drm_info_list debugfs_files[] = {
189dec72739SThierry Reding 	{ "regs", tegra_dsi_show_regs, 0, NULL },
190dec72739SThierry Reding };
191dec72739SThierry Reding 
192dec72739SThierry Reding static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi,
193dec72739SThierry Reding 				  struct drm_minor *minor)
194dec72739SThierry Reding {
195dec72739SThierry Reding 	const char *name = dev_name(dsi->dev);
196dec72739SThierry Reding 	unsigned int i;
197dec72739SThierry Reding 	int err;
198dec72739SThierry Reding 
199dec72739SThierry Reding 	dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root);
200dec72739SThierry Reding 	if (!dsi->debugfs)
201dec72739SThierry Reding 		return -ENOMEM;
202dec72739SThierry Reding 
203dec72739SThierry Reding 	dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
204dec72739SThierry Reding 				     GFP_KERNEL);
205dec72739SThierry Reding 	if (!dsi->debugfs_files) {
206dec72739SThierry Reding 		err = -ENOMEM;
207dec72739SThierry Reding 		goto remove;
208dec72739SThierry Reding 	}
209dec72739SThierry Reding 
210dec72739SThierry Reding 	for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
211dec72739SThierry Reding 		dsi->debugfs_files[i].data = dsi;
212dec72739SThierry Reding 
213dec72739SThierry Reding 	err = drm_debugfs_create_files(dsi->debugfs_files,
214dec72739SThierry Reding 				       ARRAY_SIZE(debugfs_files),
215dec72739SThierry Reding 				       dsi->debugfs, minor);
216dec72739SThierry Reding 	if (err < 0)
217dec72739SThierry Reding 		goto free;
218dec72739SThierry Reding 
219dec72739SThierry Reding 	dsi->minor = minor;
220dec72739SThierry Reding 
221dec72739SThierry Reding 	return 0;
222dec72739SThierry Reding 
223dec72739SThierry Reding free:
224dec72739SThierry Reding 	kfree(dsi->debugfs_files);
225dec72739SThierry Reding 	dsi->debugfs_files = NULL;
226dec72739SThierry Reding remove:
227dec72739SThierry Reding 	debugfs_remove(dsi->debugfs);
228dec72739SThierry Reding 	dsi->debugfs = NULL;
229dec72739SThierry Reding 
230dec72739SThierry Reding 	return err;
231dec72739SThierry Reding }
232dec72739SThierry Reding 
233dec72739SThierry Reding static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
234dec72739SThierry Reding {
235dec72739SThierry Reding 	drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
236dec72739SThierry Reding 				 dsi->minor);
237dec72739SThierry Reding 	dsi->minor = NULL;
238dec72739SThierry Reding 
239dec72739SThierry Reding 	kfree(dsi->debugfs_files);
240dec72739SThierry Reding 	dsi->debugfs_files = NULL;
241dec72739SThierry Reding 
242dec72739SThierry Reding 	debugfs_remove(dsi->debugfs);
243dec72739SThierry Reding 	dsi->debugfs = NULL;
244dec72739SThierry Reding 
245dec72739SThierry Reding 	return 0;
246dec72739SThierry Reding }
247dec72739SThierry Reding 
248dec72739SThierry Reding #define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
249dec72739SThierry Reding #define PKT_LEN0(len)	(((len) & 0x07) <<  0)
250dec72739SThierry Reding #define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
251dec72739SThierry Reding #define PKT_LEN1(len)	(((len) & 0x07) << 10)
252dec72739SThierry Reding #define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
253dec72739SThierry Reding #define PKT_LEN2(len)	(((len) & 0x07) << 20)
254dec72739SThierry Reding 
255dec72739SThierry Reding #define PKT_LP		(1 << 30)
256dec72739SThierry Reding #define NUM_PKT_SEQ	12
257dec72739SThierry Reding 
25817297a28SThierry Reding /*
25917297a28SThierry Reding  * non-burst mode with sync pulses
26017297a28SThierry Reding  */
26117297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
262dec72739SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
263dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
264dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
265dec72739SThierry Reding 	       PKT_LP,
266dec72739SThierry Reding 	[ 1] = 0,
267dec72739SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
268dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
269dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
270dec72739SThierry Reding 	       PKT_LP,
271dec72739SThierry Reding 	[ 3] = 0,
272dec72739SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
273dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
274dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
275dec72739SThierry Reding 	       PKT_LP,
276dec72739SThierry Reding 	[ 5] = 0,
277dec72739SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
278dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
279dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
280dec72739SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
281dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
282dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
283dec72739SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
284dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
285dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
286dec72739SThierry Reding 	       PKT_LP,
287dec72739SThierry Reding 	[ 9] = 0,
288dec72739SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
289dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
290dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
291dec72739SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
292dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
293dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
294dec72739SThierry Reding };
295dec72739SThierry Reding 
29617297a28SThierry Reding /*
29717297a28SThierry Reding  * non-burst mode with sync events
29817297a28SThierry Reding  */
29917297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
30017297a28SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
30117297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
30217297a28SThierry Reding 	       PKT_LP,
30317297a28SThierry Reding 	[ 1] = 0,
30417297a28SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
30517297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
30617297a28SThierry Reding 	       PKT_LP,
30717297a28SThierry Reding 	[ 3] = 0,
30817297a28SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
30917297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
31017297a28SThierry Reding 	       PKT_LP,
31117297a28SThierry Reding 	[ 5] = 0,
31217297a28SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
31317297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
31417297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
31517297a28SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
31617297a28SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
31717297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
31817297a28SThierry Reding 	       PKT_LP,
31917297a28SThierry Reding 	[ 9] = 0,
32017297a28SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
32117297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
32217297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
32317297a28SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
32417297a28SThierry Reding };
32517297a28SThierry Reding 
326337b443dSThierry Reding static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
327337b443dSThierry Reding 	[ 0] = 0,
328337b443dSThierry Reding 	[ 1] = 0,
329337b443dSThierry Reding 	[ 2] = 0,
330337b443dSThierry Reding 	[ 3] = 0,
331337b443dSThierry Reding 	[ 4] = 0,
332337b443dSThierry Reding 	[ 5] = 0,
333337b443dSThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
334337b443dSThierry Reding 	[ 7] = 0,
335337b443dSThierry Reding 	[ 8] = 0,
336337b443dSThierry Reding 	[ 9] = 0,
337337b443dSThierry Reding 	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
338337b443dSThierry Reding 	[11] = 0,
339337b443dSThierry Reding };
340337b443dSThierry Reding 
341dec72739SThierry Reding static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
342dec72739SThierry Reding {
343dec72739SThierry Reding 	struct mipi_dphy_timing timing;
344dec72739SThierry Reding 	unsigned long value, period;
345dec72739SThierry Reding 	long rate;
346dec72739SThierry Reding 	int err;
347dec72739SThierry Reding 
348dec72739SThierry Reding 	rate = clk_get_rate(dsi->clk);
349dec72739SThierry Reding 	if (rate < 0)
350dec72739SThierry Reding 		return rate;
351dec72739SThierry Reding 
352369bc65bSThierry Reding 	period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
353dec72739SThierry Reding 
354dec72739SThierry Reding 	err = mipi_dphy_timing_get_default(&timing, period);
355dec72739SThierry Reding 	if (err < 0)
356dec72739SThierry Reding 		return err;
357dec72739SThierry Reding 
358dec72739SThierry Reding 	err = mipi_dphy_timing_validate(&timing, period);
359dec72739SThierry Reding 	if (err < 0) {
360dec72739SThierry Reding 		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
361dec72739SThierry Reding 		return err;
362dec72739SThierry Reding 	}
363dec72739SThierry Reding 
364dec72739SThierry Reding 	/*
365dec72739SThierry Reding 	 * The D-PHY timing fields below are expressed in byte-clock cycles,
366dec72739SThierry Reding 	 * so multiply the period by 8.
367dec72739SThierry Reding 	 */
368dec72739SThierry Reding 	period *= 8;
369dec72739SThierry Reding 
370dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
371dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
372dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
373dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hsprepare, period, 1);
374dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
375dec72739SThierry Reding 
376dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
377dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
378dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
379dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.lpx, period, 1);
380dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
381dec72739SThierry Reding 
382dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
383dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
384dec72739SThierry Reding 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
385dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
386dec72739SThierry Reding 
387dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
388dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
389dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.tago, period, 1);
390dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
391dec72739SThierry Reding 
392dec72739SThierry Reding 	return 0;
393dec72739SThierry Reding }
394dec72739SThierry Reding 
395dec72739SThierry Reding static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
396dec72739SThierry Reding 				unsigned int *mulp, unsigned int *divp)
397dec72739SThierry Reding {
398dec72739SThierry Reding 	switch (format) {
399dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
400dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB888:
401dec72739SThierry Reding 		*mulp = 3;
402dec72739SThierry Reding 		*divp = 1;
403dec72739SThierry Reding 		break;
404dec72739SThierry Reding 
405dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB565:
406dec72739SThierry Reding 		*mulp = 2;
407dec72739SThierry Reding 		*divp = 1;
408dec72739SThierry Reding 		break;
409dec72739SThierry Reding 
410dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666:
411dec72739SThierry Reding 		*mulp = 9;
412dec72739SThierry Reding 		*divp = 4;
413dec72739SThierry Reding 		break;
414dec72739SThierry Reding 
415dec72739SThierry Reding 	default:
416dec72739SThierry Reding 		return -EINVAL;
417dec72739SThierry Reding 	}
418dec72739SThierry Reding 
419dec72739SThierry Reding 	return 0;
420dec72739SThierry Reding }
421dec72739SThierry Reding 
422f7d6889bSThierry Reding static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
423f7d6889bSThierry Reding 				enum tegra_dsi_format *fmt)
424f7d6889bSThierry Reding {
425f7d6889bSThierry Reding 	switch (format) {
426f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB888:
427f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_24P;
428f7d6889bSThierry Reding 		break;
429f7d6889bSThierry Reding 
430f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666:
431f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18NP;
432f7d6889bSThierry Reding 		break;
433f7d6889bSThierry Reding 
434f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
435f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18P;
436f7d6889bSThierry Reding 		break;
437f7d6889bSThierry Reding 
438f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB565:
439f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_16P;
440f7d6889bSThierry Reding 		break;
441f7d6889bSThierry Reding 
442f7d6889bSThierry Reding 	default:
443f7d6889bSThierry Reding 		return -EINVAL;
444f7d6889bSThierry Reding 	}
445f7d6889bSThierry Reding 
446f7d6889bSThierry Reding 	return 0;
447f7d6889bSThierry Reding }
448f7d6889bSThierry Reding 
449e94236cdSThierry Reding static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
450e94236cdSThierry Reding 				    unsigned int size)
451e94236cdSThierry Reding {
452e94236cdSThierry Reding 	u32 value;
453e94236cdSThierry Reding 
454e94236cdSThierry Reding 	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
455e94236cdSThierry Reding 	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
456e94236cdSThierry Reding 
457e94236cdSThierry Reding 	value = DSI_GANGED_MODE_CONTROL_ENABLE;
458e94236cdSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
459e94236cdSThierry Reding }
460e94236cdSThierry Reding 
461563eff1fSThierry Reding static void tegra_dsi_enable(struct tegra_dsi *dsi)
462dec72739SThierry Reding {
463563eff1fSThierry Reding 	u32 value;
464dec72739SThierry Reding 
465563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
466563eff1fSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
467563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
468e94236cdSThierry Reding 
469e94236cdSThierry Reding 	if (dsi->slave)
470e94236cdSThierry Reding 		tegra_dsi_enable(dsi->slave);
471e94236cdSThierry Reding }
472e94236cdSThierry Reding 
473e94236cdSThierry Reding static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
474e94236cdSThierry Reding {
475e94236cdSThierry Reding 	if (dsi->master)
476e94236cdSThierry Reding 		return dsi->master->lanes + dsi->lanes;
477e94236cdSThierry Reding 
478e94236cdSThierry Reding 	if (dsi->slave)
479e94236cdSThierry Reding 		return dsi->lanes + dsi->slave->lanes;
480e94236cdSThierry Reding 
481e94236cdSThierry Reding 	return dsi->lanes;
482563eff1fSThierry Reding }
483563eff1fSThierry Reding 
484563eff1fSThierry Reding static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
485563eff1fSThierry Reding 			       const struct drm_display_mode *mode)
486563eff1fSThierry Reding {
487563eff1fSThierry Reding 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
488563eff1fSThierry Reding 	enum tegra_dsi_format format;
489563eff1fSThierry Reding 	const u32 *pkt_seq;
490563eff1fSThierry Reding 	u32 value;
491563eff1fSThierry Reding 	int err;
492334ae6b5SThierry Reding 
49317297a28SThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
49417297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
49517297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
496337b443dSThierry Reding 	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
49717297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
49817297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_events;
499337b443dSThierry Reding 	} else {
500337b443dSThierry Reding 		DRM_DEBUG_KMS("Command mode\n");
501337b443dSThierry Reding 		pkt_seq = pkt_seq_command_mode;
50217297a28SThierry Reding 	}
50317297a28SThierry Reding 
504dec72739SThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
505dec72739SThierry Reding 	if (err < 0)
506dec72739SThierry Reding 		return err;
507dec72739SThierry Reding 
508f7d6889bSThierry Reding 	err = tegra_dsi_get_format(dsi->format, &format);
509f7d6889bSThierry Reding 	if (err < 0)
510f7d6889bSThierry Reding 		return err;
511f7d6889bSThierry Reding 
512f7d6889bSThierry Reding 	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
513dec72739SThierry Reding 		DSI_CONTROL_LANES(dsi->lanes - 1) |
514563eff1fSThierry Reding 		DSI_CONTROL_SOURCE(pipe);
515dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
516dec72739SThierry Reding 
517976cebc3SThierry Reding 	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
518dec72739SThierry Reding 
519563eff1fSThierry Reding 	value = DSI_HOST_CONTROL_HS;
520dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
521dec72739SThierry Reding 
522dec72739SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
523563eff1fSThierry Reding 
5240c6b1e4bSAlexandre Courbot 	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
525dec72739SThierry Reding 		value |= DSI_CONTROL_HS_CLK_CTRL;
526563eff1fSThierry Reding 
527dec72739SThierry Reding 	value &= ~DSI_CONTROL_TX_TRIG(3);
528337b443dSThierry Reding 
529337b443dSThierry Reding 	/* enable DCS commands for command mode */
530337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
531dec72739SThierry Reding 		value &= ~DSI_CONTROL_DCS_ENABLE;
532337b443dSThierry Reding 	else
533337b443dSThierry Reding 		value |= DSI_CONTROL_DCS_ENABLE;
534337b443dSThierry Reding 
535dec72739SThierry Reding 	value |= DSI_CONTROL_VIDEO_ENABLE;
536dec72739SThierry Reding 	value &= ~DSI_CONTROL_HOST_ENABLE;
537dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
538dec72739SThierry Reding 
539dec72739SThierry Reding 	err = tegra_dsi_set_phy_timing(dsi);
540dec72739SThierry Reding 	if (err < 0)
541dec72739SThierry Reding 		return err;
542dec72739SThierry Reding 
543dec72739SThierry Reding 	for (i = 0; i < NUM_PKT_SEQ; i++)
544dec72739SThierry Reding 		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
545dec72739SThierry Reding 
546337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
547dec72739SThierry Reding 		/* horizontal active pixels */
548dec72739SThierry Reding 		hact = mode->hdisplay * mul / div;
549dec72739SThierry Reding 
550dec72739SThierry Reding 		/* horizontal sync width */
551dec72739SThierry Reding 		hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
552dec72739SThierry Reding 		hsw -= 10;
553dec72739SThierry Reding 
554dec72739SThierry Reding 		/* horizontal back porch */
555dec72739SThierry Reding 		hbp = (mode->htotal - mode->hsync_end) * mul / div;
556dec72739SThierry Reding 		hbp -= 14;
557dec72739SThierry Reding 
558dec72739SThierry Reding 		/* horizontal front porch */
559dec72739SThierry Reding 		hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
560dec72739SThierry Reding 		hfp -= 8;
561dec72739SThierry Reding 
562dec72739SThierry Reding 		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
563dec72739SThierry Reding 		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
564dec72739SThierry Reding 		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
565dec72739SThierry Reding 		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
566dec72739SThierry Reding 
567563eff1fSThierry Reding 		/* set SOL delay (for non-burst mode only) */
568dec72739SThierry Reding 		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
569e94236cdSThierry Reding 
570e94236cdSThierry Reding 		/* TODO: implement ganged mode */
571337b443dSThierry Reding 	} else {
572337b443dSThierry Reding 		u16 bytes;
573337b443dSThierry Reding 
574e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
575e94236cdSThierry Reding 			/*
576e94236cdSThierry Reding 			 * For ganged mode, assume symmetric left-right mode.
577e94236cdSThierry Reding 			 */
578e94236cdSThierry Reding 			bytes = 1 + (mode->hdisplay / 2) * mul / div;
579e94236cdSThierry Reding 		} else {
580337b443dSThierry Reding 			/* 1 byte (DCS command) + pixel data */
581337b443dSThierry Reding 			bytes = 1 + mode->hdisplay * mul / div;
582e94236cdSThierry Reding 		}
583337b443dSThierry Reding 
584337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
585337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
586337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
587337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
588337b443dSThierry Reding 
589337b443dSThierry Reding 		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
590337b443dSThierry Reding 			MIPI_DCS_WRITE_MEMORY_CONTINUE;
591337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
592337b443dSThierry Reding 
593e94236cdSThierry Reding 		/* set SOL delay */
594e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
595e94236cdSThierry Reding 			unsigned int lanes = tegra_dsi_get_lanes(dsi);
596e94236cdSThierry Reding 			unsigned long delay, bclk, bclk_ganged;
597e94236cdSThierry Reding 
598e94236cdSThierry Reding 			/* SOL to valid, valid to FIFO and FIFO write delay */
599e94236cdSThierry Reding 			delay = 4 + 4 + 2;
600e94236cdSThierry Reding 			delay = DIV_ROUND_UP(delay * mul, div * lanes);
601e94236cdSThierry Reding 			/* FIFO read delay */
602e94236cdSThierry Reding 			delay = delay + 6;
603e94236cdSThierry Reding 
604e94236cdSThierry Reding 			bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes);
605e94236cdSThierry Reding 			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
606e94236cdSThierry Reding 			value = bclk - bclk_ganged + delay + 20;
607e94236cdSThierry Reding 		} else {
608e94236cdSThierry Reding 			/* TODO: revisit for non-ganged mode */
609337b443dSThierry Reding 			value = 8 * mul / div;
610e94236cdSThierry Reding 		}
611337b443dSThierry Reding 
612337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
613337b443dSThierry Reding 	}
614dec72739SThierry Reding 
615e94236cdSThierry Reding 	if (dsi->slave) {
616e94236cdSThierry Reding 		err = tegra_dsi_configure(dsi->slave, pipe, mode);
617e94236cdSThierry Reding 		if (err < 0)
618e94236cdSThierry Reding 			return err;
619e94236cdSThierry Reding 
620e94236cdSThierry Reding 		/*
621e94236cdSThierry Reding 		 * TODO: Support modes other than symmetrical left-right
622e94236cdSThierry Reding 		 * split.
623e94236cdSThierry Reding 		 */
624e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
625e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
626e94236cdSThierry Reding 					mode->hdisplay / 2);
627e94236cdSThierry Reding 	}
628e94236cdSThierry Reding 
629563eff1fSThierry Reding 	return 0;
630563eff1fSThierry Reding }
631563eff1fSThierry Reding 
632563eff1fSThierry Reding static int tegra_output_dsi_enable(struct tegra_output *output)
633563eff1fSThierry Reding {
634563eff1fSThierry Reding 	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
635563eff1fSThierry Reding 	const struct drm_display_mode *mode = &dc->base.mode;
636563eff1fSThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
637563eff1fSThierry Reding 	u32 value;
638563eff1fSThierry Reding 	int err;
639563eff1fSThierry Reding 
640563eff1fSThierry Reding 	if (dsi->enabled)
641563eff1fSThierry Reding 		return 0;
642563eff1fSThierry Reding 
643563eff1fSThierry Reding 	err = tegra_dsi_configure(dsi, dc->pipe, mode);
644563eff1fSThierry Reding 	if (err < 0)
645563eff1fSThierry Reding 		return err;
646563eff1fSThierry Reding 
647dec72739SThierry Reding 	/* enable display controller */
648dec72739SThierry Reding 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
649dec72739SThierry Reding 	value |= DSI_ENABLE;
650dec72739SThierry Reding 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
651dec72739SThierry Reding 
652dec72739SThierry Reding 	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
653dec72739SThierry Reding 	value &= ~DISP_CTRL_MODE_MASK;
654dec72739SThierry Reding 	value |= DISP_CTRL_MODE_C_DISPLAY;
655dec72739SThierry Reding 	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
656dec72739SThierry Reding 
65772d30286SThierry Reding 	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
65872d30286SThierry Reding 	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
65972d30286SThierry Reding 		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
66072d30286SThierry Reding 	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
66172d30286SThierry Reding 
662dec72739SThierry Reding 	tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
663dec72739SThierry Reding 	tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
664dec72739SThierry Reding 
665dec72739SThierry Reding 	/* enable DSI controller */
666563eff1fSThierry Reding 	tegra_dsi_enable(dsi);
667dec72739SThierry Reding 
668334ae6b5SThierry Reding 	dsi->enabled = true;
669334ae6b5SThierry Reding 
670dec72739SThierry Reding 	return 0;
671dec72739SThierry Reding }
672dec72739SThierry Reding 
673563eff1fSThierry Reding static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
674563eff1fSThierry Reding {
675563eff1fSThierry Reding 	u32 value;
676563eff1fSThierry Reding 
677563eff1fSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
678563eff1fSThierry Reding 
679563eff1fSThierry Reding 	while (time_before(jiffies, timeout)) {
680563eff1fSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_STATUS);
681563eff1fSThierry Reding 		if (value & DSI_STATUS_IDLE)
682563eff1fSThierry Reding 			return 0;
683563eff1fSThierry Reding 
684563eff1fSThierry Reding 		usleep_range(1000, 2000);
685563eff1fSThierry Reding 	}
686563eff1fSThierry Reding 
687563eff1fSThierry Reding 	return -ETIMEDOUT;
688563eff1fSThierry Reding }
689563eff1fSThierry Reding 
690563eff1fSThierry Reding static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
691563eff1fSThierry Reding {
692563eff1fSThierry Reding 	u32 value;
693563eff1fSThierry Reding 
694563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
695563eff1fSThierry Reding 	value &= ~DSI_CONTROL_VIDEO_ENABLE;
696563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
697e94236cdSThierry Reding 
698e94236cdSThierry Reding 	if (dsi->slave)
699e94236cdSThierry Reding 		tegra_dsi_video_disable(dsi->slave);
700e94236cdSThierry Reding }
701e94236cdSThierry Reding 
702e94236cdSThierry Reding static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
703e94236cdSThierry Reding {
704e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
705e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
706e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
707563eff1fSThierry Reding }
708563eff1fSThierry Reding 
709563eff1fSThierry Reding static void tegra_dsi_disable(struct tegra_dsi *dsi)
710563eff1fSThierry Reding {
711563eff1fSThierry Reding 	u32 value;
712563eff1fSThierry Reding 
713e94236cdSThierry Reding 	if (dsi->slave) {
714e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi->slave);
715e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi);
716e94236cdSThierry Reding 	}
717e94236cdSThierry Reding 
718563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
719563eff1fSThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
720563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
721563eff1fSThierry Reding 
722e94236cdSThierry Reding 	if (dsi->slave)
723e94236cdSThierry Reding 		tegra_dsi_disable(dsi->slave);
724e94236cdSThierry Reding 
725563eff1fSThierry Reding 	usleep_range(5000, 10000);
726563eff1fSThierry Reding }
727563eff1fSThierry Reding 
728dec72739SThierry Reding static int tegra_output_dsi_disable(struct tegra_output *output)
729dec72739SThierry Reding {
730dec72739SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
731dec72739SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
732dec72739SThierry Reding 	unsigned long value;
733563eff1fSThierry Reding 	int err;
734dec72739SThierry Reding 
735334ae6b5SThierry Reding 	if (!dsi->enabled)
736334ae6b5SThierry Reding 		return 0;
737334ae6b5SThierry Reding 
738563eff1fSThierry Reding 	tegra_dsi_video_disable(dsi);
739dec72739SThierry Reding 
740dec72739SThierry Reding 	/*
74172d30286SThierry Reding 	 * The following accesses registers of the display controller, so make
74272d30286SThierry Reding 	 * sure it's only executed when the output is attached to one.
743dec72739SThierry Reding 	 */
744dec72739SThierry Reding 	if (dc) {
74572d30286SThierry Reding 		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
74672d30286SThierry Reding 		value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
74772d30286SThierry Reding 			   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
74872d30286SThierry Reding 		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
74972d30286SThierry Reding 
750dec72739SThierry Reding 		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
751dec72739SThierry Reding 		value &= ~DISP_CTRL_MODE_MASK;
752dec72739SThierry Reding 		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
753dec72739SThierry Reding 
754dec72739SThierry Reding 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
755dec72739SThierry Reding 		value &= ~DSI_ENABLE;
756dec72739SThierry Reding 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
75772d30286SThierry Reding 
75872d30286SThierry Reding 		tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
75972d30286SThierry Reding 		tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
760dec72739SThierry Reding 	}
761dec72739SThierry Reding 
762563eff1fSThierry Reding 	err = tegra_dsi_wait_idle(dsi, 100);
763563eff1fSThierry Reding 	if (err < 0)
764563eff1fSThierry Reding 		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
765563eff1fSThierry Reding 
766563eff1fSThierry Reding 	tegra_dsi_disable(dsi);
767563eff1fSThierry Reding 
768334ae6b5SThierry Reding 	dsi->enabled = false;
769334ae6b5SThierry Reding 
770dec72739SThierry Reding 	return 0;
771dec72739SThierry Reding }
772dec72739SThierry Reding 
7733f6b406fSThierry Reding static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
7743f6b406fSThierry Reding 				  unsigned int vrefresh)
7753f6b406fSThierry Reding {
7763f6b406fSThierry Reding 	unsigned int timeout;
7773f6b406fSThierry Reding 	u32 value;
7783f6b406fSThierry Reding 
7793f6b406fSThierry Reding 	/* one frame high-speed transmission timeout */
7803f6b406fSThierry Reding 	timeout = (bclk / vrefresh) / 512;
7813f6b406fSThierry Reding 	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
7823f6b406fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
7833f6b406fSThierry Reding 
7843f6b406fSThierry Reding 	/* 2 ms peripheral timeout for panel */
7853f6b406fSThierry Reding 	timeout = 2 * bclk / 512 * 1000;
7863f6b406fSThierry Reding 	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
7873f6b406fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
7883f6b406fSThierry Reding 
7893f6b406fSThierry Reding 	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
7903f6b406fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
791e94236cdSThierry Reding 
792e94236cdSThierry Reding 	if (dsi->slave)
793e94236cdSThierry Reding 		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
7943f6b406fSThierry Reding }
7953f6b406fSThierry Reding 
796dec72739SThierry Reding static int tegra_output_dsi_setup_clock(struct tegra_output *output,
79791eded9bSThierry Reding 					struct clk *clk, unsigned long pclk,
79891eded9bSThierry Reding 					unsigned int *divp)
799dec72739SThierry Reding {
800dec72739SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
801dec72739SThierry Reding 	struct drm_display_mode *mode = &dc->base.mode;
802dec72739SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
803e94236cdSThierry Reding 	unsigned int mul, div, vrefresh, lanes;
8043f6b406fSThierry Reding 	unsigned long bclk, plld;
805dec72739SThierry Reding 	int err;
806dec72739SThierry Reding 
807e94236cdSThierry Reding 	lanes = tegra_dsi_get_lanes(dsi);
808e94236cdSThierry Reding 
809dec72739SThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
810dec72739SThierry Reding 	if (err < 0)
811dec72739SThierry Reding 		return err;
812dec72739SThierry Reding 
813e94236cdSThierry Reding 	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes);
814dec72739SThierry Reding 	vrefresh = drm_mode_vrefresh(mode);
81591eded9bSThierry Reding 	DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
816dec72739SThierry Reding 
81791eded9bSThierry Reding 	/* compute byte clock */
818e94236cdSThierry Reding 	bclk = (pclk * mul) / (div * lanes);
81991eded9bSThierry Reding 
82091eded9bSThierry Reding 	/*
82191eded9bSThierry Reding 	 * Compute bit clock and round up to the next MHz.
82291eded9bSThierry Reding 	 */
823*030611ecSThierry Reding 	plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
82491eded9bSThierry Reding 
82591eded9bSThierry Reding 	/*
82691eded9bSThierry Reding 	 * We divide the frequency by two here, but we make up for that by
82791eded9bSThierry Reding 	 * setting the shift clock divider (further below) to half of the
82891eded9bSThierry Reding 	 * correct value.
82991eded9bSThierry Reding 	 */
83091eded9bSThierry Reding 	plld /= 2;
831dec72739SThierry Reding 
832dec72739SThierry Reding 	err = clk_set_parent(clk, dsi->clk_parent);
833dec72739SThierry Reding 	if (err < 0) {
834dec72739SThierry Reding 		dev_err(dsi->dev, "failed to set parent clock: %d\n", err);
835dec72739SThierry Reding 		return err;
836dec72739SThierry Reding 	}
837dec72739SThierry Reding 
83891eded9bSThierry Reding 	err = clk_set_rate(dsi->clk_parent, plld);
839dec72739SThierry Reding 	if (err < 0) {
840dec72739SThierry Reding 		dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
84191eded9bSThierry Reding 			plld);
842dec72739SThierry Reding 		return err;
843dec72739SThierry Reding 	}
844dec72739SThierry Reding 
845dec72739SThierry Reding 	/*
84691eded9bSThierry Reding 	 * Derive pixel clock from bit clock using the shift clock divider.
84791eded9bSThierry Reding 	 * Note that this is only half of what we would expect, but we need
84891eded9bSThierry Reding 	 * that to make up for the fact that we divided the bit clock by a
84991eded9bSThierry Reding 	 * factor of two above.
85091eded9bSThierry Reding 	 *
85191eded9bSThierry Reding 	 * It's not clear exactly why this is necessary, but the display is
85291eded9bSThierry Reding 	 * not working properly otherwise. Perhaps the PLLs cannot generate
85391eded9bSThierry Reding 	 * frequencies sufficiently high.
85491eded9bSThierry Reding 	 */
855e94236cdSThierry Reding 	*divp = ((8 * mul) / (div * lanes)) - 2;
85691eded9bSThierry Reding 
85791eded9bSThierry Reding 	/*
858dec72739SThierry Reding 	 * XXX: Move the below somewhere else so that we don't need to have
859dec72739SThierry Reding 	 * access to the vrefresh in this function?
860dec72739SThierry Reding 	 */
8613f6b406fSThierry Reding 	tegra_dsi_set_timeout(dsi, bclk, vrefresh);
862dec72739SThierry Reding 
863dec72739SThierry Reding 	return 0;
864dec72739SThierry Reding }
865dec72739SThierry Reding 
866dec72739SThierry Reding static int tegra_output_dsi_check_mode(struct tegra_output *output,
867dec72739SThierry Reding 				       struct drm_display_mode *mode,
868dec72739SThierry Reding 				       enum drm_mode_status *status)
869dec72739SThierry Reding {
870dec72739SThierry Reding 	/*
871dec72739SThierry Reding 	 * FIXME: For now, always assume that the mode is okay.
872dec72739SThierry Reding 	 */
873dec72739SThierry Reding 
874dec72739SThierry Reding 	*status = MODE_OK;
875dec72739SThierry Reding 
876dec72739SThierry Reding 	return 0;
877dec72739SThierry Reding }
878dec72739SThierry Reding 
879dec72739SThierry Reding static const struct tegra_output_ops dsi_ops = {
880dec72739SThierry Reding 	.enable = tegra_output_dsi_enable,
881dec72739SThierry Reding 	.disable = tegra_output_dsi_disable,
882dec72739SThierry Reding 	.setup_clock = tegra_output_dsi_setup_clock,
883dec72739SThierry Reding 	.check_mode = tegra_output_dsi_check_mode,
884dec72739SThierry Reding };
885dec72739SThierry Reding 
886dec72739SThierry Reding static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
887dec72739SThierry Reding {
888dec72739SThierry Reding 	unsigned long value;
889dec72739SThierry Reding 
890dec72739SThierry Reding 	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
891dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
892dec72739SThierry Reding 
893dec72739SThierry Reding 	return 0;
894dec72739SThierry Reding }
895dec72739SThierry Reding 
896dec72739SThierry Reding static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
897dec72739SThierry Reding {
898183ef288SThierry Reding 	u32 value;
899dec72739SThierry Reding 
900dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
901dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
902dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
903dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
904dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
905dec72739SThierry Reding 
906dec72739SThierry Reding 	/* start calibration */
907dec72739SThierry Reding 	tegra_dsi_pad_enable(dsi);
908dec72739SThierry Reding 
909dec72739SThierry Reding 	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
910dec72739SThierry Reding 		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
911dec72739SThierry Reding 		DSI_PAD_OUT_CLK(0x0);
912dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
913dec72739SThierry Reding 
914dec72739SThierry Reding 	return tegra_mipi_calibrate(dsi->mipi);
915dec72739SThierry Reding }
916dec72739SThierry Reding 
917dec72739SThierry Reding static int tegra_dsi_init(struct host1x_client *client)
918dec72739SThierry Reding {
9199910f5c4SThierry Reding 	struct drm_device *drm = dev_get_drvdata(client->parent);
920dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
921dec72739SThierry Reding 	int err;
922dec72739SThierry Reding 
923e94236cdSThierry Reding 	/* Gangsters must not register their own outputs. */
924e94236cdSThierry Reding 	if (!dsi->master) {
925dec72739SThierry Reding 		dsi->output.type = TEGRA_OUTPUT_DSI;
926dec72739SThierry Reding 		dsi->output.dev = client->dev;
927dec72739SThierry Reding 		dsi->output.ops = &dsi_ops;
928dec72739SThierry Reding 
9299910f5c4SThierry Reding 		err = tegra_output_init(drm, &dsi->output);
930dec72739SThierry Reding 		if (err < 0) {
931dec72739SThierry Reding 			dev_err(client->dev, "output setup failed: %d\n", err);
932dec72739SThierry Reding 			return err;
933dec72739SThierry Reding 		}
934e94236cdSThierry Reding 	}
935dec72739SThierry Reding 
936dec72739SThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
9379910f5c4SThierry Reding 		err = tegra_dsi_debugfs_init(dsi, drm->primary);
938dec72739SThierry Reding 		if (err < 0)
939dec72739SThierry Reding 			dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
940dec72739SThierry Reding 	}
941dec72739SThierry Reding 
942dec72739SThierry Reding 	return 0;
943dec72739SThierry Reding }
944dec72739SThierry Reding 
945dec72739SThierry Reding static int tegra_dsi_exit(struct host1x_client *client)
946dec72739SThierry Reding {
947dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
948dec72739SThierry Reding 	int err;
949dec72739SThierry Reding 
950dec72739SThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
951dec72739SThierry Reding 		err = tegra_dsi_debugfs_exit(dsi);
952dec72739SThierry Reding 		if (err < 0)
953dec72739SThierry Reding 			dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
954dec72739SThierry Reding 	}
955dec72739SThierry Reding 
956e94236cdSThierry Reding 	if (!dsi->master) {
957dec72739SThierry Reding 		err = tegra_output_disable(&dsi->output);
958dec72739SThierry Reding 		if (err < 0) {
959e94236cdSThierry Reding 			dev_err(client->dev, "output failed to disable: %d\n",
960e94236cdSThierry Reding 				err);
961dec72739SThierry Reding 			return err;
962dec72739SThierry Reding 		}
963dec72739SThierry Reding 
964dec72739SThierry Reding 		err = tegra_output_exit(&dsi->output);
965dec72739SThierry Reding 		if (err < 0) {
966e94236cdSThierry Reding 			dev_err(client->dev, "output cleanup failed: %d\n",
967e94236cdSThierry Reding 				err);
968dec72739SThierry Reding 			return err;
969dec72739SThierry Reding 		}
970e94236cdSThierry Reding 	}
971dec72739SThierry Reding 
972dec72739SThierry Reding 	return 0;
973dec72739SThierry Reding }
974dec72739SThierry Reding 
975dec72739SThierry Reding static const struct host1x_client_ops dsi_client_ops = {
976dec72739SThierry Reding 	.init = tegra_dsi_init,
977dec72739SThierry Reding 	.exit = tegra_dsi_exit,
978dec72739SThierry Reding };
979dec72739SThierry Reding 
980dec72739SThierry Reding static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
981dec72739SThierry Reding {
982dec72739SThierry Reding 	struct clk *parent;
983dec72739SThierry Reding 	int err;
984dec72739SThierry Reding 
985dec72739SThierry Reding 	parent = clk_get_parent(dsi->clk);
986dec72739SThierry Reding 	if (!parent)
987dec72739SThierry Reding 		return -EINVAL;
988dec72739SThierry Reding 
989dec72739SThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
990dec72739SThierry Reding 	if (err < 0)
991dec72739SThierry Reding 		return err;
992dec72739SThierry Reding 
993dec72739SThierry Reding 	return 0;
994dec72739SThierry Reding }
995dec72739SThierry Reding 
9960fffdf6cSThierry Reding static const char * const error_report[16] = {
9970fffdf6cSThierry Reding 	"SoT Error",
9980fffdf6cSThierry Reding 	"SoT Sync Error",
9990fffdf6cSThierry Reding 	"EoT Sync Error",
10000fffdf6cSThierry Reding 	"Escape Mode Entry Command Error",
10010fffdf6cSThierry Reding 	"Low-Power Transmit Sync Error",
10020fffdf6cSThierry Reding 	"Peripheral Timeout Error",
10030fffdf6cSThierry Reding 	"False Control Error",
10040fffdf6cSThierry Reding 	"Contention Detected",
10050fffdf6cSThierry Reding 	"ECC Error, single-bit",
10060fffdf6cSThierry Reding 	"ECC Error, multi-bit",
10070fffdf6cSThierry Reding 	"Checksum Error",
10080fffdf6cSThierry Reding 	"DSI Data Type Not Recognized",
10090fffdf6cSThierry Reding 	"DSI VC ID Invalid",
10100fffdf6cSThierry Reding 	"Invalid Transmission Length",
10110fffdf6cSThierry Reding 	"Reserved",
10120fffdf6cSThierry Reding 	"DSI Protocol Violation",
10130fffdf6cSThierry Reding };
10140fffdf6cSThierry Reding 
10150fffdf6cSThierry Reding static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
10160fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg,
10170fffdf6cSThierry Reding 				       size_t count)
10180fffdf6cSThierry Reding {
10190fffdf6cSThierry Reding 	u8 *rx = msg->rx_buf;
10200fffdf6cSThierry Reding 	unsigned int i, j, k;
10210fffdf6cSThierry Reding 	size_t size = 0;
10220fffdf6cSThierry Reding 	u16 errors;
10230fffdf6cSThierry Reding 	u32 value;
10240fffdf6cSThierry Reding 
10250fffdf6cSThierry Reding 	/* read and parse packet header */
10260fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
10270fffdf6cSThierry Reding 
10280fffdf6cSThierry Reding 	switch (value & 0x3f) {
10290fffdf6cSThierry Reding 	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
10300fffdf6cSThierry Reding 		errors = (value >> 8) & 0xffff;
10310fffdf6cSThierry Reding 		dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
10320fffdf6cSThierry Reding 			errors);
10330fffdf6cSThierry Reding 		for (i = 0; i < ARRAY_SIZE(error_report); i++)
10340fffdf6cSThierry Reding 			if (errors & BIT(i))
10350fffdf6cSThierry Reding 				dev_dbg(dsi->dev, "  %2u: %s\n", i,
10360fffdf6cSThierry Reding 					error_report[i]);
10370fffdf6cSThierry Reding 		break;
10380fffdf6cSThierry Reding 
10390fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
10400fffdf6cSThierry Reding 		rx[0] = (value >> 8) & 0xff;
10410fffdf6cSThierry Reding 		size = 1;
10420fffdf6cSThierry Reding 		break;
10430fffdf6cSThierry Reding 
10440fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
10450fffdf6cSThierry Reding 		rx[0] = (value >>  8) & 0xff;
10460fffdf6cSThierry Reding 		rx[1] = (value >> 16) & 0xff;
10470fffdf6cSThierry Reding 		size = 2;
10480fffdf6cSThierry Reding 		break;
10490fffdf6cSThierry Reding 
10500fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
10510fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
10520fffdf6cSThierry Reding 		break;
10530fffdf6cSThierry Reding 
10540fffdf6cSThierry Reding 	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
10550fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
10560fffdf6cSThierry Reding 		break;
10570fffdf6cSThierry Reding 
10580fffdf6cSThierry Reding 	default:
10590fffdf6cSThierry Reding 		dev_err(dsi->dev, "unhandled response type: %02x\n",
10600fffdf6cSThierry Reding 			value & 0x3f);
10610fffdf6cSThierry Reding 		return -EPROTO;
10620fffdf6cSThierry Reding 	}
10630fffdf6cSThierry Reding 
10640fffdf6cSThierry Reding 	size = min(size, msg->rx_len);
10650fffdf6cSThierry Reding 
10660fffdf6cSThierry Reding 	if (msg->rx_buf && size > 0) {
10670fffdf6cSThierry Reding 		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
10680fffdf6cSThierry Reding 			u8 *rx = msg->rx_buf + j;
10690fffdf6cSThierry Reding 
10700fffdf6cSThierry Reding 			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
10710fffdf6cSThierry Reding 
10720fffdf6cSThierry Reding 			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
10730fffdf6cSThierry Reding 				rx[j + k] = (value >> (k << 3)) & 0xff;
10740fffdf6cSThierry Reding 		}
10750fffdf6cSThierry Reding 	}
10760fffdf6cSThierry Reding 
10770fffdf6cSThierry Reding 	return size;
10780fffdf6cSThierry Reding }
10790fffdf6cSThierry Reding 
10800fffdf6cSThierry Reding static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
10810fffdf6cSThierry Reding {
10820fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
10830fffdf6cSThierry Reding 
10840fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
10850fffdf6cSThierry Reding 
10860fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
10870fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
10880fffdf6cSThierry Reding 		if ((value & DSI_TRIGGER_HOST) == 0)
10890fffdf6cSThierry Reding 			return 0;
10900fffdf6cSThierry Reding 
10910fffdf6cSThierry Reding 		usleep_range(1000, 2000);
10920fffdf6cSThierry Reding 	}
10930fffdf6cSThierry Reding 
10940fffdf6cSThierry Reding 	DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
10950fffdf6cSThierry Reding 	return -ETIMEDOUT;
10960fffdf6cSThierry Reding }
10970fffdf6cSThierry Reding 
10980fffdf6cSThierry Reding static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
10990fffdf6cSThierry Reding 				       unsigned long timeout)
11000fffdf6cSThierry Reding {
11010fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(250);
11020fffdf6cSThierry Reding 
11030fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
11040fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
11050fffdf6cSThierry Reding 		u8 count = value & 0x1f;
11060fffdf6cSThierry Reding 
11070fffdf6cSThierry Reding 		if (count > 0)
11080fffdf6cSThierry Reding 			return count;
11090fffdf6cSThierry Reding 
11100fffdf6cSThierry Reding 		usleep_range(1000, 2000);
11110fffdf6cSThierry Reding 	}
11120fffdf6cSThierry Reding 
11130fffdf6cSThierry Reding 	DRM_DEBUG_KMS("peripheral returned no data\n");
11140fffdf6cSThierry Reding 	return -ETIMEDOUT;
11150fffdf6cSThierry Reding }
11160fffdf6cSThierry Reding 
11170fffdf6cSThierry Reding static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
11180fffdf6cSThierry Reding 			      const void *buffer, size_t size)
11190fffdf6cSThierry Reding {
11200fffdf6cSThierry Reding 	const u8 *buf = buffer;
11210fffdf6cSThierry Reding 	size_t i, j;
11220fffdf6cSThierry Reding 	u32 value;
11230fffdf6cSThierry Reding 
11240fffdf6cSThierry Reding 	for (j = 0; j < size; j += 4) {
11250fffdf6cSThierry Reding 		value = 0;
11260fffdf6cSThierry Reding 
11270fffdf6cSThierry Reding 		for (i = 0; i < 4 && j + i < size; i++)
11280fffdf6cSThierry Reding 			value |= buf[j + i] << (i << 3);
11290fffdf6cSThierry Reding 
11300fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_WR_DATA);
11310fffdf6cSThierry Reding 	}
11320fffdf6cSThierry Reding }
11330fffdf6cSThierry Reding 
11340fffdf6cSThierry Reding static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
11350fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg)
11360fffdf6cSThierry Reding {
11370fffdf6cSThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
11380fffdf6cSThierry Reding 	struct mipi_dsi_packet packet;
11390fffdf6cSThierry Reding 	const u8 *header;
11400fffdf6cSThierry Reding 	size_t count;
11410fffdf6cSThierry Reding 	ssize_t err;
11420fffdf6cSThierry Reding 	u32 value;
11430fffdf6cSThierry Reding 
11440fffdf6cSThierry Reding 	err = mipi_dsi_create_packet(&packet, msg);
11450fffdf6cSThierry Reding 	if (err < 0)
11460fffdf6cSThierry Reding 		return err;
11470fffdf6cSThierry Reding 
11480fffdf6cSThierry Reding 	header = packet.header;
11490fffdf6cSThierry Reding 
11500fffdf6cSThierry Reding 	/* maximum FIFO depth is 1920 words */
11510fffdf6cSThierry Reding 	if (packet.size > dsi->video_fifo_depth * 4)
11520fffdf6cSThierry Reding 		return -ENOSPC;
11530fffdf6cSThierry Reding 
11540fffdf6cSThierry Reding 	/* reset underflow/overflow flags */
11550fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_STATUS);
11560fffdf6cSThierry Reding 	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
11570fffdf6cSThierry Reding 		value = DSI_HOST_CONTROL_FIFO_RESET;
11580fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
11590fffdf6cSThierry Reding 		usleep_range(10, 20);
11600fffdf6cSThierry Reding 	}
11610fffdf6cSThierry Reding 
11620fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
11630fffdf6cSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
11640fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
11650fffdf6cSThierry Reding 
11660fffdf6cSThierry Reding 	usleep_range(5000, 10000);
11670fffdf6cSThierry Reding 
11680fffdf6cSThierry Reding 	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
11690fffdf6cSThierry Reding 		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
11700fffdf6cSThierry Reding 
11710fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
11720fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_HS;
11730fffdf6cSThierry Reding 
11740fffdf6cSThierry Reding 	/*
11750fffdf6cSThierry Reding 	 * The host FIFO has a maximum of 64 words, so larger transmissions
11760fffdf6cSThierry Reding 	 * need to use the video FIFO.
11770fffdf6cSThierry Reding 	 */
11780fffdf6cSThierry Reding 	if (packet.size > dsi->host_fifo_depth * 4)
11790fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_FIFO_SEL;
11800fffdf6cSThierry Reding 
11810fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
11820fffdf6cSThierry Reding 
11830fffdf6cSThierry Reding 	/*
11840fffdf6cSThierry Reding 	 * For reads and messages with explicitly requested ACK, generate a
11850fffdf6cSThierry Reding 	 * BTA sequence after the transmission of the packet.
11860fffdf6cSThierry Reding 	 */
11870fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
11880fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
11890fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
11900fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_PKT_BTA;
11910fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
11920fffdf6cSThierry Reding 	}
11930fffdf6cSThierry Reding 
11940fffdf6cSThierry Reding 	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
11950fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
11960fffdf6cSThierry Reding 
11970fffdf6cSThierry Reding 	/* write packet header, ECC is generated by hardware */
11980fffdf6cSThierry Reding 	value = header[2] << 16 | header[1] << 8 | header[0];
11990fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
12000fffdf6cSThierry Reding 
12010fffdf6cSThierry Reding 	/* write payload (if any) */
12020fffdf6cSThierry Reding 	if (packet.payload_length > 0)
12030fffdf6cSThierry Reding 		tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
12040fffdf6cSThierry Reding 				  packet.payload_length);
12050fffdf6cSThierry Reding 
12060fffdf6cSThierry Reding 	err = tegra_dsi_transmit(dsi, 250);
12070fffdf6cSThierry Reding 	if (err < 0)
12080fffdf6cSThierry Reding 		return err;
12090fffdf6cSThierry Reding 
12100fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
12110fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
12120fffdf6cSThierry Reding 		err = tegra_dsi_wait_for_response(dsi, 250);
12130fffdf6cSThierry Reding 		if (err < 0)
12140fffdf6cSThierry Reding 			return err;
12150fffdf6cSThierry Reding 
12160fffdf6cSThierry Reding 		count = err;
12170fffdf6cSThierry Reding 
12180fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12190fffdf6cSThierry Reding 		switch (value) {
12200fffdf6cSThierry Reding 		case 0x84:
12210fffdf6cSThierry Reding 			/*
12220fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ACK\n");
12230fffdf6cSThierry Reding 			*/
12240fffdf6cSThierry Reding 			break;
12250fffdf6cSThierry Reding 
12260fffdf6cSThierry Reding 		case 0x87:
12270fffdf6cSThierry Reding 			/*
12280fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ESCAPE\n");
12290fffdf6cSThierry Reding 			*/
12300fffdf6cSThierry Reding 			break;
12310fffdf6cSThierry Reding 
12320fffdf6cSThierry Reding 		default:
12330fffdf6cSThierry Reding 			dev_err(dsi->dev, "unknown status: %08x\n", value);
12340fffdf6cSThierry Reding 			break;
12350fffdf6cSThierry Reding 		}
12360fffdf6cSThierry Reding 
12370fffdf6cSThierry Reding 		if (count > 1) {
12380fffdf6cSThierry Reding 			err = tegra_dsi_read_response(dsi, msg, count);
12390fffdf6cSThierry Reding 			if (err < 0)
12400fffdf6cSThierry Reding 				dev_err(dsi->dev,
12410fffdf6cSThierry Reding 					"failed to parse response: %zd\n",
12420fffdf6cSThierry Reding 					err);
12430fffdf6cSThierry Reding 			else {
12440fffdf6cSThierry Reding 				/*
12450fffdf6cSThierry Reding 				 * For read commands, return the number of
12460fffdf6cSThierry Reding 				 * bytes returned by the peripheral.
12470fffdf6cSThierry Reding 				 */
12480fffdf6cSThierry Reding 				count = err;
12490fffdf6cSThierry Reding 			}
12500fffdf6cSThierry Reding 		}
12510fffdf6cSThierry Reding 	} else {
12520fffdf6cSThierry Reding 		/*
12530fffdf6cSThierry Reding 		 * For write commands, we have transmitted the 4-byte header
12540fffdf6cSThierry Reding 		 * plus the variable-length payload.
12550fffdf6cSThierry Reding 		 */
12560fffdf6cSThierry Reding 		count = 4 + packet.payload_length;
12570fffdf6cSThierry Reding 	}
12580fffdf6cSThierry Reding 
12590fffdf6cSThierry Reding 	return count;
12600fffdf6cSThierry Reding }
12610fffdf6cSThierry Reding 
1262e94236cdSThierry Reding static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
1263e94236cdSThierry Reding {
1264e94236cdSThierry Reding 	struct clk *parent;
1265e94236cdSThierry Reding 	int err;
1266e94236cdSThierry Reding 
1267e94236cdSThierry Reding 	/* make sure both DSI controllers share the same PLL */
1268e94236cdSThierry Reding 	parent = clk_get_parent(dsi->slave->clk);
1269e94236cdSThierry Reding 	if (!parent)
1270e94236cdSThierry Reding 		return -EINVAL;
1271e94236cdSThierry Reding 
1272e94236cdSThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1273e94236cdSThierry Reding 	if (err < 0)
1274e94236cdSThierry Reding 		return err;
1275e94236cdSThierry Reding 
1276e94236cdSThierry Reding 	return 0;
1277e94236cdSThierry Reding }
1278e94236cdSThierry Reding 
1279dec72739SThierry Reding static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
1280dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1281dec72739SThierry Reding {
1282dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1283dec72739SThierry Reding 
128417297a28SThierry Reding 	dsi->flags = device->mode_flags;
1285dec72739SThierry Reding 	dsi->format = device->format;
1286dec72739SThierry Reding 	dsi->lanes = device->lanes;
1287dec72739SThierry Reding 
1288e94236cdSThierry Reding 	if (dsi->slave) {
1289e94236cdSThierry Reding 		int err;
1290e94236cdSThierry Reding 
1291e94236cdSThierry Reding 		dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
1292e94236cdSThierry Reding 			dev_name(&device->dev));
1293e94236cdSThierry Reding 
1294e94236cdSThierry Reding 		err = tegra_dsi_ganged_setup(dsi);
1295e94236cdSThierry Reding 		if (err < 0) {
1296e94236cdSThierry Reding 			dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
1297e94236cdSThierry Reding 				err);
1298e94236cdSThierry Reding 			return err;
1299e94236cdSThierry Reding 		}
1300e94236cdSThierry Reding 	}
1301e94236cdSThierry Reding 
1302e94236cdSThierry Reding 	/*
1303e94236cdSThierry Reding 	 * Slaves don't have a panel associated with them, so they provide
1304e94236cdSThierry Reding 	 * merely the second channel.
1305e94236cdSThierry Reding 	 */
1306e94236cdSThierry Reding 	if (!dsi->master) {
1307e94236cdSThierry Reding 		struct tegra_output *output = &dsi->output;
1308e94236cdSThierry Reding 
1309dec72739SThierry Reding 		output->panel = of_drm_find_panel(device->dev.of_node);
1310e94236cdSThierry Reding 		if (output->panel && output->connector.dev) {
1311e94236cdSThierry Reding 			drm_panel_attach(output->panel, &output->connector);
1312dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1313dec72739SThierry Reding 		}
1314e94236cdSThierry Reding 	}
1315dec72739SThierry Reding 
1316dec72739SThierry Reding 	return 0;
1317dec72739SThierry Reding }
1318dec72739SThierry Reding 
1319dec72739SThierry Reding static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
1320dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1321dec72739SThierry Reding {
1322dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1323dec72739SThierry Reding 	struct tegra_output *output = &dsi->output;
1324dec72739SThierry Reding 
1325dec72739SThierry Reding 	if (output->panel && &device->dev == output->panel->dev) {
1326ba3df979SThierry Reding 		output->panel = NULL;
1327ba3df979SThierry Reding 
1328dec72739SThierry Reding 		if (output->connector.dev)
1329dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1330dec72739SThierry Reding 	}
1331dec72739SThierry Reding 
1332dec72739SThierry Reding 	return 0;
1333dec72739SThierry Reding }
1334dec72739SThierry Reding 
1335dec72739SThierry Reding static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
1336dec72739SThierry Reding 	.attach = tegra_dsi_host_attach,
1337dec72739SThierry Reding 	.detach = tegra_dsi_host_detach,
13380fffdf6cSThierry Reding 	.transfer = tegra_dsi_host_transfer,
1339dec72739SThierry Reding };
1340dec72739SThierry Reding 
1341e94236cdSThierry Reding static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
1342e94236cdSThierry Reding {
1343e94236cdSThierry Reding 	struct device_node *np;
1344e94236cdSThierry Reding 
1345e94236cdSThierry Reding 	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
1346e94236cdSThierry Reding 	if (np) {
1347e94236cdSThierry Reding 		struct platform_device *gangster = of_find_device_by_node(np);
1348e94236cdSThierry Reding 
1349e94236cdSThierry Reding 		dsi->slave = platform_get_drvdata(gangster);
1350e94236cdSThierry Reding 		of_node_put(np);
1351e94236cdSThierry Reding 
1352e94236cdSThierry Reding 		if (!dsi->slave)
1353e94236cdSThierry Reding 			return -EPROBE_DEFER;
1354e94236cdSThierry Reding 
1355e94236cdSThierry Reding 		dsi->slave->master = dsi;
1356e94236cdSThierry Reding 	}
1357e94236cdSThierry Reding 
1358e94236cdSThierry Reding 	return 0;
1359e94236cdSThierry Reding }
1360e94236cdSThierry Reding 
1361dec72739SThierry Reding static int tegra_dsi_probe(struct platform_device *pdev)
1362dec72739SThierry Reding {
1363dec72739SThierry Reding 	struct tegra_dsi *dsi;
1364dec72739SThierry Reding 	struct resource *regs;
1365dec72739SThierry Reding 	int err;
1366dec72739SThierry Reding 
1367dec72739SThierry Reding 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
1368dec72739SThierry Reding 	if (!dsi)
1369dec72739SThierry Reding 		return -ENOMEM;
1370dec72739SThierry Reding 
1371dec72739SThierry Reding 	dsi->output.dev = dsi->dev = &pdev->dev;
1372976cebc3SThierry Reding 	dsi->video_fifo_depth = 1920;
1373976cebc3SThierry Reding 	dsi->host_fifo_depth = 64;
1374dec72739SThierry Reding 
1375e94236cdSThierry Reding 	err = tegra_dsi_ganged_probe(dsi);
1376e94236cdSThierry Reding 	if (err < 0)
1377e94236cdSThierry Reding 		return err;
1378e94236cdSThierry Reding 
1379dec72739SThierry Reding 	err = tegra_output_probe(&dsi->output);
1380dec72739SThierry Reding 	if (err < 0)
1381dec72739SThierry Reding 		return err;
1382dec72739SThierry Reding 
1383ba3df979SThierry Reding 	dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
1384ba3df979SThierry Reding 
1385dec72739SThierry Reding 	/*
1386dec72739SThierry Reding 	 * Assume these values by default. When a DSI peripheral driver
1387dec72739SThierry Reding 	 * attaches to the DSI host, the parameters will be taken from
1388dec72739SThierry Reding 	 * the attached device.
1389dec72739SThierry Reding 	 */
139017297a28SThierry Reding 	dsi->flags = MIPI_DSI_MODE_VIDEO;
1391dec72739SThierry Reding 	dsi->format = MIPI_DSI_FMT_RGB888;
1392dec72739SThierry Reding 	dsi->lanes = 4;
1393dec72739SThierry Reding 
1394dec72739SThierry Reding 	dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
1395dec72739SThierry Reding 	if (IS_ERR(dsi->rst))
1396dec72739SThierry Reding 		return PTR_ERR(dsi->rst);
1397dec72739SThierry Reding 
1398183ef288SThierry Reding 	err = reset_control_deassert(dsi->rst);
1399183ef288SThierry Reding 	if (err < 0) {
1400183ef288SThierry Reding 		dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n",
1401183ef288SThierry Reding 			err);
1402183ef288SThierry Reding 		return err;
1403183ef288SThierry Reding 	}
1404183ef288SThierry Reding 
1405dec72739SThierry Reding 	dsi->clk = devm_clk_get(&pdev->dev, NULL);
1406dec72739SThierry Reding 	if (IS_ERR(dsi->clk)) {
1407dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get DSI clock\n");
1408d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk);
1409d2d0a9d2SThierry Reding 		goto reset;
1410dec72739SThierry Reding 	}
1411dec72739SThierry Reding 
1412dec72739SThierry Reding 	err = clk_prepare_enable(dsi->clk);
1413dec72739SThierry Reding 	if (err < 0) {
1414dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot enable DSI clock\n");
1415d2d0a9d2SThierry Reding 		goto reset;
1416dec72739SThierry Reding 	}
1417dec72739SThierry Reding 
1418dec72739SThierry Reding 	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
1419dec72739SThierry Reding 	if (IS_ERR(dsi->clk_lp)) {
1420dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get low-power clock\n");
1421d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk_lp);
1422d2d0a9d2SThierry Reding 		goto disable_clk;
1423dec72739SThierry Reding 	}
1424dec72739SThierry Reding 
1425dec72739SThierry Reding 	err = clk_prepare_enable(dsi->clk_lp);
1426dec72739SThierry Reding 	if (err < 0) {
1427dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot enable low-power clock\n");
1428d2d0a9d2SThierry Reding 		goto disable_clk;
1429dec72739SThierry Reding 	}
1430dec72739SThierry Reding 
1431dec72739SThierry Reding 	dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
1432dec72739SThierry Reding 	if (IS_ERR(dsi->clk_parent)) {
1433dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get parent clock\n");
1434d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk_parent);
1435d2d0a9d2SThierry Reding 		goto disable_clk_lp;
1436dec72739SThierry Reding 	}
1437dec72739SThierry Reding 
14383b077afbSThierry Reding 	dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
14393b077afbSThierry Reding 	if (IS_ERR(dsi->vdd)) {
14403b077afbSThierry Reding 		dev_err(&pdev->dev, "cannot get VDD supply\n");
1441d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->vdd);
1442d2d0a9d2SThierry Reding 		goto disable_clk_lp;
14433b077afbSThierry Reding 	}
14443b077afbSThierry Reding 
14453b077afbSThierry Reding 	err = regulator_enable(dsi->vdd);
14463b077afbSThierry Reding 	if (err < 0) {
14473b077afbSThierry Reding 		dev_err(&pdev->dev, "cannot enable VDD supply\n");
1448d2d0a9d2SThierry Reding 		goto disable_clk_lp;
14493b077afbSThierry Reding 	}
14503b077afbSThierry Reding 
1451dec72739SThierry Reding 	err = tegra_dsi_setup_clocks(dsi);
1452dec72739SThierry Reding 	if (err < 0) {
1453dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot setup clocks\n");
1454d2d0a9d2SThierry Reding 		goto disable_vdd;
1455dec72739SThierry Reding 	}
1456dec72739SThierry Reding 
1457dec72739SThierry Reding 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1458dec72739SThierry Reding 	dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
1459d2d0a9d2SThierry Reding 	if (IS_ERR(dsi->regs)) {
1460d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->regs);
1461d2d0a9d2SThierry Reding 		goto disable_vdd;
1462d2d0a9d2SThierry Reding 	}
1463dec72739SThierry Reding 
1464dec72739SThierry Reding 	dsi->mipi = tegra_mipi_request(&pdev->dev);
1465d2d0a9d2SThierry Reding 	if (IS_ERR(dsi->mipi)) {
1466d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->mipi);
1467d2d0a9d2SThierry Reding 		goto disable_vdd;
1468d2d0a9d2SThierry Reding 	}
1469dec72739SThierry Reding 
1470183ef288SThierry Reding 	err = tegra_dsi_pad_calibrate(dsi);
1471183ef288SThierry Reding 	if (err < 0) {
1472183ef288SThierry Reding 		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
1473d2d0a9d2SThierry Reding 		goto mipi_free;
1474183ef288SThierry Reding 	}
1475183ef288SThierry Reding 
1476dec72739SThierry Reding 	dsi->host.ops = &tegra_dsi_host_ops;
1477dec72739SThierry Reding 	dsi->host.dev = &pdev->dev;
1478dec72739SThierry Reding 
1479dec72739SThierry Reding 	err = mipi_dsi_host_register(&dsi->host);
1480dec72739SThierry Reding 	if (err < 0) {
1481dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
1482d2d0a9d2SThierry Reding 		goto mipi_free;
1483dec72739SThierry Reding 	}
1484dec72739SThierry Reding 
1485dec72739SThierry Reding 	INIT_LIST_HEAD(&dsi->client.list);
1486dec72739SThierry Reding 	dsi->client.ops = &dsi_client_ops;
1487dec72739SThierry Reding 	dsi->client.dev = &pdev->dev;
1488dec72739SThierry Reding 
1489dec72739SThierry Reding 	err = host1x_client_register(&dsi->client);
1490dec72739SThierry Reding 	if (err < 0) {
1491dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1492dec72739SThierry Reding 			err);
1493d2d0a9d2SThierry Reding 		goto unregister;
1494dec72739SThierry Reding 	}
1495dec72739SThierry Reding 
1496dec72739SThierry Reding 	platform_set_drvdata(pdev, dsi);
1497dec72739SThierry Reding 
1498dec72739SThierry Reding 	return 0;
1499d2d0a9d2SThierry Reding 
1500d2d0a9d2SThierry Reding unregister:
1501d2d0a9d2SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1502d2d0a9d2SThierry Reding mipi_free:
1503d2d0a9d2SThierry Reding 	tegra_mipi_free(dsi->mipi);
1504d2d0a9d2SThierry Reding disable_vdd:
1505d2d0a9d2SThierry Reding 	regulator_disable(dsi->vdd);
1506d2d0a9d2SThierry Reding disable_clk_lp:
1507d2d0a9d2SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1508d2d0a9d2SThierry Reding disable_clk:
1509d2d0a9d2SThierry Reding 	clk_disable_unprepare(dsi->clk);
1510d2d0a9d2SThierry Reding reset:
1511d2d0a9d2SThierry Reding 	reset_control_assert(dsi->rst);
1512d2d0a9d2SThierry Reding 	return err;
1513dec72739SThierry Reding }
1514dec72739SThierry Reding 
1515dec72739SThierry Reding static int tegra_dsi_remove(struct platform_device *pdev)
1516dec72739SThierry Reding {
1517dec72739SThierry Reding 	struct tegra_dsi *dsi = platform_get_drvdata(pdev);
1518dec72739SThierry Reding 	int err;
1519dec72739SThierry Reding 
1520dec72739SThierry Reding 	err = host1x_client_unregister(&dsi->client);
1521dec72739SThierry Reding 	if (err < 0) {
1522dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1523dec72739SThierry Reding 			err);
1524dec72739SThierry Reding 		return err;
1525dec72739SThierry Reding 	}
1526dec72739SThierry Reding 
1527dec72739SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1528dec72739SThierry Reding 	tegra_mipi_free(dsi->mipi);
1529dec72739SThierry Reding 
15303b077afbSThierry Reding 	regulator_disable(dsi->vdd);
1531dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1532dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk);
1533cb825d89SThierry Reding 	reset_control_assert(dsi->rst);
1534dec72739SThierry Reding 
1535dec72739SThierry Reding 	err = tegra_output_remove(&dsi->output);
1536dec72739SThierry Reding 	if (err < 0) {
1537dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to remove output: %d\n", err);
1538dec72739SThierry Reding 		return err;
1539dec72739SThierry Reding 	}
1540dec72739SThierry Reding 
1541dec72739SThierry Reding 	return 0;
1542dec72739SThierry Reding }
1543dec72739SThierry Reding 
1544dec72739SThierry Reding static const struct of_device_id tegra_dsi_of_match[] = {
1545dec72739SThierry Reding 	{ .compatible = "nvidia,tegra114-dsi", },
1546dec72739SThierry Reding 	{ },
1547dec72739SThierry Reding };
1548ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
1549dec72739SThierry Reding 
1550dec72739SThierry Reding struct platform_driver tegra_dsi_driver = {
1551dec72739SThierry Reding 	.driver = {
1552dec72739SThierry Reding 		.name = "tegra-dsi",
1553dec72739SThierry Reding 		.of_match_table = tegra_dsi_of_match,
1554dec72739SThierry Reding 	},
1555dec72739SThierry Reding 	.probe = tegra_dsi_probe,
1556dec72739SThierry Reding 	.remove = tegra_dsi_remove,
1557dec72739SThierry Reding };
1558