xref: /linux/drivers/gpu/drm/tegra/dsi.c (revision 4aa3df7149a00cb061d2ba74e2136cd14a6d885a)
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 
20*4aa3df71SThierry Reding #include <drm/drm_atomic_helper.h>
21dec72739SThierry Reding #include <drm/drm_mipi_dsi.h>
22dec72739SThierry Reding #include <drm/drm_panel.h>
23dec72739SThierry Reding 
24dec72739SThierry Reding #include <video/mipi_display.h>
25dec72739SThierry Reding 
26dec72739SThierry Reding #include "dc.h"
27dec72739SThierry Reding #include "drm.h"
28dec72739SThierry Reding #include "dsi.h"
29dec72739SThierry Reding #include "mipi-phy.h"
30dec72739SThierry Reding 
31dec72739SThierry Reding struct tegra_dsi {
32dec72739SThierry Reding 	struct host1x_client client;
33dec72739SThierry Reding 	struct tegra_output output;
34dec72739SThierry Reding 	struct device *dev;
35dec72739SThierry Reding 
36dec72739SThierry Reding 	void __iomem *regs;
37dec72739SThierry Reding 
38dec72739SThierry Reding 	struct reset_control *rst;
39dec72739SThierry Reding 	struct clk *clk_parent;
40dec72739SThierry Reding 	struct clk *clk_lp;
41dec72739SThierry Reding 	struct clk *clk;
42dec72739SThierry Reding 
43dec72739SThierry Reding 	struct drm_info_list *debugfs_files;
44dec72739SThierry Reding 	struct drm_minor *minor;
45dec72739SThierry Reding 	struct dentry *debugfs;
46dec72739SThierry Reding 
4717297a28SThierry Reding 	unsigned long flags;
48dec72739SThierry Reding 	enum mipi_dsi_pixel_format format;
49dec72739SThierry Reding 	unsigned int lanes;
50dec72739SThierry Reding 
51dec72739SThierry Reding 	struct tegra_mipi_device *mipi;
52dec72739SThierry Reding 	struct mipi_dsi_host host;
533b077afbSThierry Reding 
543b077afbSThierry Reding 	struct regulator *vdd;
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 
809c0b4ca1SThierry Reding static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned long reg)
81dec72739SThierry Reding {
82dec72739SThierry Reding 	return readl(dsi->regs + (reg << 2));
83dec72739SThierry Reding }
84dec72739SThierry Reding 
859c0b4ca1SThierry Reding static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
86dec72739SThierry Reding 				    unsigned long reg)
87dec72739SThierry Reding {
88dec72739SThierry Reding 	writel(value, dsi->regs + (reg << 2));
89dec72739SThierry Reding }
90dec72739SThierry Reding 
91dec72739SThierry Reding static int tegra_dsi_show_regs(struct seq_file *s, void *data)
92dec72739SThierry Reding {
93dec72739SThierry Reding 	struct drm_info_node *node = s->private;
94dec72739SThierry Reding 	struct tegra_dsi *dsi = node->info_ent->data;
95dec72739SThierry Reding 
96dec72739SThierry Reding #define DUMP_REG(name)						\
979c0b4ca1SThierry Reding 	seq_printf(s, "%-32s %#05x %08x\n", #name, name,	\
98dec72739SThierry Reding 		   tegra_dsi_readl(dsi, name))
99dec72739SThierry Reding 
100dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT);
101dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT_CONTROL);
102dec72739SThierry Reding 	DUMP_REG(DSI_INCR_SYNCPT_ERROR);
103dec72739SThierry Reding 	DUMP_REG(DSI_CTXSW);
104dec72739SThierry Reding 	DUMP_REG(DSI_RD_DATA);
105dec72739SThierry Reding 	DUMP_REG(DSI_WR_DATA);
106dec72739SThierry Reding 	DUMP_REG(DSI_POWER_CONTROL);
107dec72739SThierry Reding 	DUMP_REG(DSI_INT_ENABLE);
108dec72739SThierry Reding 	DUMP_REG(DSI_INT_STATUS);
109dec72739SThierry Reding 	DUMP_REG(DSI_INT_MASK);
110dec72739SThierry Reding 	DUMP_REG(DSI_HOST_CONTROL);
111dec72739SThierry Reding 	DUMP_REG(DSI_CONTROL);
112dec72739SThierry Reding 	DUMP_REG(DSI_SOL_DELAY);
113dec72739SThierry Reding 	DUMP_REG(DSI_MAX_THRESHOLD);
114dec72739SThierry Reding 	DUMP_REG(DSI_TRIGGER);
115dec72739SThierry Reding 	DUMP_REG(DSI_TX_CRC);
116dec72739SThierry Reding 	DUMP_REG(DSI_STATUS);
117dec72739SThierry Reding 
118dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_CONTROL);
119dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_0);
120dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_1);
121dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_2);
122dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_3);
123dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_4);
124dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_5);
125dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_6);
126dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_7);
127dec72739SThierry Reding 
128dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_0_LO);
129dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_0_HI);
130dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_1_LO);
131dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_1_HI);
132dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_2_LO);
133dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_2_HI);
134dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_3_LO);
135dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_3_HI);
136dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_4_LO);
137dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_4_HI);
138dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_5_LO);
139dec72739SThierry Reding 	DUMP_REG(DSI_PKT_SEQ_5_HI);
140dec72739SThierry Reding 
141dec72739SThierry Reding 	DUMP_REG(DSI_DCS_CMDS);
142dec72739SThierry Reding 
143dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_0_1);
144dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_2_3);
145dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_4_5);
146dec72739SThierry Reding 	DUMP_REG(DSI_PKT_LEN_6_7);
147dec72739SThierry Reding 
148dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_0);
149dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_1);
150dec72739SThierry Reding 	DUMP_REG(DSI_PHY_TIMING_2);
151dec72739SThierry Reding 	DUMP_REG(DSI_BTA_TIMING);
152dec72739SThierry Reding 
153dec72739SThierry Reding 	DUMP_REG(DSI_TIMEOUT_0);
154dec72739SThierry Reding 	DUMP_REG(DSI_TIMEOUT_1);
155dec72739SThierry Reding 	DUMP_REG(DSI_TO_TALLY);
156dec72739SThierry Reding 
157dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_0);
158dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_CD);
159dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CD_STATUS);
160dec72739SThierry Reding 	DUMP_REG(DSI_VIDEO_MODE_CONTROL);
161dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_1);
162dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_2);
163dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_3);
164dec72739SThierry Reding 	DUMP_REG(DSI_PAD_CONTROL_4);
165dec72739SThierry Reding 
166dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_CONTROL);
167dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_START);
168dec72739SThierry Reding 	DUMP_REG(DSI_GANGED_MODE_SIZE);
169dec72739SThierry Reding 
170dec72739SThierry Reding 	DUMP_REG(DSI_RAW_DATA_BYTE_COUNT);
171dec72739SThierry Reding 	DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL);
172dec72739SThierry Reding 
173dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_8);
174dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_9);
175dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_10);
176dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_11);
177dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_12);
178dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_13);
179dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_14);
180dec72739SThierry Reding 	DUMP_REG(DSI_INIT_SEQ_DATA_15);
181dec72739SThierry Reding 
182dec72739SThierry Reding #undef DUMP_REG
183dec72739SThierry Reding 
184dec72739SThierry Reding 	return 0;
185dec72739SThierry Reding }
186dec72739SThierry Reding 
187dec72739SThierry Reding static struct drm_info_list debugfs_files[] = {
188dec72739SThierry Reding 	{ "regs", tegra_dsi_show_regs, 0, NULL },
189dec72739SThierry Reding };
190dec72739SThierry Reding 
191dec72739SThierry Reding static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi,
192dec72739SThierry Reding 				  struct drm_minor *minor)
193dec72739SThierry Reding {
194dec72739SThierry Reding 	const char *name = dev_name(dsi->dev);
195dec72739SThierry Reding 	unsigned int i;
196dec72739SThierry Reding 	int err;
197dec72739SThierry Reding 
198dec72739SThierry Reding 	dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root);
199dec72739SThierry Reding 	if (!dsi->debugfs)
200dec72739SThierry Reding 		return -ENOMEM;
201dec72739SThierry Reding 
202dec72739SThierry Reding 	dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
203dec72739SThierry Reding 				     GFP_KERNEL);
204dec72739SThierry Reding 	if (!dsi->debugfs_files) {
205dec72739SThierry Reding 		err = -ENOMEM;
206dec72739SThierry Reding 		goto remove;
207dec72739SThierry Reding 	}
208dec72739SThierry Reding 
209dec72739SThierry Reding 	for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
210dec72739SThierry Reding 		dsi->debugfs_files[i].data = dsi;
211dec72739SThierry Reding 
212dec72739SThierry Reding 	err = drm_debugfs_create_files(dsi->debugfs_files,
213dec72739SThierry Reding 				       ARRAY_SIZE(debugfs_files),
214dec72739SThierry Reding 				       dsi->debugfs, minor);
215dec72739SThierry Reding 	if (err < 0)
216dec72739SThierry Reding 		goto free;
217dec72739SThierry Reding 
218dec72739SThierry Reding 	dsi->minor = minor;
219dec72739SThierry Reding 
220dec72739SThierry Reding 	return 0;
221dec72739SThierry Reding 
222dec72739SThierry Reding free:
223dec72739SThierry Reding 	kfree(dsi->debugfs_files);
224dec72739SThierry Reding 	dsi->debugfs_files = NULL;
225dec72739SThierry Reding remove:
226dec72739SThierry Reding 	debugfs_remove(dsi->debugfs);
227dec72739SThierry Reding 	dsi->debugfs = NULL;
228dec72739SThierry Reding 
229dec72739SThierry Reding 	return err;
230dec72739SThierry Reding }
231dec72739SThierry Reding 
2324009c224SThierry Reding static void tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
233dec72739SThierry Reding {
234dec72739SThierry Reding 	drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
235dec72739SThierry Reding 				 dsi->minor);
236dec72739SThierry Reding 	dsi->minor = NULL;
237dec72739SThierry Reding 
238dec72739SThierry Reding 	kfree(dsi->debugfs_files);
239dec72739SThierry Reding 	dsi->debugfs_files = NULL;
240dec72739SThierry Reding 
241dec72739SThierry Reding 	debugfs_remove(dsi->debugfs);
242dec72739SThierry Reding 	dsi->debugfs = NULL;
243dec72739SThierry Reding }
244dec72739SThierry Reding 
245dec72739SThierry Reding #define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
246dec72739SThierry Reding #define PKT_LEN0(len)	(((len) & 0x07) <<  0)
247dec72739SThierry Reding #define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
248dec72739SThierry Reding #define PKT_LEN1(len)	(((len) & 0x07) << 10)
249dec72739SThierry Reding #define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
250dec72739SThierry Reding #define PKT_LEN2(len)	(((len) & 0x07) << 20)
251dec72739SThierry Reding 
252dec72739SThierry Reding #define PKT_LP		(1 << 30)
253dec72739SThierry Reding #define NUM_PKT_SEQ	12
254dec72739SThierry Reding 
25517297a28SThierry Reding /*
25617297a28SThierry Reding  * non-burst mode with sync pulses
25717297a28SThierry Reding  */
25817297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
259dec72739SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
260dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
261dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
262dec72739SThierry Reding 	       PKT_LP,
263dec72739SThierry Reding 	[ 1] = 0,
264dec72739SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
265dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
266dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
267dec72739SThierry Reding 	       PKT_LP,
268dec72739SThierry Reding 	[ 3] = 0,
269dec72739SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
270dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
271dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
272dec72739SThierry Reding 	       PKT_LP,
273dec72739SThierry Reding 	[ 5] = 0,
274dec72739SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
275dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
276dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
277dec72739SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
278dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
279dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
280dec72739SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
281dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
282dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
283dec72739SThierry Reding 	       PKT_LP,
284dec72739SThierry Reding 	[ 9] = 0,
285dec72739SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
286dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
287dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
288dec72739SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
289dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
290dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
291dec72739SThierry Reding };
292dec72739SThierry Reding 
29317297a28SThierry Reding /*
29417297a28SThierry Reding  * non-burst mode with sync events
29517297a28SThierry Reding  */
29617297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
29717297a28SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
29817297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
29917297a28SThierry Reding 	       PKT_LP,
30017297a28SThierry Reding 	[ 1] = 0,
30117297a28SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
30217297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
30317297a28SThierry Reding 	       PKT_LP,
30417297a28SThierry Reding 	[ 3] = 0,
30517297a28SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
30617297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
30717297a28SThierry Reding 	       PKT_LP,
30817297a28SThierry Reding 	[ 5] = 0,
30917297a28SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
31017297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
31117297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
31217297a28SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
31317297a28SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
31417297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
31517297a28SThierry Reding 	       PKT_LP,
31617297a28SThierry Reding 	[ 9] = 0,
31717297a28SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
31817297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
31917297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
32017297a28SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
32117297a28SThierry Reding };
32217297a28SThierry Reding 
323337b443dSThierry Reding static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
324337b443dSThierry Reding 	[ 0] = 0,
325337b443dSThierry Reding 	[ 1] = 0,
326337b443dSThierry Reding 	[ 2] = 0,
327337b443dSThierry Reding 	[ 3] = 0,
328337b443dSThierry Reding 	[ 4] = 0,
329337b443dSThierry Reding 	[ 5] = 0,
330337b443dSThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
331337b443dSThierry Reding 	[ 7] = 0,
332337b443dSThierry Reding 	[ 8] = 0,
333337b443dSThierry Reding 	[ 9] = 0,
334337b443dSThierry Reding 	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
335337b443dSThierry Reding 	[11] = 0,
336337b443dSThierry Reding };
337337b443dSThierry Reding 
338dec72739SThierry Reding static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
339dec72739SThierry Reding {
340dec72739SThierry Reding 	struct mipi_dphy_timing timing;
3419c0b4ca1SThierry Reding 	unsigned long period;
3429c0b4ca1SThierry Reding 	u32 value;
343dec72739SThierry Reding 	long rate;
344dec72739SThierry Reding 	int err;
345dec72739SThierry Reding 
346dec72739SThierry Reding 	rate = clk_get_rate(dsi->clk);
347dec72739SThierry Reding 	if (rate < 0)
348dec72739SThierry Reding 		return rate;
349dec72739SThierry Reding 
350369bc65bSThierry Reding 	period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
351dec72739SThierry Reding 
352dec72739SThierry Reding 	err = mipi_dphy_timing_get_default(&timing, period);
353dec72739SThierry Reding 	if (err < 0)
354dec72739SThierry Reding 		return err;
355dec72739SThierry Reding 
356dec72739SThierry Reding 	err = mipi_dphy_timing_validate(&timing, period);
357dec72739SThierry Reding 	if (err < 0) {
358dec72739SThierry Reding 		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
359dec72739SThierry Reding 		return err;
360dec72739SThierry Reding 	}
361dec72739SThierry Reding 
362dec72739SThierry Reding 	/*
363dec72739SThierry Reding 	 * The D-PHY timing fields below are expressed in byte-clock cycles,
364dec72739SThierry Reding 	 * so multiply the period by 8.
365dec72739SThierry Reding 	 */
366dec72739SThierry Reding 	period *= 8;
367dec72739SThierry Reding 
368dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
369dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
370dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
371dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.hsprepare, period, 1);
372dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
373dec72739SThierry Reding 
374dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
375dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
376dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
377dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.lpx, period, 1);
378dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
379dec72739SThierry Reding 
380dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
381dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
382dec72739SThierry Reding 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
383dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
384dec72739SThierry Reding 
385dec72739SThierry Reding 	value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
386dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
387dec72739SThierry Reding 		DSI_TIMING_FIELD(timing.tago, period, 1);
388dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
389dec72739SThierry Reding 
3907e3bc3a9SSean Paul 	if (dsi->slave)
3917e3bc3a9SSean Paul 		return tegra_dsi_set_phy_timing(dsi->slave);
3927e3bc3a9SSean Paul 
393dec72739SThierry Reding 	return 0;
394dec72739SThierry Reding }
395dec72739SThierry Reding 
396dec72739SThierry Reding static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
397dec72739SThierry Reding 				unsigned int *mulp, unsigned int *divp)
398dec72739SThierry Reding {
399dec72739SThierry Reding 	switch (format) {
400dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
401dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB888:
402dec72739SThierry Reding 		*mulp = 3;
403dec72739SThierry Reding 		*divp = 1;
404dec72739SThierry Reding 		break;
405dec72739SThierry Reding 
406dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB565:
407dec72739SThierry Reding 		*mulp = 2;
408dec72739SThierry Reding 		*divp = 1;
409dec72739SThierry Reding 		break;
410dec72739SThierry Reding 
411dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666:
412dec72739SThierry Reding 		*mulp = 9;
413dec72739SThierry Reding 		*divp = 4;
414dec72739SThierry Reding 		break;
415dec72739SThierry Reding 
416dec72739SThierry Reding 	default:
417dec72739SThierry Reding 		return -EINVAL;
418dec72739SThierry Reding 	}
419dec72739SThierry Reding 
420dec72739SThierry Reding 	return 0;
421dec72739SThierry Reding }
422dec72739SThierry Reding 
423f7d6889bSThierry Reding static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
424f7d6889bSThierry Reding 				enum tegra_dsi_format *fmt)
425f7d6889bSThierry Reding {
426f7d6889bSThierry Reding 	switch (format) {
427f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB888:
428f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_24P;
429f7d6889bSThierry Reding 		break;
430f7d6889bSThierry Reding 
431f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666:
432f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18NP;
433f7d6889bSThierry Reding 		break;
434f7d6889bSThierry Reding 
435f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
436f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18P;
437f7d6889bSThierry Reding 		break;
438f7d6889bSThierry Reding 
439f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB565:
440f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_16P;
441f7d6889bSThierry Reding 		break;
442f7d6889bSThierry Reding 
443f7d6889bSThierry Reding 	default:
444f7d6889bSThierry Reding 		return -EINVAL;
445f7d6889bSThierry Reding 	}
446f7d6889bSThierry Reding 
447f7d6889bSThierry Reding 	return 0;
448f7d6889bSThierry Reding }
449f7d6889bSThierry Reding 
450e94236cdSThierry Reding static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
451e94236cdSThierry Reding 				    unsigned int size)
452e94236cdSThierry Reding {
453e94236cdSThierry Reding 	u32 value;
454e94236cdSThierry Reding 
455e94236cdSThierry Reding 	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
456e94236cdSThierry Reding 	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
457e94236cdSThierry Reding 
458e94236cdSThierry Reding 	value = DSI_GANGED_MODE_CONTROL_ENABLE;
459e94236cdSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
460e94236cdSThierry Reding }
461e94236cdSThierry Reding 
462563eff1fSThierry Reding static void tegra_dsi_enable(struct tegra_dsi *dsi)
463dec72739SThierry Reding {
464563eff1fSThierry Reding 	u32 value;
465dec72739SThierry Reding 
466563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
467563eff1fSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
468563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
469e94236cdSThierry Reding 
470e94236cdSThierry Reding 	if (dsi->slave)
471e94236cdSThierry Reding 		tegra_dsi_enable(dsi->slave);
472e94236cdSThierry Reding }
473e94236cdSThierry Reding 
474e94236cdSThierry Reding static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
475e94236cdSThierry Reding {
476e94236cdSThierry Reding 	if (dsi->master)
477e94236cdSThierry Reding 		return dsi->master->lanes + dsi->lanes;
478e94236cdSThierry Reding 
479e94236cdSThierry Reding 	if (dsi->slave)
480e94236cdSThierry Reding 		return dsi->lanes + dsi->slave->lanes;
481e94236cdSThierry Reding 
482e94236cdSThierry Reding 	return dsi->lanes;
483563eff1fSThierry Reding }
484563eff1fSThierry Reding 
485563eff1fSThierry Reding static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
486563eff1fSThierry Reding 			       const struct drm_display_mode *mode)
487563eff1fSThierry Reding {
488563eff1fSThierry Reding 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
489563eff1fSThierry Reding 	enum tegra_dsi_format format;
490563eff1fSThierry Reding 	const u32 *pkt_seq;
491563eff1fSThierry Reding 	u32 value;
492563eff1fSThierry Reding 	int err;
493334ae6b5SThierry Reding 
49417297a28SThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
49517297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
49617297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
497337b443dSThierry Reding 	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
49817297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
49917297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_events;
500337b443dSThierry Reding 	} else {
501337b443dSThierry Reding 		DRM_DEBUG_KMS("Command mode\n");
502337b443dSThierry Reding 		pkt_seq = pkt_seq_command_mode;
50317297a28SThierry Reding 	}
50417297a28SThierry Reding 
505dec72739SThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
506dec72739SThierry Reding 	if (err < 0)
507dec72739SThierry Reding 		return err;
508dec72739SThierry Reding 
509f7d6889bSThierry Reding 	err = tegra_dsi_get_format(dsi->format, &format);
510f7d6889bSThierry Reding 	if (err < 0)
511f7d6889bSThierry Reding 		return err;
512f7d6889bSThierry Reding 
513f7d6889bSThierry Reding 	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
514dec72739SThierry Reding 		DSI_CONTROL_LANES(dsi->lanes - 1) |
515563eff1fSThierry Reding 		DSI_CONTROL_SOURCE(pipe);
516dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
517dec72739SThierry Reding 
518976cebc3SThierry Reding 	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
519dec72739SThierry Reding 
520563eff1fSThierry Reding 	value = DSI_HOST_CONTROL_HS;
521dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
522dec72739SThierry Reding 
523dec72739SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
524563eff1fSThierry Reding 
5250c6b1e4bSAlexandre Courbot 	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
526dec72739SThierry Reding 		value |= DSI_CONTROL_HS_CLK_CTRL;
527563eff1fSThierry Reding 
528dec72739SThierry Reding 	value &= ~DSI_CONTROL_TX_TRIG(3);
529337b443dSThierry Reding 
530337b443dSThierry Reding 	/* enable DCS commands for command mode */
531337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
532dec72739SThierry Reding 		value &= ~DSI_CONTROL_DCS_ENABLE;
533337b443dSThierry Reding 	else
534337b443dSThierry Reding 		value |= DSI_CONTROL_DCS_ENABLE;
535337b443dSThierry Reding 
536dec72739SThierry Reding 	value |= DSI_CONTROL_VIDEO_ENABLE;
537dec72739SThierry Reding 	value &= ~DSI_CONTROL_HOST_ENABLE;
538dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
539dec72739SThierry Reding 
540dec72739SThierry Reding 	for (i = 0; i < NUM_PKT_SEQ; i++)
541dec72739SThierry Reding 		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
542dec72739SThierry Reding 
543337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
544dec72739SThierry Reding 		/* horizontal active pixels */
545dec72739SThierry Reding 		hact = mode->hdisplay * mul / div;
546dec72739SThierry Reding 
547dec72739SThierry Reding 		/* horizontal sync width */
548dec72739SThierry Reding 		hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
549dec72739SThierry Reding 		hsw -= 10;
550dec72739SThierry Reding 
551dec72739SThierry Reding 		/* horizontal back porch */
552dec72739SThierry Reding 		hbp = (mode->htotal - mode->hsync_end) * mul / div;
553dec72739SThierry Reding 		hbp -= 14;
554dec72739SThierry Reding 
555dec72739SThierry Reding 		/* horizontal front porch */
556dec72739SThierry Reding 		hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
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 int lanes = tegra_dsi_get_lanes(dsi);
593e94236cdSThierry Reding 			unsigned long delay, bclk, bclk_ganged;
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) {
613e94236cdSThierry Reding 		err = tegra_dsi_configure(dsi->slave, pipe, mode);
614e94236cdSThierry Reding 		if (err < 0)
615e94236cdSThierry Reding 			return err;
616e94236cdSThierry Reding 
617e94236cdSThierry Reding 		/*
618e94236cdSThierry Reding 		 * TODO: Support modes other than symmetrical left-right
619e94236cdSThierry Reding 		 * split.
620e94236cdSThierry Reding 		 */
621e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
622e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
623e94236cdSThierry Reding 					mode->hdisplay / 2);
624e94236cdSThierry Reding 	}
625e94236cdSThierry Reding 
626563eff1fSThierry Reding 	return 0;
627563eff1fSThierry Reding }
628563eff1fSThierry Reding 
629563eff1fSThierry Reding static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
630563eff1fSThierry Reding {
631563eff1fSThierry Reding 	u32 value;
632563eff1fSThierry Reding 
633563eff1fSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
634563eff1fSThierry Reding 
635563eff1fSThierry Reding 	while (time_before(jiffies, timeout)) {
636563eff1fSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_STATUS);
637563eff1fSThierry Reding 		if (value & DSI_STATUS_IDLE)
638563eff1fSThierry Reding 			return 0;
639563eff1fSThierry Reding 
640563eff1fSThierry Reding 		usleep_range(1000, 2000);
641563eff1fSThierry Reding 	}
642563eff1fSThierry Reding 
643563eff1fSThierry Reding 	return -ETIMEDOUT;
644563eff1fSThierry Reding }
645563eff1fSThierry Reding 
646563eff1fSThierry Reding static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
647563eff1fSThierry Reding {
648563eff1fSThierry Reding 	u32 value;
649563eff1fSThierry Reding 
650563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
651563eff1fSThierry Reding 	value &= ~DSI_CONTROL_VIDEO_ENABLE;
652563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
653e94236cdSThierry Reding 
654e94236cdSThierry Reding 	if (dsi->slave)
655e94236cdSThierry Reding 		tegra_dsi_video_disable(dsi->slave);
656e94236cdSThierry Reding }
657e94236cdSThierry Reding 
658e94236cdSThierry Reding static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
659e94236cdSThierry Reding {
660e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
661e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
662e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
663563eff1fSThierry Reding }
664563eff1fSThierry Reding 
6655b901e78SThierry Reding static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
6665b901e78SThierry Reding 				  unsigned int vrefresh)
6675b901e78SThierry Reding {
6685b901e78SThierry Reding 	unsigned int timeout;
6695b901e78SThierry Reding 	u32 value;
6705b901e78SThierry Reding 
6715b901e78SThierry Reding 	/* one frame high-speed transmission timeout */
6725b901e78SThierry Reding 	timeout = (bclk / vrefresh) / 512;
6735b901e78SThierry Reding 	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
6745b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
6755b901e78SThierry Reding 
6765b901e78SThierry Reding 	/* 2 ms peripheral timeout for panel */
6775b901e78SThierry Reding 	timeout = 2 * bclk / 512 * 1000;
6785b901e78SThierry Reding 	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
6795b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
6805b901e78SThierry Reding 
6815b901e78SThierry Reding 	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
6825b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
6835b901e78SThierry Reding 
6845b901e78SThierry Reding 	if (dsi->slave)
6855b901e78SThierry Reding 		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
6865b901e78SThierry Reding }
6875b901e78SThierry Reding 
688563eff1fSThierry Reding static void tegra_dsi_disable(struct tegra_dsi *dsi)
689563eff1fSThierry Reding {
690563eff1fSThierry Reding 	u32 value;
691563eff1fSThierry Reding 
692e94236cdSThierry Reding 	if (dsi->slave) {
693e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi->slave);
694e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi);
695e94236cdSThierry Reding 	}
696e94236cdSThierry Reding 
697563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
698563eff1fSThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
699563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
700563eff1fSThierry Reding 
701e94236cdSThierry Reding 	if (dsi->slave)
702e94236cdSThierry Reding 		tegra_dsi_disable(dsi->slave);
703e94236cdSThierry Reding 
704563eff1fSThierry Reding 	usleep_range(5000, 10000);
705563eff1fSThierry Reding }
706563eff1fSThierry Reding 
70792f0e073SThierry Reding static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
70892f0e073SThierry Reding {
70992f0e073SThierry Reding 	u32 value;
71092f0e073SThierry Reding 
71192f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
71292f0e073SThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
71392f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
71492f0e073SThierry Reding 
71592f0e073SThierry Reding 	usleep_range(300, 1000);
71692f0e073SThierry Reding 
71792f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
71892f0e073SThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
71992f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
72092f0e073SThierry Reding 
72192f0e073SThierry Reding 	usleep_range(300, 1000);
72292f0e073SThierry Reding 
72392f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_TRIGGER);
72492f0e073SThierry Reding 	if (value)
72592f0e073SThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
72692f0e073SThierry Reding 
72792f0e073SThierry Reding 	if (dsi->slave)
72892f0e073SThierry Reding 		tegra_dsi_soft_reset(dsi->slave);
72992f0e073SThierry Reding }
73092f0e073SThierry Reding 
7315b901e78SThierry Reding static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
732dec72739SThierry Reding {
7335b901e78SThierry Reding }
7345b901e78SThierry Reding 
7355b901e78SThierry Reding static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
7365b901e78SThierry Reding 	.dpms = tegra_dsi_connector_dpms,
7375b901e78SThierry Reding 	.detect = tegra_output_connector_detect,
7385b901e78SThierry Reding 	.fill_modes = drm_helper_probe_single_connector_modes,
7395b901e78SThierry Reding 	.destroy = tegra_output_connector_destroy,
740*4aa3df71SThierry Reding 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
7415b901e78SThierry Reding };
7425b901e78SThierry Reding 
7435b901e78SThierry Reding static enum drm_mode_status
7445b901e78SThierry Reding tegra_dsi_connector_mode_valid(struct drm_connector *connector,
7455b901e78SThierry Reding 			       struct drm_display_mode *mode)
7465b901e78SThierry Reding {
7475b901e78SThierry Reding 	return MODE_OK;
7485b901e78SThierry Reding }
7495b901e78SThierry Reding 
7505b901e78SThierry Reding static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
7515b901e78SThierry Reding 	.get_modes = tegra_output_connector_get_modes,
7525b901e78SThierry Reding 	.mode_valid = tegra_dsi_connector_mode_valid,
7535b901e78SThierry Reding 	.best_encoder = tegra_output_connector_best_encoder,
7545b901e78SThierry Reding };
7555b901e78SThierry Reding 
7565b901e78SThierry Reding static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
7575b901e78SThierry Reding 	.destroy = tegra_output_encoder_destroy,
7585b901e78SThierry Reding };
7595b901e78SThierry Reding 
7605b901e78SThierry Reding static void tegra_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
7615b901e78SThierry Reding {
7625b901e78SThierry Reding }
7635b901e78SThierry Reding 
7645b901e78SThierry Reding static bool tegra_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
7655b901e78SThierry Reding 					 const struct drm_display_mode *mode,
7665b901e78SThierry Reding 					 struct drm_display_mode *adjusted)
7675b901e78SThierry Reding {
7685b901e78SThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
7695b901e78SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
7705b901e78SThierry Reding 	unsigned int mul, div, scdiv, vrefresh, lanes;
771dec72739SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
7725b901e78SThierry Reding 	unsigned long pclk, bclk, plld;
773dec72739SThierry Reding 	int err;
774dec72739SThierry Reding 
775e94236cdSThierry Reding 	lanes = tegra_dsi_get_lanes(dsi);
7765b901e78SThierry Reding 	pclk = mode->clock * 1000;
777e94236cdSThierry Reding 
778dec72739SThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
779dec72739SThierry Reding 	if (err < 0)
780dec72739SThierry Reding 		return err;
781dec72739SThierry Reding 
782e94236cdSThierry Reding 	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes);
783dec72739SThierry Reding 	vrefresh = drm_mode_vrefresh(mode);
78491eded9bSThierry Reding 	DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
785dec72739SThierry Reding 
78691eded9bSThierry Reding 	/* compute byte clock */
787e94236cdSThierry Reding 	bclk = (pclk * mul) / (div * lanes);
78891eded9bSThierry Reding 
78991eded9bSThierry Reding 	/*
79091eded9bSThierry Reding 	 * Compute bit clock and round up to the next MHz.
79191eded9bSThierry Reding 	 */
792030611ecSThierry Reding 	plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
79391eded9bSThierry Reding 
79491eded9bSThierry Reding 	/*
79591eded9bSThierry Reding 	 * We divide the frequency by two here, but we make up for that by
79691eded9bSThierry Reding 	 * setting the shift clock divider (further below) to half of the
79791eded9bSThierry Reding 	 * correct value.
79891eded9bSThierry Reding 	 */
79991eded9bSThierry Reding 	plld /= 2;
800dec72739SThierry Reding 
801dec72739SThierry Reding 	/*
80291eded9bSThierry Reding 	 * Derive pixel clock from bit clock using the shift clock divider.
80391eded9bSThierry Reding 	 * Note that this is only half of what we would expect, but we need
80491eded9bSThierry Reding 	 * that to make up for the fact that we divided the bit clock by a
80591eded9bSThierry Reding 	 * factor of two above.
80691eded9bSThierry Reding 	 *
80791eded9bSThierry Reding 	 * It's not clear exactly why this is necessary, but the display is
80891eded9bSThierry Reding 	 * not working properly otherwise. Perhaps the PLLs cannot generate
80991eded9bSThierry Reding 	 * frequencies sufficiently high.
81091eded9bSThierry Reding 	 */
8115b901e78SThierry Reding 	scdiv = ((8 * mul) / (div * lanes)) - 2;
81291eded9bSThierry Reding 
8135b901e78SThierry Reding 	err = tegra_dc_setup_clock(dc, dsi->clk_parent, plld, scdiv);
8145b901e78SThierry Reding 	if (err < 0) {
8155b901e78SThierry Reding 		dev_err(output->dev, "failed to setup DC clock: %d\n", err);
8165b901e78SThierry Reding 		return false;
8175b901e78SThierry Reding 	}
8185b901e78SThierry Reding 
8195b901e78SThierry Reding 	err = clk_set_rate(dsi->clk_parent, plld);
8205b901e78SThierry Reding 	if (err < 0) {
8215b901e78SThierry Reding 		dev_err(dsi->dev, "failed to set clock rate to %lu Hz\n",
8225b901e78SThierry Reding 			plld);
8235b901e78SThierry Reding 		return false;
8245b901e78SThierry Reding 	}
8255b901e78SThierry Reding 
8263f6b406fSThierry Reding 	tegra_dsi_set_timeout(dsi, bclk, vrefresh);
827dec72739SThierry Reding 
8287e3bc3a9SSean Paul 	err = tegra_dsi_set_phy_timing(dsi);
8295b901e78SThierry Reding 	if (err < 0) {
8305b901e78SThierry Reding 		dev_err(dsi->dev, "failed to setup D-PHY timing: %d\n", err);
8315b901e78SThierry Reding 		return false;
832dec72739SThierry Reding 	}
833dec72739SThierry Reding 
8345b901e78SThierry Reding 	return true;
8355b901e78SThierry Reding }
8365b901e78SThierry Reding 
8375b901e78SThierry Reding static void tegra_dsi_encoder_prepare(struct drm_encoder *encoder)
838dec72739SThierry Reding {
839dec72739SThierry Reding }
840dec72739SThierry Reding 
8415b901e78SThierry Reding static void tegra_dsi_encoder_commit(struct drm_encoder *encoder)
8425b901e78SThierry Reding {
8435b901e78SThierry Reding }
8445b901e78SThierry Reding 
8455b901e78SThierry Reding static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
8465b901e78SThierry Reding 				       struct drm_display_mode *mode,
8475b901e78SThierry Reding 				       struct drm_display_mode *adjusted)
8485b901e78SThierry Reding {
8495b901e78SThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
8505b901e78SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
8515b901e78SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
8525b901e78SThierry Reding 	u32 value;
8535b901e78SThierry Reding 	int err;
8545b901e78SThierry Reding 
8555b901e78SThierry Reding 
8565b901e78SThierry Reding 	err = tegra_dsi_configure(dsi, dc->pipe, mode);
8575b901e78SThierry Reding 	if (err < 0) {
8585b901e78SThierry Reding 		dev_err(dsi->dev, "failed to configure DSI: %d\n", err);
8595b901e78SThierry Reding 		return;
8605b901e78SThierry Reding 	}
8615b901e78SThierry Reding 
8625b901e78SThierry Reding 	if (output->panel)
8635b901e78SThierry Reding 		drm_panel_prepare(output->panel);
8645b901e78SThierry Reding 
8655b901e78SThierry Reding 	/* enable display controller */
8665b901e78SThierry Reding 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
8675b901e78SThierry Reding 	value |= DSI_ENABLE;
8685b901e78SThierry Reding 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
8695b901e78SThierry Reding 
8705b901e78SThierry Reding 	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
8715b901e78SThierry Reding 	value &= ~DISP_CTRL_MODE_MASK;
8725b901e78SThierry Reding 	value |= DISP_CTRL_MODE_C_DISPLAY;
8735b901e78SThierry Reding 	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
8745b901e78SThierry Reding 
8755b901e78SThierry Reding 	value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
8765b901e78SThierry Reding 	value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
8775b901e78SThierry Reding 		 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
8785b901e78SThierry Reding 	tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
8795b901e78SThierry Reding 
8805b901e78SThierry Reding 	tegra_dc_commit(dc);
8815b901e78SThierry Reding 
8825b901e78SThierry Reding 	/* enable DSI controller */
8835b901e78SThierry Reding 	tegra_dsi_enable(dsi);
8845b901e78SThierry Reding 
8855b901e78SThierry Reding 	if (output->panel)
8865b901e78SThierry Reding 		drm_panel_enable(output->panel);
8875b901e78SThierry Reding 
8885b901e78SThierry Reding 	return;
8895b901e78SThierry Reding }
8905b901e78SThierry Reding 
8915b901e78SThierry Reding static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
8925b901e78SThierry Reding {
8935b901e78SThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
8945b901e78SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
8955b901e78SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
8965b901e78SThierry Reding 	u32 value;
8975b901e78SThierry Reding 	int err;
8985b901e78SThierry Reding 
8995b901e78SThierry Reding 	if (output->panel)
9005b901e78SThierry Reding 		drm_panel_disable(output->panel);
9015b901e78SThierry Reding 
9025b901e78SThierry Reding 	tegra_dsi_video_disable(dsi);
9035b901e78SThierry Reding 
9045b901e78SThierry Reding 	/*
9055b901e78SThierry Reding 	 * The following accesses registers of the display controller, so make
9065b901e78SThierry Reding 	 * sure it's only executed when the output is attached to one.
9075b901e78SThierry Reding 	 */
9085b901e78SThierry Reding 	if (dc) {
9095b901e78SThierry Reding 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
9105b901e78SThierry Reding 		value &= ~DSI_ENABLE;
9115b901e78SThierry Reding 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
9125b901e78SThierry Reding 
9135b901e78SThierry Reding 		tegra_dc_commit(dc);
9145b901e78SThierry Reding 	}
9155b901e78SThierry Reding 
9165b901e78SThierry Reding 	err = tegra_dsi_wait_idle(dsi, 100);
9175b901e78SThierry Reding 	if (err < 0)
9185b901e78SThierry Reding 		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
9195b901e78SThierry Reding 
9205b901e78SThierry Reding 	tegra_dsi_soft_reset(dsi);
9215b901e78SThierry Reding 
9225b901e78SThierry Reding 	if (output->panel)
9235b901e78SThierry Reding 		drm_panel_unprepare(output->panel);
9245b901e78SThierry Reding 
9255b901e78SThierry Reding 	tegra_dsi_disable(dsi);
9265b901e78SThierry Reding 
9275b901e78SThierry Reding 	return;
9285b901e78SThierry Reding }
9295b901e78SThierry Reding 
9305b901e78SThierry Reding static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
9315b901e78SThierry Reding 	.dpms = tegra_dsi_encoder_dpms,
9325b901e78SThierry Reding 	.mode_fixup = tegra_dsi_encoder_mode_fixup,
9335b901e78SThierry Reding 	.prepare = tegra_dsi_encoder_prepare,
9345b901e78SThierry Reding 	.commit = tegra_dsi_encoder_commit,
9355b901e78SThierry Reding 	.mode_set = tegra_dsi_encoder_mode_set,
9365b901e78SThierry Reding 	.disable = tegra_dsi_encoder_disable,
937dec72739SThierry Reding };
938dec72739SThierry Reding 
939dec72739SThierry Reding static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
940dec72739SThierry Reding {
9419c0b4ca1SThierry Reding 	u32 value;
942dec72739SThierry Reding 
943dec72739SThierry Reding 	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
944dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
945dec72739SThierry Reding 
946dec72739SThierry Reding 	return 0;
947dec72739SThierry Reding }
948dec72739SThierry Reding 
949dec72739SThierry Reding static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
950dec72739SThierry Reding {
951183ef288SThierry Reding 	u32 value;
952dec72739SThierry Reding 
953dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
954dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
955dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
956dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
957dec72739SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
958dec72739SThierry Reding 
959dec72739SThierry Reding 	/* start calibration */
960dec72739SThierry Reding 	tegra_dsi_pad_enable(dsi);
961dec72739SThierry Reding 
962dec72739SThierry Reding 	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
963dec72739SThierry Reding 		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
964dec72739SThierry Reding 		DSI_PAD_OUT_CLK(0x0);
965dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
966dec72739SThierry Reding 
967dec72739SThierry Reding 	return tegra_mipi_calibrate(dsi->mipi);
968dec72739SThierry Reding }
969dec72739SThierry Reding 
970dec72739SThierry Reding static int tegra_dsi_init(struct host1x_client *client)
971dec72739SThierry Reding {
9729910f5c4SThierry Reding 	struct drm_device *drm = dev_get_drvdata(client->parent);
973dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
974dec72739SThierry Reding 	int err;
975dec72739SThierry Reding 
976201106d8SThierry Reding 	reset_control_deassert(dsi->rst);
977201106d8SThierry Reding 
978201106d8SThierry Reding 	err = tegra_dsi_pad_calibrate(dsi);
979201106d8SThierry Reding 	if (err < 0) {
980201106d8SThierry Reding 		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
981201106d8SThierry Reding 		goto reset;
982201106d8SThierry Reding 	}
983201106d8SThierry Reding 
984e94236cdSThierry Reding 	/* Gangsters must not register their own outputs. */
985e94236cdSThierry Reding 	if (!dsi->master) {
986dec72739SThierry Reding 		dsi->output.dev = client->dev;
987dec72739SThierry Reding 
9885b901e78SThierry Reding 		drm_connector_init(drm, &dsi->output.connector,
9895b901e78SThierry Reding 				   &tegra_dsi_connector_funcs,
9905b901e78SThierry Reding 				   DRM_MODE_CONNECTOR_DSI);
9915b901e78SThierry Reding 		drm_connector_helper_add(&dsi->output.connector,
9925b901e78SThierry Reding 					 &tegra_dsi_connector_helper_funcs);
9935b901e78SThierry Reding 		dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
9945b901e78SThierry Reding 
9955b901e78SThierry Reding 		drm_encoder_init(drm, &dsi->output.encoder,
9965b901e78SThierry Reding 				 &tegra_dsi_encoder_funcs,
9975b901e78SThierry Reding 				 DRM_MODE_ENCODER_DSI);
9985b901e78SThierry Reding 		drm_encoder_helper_add(&dsi->output.encoder,
9995b901e78SThierry Reding 				       &tegra_dsi_encoder_helper_funcs);
10005b901e78SThierry Reding 
10015b901e78SThierry Reding 		drm_mode_connector_attach_encoder(&dsi->output.connector,
10025b901e78SThierry Reding 						  &dsi->output.encoder);
10035b901e78SThierry Reding 		drm_connector_register(&dsi->output.connector);
10045b901e78SThierry Reding 
1005ea130b24SThierry Reding 		err = tegra_output_init(drm, &dsi->output);
1006ea130b24SThierry Reding 		if (err < 0) {
1007ea130b24SThierry Reding 			dev_err(client->dev,
1008ea130b24SThierry Reding 				"failed to initialize output: %d\n",
1009ea130b24SThierry Reding 				err);
1010ea130b24SThierry Reding 			goto reset;
1011ea130b24SThierry Reding 		}
1012ea130b24SThierry Reding 
10135b901e78SThierry Reding 		dsi->output.encoder.possible_crtcs = 0x3;
1014e94236cdSThierry Reding 	}
1015dec72739SThierry Reding 
1016dec72739SThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
10179910f5c4SThierry Reding 		err = tegra_dsi_debugfs_init(dsi, drm->primary);
1018dec72739SThierry Reding 		if (err < 0)
1019dec72739SThierry Reding 			dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
1020dec72739SThierry Reding 	}
1021dec72739SThierry Reding 
1022dec72739SThierry Reding 	return 0;
1023201106d8SThierry Reding 
1024201106d8SThierry Reding reset:
1025201106d8SThierry Reding 	reset_control_assert(dsi->rst);
1026201106d8SThierry Reding 	return err;
1027dec72739SThierry Reding }
1028dec72739SThierry Reding 
1029dec72739SThierry Reding static int tegra_dsi_exit(struct host1x_client *client)
1030dec72739SThierry Reding {
1031dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1032dec72739SThierry Reding 
10335b901e78SThierry Reding 	tegra_output_exit(&dsi->output);
10345b901e78SThierry Reding 
10354009c224SThierry Reding 	if (IS_ENABLED(CONFIG_DEBUG_FS))
10364009c224SThierry Reding 		tegra_dsi_debugfs_exit(dsi);
1037dec72739SThierry Reding 
1038201106d8SThierry Reding 	reset_control_assert(dsi->rst);
1039201106d8SThierry Reding 
1040dec72739SThierry Reding 	return 0;
1041dec72739SThierry Reding }
1042dec72739SThierry Reding 
1043dec72739SThierry Reding static const struct host1x_client_ops dsi_client_ops = {
1044dec72739SThierry Reding 	.init = tegra_dsi_init,
1045dec72739SThierry Reding 	.exit = tegra_dsi_exit,
1046dec72739SThierry Reding };
1047dec72739SThierry Reding 
1048dec72739SThierry Reding static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
1049dec72739SThierry Reding {
1050dec72739SThierry Reding 	struct clk *parent;
1051dec72739SThierry Reding 	int err;
1052dec72739SThierry Reding 
1053dec72739SThierry Reding 	parent = clk_get_parent(dsi->clk);
1054dec72739SThierry Reding 	if (!parent)
1055dec72739SThierry Reding 		return -EINVAL;
1056dec72739SThierry Reding 
1057dec72739SThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1058dec72739SThierry Reding 	if (err < 0)
1059dec72739SThierry Reding 		return err;
1060dec72739SThierry Reding 
1061dec72739SThierry Reding 	return 0;
1062dec72739SThierry Reding }
1063dec72739SThierry Reding 
10640fffdf6cSThierry Reding static const char * const error_report[16] = {
10650fffdf6cSThierry Reding 	"SoT Error",
10660fffdf6cSThierry Reding 	"SoT Sync Error",
10670fffdf6cSThierry Reding 	"EoT Sync Error",
10680fffdf6cSThierry Reding 	"Escape Mode Entry Command Error",
10690fffdf6cSThierry Reding 	"Low-Power Transmit Sync Error",
10700fffdf6cSThierry Reding 	"Peripheral Timeout Error",
10710fffdf6cSThierry Reding 	"False Control Error",
10720fffdf6cSThierry Reding 	"Contention Detected",
10730fffdf6cSThierry Reding 	"ECC Error, single-bit",
10740fffdf6cSThierry Reding 	"ECC Error, multi-bit",
10750fffdf6cSThierry Reding 	"Checksum Error",
10760fffdf6cSThierry Reding 	"DSI Data Type Not Recognized",
10770fffdf6cSThierry Reding 	"DSI VC ID Invalid",
10780fffdf6cSThierry Reding 	"Invalid Transmission Length",
10790fffdf6cSThierry Reding 	"Reserved",
10800fffdf6cSThierry Reding 	"DSI Protocol Violation",
10810fffdf6cSThierry Reding };
10820fffdf6cSThierry Reding 
10830fffdf6cSThierry Reding static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
10840fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg,
10850fffdf6cSThierry Reding 				       size_t count)
10860fffdf6cSThierry Reding {
10870fffdf6cSThierry Reding 	u8 *rx = msg->rx_buf;
10880fffdf6cSThierry Reding 	unsigned int i, j, k;
10890fffdf6cSThierry Reding 	size_t size = 0;
10900fffdf6cSThierry Reding 	u16 errors;
10910fffdf6cSThierry Reding 	u32 value;
10920fffdf6cSThierry Reding 
10930fffdf6cSThierry Reding 	/* read and parse packet header */
10940fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
10950fffdf6cSThierry Reding 
10960fffdf6cSThierry Reding 	switch (value & 0x3f) {
10970fffdf6cSThierry Reding 	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
10980fffdf6cSThierry Reding 		errors = (value >> 8) & 0xffff;
10990fffdf6cSThierry Reding 		dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
11000fffdf6cSThierry Reding 			errors);
11010fffdf6cSThierry Reding 		for (i = 0; i < ARRAY_SIZE(error_report); i++)
11020fffdf6cSThierry Reding 			if (errors & BIT(i))
11030fffdf6cSThierry Reding 				dev_dbg(dsi->dev, "  %2u: %s\n", i,
11040fffdf6cSThierry Reding 					error_report[i]);
11050fffdf6cSThierry Reding 		break;
11060fffdf6cSThierry Reding 
11070fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
11080fffdf6cSThierry Reding 		rx[0] = (value >> 8) & 0xff;
11090fffdf6cSThierry Reding 		size = 1;
11100fffdf6cSThierry Reding 		break;
11110fffdf6cSThierry Reding 
11120fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
11130fffdf6cSThierry Reding 		rx[0] = (value >>  8) & 0xff;
11140fffdf6cSThierry Reding 		rx[1] = (value >> 16) & 0xff;
11150fffdf6cSThierry Reding 		size = 2;
11160fffdf6cSThierry Reding 		break;
11170fffdf6cSThierry Reding 
11180fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
11190fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
11200fffdf6cSThierry Reding 		break;
11210fffdf6cSThierry Reding 
11220fffdf6cSThierry Reding 	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
11230fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
11240fffdf6cSThierry Reding 		break;
11250fffdf6cSThierry Reding 
11260fffdf6cSThierry Reding 	default:
11270fffdf6cSThierry Reding 		dev_err(dsi->dev, "unhandled response type: %02x\n",
11280fffdf6cSThierry Reding 			value & 0x3f);
11290fffdf6cSThierry Reding 		return -EPROTO;
11300fffdf6cSThierry Reding 	}
11310fffdf6cSThierry Reding 
11320fffdf6cSThierry Reding 	size = min(size, msg->rx_len);
11330fffdf6cSThierry Reding 
11340fffdf6cSThierry Reding 	if (msg->rx_buf && size > 0) {
11350fffdf6cSThierry Reding 		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
11360fffdf6cSThierry Reding 			u8 *rx = msg->rx_buf + j;
11370fffdf6cSThierry Reding 
11380fffdf6cSThierry Reding 			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
11390fffdf6cSThierry Reding 
11400fffdf6cSThierry Reding 			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
11410fffdf6cSThierry Reding 				rx[j + k] = (value >> (k << 3)) & 0xff;
11420fffdf6cSThierry Reding 		}
11430fffdf6cSThierry Reding 	}
11440fffdf6cSThierry Reding 
11450fffdf6cSThierry Reding 	return size;
11460fffdf6cSThierry Reding }
11470fffdf6cSThierry Reding 
11480fffdf6cSThierry Reding static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
11490fffdf6cSThierry Reding {
11500fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
11510fffdf6cSThierry Reding 
11520fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
11530fffdf6cSThierry Reding 
11540fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
11550fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
11560fffdf6cSThierry Reding 		if ((value & DSI_TRIGGER_HOST) == 0)
11570fffdf6cSThierry Reding 			return 0;
11580fffdf6cSThierry Reding 
11590fffdf6cSThierry Reding 		usleep_range(1000, 2000);
11600fffdf6cSThierry Reding 	}
11610fffdf6cSThierry Reding 
11620fffdf6cSThierry Reding 	DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
11630fffdf6cSThierry Reding 	return -ETIMEDOUT;
11640fffdf6cSThierry Reding }
11650fffdf6cSThierry Reding 
11660fffdf6cSThierry Reding static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
11670fffdf6cSThierry Reding 				       unsigned long timeout)
11680fffdf6cSThierry Reding {
11690fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(250);
11700fffdf6cSThierry Reding 
11710fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
11720fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
11730fffdf6cSThierry Reding 		u8 count = value & 0x1f;
11740fffdf6cSThierry Reding 
11750fffdf6cSThierry Reding 		if (count > 0)
11760fffdf6cSThierry Reding 			return count;
11770fffdf6cSThierry Reding 
11780fffdf6cSThierry Reding 		usleep_range(1000, 2000);
11790fffdf6cSThierry Reding 	}
11800fffdf6cSThierry Reding 
11810fffdf6cSThierry Reding 	DRM_DEBUG_KMS("peripheral returned no data\n");
11820fffdf6cSThierry Reding 	return -ETIMEDOUT;
11830fffdf6cSThierry Reding }
11840fffdf6cSThierry Reding 
11850fffdf6cSThierry Reding static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
11860fffdf6cSThierry Reding 			      const void *buffer, size_t size)
11870fffdf6cSThierry Reding {
11880fffdf6cSThierry Reding 	const u8 *buf = buffer;
11890fffdf6cSThierry Reding 	size_t i, j;
11900fffdf6cSThierry Reding 	u32 value;
11910fffdf6cSThierry Reding 
11920fffdf6cSThierry Reding 	for (j = 0; j < size; j += 4) {
11930fffdf6cSThierry Reding 		value = 0;
11940fffdf6cSThierry Reding 
11950fffdf6cSThierry Reding 		for (i = 0; i < 4 && j + i < size; i++)
11960fffdf6cSThierry Reding 			value |= buf[j + i] << (i << 3);
11970fffdf6cSThierry Reding 
11980fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_WR_DATA);
11990fffdf6cSThierry Reding 	}
12000fffdf6cSThierry Reding }
12010fffdf6cSThierry Reding 
12020fffdf6cSThierry Reding static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
12030fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg)
12040fffdf6cSThierry Reding {
12050fffdf6cSThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
12060fffdf6cSThierry Reding 	struct mipi_dsi_packet packet;
12070fffdf6cSThierry Reding 	const u8 *header;
12080fffdf6cSThierry Reding 	size_t count;
12090fffdf6cSThierry Reding 	ssize_t err;
12100fffdf6cSThierry Reding 	u32 value;
12110fffdf6cSThierry Reding 
12120fffdf6cSThierry Reding 	err = mipi_dsi_create_packet(&packet, msg);
12130fffdf6cSThierry Reding 	if (err < 0)
12140fffdf6cSThierry Reding 		return err;
12150fffdf6cSThierry Reding 
12160fffdf6cSThierry Reding 	header = packet.header;
12170fffdf6cSThierry Reding 
12180fffdf6cSThierry Reding 	/* maximum FIFO depth is 1920 words */
12190fffdf6cSThierry Reding 	if (packet.size > dsi->video_fifo_depth * 4)
12200fffdf6cSThierry Reding 		return -ENOSPC;
12210fffdf6cSThierry Reding 
12220fffdf6cSThierry Reding 	/* reset underflow/overflow flags */
12230fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_STATUS);
12240fffdf6cSThierry Reding 	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
12250fffdf6cSThierry Reding 		value = DSI_HOST_CONTROL_FIFO_RESET;
12260fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12270fffdf6cSThierry Reding 		usleep_range(10, 20);
12280fffdf6cSThierry Reding 	}
12290fffdf6cSThierry Reding 
12300fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
12310fffdf6cSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
12320fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
12330fffdf6cSThierry Reding 
12340fffdf6cSThierry Reding 	usleep_range(5000, 10000);
12350fffdf6cSThierry Reding 
12360fffdf6cSThierry Reding 	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
12370fffdf6cSThierry Reding 		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
12380fffdf6cSThierry Reding 
12390fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
12400fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_HS;
12410fffdf6cSThierry Reding 
12420fffdf6cSThierry Reding 	/*
12430fffdf6cSThierry Reding 	 * The host FIFO has a maximum of 64 words, so larger transmissions
12440fffdf6cSThierry Reding 	 * need to use the video FIFO.
12450fffdf6cSThierry Reding 	 */
12460fffdf6cSThierry Reding 	if (packet.size > dsi->host_fifo_depth * 4)
12470fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_FIFO_SEL;
12480fffdf6cSThierry Reding 
12490fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12500fffdf6cSThierry Reding 
12510fffdf6cSThierry Reding 	/*
12520fffdf6cSThierry Reding 	 * For reads and messages with explicitly requested ACK, generate a
12530fffdf6cSThierry Reding 	 * BTA sequence after the transmission of the packet.
12540fffdf6cSThierry Reding 	 */
12550fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
12560fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
12570fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
12580fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_PKT_BTA;
12590fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12600fffdf6cSThierry Reding 	}
12610fffdf6cSThierry Reding 
12620fffdf6cSThierry Reding 	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
12630fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
12640fffdf6cSThierry Reding 
12650fffdf6cSThierry Reding 	/* write packet header, ECC is generated by hardware */
12660fffdf6cSThierry Reding 	value = header[2] << 16 | header[1] << 8 | header[0];
12670fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
12680fffdf6cSThierry Reding 
12690fffdf6cSThierry Reding 	/* write payload (if any) */
12700fffdf6cSThierry Reding 	if (packet.payload_length > 0)
12710fffdf6cSThierry Reding 		tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
12720fffdf6cSThierry Reding 				  packet.payload_length);
12730fffdf6cSThierry Reding 
12740fffdf6cSThierry Reding 	err = tegra_dsi_transmit(dsi, 250);
12750fffdf6cSThierry Reding 	if (err < 0)
12760fffdf6cSThierry Reding 		return err;
12770fffdf6cSThierry Reding 
12780fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
12790fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
12800fffdf6cSThierry Reding 		err = tegra_dsi_wait_for_response(dsi, 250);
12810fffdf6cSThierry Reding 		if (err < 0)
12820fffdf6cSThierry Reding 			return err;
12830fffdf6cSThierry Reding 
12840fffdf6cSThierry Reding 		count = err;
12850fffdf6cSThierry Reding 
12860fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
12870fffdf6cSThierry Reding 		switch (value) {
12880fffdf6cSThierry Reding 		case 0x84:
12890fffdf6cSThierry Reding 			/*
12900fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ACK\n");
12910fffdf6cSThierry Reding 			*/
12920fffdf6cSThierry Reding 			break;
12930fffdf6cSThierry Reding 
12940fffdf6cSThierry Reding 		case 0x87:
12950fffdf6cSThierry Reding 			/*
12960fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ESCAPE\n");
12970fffdf6cSThierry Reding 			*/
12980fffdf6cSThierry Reding 			break;
12990fffdf6cSThierry Reding 
13000fffdf6cSThierry Reding 		default:
13010fffdf6cSThierry Reding 			dev_err(dsi->dev, "unknown status: %08x\n", value);
13020fffdf6cSThierry Reding 			break;
13030fffdf6cSThierry Reding 		}
13040fffdf6cSThierry Reding 
13050fffdf6cSThierry Reding 		if (count > 1) {
13060fffdf6cSThierry Reding 			err = tegra_dsi_read_response(dsi, msg, count);
13070fffdf6cSThierry Reding 			if (err < 0)
13080fffdf6cSThierry Reding 				dev_err(dsi->dev,
13090fffdf6cSThierry Reding 					"failed to parse response: %zd\n",
13100fffdf6cSThierry Reding 					err);
13110fffdf6cSThierry Reding 			else {
13120fffdf6cSThierry Reding 				/*
13130fffdf6cSThierry Reding 				 * For read commands, return the number of
13140fffdf6cSThierry Reding 				 * bytes returned by the peripheral.
13150fffdf6cSThierry Reding 				 */
13160fffdf6cSThierry Reding 				count = err;
13170fffdf6cSThierry Reding 			}
13180fffdf6cSThierry Reding 		}
13190fffdf6cSThierry Reding 	} else {
13200fffdf6cSThierry Reding 		/*
13210fffdf6cSThierry Reding 		 * For write commands, we have transmitted the 4-byte header
13220fffdf6cSThierry Reding 		 * plus the variable-length payload.
13230fffdf6cSThierry Reding 		 */
13240fffdf6cSThierry Reding 		count = 4 + packet.payload_length;
13250fffdf6cSThierry Reding 	}
13260fffdf6cSThierry Reding 
13270fffdf6cSThierry Reding 	return count;
13280fffdf6cSThierry Reding }
13290fffdf6cSThierry Reding 
1330e94236cdSThierry Reding static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
1331e94236cdSThierry Reding {
1332e94236cdSThierry Reding 	struct clk *parent;
1333e94236cdSThierry Reding 	int err;
1334e94236cdSThierry Reding 
1335e94236cdSThierry Reding 	/* make sure both DSI controllers share the same PLL */
1336e94236cdSThierry Reding 	parent = clk_get_parent(dsi->slave->clk);
1337e94236cdSThierry Reding 	if (!parent)
1338e94236cdSThierry Reding 		return -EINVAL;
1339e94236cdSThierry Reding 
1340e94236cdSThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1341e94236cdSThierry Reding 	if (err < 0)
1342e94236cdSThierry Reding 		return err;
1343e94236cdSThierry Reding 
1344e94236cdSThierry Reding 	return 0;
1345e94236cdSThierry Reding }
1346e94236cdSThierry Reding 
1347dec72739SThierry Reding static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
1348dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1349dec72739SThierry Reding {
1350dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1351dec72739SThierry Reding 
135217297a28SThierry Reding 	dsi->flags = device->mode_flags;
1353dec72739SThierry Reding 	dsi->format = device->format;
1354dec72739SThierry Reding 	dsi->lanes = device->lanes;
1355dec72739SThierry Reding 
1356e94236cdSThierry Reding 	if (dsi->slave) {
1357e94236cdSThierry Reding 		int err;
1358e94236cdSThierry Reding 
1359e94236cdSThierry Reding 		dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
1360e94236cdSThierry Reding 			dev_name(&device->dev));
1361e94236cdSThierry Reding 
1362e94236cdSThierry Reding 		err = tegra_dsi_ganged_setup(dsi);
1363e94236cdSThierry Reding 		if (err < 0) {
1364e94236cdSThierry Reding 			dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
1365e94236cdSThierry Reding 				err);
1366e94236cdSThierry Reding 			return err;
1367e94236cdSThierry Reding 		}
1368e94236cdSThierry Reding 	}
1369e94236cdSThierry Reding 
1370e94236cdSThierry Reding 	/*
1371e94236cdSThierry Reding 	 * Slaves don't have a panel associated with them, so they provide
1372e94236cdSThierry Reding 	 * merely the second channel.
1373e94236cdSThierry Reding 	 */
1374e94236cdSThierry Reding 	if (!dsi->master) {
1375e94236cdSThierry Reding 		struct tegra_output *output = &dsi->output;
1376e94236cdSThierry Reding 
1377dec72739SThierry Reding 		output->panel = of_drm_find_panel(device->dev.of_node);
1378e94236cdSThierry Reding 		if (output->panel && output->connector.dev) {
1379e94236cdSThierry Reding 			drm_panel_attach(output->panel, &output->connector);
1380dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1381dec72739SThierry Reding 		}
1382e94236cdSThierry Reding 	}
1383dec72739SThierry Reding 
1384dec72739SThierry Reding 	return 0;
1385dec72739SThierry Reding }
1386dec72739SThierry Reding 
1387dec72739SThierry Reding static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
1388dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1389dec72739SThierry Reding {
1390dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1391dec72739SThierry Reding 	struct tegra_output *output = &dsi->output;
1392dec72739SThierry Reding 
1393dec72739SThierry Reding 	if (output->panel && &device->dev == output->panel->dev) {
1394ba3df979SThierry Reding 		output->panel = NULL;
1395ba3df979SThierry Reding 
1396dec72739SThierry Reding 		if (output->connector.dev)
1397dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1398dec72739SThierry Reding 	}
1399dec72739SThierry Reding 
1400dec72739SThierry Reding 	return 0;
1401dec72739SThierry Reding }
1402dec72739SThierry Reding 
1403dec72739SThierry Reding static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
1404dec72739SThierry Reding 	.attach = tegra_dsi_host_attach,
1405dec72739SThierry Reding 	.detach = tegra_dsi_host_detach,
14060fffdf6cSThierry Reding 	.transfer = tegra_dsi_host_transfer,
1407dec72739SThierry Reding };
1408dec72739SThierry Reding 
1409e94236cdSThierry Reding static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
1410e94236cdSThierry Reding {
1411e94236cdSThierry Reding 	struct device_node *np;
1412e94236cdSThierry Reding 
1413e94236cdSThierry Reding 	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
1414e94236cdSThierry Reding 	if (np) {
1415e94236cdSThierry Reding 		struct platform_device *gangster = of_find_device_by_node(np);
1416e94236cdSThierry Reding 
1417e94236cdSThierry Reding 		dsi->slave = platform_get_drvdata(gangster);
1418e94236cdSThierry Reding 		of_node_put(np);
1419e94236cdSThierry Reding 
1420e94236cdSThierry Reding 		if (!dsi->slave)
1421e94236cdSThierry Reding 			return -EPROBE_DEFER;
1422e94236cdSThierry Reding 
1423e94236cdSThierry Reding 		dsi->slave->master = dsi;
1424e94236cdSThierry Reding 	}
1425e94236cdSThierry Reding 
1426e94236cdSThierry Reding 	return 0;
1427e94236cdSThierry Reding }
1428e94236cdSThierry Reding 
1429dec72739SThierry Reding static int tegra_dsi_probe(struct platform_device *pdev)
1430dec72739SThierry Reding {
1431dec72739SThierry Reding 	struct tegra_dsi *dsi;
1432dec72739SThierry Reding 	struct resource *regs;
1433dec72739SThierry Reding 	int err;
1434dec72739SThierry Reding 
1435dec72739SThierry Reding 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
1436dec72739SThierry Reding 	if (!dsi)
1437dec72739SThierry Reding 		return -ENOMEM;
1438dec72739SThierry Reding 
1439dec72739SThierry Reding 	dsi->output.dev = dsi->dev = &pdev->dev;
1440976cebc3SThierry Reding 	dsi->video_fifo_depth = 1920;
1441976cebc3SThierry Reding 	dsi->host_fifo_depth = 64;
1442dec72739SThierry Reding 
1443e94236cdSThierry Reding 	err = tegra_dsi_ganged_probe(dsi);
1444e94236cdSThierry Reding 	if (err < 0)
1445e94236cdSThierry Reding 		return err;
1446e94236cdSThierry Reding 
1447dec72739SThierry Reding 	err = tegra_output_probe(&dsi->output);
1448dec72739SThierry Reding 	if (err < 0)
1449dec72739SThierry Reding 		return err;
1450dec72739SThierry Reding 
1451ba3df979SThierry Reding 	dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
1452ba3df979SThierry Reding 
1453dec72739SThierry Reding 	/*
1454dec72739SThierry Reding 	 * Assume these values by default. When a DSI peripheral driver
1455dec72739SThierry Reding 	 * attaches to the DSI host, the parameters will be taken from
1456dec72739SThierry Reding 	 * the attached device.
1457dec72739SThierry Reding 	 */
145817297a28SThierry Reding 	dsi->flags = MIPI_DSI_MODE_VIDEO;
1459dec72739SThierry Reding 	dsi->format = MIPI_DSI_FMT_RGB888;
1460dec72739SThierry Reding 	dsi->lanes = 4;
1461dec72739SThierry Reding 
1462dec72739SThierry Reding 	dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
1463dec72739SThierry Reding 	if (IS_ERR(dsi->rst))
1464dec72739SThierry Reding 		return PTR_ERR(dsi->rst);
1465dec72739SThierry Reding 
1466dec72739SThierry Reding 	dsi->clk = devm_clk_get(&pdev->dev, NULL);
1467dec72739SThierry Reding 	if (IS_ERR(dsi->clk)) {
1468dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get DSI clock\n");
1469d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk);
1470d2d0a9d2SThierry Reding 		goto reset;
1471dec72739SThierry Reding 	}
1472dec72739SThierry Reding 
1473dec72739SThierry Reding 	err = clk_prepare_enable(dsi->clk);
1474dec72739SThierry Reding 	if (err < 0) {
1475dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot enable DSI clock\n");
1476d2d0a9d2SThierry Reding 		goto reset;
1477dec72739SThierry Reding 	}
1478dec72739SThierry Reding 
1479dec72739SThierry Reding 	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
1480dec72739SThierry Reding 	if (IS_ERR(dsi->clk_lp)) {
1481dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get low-power clock\n");
1482d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk_lp);
1483d2d0a9d2SThierry Reding 		goto disable_clk;
1484dec72739SThierry Reding 	}
1485dec72739SThierry Reding 
1486dec72739SThierry Reding 	err = clk_prepare_enable(dsi->clk_lp);
1487dec72739SThierry Reding 	if (err < 0) {
1488dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot enable low-power clock\n");
1489d2d0a9d2SThierry Reding 		goto disable_clk;
1490dec72739SThierry Reding 	}
1491dec72739SThierry Reding 
1492dec72739SThierry Reding 	dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
1493dec72739SThierry Reding 	if (IS_ERR(dsi->clk_parent)) {
1494dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get parent clock\n");
1495d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->clk_parent);
1496d2d0a9d2SThierry Reding 		goto disable_clk_lp;
1497dec72739SThierry Reding 	}
1498dec72739SThierry Reding 
14993b077afbSThierry Reding 	dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
15003b077afbSThierry Reding 	if (IS_ERR(dsi->vdd)) {
15013b077afbSThierry Reding 		dev_err(&pdev->dev, "cannot get VDD supply\n");
1502d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->vdd);
1503d2d0a9d2SThierry Reding 		goto disable_clk_lp;
15043b077afbSThierry Reding 	}
15053b077afbSThierry Reding 
15063b077afbSThierry Reding 	err = regulator_enable(dsi->vdd);
15073b077afbSThierry Reding 	if (err < 0) {
15083b077afbSThierry Reding 		dev_err(&pdev->dev, "cannot enable VDD supply\n");
1509d2d0a9d2SThierry Reding 		goto disable_clk_lp;
15103b077afbSThierry Reding 	}
15113b077afbSThierry Reding 
1512dec72739SThierry Reding 	err = tegra_dsi_setup_clocks(dsi);
1513dec72739SThierry Reding 	if (err < 0) {
1514dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot setup clocks\n");
1515d2d0a9d2SThierry Reding 		goto disable_vdd;
1516dec72739SThierry Reding 	}
1517dec72739SThierry Reding 
1518dec72739SThierry Reding 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1519dec72739SThierry Reding 	dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
1520d2d0a9d2SThierry Reding 	if (IS_ERR(dsi->regs)) {
1521d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->regs);
1522d2d0a9d2SThierry Reding 		goto disable_vdd;
1523d2d0a9d2SThierry Reding 	}
1524dec72739SThierry Reding 
1525dec72739SThierry Reding 	dsi->mipi = tegra_mipi_request(&pdev->dev);
1526d2d0a9d2SThierry Reding 	if (IS_ERR(dsi->mipi)) {
1527d2d0a9d2SThierry Reding 		err = PTR_ERR(dsi->mipi);
1528d2d0a9d2SThierry Reding 		goto disable_vdd;
1529d2d0a9d2SThierry Reding 	}
1530dec72739SThierry Reding 
1531dec72739SThierry Reding 	dsi->host.ops = &tegra_dsi_host_ops;
1532dec72739SThierry Reding 	dsi->host.dev = &pdev->dev;
1533dec72739SThierry Reding 
1534dec72739SThierry Reding 	err = mipi_dsi_host_register(&dsi->host);
1535dec72739SThierry Reding 	if (err < 0) {
1536dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
1537d2d0a9d2SThierry Reding 		goto mipi_free;
1538dec72739SThierry Reding 	}
1539dec72739SThierry Reding 
1540dec72739SThierry Reding 	INIT_LIST_HEAD(&dsi->client.list);
1541dec72739SThierry Reding 	dsi->client.ops = &dsi_client_ops;
1542dec72739SThierry Reding 	dsi->client.dev = &pdev->dev;
1543dec72739SThierry Reding 
1544dec72739SThierry Reding 	err = host1x_client_register(&dsi->client);
1545dec72739SThierry Reding 	if (err < 0) {
1546dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1547dec72739SThierry Reding 			err);
1548d2d0a9d2SThierry Reding 		goto unregister;
1549dec72739SThierry Reding 	}
1550dec72739SThierry Reding 
1551dec72739SThierry Reding 	platform_set_drvdata(pdev, dsi);
1552dec72739SThierry Reding 
1553dec72739SThierry Reding 	return 0;
1554d2d0a9d2SThierry Reding 
1555d2d0a9d2SThierry Reding unregister:
1556d2d0a9d2SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1557d2d0a9d2SThierry Reding mipi_free:
1558d2d0a9d2SThierry Reding 	tegra_mipi_free(dsi->mipi);
1559d2d0a9d2SThierry Reding disable_vdd:
1560d2d0a9d2SThierry Reding 	regulator_disable(dsi->vdd);
1561d2d0a9d2SThierry Reding disable_clk_lp:
1562d2d0a9d2SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1563d2d0a9d2SThierry Reding disable_clk:
1564d2d0a9d2SThierry Reding 	clk_disable_unprepare(dsi->clk);
1565d2d0a9d2SThierry Reding reset:
1566d2d0a9d2SThierry Reding 	reset_control_assert(dsi->rst);
1567d2d0a9d2SThierry Reding 	return err;
1568dec72739SThierry Reding }
1569dec72739SThierry Reding 
1570dec72739SThierry Reding static int tegra_dsi_remove(struct platform_device *pdev)
1571dec72739SThierry Reding {
1572dec72739SThierry Reding 	struct tegra_dsi *dsi = platform_get_drvdata(pdev);
1573dec72739SThierry Reding 	int err;
1574dec72739SThierry Reding 
1575dec72739SThierry Reding 	err = host1x_client_unregister(&dsi->client);
1576dec72739SThierry Reding 	if (err < 0) {
1577dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1578dec72739SThierry Reding 			err);
1579dec72739SThierry Reding 		return err;
1580dec72739SThierry Reding 	}
1581dec72739SThierry Reding 
1582328ec69eSThierry Reding 	tegra_output_remove(&dsi->output);
15835b901e78SThierry Reding 
1584dec72739SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1585dec72739SThierry Reding 	tegra_mipi_free(dsi->mipi);
1586dec72739SThierry Reding 
15873b077afbSThierry Reding 	regulator_disable(dsi->vdd);
1588dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1589dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk);
1590cb825d89SThierry Reding 	reset_control_assert(dsi->rst);
1591dec72739SThierry Reding 
1592dec72739SThierry Reding 	return 0;
1593dec72739SThierry Reding }
1594dec72739SThierry Reding 
1595dec72739SThierry Reding static const struct of_device_id tegra_dsi_of_match[] = {
1596dec72739SThierry Reding 	{ .compatible = "nvidia,tegra114-dsi", },
1597dec72739SThierry Reding 	{ },
1598dec72739SThierry Reding };
1599ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
1600dec72739SThierry Reding 
1601dec72739SThierry Reding struct platform_driver tegra_dsi_driver = {
1602dec72739SThierry Reding 	.driver = {
1603dec72739SThierry Reding 		.name = "tegra-dsi",
1604dec72739SThierry Reding 		.of_match_table = tegra_dsi_of_match,
1605dec72739SThierry Reding 	},
1606dec72739SThierry Reding 	.probe = tegra_dsi_probe,
1607dec72739SThierry Reding 	.remove = tegra_dsi_remove,
1608dec72739SThierry Reding };
1609