xref: /linux/drivers/gpu/drm/tegra/dsi.c (revision eb1df694cd7271632763bb99f7fb3891357461d8)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2dec72739SThierry Reding /*
3dec72739SThierry Reding  * Copyright (C) 2013 NVIDIA Corporation
4dec72739SThierry Reding  */
5dec72739SThierry Reding 
6dec72739SThierry Reding #include <linux/clk.h>
7dec72739SThierry Reding #include <linux/debugfs.h>
8*eb1df694SSam Ravnborg #include <linux/delay.h>
9dec72739SThierry Reding #include <linux/host1x.h>
10dec72739SThierry Reding #include <linux/module.h>
11dec72739SThierry Reding #include <linux/of.h>
12e94236cdSThierry Reding #include <linux/of_platform.h>
13dec72739SThierry Reding #include <linux/platform_device.h>
14ef8187d7SThierry Reding #include <linux/pm_runtime.h>
15*eb1df694SSam Ravnborg #include <linux/regulator/consumer.h>
16dec72739SThierry Reding #include <linux/reset.h>
17dec72739SThierry Reding 
18*eb1df694SSam Ravnborg #include <video/mipi_display.h>
193b077afbSThierry Reding 
204aa3df71SThierry Reding #include <drm/drm_atomic_helper.h>
21*eb1df694SSam Ravnborg #include <drm/drm_debugfs.h>
22*eb1df694SSam Ravnborg #include <drm/drm_file.h>
23dec72739SThierry Reding #include <drm/drm_mipi_dsi.h>
24dec72739SThierry Reding #include <drm/drm_panel.h>
25dec72739SThierry Reding 
26dec72739SThierry Reding #include "dc.h"
27dec72739SThierry Reding #include "drm.h"
28dec72739SThierry Reding #include "dsi.h"
29dec72739SThierry Reding #include "mipi-phy.h"
3075af8fa7SThierry Reding #include "trace.h"
31dec72739SThierry Reding 
32ebd14afeSThierry Reding struct tegra_dsi_state {
33ebd14afeSThierry Reding 	struct drm_connector_state base;
34ebd14afeSThierry Reding 
35ebd14afeSThierry Reding 	struct mipi_dphy_timing timing;
36ebd14afeSThierry Reding 	unsigned long period;
37ebd14afeSThierry Reding 
38ebd14afeSThierry Reding 	unsigned int vrefresh;
39ebd14afeSThierry Reding 	unsigned int lanes;
40ebd14afeSThierry Reding 	unsigned long pclk;
41ebd14afeSThierry Reding 	unsigned long bclk;
42ebd14afeSThierry Reding 
43ebd14afeSThierry Reding 	enum tegra_dsi_format format;
44ebd14afeSThierry Reding 	unsigned int mul;
45ebd14afeSThierry Reding 	unsigned int div;
46ebd14afeSThierry Reding };
47ebd14afeSThierry Reding 
48ebd14afeSThierry Reding static inline struct tegra_dsi_state *
49ebd14afeSThierry Reding to_dsi_state(struct drm_connector_state *state)
50ebd14afeSThierry Reding {
51ebd14afeSThierry Reding 	return container_of(state, struct tegra_dsi_state, base);
52ebd14afeSThierry Reding }
53ebd14afeSThierry Reding 
54dec72739SThierry Reding struct tegra_dsi {
55dec72739SThierry Reding 	struct host1x_client client;
56dec72739SThierry Reding 	struct tegra_output output;
57dec72739SThierry Reding 	struct device *dev;
58dec72739SThierry Reding 
59dec72739SThierry Reding 	void __iomem *regs;
60dec72739SThierry Reding 
61dec72739SThierry Reding 	struct reset_control *rst;
62dec72739SThierry Reding 	struct clk *clk_parent;
63dec72739SThierry Reding 	struct clk *clk_lp;
64dec72739SThierry Reding 	struct clk *clk;
65dec72739SThierry Reding 
66dec72739SThierry Reding 	struct drm_info_list *debugfs_files;
67dec72739SThierry Reding 
6817297a28SThierry Reding 	unsigned long flags;
69dec72739SThierry Reding 	enum mipi_dsi_pixel_format format;
70dec72739SThierry Reding 	unsigned int lanes;
71dec72739SThierry Reding 
72dec72739SThierry Reding 	struct tegra_mipi_device *mipi;
73dec72739SThierry Reding 	struct mipi_dsi_host host;
743b077afbSThierry Reding 
753b077afbSThierry Reding 	struct regulator *vdd;
76976cebc3SThierry Reding 
77976cebc3SThierry Reding 	unsigned int video_fifo_depth;
78976cebc3SThierry Reding 	unsigned int host_fifo_depth;
79e94236cdSThierry Reding 
80e94236cdSThierry Reding 	/* for ganged-mode support */
81e94236cdSThierry Reding 	struct tegra_dsi *master;
82e94236cdSThierry Reding 	struct tegra_dsi *slave;
83dec72739SThierry Reding };
84dec72739SThierry Reding 
85dec72739SThierry Reding static inline struct tegra_dsi *
86dec72739SThierry Reding host1x_client_to_dsi(struct host1x_client *client)
87dec72739SThierry Reding {
88dec72739SThierry Reding 	return container_of(client, struct tegra_dsi, client);
89dec72739SThierry Reding }
90dec72739SThierry Reding 
91dec72739SThierry Reding static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
92dec72739SThierry Reding {
93dec72739SThierry Reding 	return container_of(host, struct tegra_dsi, host);
94dec72739SThierry Reding }
95dec72739SThierry Reding 
96dec72739SThierry Reding static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
97dec72739SThierry Reding {
98dec72739SThierry Reding 	return container_of(output, struct tegra_dsi, output);
99dec72739SThierry Reding }
100dec72739SThierry Reding 
101ebd14afeSThierry Reding static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
102ebd14afeSThierry Reding {
103ebd14afeSThierry Reding 	return to_dsi_state(dsi->output.connector.state);
104ebd14afeSThierry Reding }
105ebd14afeSThierry Reding 
10612831076SThierry Reding static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned int offset)
107dec72739SThierry Reding {
10875af8fa7SThierry Reding 	u32 value = readl(dsi->regs + (offset << 2));
10975af8fa7SThierry Reding 
11075af8fa7SThierry Reding 	trace_dsi_readl(dsi->dev, offset, value);
11175af8fa7SThierry Reding 
11275af8fa7SThierry Reding 	return value;
113dec72739SThierry Reding }
114dec72739SThierry Reding 
1159c0b4ca1SThierry Reding static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
11612831076SThierry Reding 				    unsigned int offset)
117dec72739SThierry Reding {
11875af8fa7SThierry Reding 	trace_dsi_writel(dsi->dev, offset, value);
11912831076SThierry Reding 	writel(value, dsi->regs + (offset << 2));
120dec72739SThierry Reding }
121dec72739SThierry Reding 
122a40051c0SThierry Reding #define DEBUGFS_REG32(_name) { .name = #_name, .offset = _name }
123a40051c0SThierry Reding 
124a40051c0SThierry Reding static const struct debugfs_reg32 tegra_dsi_regs[] = {
125a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT),
126a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT_CONTROL),
127a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INCR_SYNCPT_ERROR),
128a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_CTXSW),
129a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_RD_DATA),
130a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_WR_DATA),
131a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_POWER_CONTROL),
132a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_ENABLE),
133a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_STATUS),
134a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INT_MASK),
135a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_HOST_CONTROL),
136a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_CONTROL),
137a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_SOL_DELAY),
138a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_MAX_THRESHOLD),
139a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TRIGGER),
140a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TX_CRC),
141a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_STATUS),
142a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_CONTROL),
143a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_0),
144a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_1),
145a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_2),
146a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_3),
147a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_4),
148a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_5),
149a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_6),
150a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_7),
151a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_0_LO),
152a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_0_HI),
153a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_1_LO),
154a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_1_HI),
155a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_2_LO),
156a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_2_HI),
157a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_3_LO),
158a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_3_HI),
159a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_4_LO),
160a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_4_HI),
161a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_5_LO),
162a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_SEQ_5_HI),
163a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_DCS_CMDS),
164a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_0_1),
165a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_2_3),
166a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_4_5),
167a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PKT_LEN_6_7),
168a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_0),
169a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_1),
170a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PHY_TIMING_2),
171a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_BTA_TIMING),
172a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TIMEOUT_0),
173a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TIMEOUT_1),
174a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_TO_TALLY),
175a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_0),
176a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_CD),
177a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CD_STATUS),
178a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_VIDEO_MODE_CONTROL),
179a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_1),
180a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_2),
181a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_3),
182a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_PAD_CONTROL_4),
183a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_CONTROL),
184a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_START),
185a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_GANGED_MODE_SIZE),
186a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_RAW_DATA_BYTE_COUNT),
187a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_ULTRA_LOW_POWER_CONTROL),
188a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_8),
189a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_9),
190a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_10),
191a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_11),
192a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_12),
193a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_13),
194a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_14),
195a40051c0SThierry Reding 	DEBUGFS_REG32(DSI_INIT_SEQ_DATA_15),
196a40051c0SThierry Reding };
197a40051c0SThierry Reding 
198dec72739SThierry Reding static int tegra_dsi_show_regs(struct seq_file *s, void *data)
199dec72739SThierry Reding {
200dec72739SThierry Reding 	struct drm_info_node *node = s->private;
201dec72739SThierry Reding 	struct tegra_dsi *dsi = node->info_ent->data;
202171e2e6dSThierry Reding 	struct drm_crtc *crtc = dsi->output.encoder.crtc;
203171e2e6dSThierry Reding 	struct drm_device *drm = node->minor->dev;
204a40051c0SThierry Reding 	unsigned int i;
205171e2e6dSThierry Reding 	int err = 0;
206171e2e6dSThierry Reding 
207171e2e6dSThierry Reding 	drm_modeset_lock_all(drm);
208171e2e6dSThierry Reding 
209171e2e6dSThierry Reding 	if (!crtc || !crtc->state->active) {
210171e2e6dSThierry Reding 		err = -EBUSY;
211171e2e6dSThierry Reding 		goto unlock;
212171e2e6dSThierry Reding 	}
213dec72739SThierry Reding 
214a40051c0SThierry Reding 	for (i = 0; i < ARRAY_SIZE(tegra_dsi_regs); i++) {
215a40051c0SThierry Reding 		unsigned int offset = tegra_dsi_regs[i].offset;
216dec72739SThierry Reding 
217a40051c0SThierry Reding 		seq_printf(s, "%-32s %#05x %08x\n", tegra_dsi_regs[i].name,
218a40051c0SThierry Reding 			   offset, tegra_dsi_readl(dsi, offset));
219a40051c0SThierry Reding 	}
220dec72739SThierry Reding 
221171e2e6dSThierry Reding unlock:
222171e2e6dSThierry Reding 	drm_modeset_unlock_all(drm);
223171e2e6dSThierry Reding 	return err;
224dec72739SThierry Reding }
225dec72739SThierry Reding 
226dec72739SThierry Reding static struct drm_info_list debugfs_files[] = {
227dec72739SThierry Reding 	{ "regs", tegra_dsi_show_regs, 0, NULL },
228dec72739SThierry Reding };
229dec72739SThierry Reding 
230a813d704SThierry Reding static int tegra_dsi_late_register(struct drm_connector *connector)
231dec72739SThierry Reding {
232a813d704SThierry Reding 	struct tegra_output *output = connector_to_output(connector);
233a813d704SThierry Reding 	unsigned int i, count = ARRAY_SIZE(debugfs_files);
234a813d704SThierry Reding 	struct drm_minor *minor = connector->dev->primary;
235a813d704SThierry Reding 	struct dentry *root = connector->debugfs_entry;
236a813d704SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
237dec72739SThierry Reding 	int err;
238dec72739SThierry Reding 
239dec72739SThierry Reding 	dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
240dec72739SThierry Reding 				     GFP_KERNEL);
241a813d704SThierry Reding 	if (!dsi->debugfs_files)
242a813d704SThierry Reding 		return -ENOMEM;
243dec72739SThierry Reding 
244a813d704SThierry Reding 	for (i = 0; i < count; i++)
245dec72739SThierry Reding 		dsi->debugfs_files[i].data = dsi;
246dec72739SThierry Reding 
247a813d704SThierry Reding 	err = drm_debugfs_create_files(dsi->debugfs_files, count, root, minor);
248dec72739SThierry Reding 	if (err < 0)
249dec72739SThierry Reding 		goto free;
250dec72739SThierry Reding 
251dec72739SThierry Reding 	return 0;
252dec72739SThierry Reding 
253dec72739SThierry Reding free:
254dec72739SThierry Reding 	kfree(dsi->debugfs_files);
255dec72739SThierry Reding 	dsi->debugfs_files = NULL;
256dec72739SThierry Reding 
257dec72739SThierry Reding 	return err;
258dec72739SThierry Reding }
259dec72739SThierry Reding 
260a813d704SThierry Reding static void tegra_dsi_early_unregister(struct drm_connector *connector)
261dec72739SThierry Reding {
262a813d704SThierry Reding 	struct tegra_output *output = connector_to_output(connector);
263a813d704SThierry Reding 	unsigned int count = ARRAY_SIZE(debugfs_files);
264a813d704SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
265dec72739SThierry Reding 
266a813d704SThierry Reding 	drm_debugfs_remove_files(dsi->debugfs_files, count,
267a813d704SThierry Reding 				 connector->dev->primary);
268dec72739SThierry Reding 	kfree(dsi->debugfs_files);
269dec72739SThierry Reding 	dsi->debugfs_files = NULL;
270dec72739SThierry Reding }
271dec72739SThierry Reding 
272dec72739SThierry Reding #define PKT_ID0(id)	((((id) & 0x3f) <<  3) | (1 <<  9))
273dec72739SThierry Reding #define PKT_LEN0(len)	(((len) & 0x07) <<  0)
274dec72739SThierry Reding #define PKT_ID1(id)	((((id) & 0x3f) << 13) | (1 << 19))
275dec72739SThierry Reding #define PKT_LEN1(len)	(((len) & 0x07) << 10)
276dec72739SThierry Reding #define PKT_ID2(id)	((((id) & 0x3f) << 23) | (1 << 29))
277dec72739SThierry Reding #define PKT_LEN2(len)	(((len) & 0x07) << 20)
278dec72739SThierry Reding 
279dec72739SThierry Reding #define PKT_LP		(1 << 30)
280dec72739SThierry Reding #define NUM_PKT_SEQ	12
281dec72739SThierry Reding 
28217297a28SThierry Reding /*
28317297a28SThierry Reding  * non-burst mode with sync pulses
28417297a28SThierry Reding  */
28517297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_pulses[NUM_PKT_SEQ] = {
286dec72739SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
287dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
288dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
289dec72739SThierry Reding 	       PKT_LP,
290dec72739SThierry Reding 	[ 1] = 0,
291dec72739SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
292dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
293dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
294dec72739SThierry Reding 	       PKT_LP,
295dec72739SThierry Reding 	[ 3] = 0,
296dec72739SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
297dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
298dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
299dec72739SThierry Reding 	       PKT_LP,
300dec72739SThierry Reding 	[ 5] = 0,
301dec72739SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
302dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
303dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
304dec72739SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
305dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
306dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
307dec72739SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
308dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
309dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
310dec72739SThierry Reding 	       PKT_LP,
311dec72739SThierry Reding 	[ 9] = 0,
312dec72739SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
313dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
314dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
315dec72739SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
316dec72739SThierry Reding 	       PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
317dec72739SThierry Reding 	       PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
318dec72739SThierry Reding };
319dec72739SThierry Reding 
32017297a28SThierry Reding /*
32117297a28SThierry Reding  * non-burst mode with sync events
32217297a28SThierry Reding  */
32317297a28SThierry Reding static const u32 pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
32417297a28SThierry Reding 	[ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
32517297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
32617297a28SThierry Reding 	       PKT_LP,
32717297a28SThierry Reding 	[ 1] = 0,
32817297a28SThierry Reding 	[ 2] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
32917297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
33017297a28SThierry Reding 	       PKT_LP,
33117297a28SThierry Reding 	[ 3] = 0,
33217297a28SThierry Reding 	[ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
33317297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
33417297a28SThierry Reding 	       PKT_LP,
33517297a28SThierry Reding 	[ 5] = 0,
33617297a28SThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
33717297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
33817297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
33917297a28SThierry Reding 	[ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
34017297a28SThierry Reding 	[ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
34117297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_END_OF_TRANSMISSION) | PKT_LEN1(7) |
34217297a28SThierry Reding 	       PKT_LP,
34317297a28SThierry Reding 	[ 9] = 0,
34417297a28SThierry Reding 	[10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
34517297a28SThierry Reding 	       PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(2) |
34617297a28SThierry Reding 	       PKT_ID2(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN2(3),
34717297a28SThierry Reding 	[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
34817297a28SThierry Reding };
34917297a28SThierry Reding 
350337b443dSThierry Reding static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
351337b443dSThierry Reding 	[ 0] = 0,
352337b443dSThierry Reding 	[ 1] = 0,
353337b443dSThierry Reding 	[ 2] = 0,
354337b443dSThierry Reding 	[ 3] = 0,
355337b443dSThierry Reding 	[ 4] = 0,
356337b443dSThierry Reding 	[ 5] = 0,
357337b443dSThierry Reding 	[ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
358337b443dSThierry Reding 	[ 7] = 0,
359337b443dSThierry Reding 	[ 8] = 0,
360337b443dSThierry Reding 	[ 9] = 0,
361337b443dSThierry Reding 	[10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
362337b443dSThierry Reding 	[11] = 0,
363337b443dSThierry Reding };
364337b443dSThierry Reding 
365ebd14afeSThierry Reding static void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
366ebd14afeSThierry Reding 				     unsigned long period,
367ebd14afeSThierry Reding 				     const struct mipi_dphy_timing *timing)
368dec72739SThierry Reding {
3699c0b4ca1SThierry Reding 	u32 value;
370dec72739SThierry Reding 
371ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
372ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
373ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
374ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->hsprepare, period, 1);
375dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
376dec72739SThierry Reding 
377ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
378ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
379ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
380ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->lpx, period, 1);
381dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
382dec72739SThierry Reding 
383ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
384ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
385dec72739SThierry Reding 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
386dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
387dec72739SThierry Reding 
388ebd14afeSThierry Reding 	value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
389ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
390ebd14afeSThierry Reding 		DSI_TIMING_FIELD(timing->tago, period, 1);
391dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
392dec72739SThierry Reding 
3937e3bc3a9SSean Paul 	if (dsi->slave)
394ebd14afeSThierry Reding 		tegra_dsi_set_phy_timing(dsi->slave, period, timing);
395dec72739SThierry Reding }
396dec72739SThierry Reding 
397dec72739SThierry Reding static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
398dec72739SThierry Reding 				unsigned int *mulp, unsigned int *divp)
399dec72739SThierry Reding {
400dec72739SThierry Reding 	switch (format) {
401dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
402dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB888:
403dec72739SThierry Reding 		*mulp = 3;
404dec72739SThierry Reding 		*divp = 1;
405dec72739SThierry Reding 		break;
406dec72739SThierry Reding 
407dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB565:
408dec72739SThierry Reding 		*mulp = 2;
409dec72739SThierry Reding 		*divp = 1;
410dec72739SThierry Reding 		break;
411dec72739SThierry Reding 
412dec72739SThierry Reding 	case MIPI_DSI_FMT_RGB666:
413dec72739SThierry Reding 		*mulp = 9;
414dec72739SThierry Reding 		*divp = 4;
415dec72739SThierry Reding 		break;
416dec72739SThierry Reding 
417dec72739SThierry Reding 	default:
418dec72739SThierry Reding 		return -EINVAL;
419dec72739SThierry Reding 	}
420dec72739SThierry Reding 
421dec72739SThierry Reding 	return 0;
422dec72739SThierry Reding }
423dec72739SThierry Reding 
424f7d6889bSThierry Reding static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format,
425f7d6889bSThierry Reding 				enum tegra_dsi_format *fmt)
426f7d6889bSThierry Reding {
427f7d6889bSThierry Reding 	switch (format) {
428f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB888:
429f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_24P;
430f7d6889bSThierry Reding 		break;
431f7d6889bSThierry Reding 
432f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666:
433f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18NP;
434f7d6889bSThierry Reding 		break;
435f7d6889bSThierry Reding 
436f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB666_PACKED:
437f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_18P;
438f7d6889bSThierry Reding 		break;
439f7d6889bSThierry Reding 
440f7d6889bSThierry Reding 	case MIPI_DSI_FMT_RGB565:
441f7d6889bSThierry Reding 		*fmt = TEGRA_DSI_FORMAT_16P;
442f7d6889bSThierry Reding 		break;
443f7d6889bSThierry Reding 
444f7d6889bSThierry Reding 	default:
445f7d6889bSThierry Reding 		return -EINVAL;
446f7d6889bSThierry Reding 	}
447f7d6889bSThierry Reding 
448f7d6889bSThierry Reding 	return 0;
449f7d6889bSThierry Reding }
450f7d6889bSThierry Reding 
451e94236cdSThierry Reding static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
452e94236cdSThierry Reding 				    unsigned int size)
453e94236cdSThierry Reding {
454e94236cdSThierry Reding 	u32 value;
455e94236cdSThierry Reding 
456e94236cdSThierry Reding 	tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
457e94236cdSThierry Reding 	tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
458e94236cdSThierry Reding 
459e94236cdSThierry Reding 	value = DSI_GANGED_MODE_CONTROL_ENABLE;
460e94236cdSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
461e94236cdSThierry Reding }
462e94236cdSThierry Reding 
463563eff1fSThierry Reding static void tegra_dsi_enable(struct tegra_dsi *dsi)
464dec72739SThierry Reding {
465563eff1fSThierry Reding 	u32 value;
466dec72739SThierry Reding 
467563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
468563eff1fSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
469563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
470e94236cdSThierry Reding 
471e94236cdSThierry Reding 	if (dsi->slave)
472e94236cdSThierry Reding 		tegra_dsi_enable(dsi->slave);
473e94236cdSThierry Reding }
474e94236cdSThierry Reding 
475e94236cdSThierry Reding static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
476e94236cdSThierry Reding {
477e94236cdSThierry Reding 	if (dsi->master)
478e94236cdSThierry Reding 		return dsi->master->lanes + dsi->lanes;
479e94236cdSThierry Reding 
480e94236cdSThierry Reding 	if (dsi->slave)
481e94236cdSThierry Reding 		return dsi->lanes + dsi->slave->lanes;
482e94236cdSThierry Reding 
483e94236cdSThierry Reding 	return dsi->lanes;
484563eff1fSThierry Reding }
485563eff1fSThierry Reding 
486ebd14afeSThierry Reding static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
487563eff1fSThierry Reding 				const struct drm_display_mode *mode)
488563eff1fSThierry Reding {
489563eff1fSThierry Reding 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
490ebd14afeSThierry Reding 	struct tegra_dsi_state *state;
491563eff1fSThierry Reding 	const u32 *pkt_seq;
492563eff1fSThierry Reding 	u32 value;
493ebd14afeSThierry Reding 
494ebd14afeSThierry Reding 	/* XXX: pass in state into this function? */
495ebd14afeSThierry Reding 	if (dsi->master)
496ebd14afeSThierry Reding 		state = tegra_dsi_get_state(dsi->master);
497ebd14afeSThierry Reding 	else
498ebd14afeSThierry Reding 		state = tegra_dsi_get_state(dsi);
499ebd14afeSThierry Reding 
500ebd14afeSThierry Reding 	mul = state->mul;
501ebd14afeSThierry Reding 	div = state->div;
502334ae6b5SThierry Reding 
50317297a28SThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
50417297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
50517297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_pulses;
506337b443dSThierry Reding 	} else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
50717297a28SThierry Reding 		DRM_DEBUG_KMS("Non-burst video mode with sync events\n");
50817297a28SThierry Reding 		pkt_seq = pkt_seq_video_non_burst_sync_events;
509337b443dSThierry Reding 	} else {
510337b443dSThierry Reding 		DRM_DEBUG_KMS("Command mode\n");
511337b443dSThierry Reding 		pkt_seq = pkt_seq_command_mode;
51217297a28SThierry Reding 	}
51317297a28SThierry Reding 
514ebd14afeSThierry Reding 	value = DSI_CONTROL_CHANNEL(0) |
515ebd14afeSThierry Reding 		DSI_CONTROL_FORMAT(state->format) |
516dec72739SThierry Reding 		DSI_CONTROL_LANES(dsi->lanes - 1) |
517563eff1fSThierry Reding 		DSI_CONTROL_SOURCE(pipe);
518dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
519dec72739SThierry Reding 
520976cebc3SThierry Reding 	tegra_dsi_writel(dsi, dsi->video_fifo_depth, DSI_MAX_THRESHOLD);
521dec72739SThierry Reding 
522563eff1fSThierry Reding 	value = DSI_HOST_CONTROL_HS;
523dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
524dec72739SThierry Reding 
525dec72739SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
526563eff1fSThierry Reding 
5270c6b1e4bSAlexandre Courbot 	if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
528dec72739SThierry Reding 		value |= DSI_CONTROL_HS_CLK_CTRL;
529563eff1fSThierry Reding 
530dec72739SThierry Reding 	value &= ~DSI_CONTROL_TX_TRIG(3);
531337b443dSThierry Reding 
532337b443dSThierry Reding 	/* enable DCS commands for command mode */
533337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO)
534dec72739SThierry Reding 		value &= ~DSI_CONTROL_DCS_ENABLE;
535337b443dSThierry Reding 	else
536337b443dSThierry Reding 		value |= DSI_CONTROL_DCS_ENABLE;
537337b443dSThierry Reding 
538dec72739SThierry Reding 	value |= DSI_CONTROL_VIDEO_ENABLE;
539dec72739SThierry Reding 	value &= ~DSI_CONTROL_HOST_ENABLE;
540dec72739SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
541dec72739SThierry Reding 
542dec72739SThierry Reding 	for (i = 0; i < NUM_PKT_SEQ; i++)
543dec72739SThierry Reding 		tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
544dec72739SThierry Reding 
545337b443dSThierry Reding 	if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
546dec72739SThierry Reding 		/* horizontal active pixels */
547dec72739SThierry Reding 		hact = mode->hdisplay * mul / div;
548dec72739SThierry Reding 
549dec72739SThierry Reding 		/* horizontal sync width */
550dec72739SThierry Reding 		hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
551dec72739SThierry Reding 
552dec72739SThierry Reding 		/* horizontal back porch */
553dec72739SThierry Reding 		hbp = (mode->htotal - mode->hsync_end) * mul / div;
554b8be0bdbSThierry Reding 
555b8be0bdbSThierry Reding 		if ((dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0)
556b8be0bdbSThierry Reding 			hbp += hsw;
557dec72739SThierry Reding 
558dec72739SThierry Reding 		/* horizontal front porch */
559dec72739SThierry Reding 		hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
560b8be0bdbSThierry Reding 
561b8be0bdbSThierry Reding 		/* subtract packet overhead */
562b8be0bdbSThierry Reding 		hsw -= 10;
563b8be0bdbSThierry Reding 		hbp -= 14;
564dec72739SThierry Reding 		hfp -= 8;
565dec72739SThierry Reding 
566dec72739SThierry Reding 		tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
567dec72739SThierry Reding 		tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
568dec72739SThierry Reding 		tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
569dec72739SThierry Reding 		tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
570dec72739SThierry Reding 
571563eff1fSThierry Reding 		/* set SOL delay (for non-burst mode only) */
572dec72739SThierry Reding 		tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
573e94236cdSThierry Reding 
574e94236cdSThierry Reding 		/* TODO: implement ganged mode */
575337b443dSThierry Reding 	} else {
576337b443dSThierry Reding 		u16 bytes;
577337b443dSThierry Reding 
578e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
579e94236cdSThierry Reding 			/*
580e94236cdSThierry Reding 			 * For ganged mode, assume symmetric left-right mode.
581e94236cdSThierry Reding 			 */
582e94236cdSThierry Reding 			bytes = 1 + (mode->hdisplay / 2) * mul / div;
583e94236cdSThierry Reding 		} else {
584337b443dSThierry Reding 			/* 1 byte (DCS command) + pixel data */
585337b443dSThierry Reding 			bytes = 1 + mode->hdisplay * mul / div;
586e94236cdSThierry Reding 		}
587337b443dSThierry Reding 
588337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1);
589337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3);
590337b443dSThierry Reding 		tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_4_5);
591337b443dSThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_6_7);
592337b443dSThierry Reding 
593337b443dSThierry Reding 		value = MIPI_DCS_WRITE_MEMORY_START << 8 |
594337b443dSThierry Reding 			MIPI_DCS_WRITE_MEMORY_CONTINUE;
595337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_DCS_CMDS);
596337b443dSThierry Reding 
597e94236cdSThierry Reding 		/* set SOL delay */
598e94236cdSThierry Reding 		if (dsi->master || dsi->slave) {
599e94236cdSThierry Reding 			unsigned long delay, bclk, bclk_ganged;
600ebd14afeSThierry Reding 			unsigned int lanes = state->lanes;
601e94236cdSThierry Reding 
602e94236cdSThierry Reding 			/* SOL to valid, valid to FIFO and FIFO write delay */
603e94236cdSThierry Reding 			delay = 4 + 4 + 2;
604e94236cdSThierry Reding 			delay = DIV_ROUND_UP(delay * mul, div * lanes);
605e94236cdSThierry Reding 			/* FIFO read delay */
606e94236cdSThierry Reding 			delay = delay + 6;
607e94236cdSThierry Reding 
608e94236cdSThierry Reding 			bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes);
609e94236cdSThierry Reding 			bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes);
610e94236cdSThierry Reding 			value = bclk - bclk_ganged + delay + 20;
611e94236cdSThierry Reding 		} else {
612e94236cdSThierry Reding 			/* TODO: revisit for non-ganged mode */
613337b443dSThierry Reding 			value = 8 * mul / div;
614e94236cdSThierry Reding 		}
615337b443dSThierry Reding 
616337b443dSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_SOL_DELAY);
617337b443dSThierry Reding 	}
618dec72739SThierry Reding 
619e94236cdSThierry Reding 	if (dsi->slave) {
620ebd14afeSThierry Reding 		tegra_dsi_configure(dsi->slave, pipe, mode);
621e94236cdSThierry Reding 
622e94236cdSThierry Reding 		/*
623e94236cdSThierry Reding 		 * TODO: Support modes other than symmetrical left-right
624e94236cdSThierry Reding 		 * split.
625e94236cdSThierry Reding 		 */
626e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2);
627e94236cdSThierry Reding 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
628e94236cdSThierry Reding 					mode->hdisplay / 2);
629e94236cdSThierry Reding 	}
630563eff1fSThierry Reding }
631563eff1fSThierry Reding 
632563eff1fSThierry Reding static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
633563eff1fSThierry Reding {
634563eff1fSThierry Reding 	u32 value;
635563eff1fSThierry Reding 
636563eff1fSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
637563eff1fSThierry Reding 
638563eff1fSThierry Reding 	while (time_before(jiffies, timeout)) {
639563eff1fSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_STATUS);
640563eff1fSThierry Reding 		if (value & DSI_STATUS_IDLE)
641563eff1fSThierry Reding 			return 0;
642563eff1fSThierry Reding 
643563eff1fSThierry Reding 		usleep_range(1000, 2000);
644563eff1fSThierry Reding 	}
645563eff1fSThierry Reding 
646563eff1fSThierry Reding 	return -ETIMEDOUT;
647563eff1fSThierry Reding }
648563eff1fSThierry Reding 
649563eff1fSThierry Reding static void tegra_dsi_video_disable(struct tegra_dsi *dsi)
650563eff1fSThierry Reding {
651563eff1fSThierry Reding 	u32 value;
652563eff1fSThierry Reding 
653563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_CONTROL);
654563eff1fSThierry Reding 	value &= ~DSI_CONTROL_VIDEO_ENABLE;
655563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
656e94236cdSThierry Reding 
657e94236cdSThierry Reding 	if (dsi->slave)
658e94236cdSThierry Reding 		tegra_dsi_video_disable(dsi->slave);
659e94236cdSThierry Reding }
660e94236cdSThierry Reding 
661e94236cdSThierry Reding static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
662e94236cdSThierry Reding {
663e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
664e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
665e94236cdSThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
666563eff1fSThierry Reding }
667563eff1fSThierry Reding 
668ef8187d7SThierry Reding static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
669ef8187d7SThierry Reding {
670ef8187d7SThierry Reding 	u32 value;
671ef8187d7SThierry Reding 
672ef8187d7SThierry Reding 	value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
673ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
674ef8187d7SThierry Reding 
675ef8187d7SThierry Reding 	return 0;
676ef8187d7SThierry Reding }
677ef8187d7SThierry Reding 
678ef8187d7SThierry Reding static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
679ef8187d7SThierry Reding {
680ef8187d7SThierry Reding 	u32 value;
681ef8187d7SThierry Reding 
682ef8187d7SThierry Reding 	/*
683ef8187d7SThierry Reding 	 * XXX Is this still needed? The module reset is deasserted right
684ef8187d7SThierry Reding 	 * before this function is called.
685ef8187d7SThierry Reding 	 */
686ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
687ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
688ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
689ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
690ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
691ef8187d7SThierry Reding 
692ef8187d7SThierry Reding 	/* start calibration */
693ef8187d7SThierry Reding 	tegra_dsi_pad_enable(dsi);
694ef8187d7SThierry Reding 
695ef8187d7SThierry Reding 	value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
696ef8187d7SThierry Reding 		DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
697ef8187d7SThierry Reding 		DSI_PAD_OUT_CLK(0x0);
698ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
699ef8187d7SThierry Reding 
700ef8187d7SThierry Reding 	value = DSI_PAD_PREEMP_PD_CLK(0x3) | DSI_PAD_PREEMP_PU_CLK(0x3) |
701ef8187d7SThierry Reding 		DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3);
702ef8187d7SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_3);
703ef8187d7SThierry Reding 
704ef8187d7SThierry Reding 	return tegra_mipi_calibrate(dsi->mipi);
705ef8187d7SThierry Reding }
706ef8187d7SThierry Reding 
7075b901e78SThierry Reding static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
7085b901e78SThierry Reding 				  unsigned int vrefresh)
7095b901e78SThierry Reding {
7105b901e78SThierry Reding 	unsigned int timeout;
7115b901e78SThierry Reding 	u32 value;
7125b901e78SThierry Reding 
7135b901e78SThierry Reding 	/* one frame high-speed transmission timeout */
7145b901e78SThierry Reding 	timeout = (bclk / vrefresh) / 512;
7155b901e78SThierry Reding 	value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
7165b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
7175b901e78SThierry Reding 
7185b901e78SThierry Reding 	/* 2 ms peripheral timeout for panel */
7195b901e78SThierry Reding 	timeout = 2 * bclk / 512 * 1000;
7205b901e78SThierry Reding 	value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
7215b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
7225b901e78SThierry Reding 
7235b901e78SThierry Reding 	value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
7245b901e78SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
7255b901e78SThierry Reding 
7265b901e78SThierry Reding 	if (dsi->slave)
7275b901e78SThierry Reding 		tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
7285b901e78SThierry Reding }
7295b901e78SThierry Reding 
730563eff1fSThierry Reding static void tegra_dsi_disable(struct tegra_dsi *dsi)
731563eff1fSThierry Reding {
732563eff1fSThierry Reding 	u32 value;
733563eff1fSThierry Reding 
734e94236cdSThierry Reding 	if (dsi->slave) {
735e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi->slave);
736e94236cdSThierry Reding 		tegra_dsi_ganged_disable(dsi);
737e94236cdSThierry Reding 	}
738e94236cdSThierry Reding 
739563eff1fSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
740563eff1fSThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
741563eff1fSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
742563eff1fSThierry Reding 
743e94236cdSThierry Reding 	if (dsi->slave)
744e94236cdSThierry Reding 		tegra_dsi_disable(dsi->slave);
745e94236cdSThierry Reding 
746563eff1fSThierry Reding 	usleep_range(5000, 10000);
747563eff1fSThierry Reding }
748563eff1fSThierry Reding 
74992f0e073SThierry Reding static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
75092f0e073SThierry Reding {
75192f0e073SThierry Reding 	u32 value;
75292f0e073SThierry Reding 
75392f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
75492f0e073SThierry Reding 	value &= ~DSI_POWER_CONTROL_ENABLE;
75592f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
75692f0e073SThierry Reding 
75792f0e073SThierry Reding 	usleep_range(300, 1000);
75892f0e073SThierry Reding 
75992f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
76092f0e073SThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
76192f0e073SThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
76292f0e073SThierry Reding 
76392f0e073SThierry Reding 	usleep_range(300, 1000);
76492f0e073SThierry Reding 
76592f0e073SThierry Reding 	value = tegra_dsi_readl(dsi, DSI_TRIGGER);
76692f0e073SThierry Reding 	if (value)
76792f0e073SThierry Reding 		tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
76892f0e073SThierry Reding 
76992f0e073SThierry Reding 	if (dsi->slave)
77092f0e073SThierry Reding 		tegra_dsi_soft_reset(dsi->slave);
77192f0e073SThierry Reding }
77292f0e073SThierry Reding 
773ebd14afeSThierry Reding static void tegra_dsi_connector_reset(struct drm_connector *connector)
774ebd14afeSThierry Reding {
775280dc0e1SJon Hunter 	struct tegra_dsi_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
776ebd14afeSThierry Reding 
777280dc0e1SJon Hunter 	if (!state)
778280dc0e1SJon Hunter 		return;
779280dc0e1SJon Hunter 
780280dc0e1SJon Hunter 	if (connector->state) {
781280dc0e1SJon Hunter 		__drm_atomic_helper_connector_destroy_state(connector->state);
782ebd14afeSThierry Reding 		kfree(connector->state);
7835459a2adSMaarten Lankhorst 	}
784280dc0e1SJon Hunter 
785280dc0e1SJon Hunter 	__drm_atomic_helper_connector_reset(connector, &state->base);
786ebd14afeSThierry Reding }
787ebd14afeSThierry Reding 
788ebd14afeSThierry Reding static struct drm_connector_state *
789ebd14afeSThierry Reding tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
790ebd14afeSThierry Reding {
791ebd14afeSThierry Reding 	struct tegra_dsi_state *state = to_dsi_state(connector->state);
792ebd14afeSThierry Reding 	struct tegra_dsi_state *copy;
793ebd14afeSThierry Reding 
794ebd14afeSThierry Reding 	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
795ebd14afeSThierry Reding 	if (!copy)
796ebd14afeSThierry Reding 		return NULL;
797ebd14afeSThierry Reding 
798280dc0e1SJon Hunter 	__drm_atomic_helper_connector_duplicate_state(connector,
799280dc0e1SJon Hunter 						      &copy->base);
800280dc0e1SJon Hunter 
801ebd14afeSThierry Reding 	return &copy->base;
802ebd14afeSThierry Reding }
803ebd14afeSThierry Reding 
8045b901e78SThierry Reding static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
805ebd14afeSThierry Reding 	.reset = tegra_dsi_connector_reset,
8065b901e78SThierry Reding 	.detect = tegra_output_connector_detect,
8075b901e78SThierry Reding 	.fill_modes = drm_helper_probe_single_connector_modes,
8085b901e78SThierry Reding 	.destroy = tegra_output_connector_destroy,
809ebd14afeSThierry Reding 	.atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
8104aa3df71SThierry Reding 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
811a813d704SThierry Reding 	.late_register = tegra_dsi_late_register,
812a813d704SThierry Reding 	.early_unregister = tegra_dsi_early_unregister,
8135b901e78SThierry Reding };
8145b901e78SThierry Reding 
8155b901e78SThierry Reding static enum drm_mode_status
8165b901e78SThierry Reding tegra_dsi_connector_mode_valid(struct drm_connector *connector,
8175b901e78SThierry Reding 			       struct drm_display_mode *mode)
8185b901e78SThierry Reding {
8195b901e78SThierry Reding 	return MODE_OK;
8205b901e78SThierry Reding }
8215b901e78SThierry Reding 
8225b901e78SThierry Reding static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
8235b901e78SThierry Reding 	.get_modes = tegra_output_connector_get_modes,
8245b901e78SThierry Reding 	.mode_valid = tegra_dsi_connector_mode_valid,
8255b901e78SThierry Reding };
8265b901e78SThierry Reding 
8275b901e78SThierry Reding static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
8285b901e78SThierry Reding 	.destroy = tegra_output_encoder_destroy,
8295b901e78SThierry Reding };
8305b901e78SThierry Reding 
83187904c3eSThierry Reding static void tegra_dsi_unprepare(struct tegra_dsi *dsi)
83287904c3eSThierry Reding {
83387904c3eSThierry Reding 	int err;
83487904c3eSThierry Reding 
83587904c3eSThierry Reding 	if (dsi->slave)
83687904c3eSThierry Reding 		tegra_dsi_unprepare(dsi->slave);
83787904c3eSThierry Reding 
83887904c3eSThierry Reding 	err = tegra_mipi_disable(dsi->mipi);
83987904c3eSThierry Reding 	if (err < 0)
84087904c3eSThierry Reding 		dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n",
84187904c3eSThierry Reding 			err);
84287904c3eSThierry Reding 
84387904c3eSThierry Reding 	pm_runtime_put(dsi->dev);
84487904c3eSThierry Reding }
84587904c3eSThierry Reding 
8465b901e78SThierry Reding static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
8475b901e78SThierry Reding {
8485b901e78SThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
8495b901e78SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
8505b901e78SThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
8515b901e78SThierry Reding 	u32 value;
8525b901e78SThierry Reding 	int err;
8535b901e78SThierry Reding 
8545b901e78SThierry Reding 	if (output->panel)
8555b901e78SThierry Reding 		drm_panel_disable(output->panel);
8565b901e78SThierry Reding 
8575b901e78SThierry Reding 	tegra_dsi_video_disable(dsi);
8585b901e78SThierry Reding 
8595b901e78SThierry Reding 	/*
8605b901e78SThierry Reding 	 * The following accesses registers of the display controller, so make
8615b901e78SThierry Reding 	 * sure it's only executed when the output is attached to one.
8625b901e78SThierry Reding 	 */
8635b901e78SThierry Reding 	if (dc) {
8645b901e78SThierry Reding 		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
8655b901e78SThierry Reding 		value &= ~DSI_ENABLE;
8665b901e78SThierry Reding 		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
8675b901e78SThierry Reding 
8685b901e78SThierry Reding 		tegra_dc_commit(dc);
8695b901e78SThierry Reding 	}
8705b901e78SThierry Reding 
8715b901e78SThierry Reding 	err = tegra_dsi_wait_idle(dsi, 100);
8725b901e78SThierry Reding 	if (err < 0)
8735b901e78SThierry Reding 		dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
8745b901e78SThierry Reding 
8755b901e78SThierry Reding 	tegra_dsi_soft_reset(dsi);
8765b901e78SThierry Reding 
8775b901e78SThierry Reding 	if (output->panel)
8785b901e78SThierry Reding 		drm_panel_unprepare(output->panel);
8795b901e78SThierry Reding 
8805b901e78SThierry Reding 	tegra_dsi_disable(dsi);
8815b901e78SThierry Reding 
88287904c3eSThierry Reding 	tegra_dsi_unprepare(dsi);
88387904c3eSThierry Reding }
88487904c3eSThierry Reding 
88587904c3eSThierry Reding static void tegra_dsi_prepare(struct tegra_dsi *dsi)
88687904c3eSThierry Reding {
88787904c3eSThierry Reding 	int err;
88887904c3eSThierry Reding 
88987904c3eSThierry Reding 	pm_runtime_get_sync(dsi->dev);
89087904c3eSThierry Reding 
89187904c3eSThierry Reding 	err = tegra_mipi_enable(dsi->mipi);
89287904c3eSThierry Reding 	if (err < 0)
89387904c3eSThierry Reding 		dev_err(dsi->dev, "failed to enable MIPI calibration: %d\n",
89487904c3eSThierry Reding 			err);
89587904c3eSThierry Reding 
89687904c3eSThierry Reding 	err = tegra_dsi_pad_calibrate(dsi);
89787904c3eSThierry Reding 	if (err < 0)
89887904c3eSThierry Reding 		dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
89987904c3eSThierry Reding 
90087904c3eSThierry Reding 	if (dsi->slave)
90187904c3eSThierry Reding 		tegra_dsi_prepare(dsi->slave);
9025b901e78SThierry Reding }
9035b901e78SThierry Reding 
904171e2e6dSThierry Reding static void tegra_dsi_encoder_enable(struct drm_encoder *encoder)
905171e2e6dSThierry Reding {
906171e2e6dSThierry Reding 	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
907171e2e6dSThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
908171e2e6dSThierry Reding 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
909171e2e6dSThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
910171e2e6dSThierry Reding 	struct tegra_dsi_state *state;
911171e2e6dSThierry Reding 	u32 value;
912ef8187d7SThierry Reding 
91387904c3eSThierry Reding 	tegra_dsi_prepare(dsi);
914171e2e6dSThierry Reding 
915171e2e6dSThierry Reding 	state = tegra_dsi_get_state(dsi);
916171e2e6dSThierry Reding 
917171e2e6dSThierry Reding 	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
918171e2e6dSThierry Reding 
919171e2e6dSThierry Reding 	/*
920171e2e6dSThierry Reding 	 * The D-PHY timing fields are expressed in byte-clock cycles, so
921171e2e6dSThierry Reding 	 * multiply the period by 8.
922171e2e6dSThierry Reding 	 */
923171e2e6dSThierry Reding 	tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
924171e2e6dSThierry Reding 
925171e2e6dSThierry Reding 	if (output->panel)
926171e2e6dSThierry Reding 		drm_panel_prepare(output->panel);
927171e2e6dSThierry Reding 
928171e2e6dSThierry Reding 	tegra_dsi_configure(dsi, dc->pipe, mode);
929171e2e6dSThierry Reding 
930171e2e6dSThierry Reding 	/* enable display controller */
931171e2e6dSThierry Reding 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
932171e2e6dSThierry Reding 	value |= DSI_ENABLE;
933171e2e6dSThierry Reding 	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
934171e2e6dSThierry Reding 
935171e2e6dSThierry Reding 	tegra_dc_commit(dc);
936171e2e6dSThierry Reding 
937171e2e6dSThierry Reding 	/* enable DSI controller */
938171e2e6dSThierry Reding 	tegra_dsi_enable(dsi);
939171e2e6dSThierry Reding 
940171e2e6dSThierry Reding 	if (output->panel)
941171e2e6dSThierry Reding 		drm_panel_enable(output->panel);
942171e2e6dSThierry Reding }
943171e2e6dSThierry Reding 
944ebd14afeSThierry Reding static int
945ebd14afeSThierry Reding tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
946ebd14afeSThierry Reding 			       struct drm_crtc_state *crtc_state,
947ebd14afeSThierry Reding 			       struct drm_connector_state *conn_state)
948ebd14afeSThierry Reding {
949ebd14afeSThierry Reding 	struct tegra_output *output = encoder_to_output(encoder);
950ebd14afeSThierry Reding 	struct tegra_dsi_state *state = to_dsi_state(conn_state);
951ebd14afeSThierry Reding 	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
952ebd14afeSThierry Reding 	struct tegra_dsi *dsi = to_dsi(output);
953ebd14afeSThierry Reding 	unsigned int scdiv;
954ebd14afeSThierry Reding 	unsigned long plld;
955ebd14afeSThierry Reding 	int err;
956ebd14afeSThierry Reding 
957ebd14afeSThierry Reding 	state->pclk = crtc_state->mode.clock * 1000;
958ebd14afeSThierry Reding 
959ebd14afeSThierry Reding 	err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
960ebd14afeSThierry Reding 	if (err < 0)
961ebd14afeSThierry Reding 		return err;
962ebd14afeSThierry Reding 
963ebd14afeSThierry Reding 	state->lanes = tegra_dsi_get_lanes(dsi);
964ebd14afeSThierry Reding 
965ebd14afeSThierry Reding 	err = tegra_dsi_get_format(dsi->format, &state->format);
966ebd14afeSThierry Reding 	if (err < 0)
967ebd14afeSThierry Reding 		return err;
968ebd14afeSThierry Reding 
969ebd14afeSThierry Reding 	state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
970ebd14afeSThierry Reding 
971ebd14afeSThierry Reding 	/* compute byte clock */
972ebd14afeSThierry Reding 	state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
973ebd14afeSThierry Reding 
974ebd14afeSThierry Reding 	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
975ebd14afeSThierry Reding 		      state->lanes);
976ebd14afeSThierry Reding 	DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
977ebd14afeSThierry Reding 		      state->vrefresh);
978ebd14afeSThierry Reding 	DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
979ebd14afeSThierry Reding 
980ebd14afeSThierry Reding 	/*
981ebd14afeSThierry Reding 	 * Compute bit clock and round up to the next MHz.
982ebd14afeSThierry Reding 	 */
983ebd14afeSThierry Reding 	plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
984ebd14afeSThierry Reding 	state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
985ebd14afeSThierry Reding 
986ebd14afeSThierry Reding 	err = mipi_dphy_timing_get_default(&state->timing, state->period);
987ebd14afeSThierry Reding 	if (err < 0)
988ebd14afeSThierry Reding 		return err;
989ebd14afeSThierry Reding 
990ebd14afeSThierry Reding 	err = mipi_dphy_timing_validate(&state->timing, state->period);
991ebd14afeSThierry Reding 	if (err < 0) {
992ebd14afeSThierry Reding 		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
993ebd14afeSThierry Reding 		return err;
994ebd14afeSThierry Reding 	}
995ebd14afeSThierry Reding 
996ebd14afeSThierry Reding 	/*
997ebd14afeSThierry Reding 	 * We divide the frequency by two here, but we make up for that by
998ebd14afeSThierry Reding 	 * setting the shift clock divider (further below) to half of the
999ebd14afeSThierry Reding 	 * correct value.
1000ebd14afeSThierry Reding 	 */
1001ebd14afeSThierry Reding 	plld /= 2;
1002ebd14afeSThierry Reding 
1003ebd14afeSThierry Reding 	/*
1004ebd14afeSThierry Reding 	 * Derive pixel clock from bit clock using the shift clock divider.
1005ebd14afeSThierry Reding 	 * Note that this is only half of what we would expect, but we need
1006ebd14afeSThierry Reding 	 * that to make up for the fact that we divided the bit clock by a
1007ebd14afeSThierry Reding 	 * factor of two above.
1008ebd14afeSThierry Reding 	 *
1009ebd14afeSThierry Reding 	 * It's not clear exactly why this is necessary, but the display is
1010ebd14afeSThierry Reding 	 * not working properly otherwise. Perhaps the PLLs cannot generate
1011ebd14afeSThierry Reding 	 * frequencies sufficiently high.
1012ebd14afeSThierry Reding 	 */
1013ebd14afeSThierry Reding 	scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
1014ebd14afeSThierry Reding 
1015ebd14afeSThierry Reding 	err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
1016ebd14afeSThierry Reding 					 plld, scdiv);
1017ebd14afeSThierry Reding 	if (err < 0) {
1018ebd14afeSThierry Reding 		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
1019ebd14afeSThierry Reding 		return err;
1020ebd14afeSThierry Reding 	}
1021ebd14afeSThierry Reding 
1022ebd14afeSThierry Reding 	return err;
1023ebd14afeSThierry Reding }
1024ebd14afeSThierry Reding 
10255b901e78SThierry Reding static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
10265b901e78SThierry Reding 	.disable = tegra_dsi_encoder_disable,
1027171e2e6dSThierry Reding 	.enable = tegra_dsi_encoder_enable,
1028ebd14afeSThierry Reding 	.atomic_check = tegra_dsi_encoder_atomic_check,
1029dec72739SThierry Reding };
1030dec72739SThierry Reding 
1031dec72739SThierry Reding static int tegra_dsi_init(struct host1x_client *client)
1032dec72739SThierry Reding {
10339910f5c4SThierry Reding 	struct drm_device *drm = dev_get_drvdata(client->parent);
1034dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1035dec72739SThierry Reding 	int err;
1036dec72739SThierry Reding 
1037e94236cdSThierry Reding 	/* Gangsters must not register their own outputs. */
1038e94236cdSThierry Reding 	if (!dsi->master) {
1039dec72739SThierry Reding 		dsi->output.dev = client->dev;
1040dec72739SThierry Reding 
10415b901e78SThierry Reding 		drm_connector_init(drm, &dsi->output.connector,
10425b901e78SThierry Reding 				   &tegra_dsi_connector_funcs,
10435b901e78SThierry Reding 				   DRM_MODE_CONNECTOR_DSI);
10445b901e78SThierry Reding 		drm_connector_helper_add(&dsi->output.connector,
10455b901e78SThierry Reding 					 &tegra_dsi_connector_helper_funcs);
10465b901e78SThierry Reding 		dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
10475b901e78SThierry Reding 
10485b901e78SThierry Reding 		drm_encoder_init(drm, &dsi->output.encoder,
10495b901e78SThierry Reding 				 &tegra_dsi_encoder_funcs,
105013a3d91fSVille Syrjälä 				 DRM_MODE_ENCODER_DSI, NULL);
10515b901e78SThierry Reding 		drm_encoder_helper_add(&dsi->output.encoder,
10525b901e78SThierry Reding 				       &tegra_dsi_encoder_helper_funcs);
10535b901e78SThierry Reding 
1054cde4c44dSDaniel Vetter 		drm_connector_attach_encoder(&dsi->output.connector,
10555b901e78SThierry Reding 						  &dsi->output.encoder);
10565b901e78SThierry Reding 		drm_connector_register(&dsi->output.connector);
10575b901e78SThierry Reding 
1058ea130b24SThierry Reding 		err = tegra_output_init(drm, &dsi->output);
1059ef8187d7SThierry Reding 		if (err < 0)
1060ef8187d7SThierry Reding 			dev_err(dsi->dev, "failed to initialize output: %d\n",
1061ea130b24SThierry Reding 				err);
1062ea130b24SThierry Reding 
10635b901e78SThierry Reding 		dsi->output.encoder.possible_crtcs = 0x3;
1064e94236cdSThierry Reding 	}
1065dec72739SThierry Reding 
1066dec72739SThierry Reding 	return 0;
1067dec72739SThierry Reding }
1068dec72739SThierry Reding 
1069dec72739SThierry Reding static int tegra_dsi_exit(struct host1x_client *client)
1070dec72739SThierry Reding {
1071dec72739SThierry Reding 	struct tegra_dsi *dsi = host1x_client_to_dsi(client);
1072dec72739SThierry Reding 
10735b901e78SThierry Reding 	tegra_output_exit(&dsi->output);
1074201106d8SThierry Reding 
1075dec72739SThierry Reding 	return 0;
1076dec72739SThierry Reding }
1077dec72739SThierry Reding 
1078dec72739SThierry Reding static const struct host1x_client_ops dsi_client_ops = {
1079dec72739SThierry Reding 	.init = tegra_dsi_init,
1080dec72739SThierry Reding 	.exit = tegra_dsi_exit,
1081dec72739SThierry Reding };
1082dec72739SThierry Reding 
1083dec72739SThierry Reding static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
1084dec72739SThierry Reding {
1085dec72739SThierry Reding 	struct clk *parent;
1086dec72739SThierry Reding 	int err;
1087dec72739SThierry Reding 
1088dec72739SThierry Reding 	parent = clk_get_parent(dsi->clk);
1089dec72739SThierry Reding 	if (!parent)
1090dec72739SThierry Reding 		return -EINVAL;
1091dec72739SThierry Reding 
1092dec72739SThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1093dec72739SThierry Reding 	if (err < 0)
1094dec72739SThierry Reding 		return err;
1095dec72739SThierry Reding 
1096dec72739SThierry Reding 	return 0;
1097dec72739SThierry Reding }
1098dec72739SThierry Reding 
10990fffdf6cSThierry Reding static const char * const error_report[16] = {
11000fffdf6cSThierry Reding 	"SoT Error",
11010fffdf6cSThierry Reding 	"SoT Sync Error",
11020fffdf6cSThierry Reding 	"EoT Sync Error",
11030fffdf6cSThierry Reding 	"Escape Mode Entry Command Error",
11040fffdf6cSThierry Reding 	"Low-Power Transmit Sync Error",
11050fffdf6cSThierry Reding 	"Peripheral Timeout Error",
11060fffdf6cSThierry Reding 	"False Control Error",
11070fffdf6cSThierry Reding 	"Contention Detected",
11080fffdf6cSThierry Reding 	"ECC Error, single-bit",
11090fffdf6cSThierry Reding 	"ECC Error, multi-bit",
11100fffdf6cSThierry Reding 	"Checksum Error",
11110fffdf6cSThierry Reding 	"DSI Data Type Not Recognized",
11120fffdf6cSThierry Reding 	"DSI VC ID Invalid",
11130fffdf6cSThierry Reding 	"Invalid Transmission Length",
11140fffdf6cSThierry Reding 	"Reserved",
11150fffdf6cSThierry Reding 	"DSI Protocol Violation",
11160fffdf6cSThierry Reding };
11170fffdf6cSThierry Reding 
11180fffdf6cSThierry Reding static ssize_t tegra_dsi_read_response(struct tegra_dsi *dsi,
11190fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg,
11200fffdf6cSThierry Reding 				       size_t count)
11210fffdf6cSThierry Reding {
11220fffdf6cSThierry Reding 	u8 *rx = msg->rx_buf;
11230fffdf6cSThierry Reding 	unsigned int i, j, k;
11240fffdf6cSThierry Reding 	size_t size = 0;
11250fffdf6cSThierry Reding 	u16 errors;
11260fffdf6cSThierry Reding 	u32 value;
11270fffdf6cSThierry Reding 
11280fffdf6cSThierry Reding 	/* read and parse packet header */
11290fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_RD_DATA);
11300fffdf6cSThierry Reding 
11310fffdf6cSThierry Reding 	switch (value & 0x3f) {
11320fffdf6cSThierry Reding 	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
11330fffdf6cSThierry Reding 		errors = (value >> 8) & 0xffff;
11340fffdf6cSThierry Reding 		dev_dbg(dsi->dev, "Acknowledge and error report: %04x\n",
11350fffdf6cSThierry Reding 			errors);
11360fffdf6cSThierry Reding 		for (i = 0; i < ARRAY_SIZE(error_report); i++)
11370fffdf6cSThierry Reding 			if (errors & BIT(i))
11380fffdf6cSThierry Reding 				dev_dbg(dsi->dev, "  %2u: %s\n", i,
11390fffdf6cSThierry Reding 					error_report[i]);
11400fffdf6cSThierry Reding 		break;
11410fffdf6cSThierry Reding 
11420fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
11430fffdf6cSThierry Reding 		rx[0] = (value >> 8) & 0xff;
11440fffdf6cSThierry Reding 		size = 1;
11450fffdf6cSThierry Reding 		break;
11460fffdf6cSThierry Reding 
11470fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
11480fffdf6cSThierry Reding 		rx[0] = (value >>  8) & 0xff;
11490fffdf6cSThierry Reding 		rx[1] = (value >> 16) & 0xff;
11500fffdf6cSThierry Reding 		size = 2;
11510fffdf6cSThierry Reding 		break;
11520fffdf6cSThierry Reding 
11530fffdf6cSThierry Reding 	case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
11540fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
11550fffdf6cSThierry Reding 		break;
11560fffdf6cSThierry Reding 
11570fffdf6cSThierry Reding 	case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
11580fffdf6cSThierry Reding 		size = ((value >> 8) & 0xff00) | ((value >> 8) & 0xff);
11590fffdf6cSThierry Reding 		break;
11600fffdf6cSThierry Reding 
11610fffdf6cSThierry Reding 	default:
11620fffdf6cSThierry Reding 		dev_err(dsi->dev, "unhandled response type: %02x\n",
11630fffdf6cSThierry Reding 			value & 0x3f);
11640fffdf6cSThierry Reding 		return -EPROTO;
11650fffdf6cSThierry Reding 	}
11660fffdf6cSThierry Reding 
11670fffdf6cSThierry Reding 	size = min(size, msg->rx_len);
11680fffdf6cSThierry Reding 
11690fffdf6cSThierry Reding 	if (msg->rx_buf && size > 0) {
11700fffdf6cSThierry Reding 		for (i = 0, j = 0; i < count - 1; i++, j += 4) {
11710fffdf6cSThierry Reding 			u8 *rx = msg->rx_buf + j;
11720fffdf6cSThierry Reding 
11730fffdf6cSThierry Reding 			value = tegra_dsi_readl(dsi, DSI_RD_DATA);
11740fffdf6cSThierry Reding 
11750fffdf6cSThierry Reding 			for (k = 0; k < 4 && (j + k) < msg->rx_len; k++)
11760fffdf6cSThierry Reding 				rx[j + k] = (value >> (k << 3)) & 0xff;
11770fffdf6cSThierry Reding 		}
11780fffdf6cSThierry Reding 	}
11790fffdf6cSThierry Reding 
11800fffdf6cSThierry Reding 	return size;
11810fffdf6cSThierry Reding }
11820fffdf6cSThierry Reding 
11830fffdf6cSThierry Reding static int tegra_dsi_transmit(struct tegra_dsi *dsi, unsigned long timeout)
11840fffdf6cSThierry Reding {
11850fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, DSI_TRIGGER_HOST, DSI_TRIGGER);
11860fffdf6cSThierry Reding 
11870fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(timeout);
11880fffdf6cSThierry Reding 
11890fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
11900fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_TRIGGER);
11910fffdf6cSThierry Reding 		if ((value & DSI_TRIGGER_HOST) == 0)
11920fffdf6cSThierry Reding 			return 0;
11930fffdf6cSThierry Reding 
11940fffdf6cSThierry Reding 		usleep_range(1000, 2000);
11950fffdf6cSThierry Reding 	}
11960fffdf6cSThierry Reding 
11970fffdf6cSThierry Reding 	DRM_DEBUG_KMS("timeout waiting for transmission to complete\n");
11980fffdf6cSThierry Reding 	return -ETIMEDOUT;
11990fffdf6cSThierry Reding }
12000fffdf6cSThierry Reding 
12010fffdf6cSThierry Reding static int tegra_dsi_wait_for_response(struct tegra_dsi *dsi,
12020fffdf6cSThierry Reding 				       unsigned long timeout)
12030fffdf6cSThierry Reding {
12040fffdf6cSThierry Reding 	timeout = jiffies + msecs_to_jiffies(250);
12050fffdf6cSThierry Reding 
12060fffdf6cSThierry Reding 	while (time_before(jiffies, timeout)) {
12070fffdf6cSThierry Reding 		u32 value = tegra_dsi_readl(dsi, DSI_STATUS);
12080fffdf6cSThierry Reding 		u8 count = value & 0x1f;
12090fffdf6cSThierry Reding 
12100fffdf6cSThierry Reding 		if (count > 0)
12110fffdf6cSThierry Reding 			return count;
12120fffdf6cSThierry Reding 
12130fffdf6cSThierry Reding 		usleep_range(1000, 2000);
12140fffdf6cSThierry Reding 	}
12150fffdf6cSThierry Reding 
12160fffdf6cSThierry Reding 	DRM_DEBUG_KMS("peripheral returned no data\n");
12170fffdf6cSThierry Reding 	return -ETIMEDOUT;
12180fffdf6cSThierry Reding }
12190fffdf6cSThierry Reding 
12200fffdf6cSThierry Reding static void tegra_dsi_writesl(struct tegra_dsi *dsi, unsigned long offset,
12210fffdf6cSThierry Reding 			      const void *buffer, size_t size)
12220fffdf6cSThierry Reding {
12230fffdf6cSThierry Reding 	const u8 *buf = buffer;
12240fffdf6cSThierry Reding 	size_t i, j;
12250fffdf6cSThierry Reding 	u32 value;
12260fffdf6cSThierry Reding 
12270fffdf6cSThierry Reding 	for (j = 0; j < size; j += 4) {
12280fffdf6cSThierry Reding 		value = 0;
12290fffdf6cSThierry Reding 
12300fffdf6cSThierry Reding 		for (i = 0; i < 4 && j + i < size; i++)
12310fffdf6cSThierry Reding 			value |= buf[j + i] << (i << 3);
12320fffdf6cSThierry Reding 
12330fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_WR_DATA);
12340fffdf6cSThierry Reding 	}
12350fffdf6cSThierry Reding }
12360fffdf6cSThierry Reding 
12370fffdf6cSThierry Reding static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host,
12380fffdf6cSThierry Reding 				       const struct mipi_dsi_msg *msg)
12390fffdf6cSThierry Reding {
12400fffdf6cSThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
12410fffdf6cSThierry Reding 	struct mipi_dsi_packet packet;
12420fffdf6cSThierry Reding 	const u8 *header;
12430fffdf6cSThierry Reding 	size_t count;
12440fffdf6cSThierry Reding 	ssize_t err;
12450fffdf6cSThierry Reding 	u32 value;
12460fffdf6cSThierry Reding 
12470fffdf6cSThierry Reding 	err = mipi_dsi_create_packet(&packet, msg);
12480fffdf6cSThierry Reding 	if (err < 0)
12490fffdf6cSThierry Reding 		return err;
12500fffdf6cSThierry Reding 
12510fffdf6cSThierry Reding 	header = packet.header;
12520fffdf6cSThierry Reding 
12530fffdf6cSThierry Reding 	/* maximum FIFO depth is 1920 words */
12540fffdf6cSThierry Reding 	if (packet.size > dsi->video_fifo_depth * 4)
12550fffdf6cSThierry Reding 		return -ENOSPC;
12560fffdf6cSThierry Reding 
12570fffdf6cSThierry Reding 	/* reset underflow/overflow flags */
12580fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_STATUS);
12590fffdf6cSThierry Reding 	if (value & (DSI_STATUS_UNDERFLOW | DSI_STATUS_OVERFLOW)) {
12600fffdf6cSThierry Reding 		value = DSI_HOST_CONTROL_FIFO_RESET;
12610fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12620fffdf6cSThierry Reding 		usleep_range(10, 20);
12630fffdf6cSThierry Reding 	}
12640fffdf6cSThierry Reding 
12650fffdf6cSThierry Reding 	value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
12660fffdf6cSThierry Reding 	value |= DSI_POWER_CONTROL_ENABLE;
12670fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
12680fffdf6cSThierry Reding 
12690fffdf6cSThierry Reding 	usleep_range(5000, 10000);
12700fffdf6cSThierry Reding 
12710fffdf6cSThierry Reding 	value = DSI_HOST_CONTROL_CRC_RESET | DSI_HOST_CONTROL_TX_TRIG_HOST |
12720fffdf6cSThierry Reding 		DSI_HOST_CONTROL_CS | DSI_HOST_CONTROL_ECC;
12730fffdf6cSThierry Reding 
12740fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_USE_LPM) == 0)
12750fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_HS;
12760fffdf6cSThierry Reding 
12770fffdf6cSThierry Reding 	/*
12780fffdf6cSThierry Reding 	 * The host FIFO has a maximum of 64 words, so larger transmissions
12790fffdf6cSThierry Reding 	 * need to use the video FIFO.
12800fffdf6cSThierry Reding 	 */
12810fffdf6cSThierry Reding 	if (packet.size > dsi->host_fifo_depth * 4)
12820fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_FIFO_SEL;
12830fffdf6cSThierry Reding 
12840fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12850fffdf6cSThierry Reding 
12860fffdf6cSThierry Reding 	/*
12870fffdf6cSThierry Reding 	 * For reads and messages with explicitly requested ACK, generate a
12880fffdf6cSThierry Reding 	 * BTA sequence after the transmission of the packet.
12890fffdf6cSThierry Reding 	 */
12900fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
12910fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
12920fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
12930fffdf6cSThierry Reding 		value |= DSI_HOST_CONTROL_PKT_BTA;
12940fffdf6cSThierry Reding 		tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
12950fffdf6cSThierry Reding 	}
12960fffdf6cSThierry Reding 
12970fffdf6cSThierry Reding 	value = DSI_CONTROL_LANES(0) | DSI_CONTROL_HOST_ENABLE;
12980fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
12990fffdf6cSThierry Reding 
13000fffdf6cSThierry Reding 	/* write packet header, ECC is generated by hardware */
13010fffdf6cSThierry Reding 	value = header[2] << 16 | header[1] << 8 | header[0];
13020fffdf6cSThierry Reding 	tegra_dsi_writel(dsi, value, DSI_WR_DATA);
13030fffdf6cSThierry Reding 
13040fffdf6cSThierry Reding 	/* write payload (if any) */
13050fffdf6cSThierry Reding 	if (packet.payload_length > 0)
13060fffdf6cSThierry Reding 		tegra_dsi_writesl(dsi, DSI_WR_DATA, packet.payload,
13070fffdf6cSThierry Reding 				  packet.payload_length);
13080fffdf6cSThierry Reding 
13090fffdf6cSThierry Reding 	err = tegra_dsi_transmit(dsi, 250);
13100fffdf6cSThierry Reding 	if (err < 0)
13110fffdf6cSThierry Reding 		return err;
13120fffdf6cSThierry Reding 
13130fffdf6cSThierry Reding 	if ((msg->flags & MIPI_DSI_MSG_REQ_ACK) ||
13140fffdf6cSThierry Reding 	    (msg->rx_buf && msg->rx_len > 0)) {
13150fffdf6cSThierry Reding 		err = tegra_dsi_wait_for_response(dsi, 250);
13160fffdf6cSThierry Reding 		if (err < 0)
13170fffdf6cSThierry Reding 			return err;
13180fffdf6cSThierry Reding 
13190fffdf6cSThierry Reding 		count = err;
13200fffdf6cSThierry Reding 
13210fffdf6cSThierry Reding 		value = tegra_dsi_readl(dsi, DSI_RD_DATA);
13220fffdf6cSThierry Reding 		switch (value) {
13230fffdf6cSThierry Reding 		case 0x84:
13240fffdf6cSThierry Reding 			/*
13250fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ACK\n");
13260fffdf6cSThierry Reding 			*/
13270fffdf6cSThierry Reding 			break;
13280fffdf6cSThierry Reding 
13290fffdf6cSThierry Reding 		case 0x87:
13300fffdf6cSThierry Reding 			/*
13310fffdf6cSThierry Reding 			dev_dbg(dsi->dev, "ESCAPE\n");
13320fffdf6cSThierry Reding 			*/
13330fffdf6cSThierry Reding 			break;
13340fffdf6cSThierry Reding 
13350fffdf6cSThierry Reding 		default:
13360fffdf6cSThierry Reding 			dev_err(dsi->dev, "unknown status: %08x\n", value);
13370fffdf6cSThierry Reding 			break;
13380fffdf6cSThierry Reding 		}
13390fffdf6cSThierry Reding 
13400fffdf6cSThierry Reding 		if (count > 1) {
13410fffdf6cSThierry Reding 			err = tegra_dsi_read_response(dsi, msg, count);
13420fffdf6cSThierry Reding 			if (err < 0)
13430fffdf6cSThierry Reding 				dev_err(dsi->dev,
13440fffdf6cSThierry Reding 					"failed to parse response: %zd\n",
13450fffdf6cSThierry Reding 					err);
13460fffdf6cSThierry Reding 			else {
13470fffdf6cSThierry Reding 				/*
13480fffdf6cSThierry Reding 				 * For read commands, return the number of
13490fffdf6cSThierry Reding 				 * bytes returned by the peripheral.
13500fffdf6cSThierry Reding 				 */
13510fffdf6cSThierry Reding 				count = err;
13520fffdf6cSThierry Reding 			}
13530fffdf6cSThierry Reding 		}
13540fffdf6cSThierry Reding 	} else {
13550fffdf6cSThierry Reding 		/*
13560fffdf6cSThierry Reding 		 * For write commands, we have transmitted the 4-byte header
13570fffdf6cSThierry Reding 		 * plus the variable-length payload.
13580fffdf6cSThierry Reding 		 */
13590fffdf6cSThierry Reding 		count = 4 + packet.payload_length;
13600fffdf6cSThierry Reding 	}
13610fffdf6cSThierry Reding 
13620fffdf6cSThierry Reding 	return count;
13630fffdf6cSThierry Reding }
13640fffdf6cSThierry Reding 
1365e94236cdSThierry Reding static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi)
1366e94236cdSThierry Reding {
1367e94236cdSThierry Reding 	struct clk *parent;
1368e94236cdSThierry Reding 	int err;
1369e94236cdSThierry Reding 
1370e94236cdSThierry Reding 	/* make sure both DSI controllers share the same PLL */
1371e94236cdSThierry Reding 	parent = clk_get_parent(dsi->slave->clk);
1372e94236cdSThierry Reding 	if (!parent)
1373e94236cdSThierry Reding 		return -EINVAL;
1374e94236cdSThierry Reding 
1375e94236cdSThierry Reding 	err = clk_set_parent(parent, dsi->clk_parent);
1376e94236cdSThierry Reding 	if (err < 0)
1377e94236cdSThierry Reding 		return err;
1378e94236cdSThierry Reding 
1379e94236cdSThierry Reding 	return 0;
1380e94236cdSThierry Reding }
1381e94236cdSThierry Reding 
1382dec72739SThierry Reding static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
1383dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1384dec72739SThierry Reding {
1385dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1386dec72739SThierry Reding 
138717297a28SThierry Reding 	dsi->flags = device->mode_flags;
1388dec72739SThierry Reding 	dsi->format = device->format;
1389dec72739SThierry Reding 	dsi->lanes = device->lanes;
1390dec72739SThierry Reding 
1391e94236cdSThierry Reding 	if (dsi->slave) {
1392e94236cdSThierry Reding 		int err;
1393e94236cdSThierry Reding 
1394e94236cdSThierry Reding 		dev_dbg(dsi->dev, "attaching dual-channel device %s\n",
1395e94236cdSThierry Reding 			dev_name(&device->dev));
1396e94236cdSThierry Reding 
1397e94236cdSThierry Reding 		err = tegra_dsi_ganged_setup(dsi);
1398e94236cdSThierry Reding 		if (err < 0) {
1399e94236cdSThierry Reding 			dev_err(dsi->dev, "failed to set up ganged mode: %d\n",
1400e94236cdSThierry Reding 				err);
1401e94236cdSThierry Reding 			return err;
1402e94236cdSThierry Reding 		}
1403e94236cdSThierry Reding 	}
1404e94236cdSThierry Reding 
1405e94236cdSThierry Reding 	/*
1406e94236cdSThierry Reding 	 * Slaves don't have a panel associated with them, so they provide
1407e94236cdSThierry Reding 	 * merely the second channel.
1408e94236cdSThierry Reding 	 */
1409e94236cdSThierry Reding 	if (!dsi->master) {
1410e94236cdSThierry Reding 		struct tegra_output *output = &dsi->output;
1411e94236cdSThierry Reding 
1412dec72739SThierry Reding 		output->panel = of_drm_find_panel(device->dev.of_node);
14135fa8e4a2SBoris Brezillon 		if (IS_ERR(output->panel))
14145fa8e4a2SBoris Brezillon 			output->panel = NULL;
14155fa8e4a2SBoris Brezillon 
1416e94236cdSThierry Reding 		if (output->panel && output->connector.dev) {
1417e94236cdSThierry Reding 			drm_panel_attach(output->panel, &output->connector);
1418dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1419dec72739SThierry Reding 		}
1420e94236cdSThierry Reding 	}
1421dec72739SThierry Reding 
1422dec72739SThierry Reding 	return 0;
1423dec72739SThierry Reding }
1424dec72739SThierry Reding 
1425dec72739SThierry Reding static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
1426dec72739SThierry Reding 				 struct mipi_dsi_device *device)
1427dec72739SThierry Reding {
1428dec72739SThierry Reding 	struct tegra_dsi *dsi = host_to_tegra(host);
1429dec72739SThierry Reding 	struct tegra_output *output = &dsi->output;
1430dec72739SThierry Reding 
1431dec72739SThierry Reding 	if (output->panel && &device->dev == output->panel->dev) {
1432ba3df979SThierry Reding 		output->panel = NULL;
1433ba3df979SThierry Reding 
1434dec72739SThierry Reding 		if (output->connector.dev)
1435dec72739SThierry Reding 			drm_helper_hpd_irq_event(output->connector.dev);
1436dec72739SThierry Reding 	}
1437dec72739SThierry Reding 
1438dec72739SThierry Reding 	return 0;
1439dec72739SThierry Reding }
1440dec72739SThierry Reding 
1441dec72739SThierry Reding static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
1442dec72739SThierry Reding 	.attach = tegra_dsi_host_attach,
1443dec72739SThierry Reding 	.detach = tegra_dsi_host_detach,
14440fffdf6cSThierry Reding 	.transfer = tegra_dsi_host_transfer,
1445dec72739SThierry Reding };
1446dec72739SThierry Reding 
1447e94236cdSThierry Reding static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi)
1448e94236cdSThierry Reding {
1449e94236cdSThierry Reding 	struct device_node *np;
1450e94236cdSThierry Reding 
1451e94236cdSThierry Reding 	np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0);
1452e94236cdSThierry Reding 	if (np) {
1453e94236cdSThierry Reding 		struct platform_device *gangster = of_find_device_by_node(np);
1454e94236cdSThierry Reding 
1455e94236cdSThierry Reding 		dsi->slave = platform_get_drvdata(gangster);
1456e94236cdSThierry Reding 		of_node_put(np);
1457e94236cdSThierry Reding 
1458e94236cdSThierry Reding 		if (!dsi->slave)
1459e94236cdSThierry Reding 			return -EPROBE_DEFER;
1460e94236cdSThierry Reding 
1461e94236cdSThierry Reding 		dsi->slave->master = dsi;
1462e94236cdSThierry Reding 	}
1463e94236cdSThierry Reding 
1464e94236cdSThierry Reding 	return 0;
1465e94236cdSThierry Reding }
1466e94236cdSThierry Reding 
1467dec72739SThierry Reding static int tegra_dsi_probe(struct platform_device *pdev)
1468dec72739SThierry Reding {
1469dec72739SThierry Reding 	struct tegra_dsi *dsi;
1470dec72739SThierry Reding 	struct resource *regs;
1471dec72739SThierry Reding 	int err;
1472dec72739SThierry Reding 
1473dec72739SThierry Reding 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
1474dec72739SThierry Reding 	if (!dsi)
1475dec72739SThierry Reding 		return -ENOMEM;
1476dec72739SThierry Reding 
1477dec72739SThierry Reding 	dsi->output.dev = dsi->dev = &pdev->dev;
1478976cebc3SThierry Reding 	dsi->video_fifo_depth = 1920;
1479976cebc3SThierry Reding 	dsi->host_fifo_depth = 64;
1480dec72739SThierry Reding 
1481e94236cdSThierry Reding 	err = tegra_dsi_ganged_probe(dsi);
1482e94236cdSThierry Reding 	if (err < 0)
1483e94236cdSThierry Reding 		return err;
1484e94236cdSThierry Reding 
1485dec72739SThierry Reding 	err = tegra_output_probe(&dsi->output);
1486dec72739SThierry Reding 	if (err < 0)
1487dec72739SThierry Reding 		return err;
1488dec72739SThierry Reding 
1489ba3df979SThierry Reding 	dsi->output.connector.polled = DRM_CONNECTOR_POLL_HPD;
1490ba3df979SThierry Reding 
1491dec72739SThierry Reding 	/*
1492dec72739SThierry Reding 	 * Assume these values by default. When a DSI peripheral driver
1493dec72739SThierry Reding 	 * attaches to the DSI host, the parameters will be taken from
1494dec72739SThierry Reding 	 * the attached device.
1495dec72739SThierry Reding 	 */
149617297a28SThierry Reding 	dsi->flags = MIPI_DSI_MODE_VIDEO;
1497dec72739SThierry Reding 	dsi->format = MIPI_DSI_FMT_RGB888;
1498dec72739SThierry Reding 	dsi->lanes = 4;
1499dec72739SThierry Reding 
150064230aa0SJon Hunter 	if (!pdev->dev.pm_domain) {
1501dec72739SThierry Reding 		dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
1502dec72739SThierry Reding 		if (IS_ERR(dsi->rst))
1503dec72739SThierry Reding 			return PTR_ERR(dsi->rst);
150464230aa0SJon Hunter 	}
1505dec72739SThierry Reding 
1506dec72739SThierry Reding 	dsi->clk = devm_clk_get(&pdev->dev, NULL);
1507dec72739SThierry Reding 	if (IS_ERR(dsi->clk)) {
1508dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get DSI clock\n");
1509ef8187d7SThierry Reding 		return PTR_ERR(dsi->clk);
1510dec72739SThierry Reding 	}
1511dec72739SThierry Reding 
1512dec72739SThierry Reding 	dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
1513dec72739SThierry Reding 	if (IS_ERR(dsi->clk_lp)) {
1514dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get low-power clock\n");
1515ef8187d7SThierry Reding 		return PTR_ERR(dsi->clk_lp);
1516dec72739SThierry Reding 	}
1517dec72739SThierry Reding 
1518dec72739SThierry Reding 	dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
1519dec72739SThierry Reding 	if (IS_ERR(dsi->clk_parent)) {
1520dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot get parent clock\n");
1521ef8187d7SThierry Reding 		return PTR_ERR(dsi->clk_parent);
1522dec72739SThierry Reding 	}
1523dec72739SThierry Reding 
15243b077afbSThierry Reding 	dsi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
15253b077afbSThierry Reding 	if (IS_ERR(dsi->vdd)) {
15263b077afbSThierry Reding 		dev_err(&pdev->dev, "cannot get VDD supply\n");
1527ef8187d7SThierry Reding 		return PTR_ERR(dsi->vdd);
15283b077afbSThierry Reding 	}
15293b077afbSThierry Reding 
1530dec72739SThierry Reding 	err = tegra_dsi_setup_clocks(dsi);
1531dec72739SThierry Reding 	if (err < 0) {
1532dec72739SThierry Reding 		dev_err(&pdev->dev, "cannot setup clocks\n");
1533ef8187d7SThierry Reding 		return err;
1534dec72739SThierry Reding 	}
1535dec72739SThierry Reding 
1536dec72739SThierry Reding 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1537dec72739SThierry Reding 	dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
1538ef8187d7SThierry Reding 	if (IS_ERR(dsi->regs))
1539ef8187d7SThierry Reding 		return PTR_ERR(dsi->regs);
1540dec72739SThierry Reding 
1541dec72739SThierry Reding 	dsi->mipi = tegra_mipi_request(&pdev->dev);
1542ef8187d7SThierry Reding 	if (IS_ERR(dsi->mipi))
1543ef8187d7SThierry Reding 		return PTR_ERR(dsi->mipi);
1544dec72739SThierry Reding 
1545dec72739SThierry Reding 	dsi->host.ops = &tegra_dsi_host_ops;
1546dec72739SThierry Reding 	dsi->host.dev = &pdev->dev;
1547dec72739SThierry Reding 
1548dec72739SThierry Reding 	err = mipi_dsi_host_register(&dsi->host);
1549dec72739SThierry Reding 	if (err < 0) {
1550dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
1551d2d0a9d2SThierry Reding 		goto mipi_free;
1552dec72739SThierry Reding 	}
1553dec72739SThierry Reding 
1554ef8187d7SThierry Reding 	platform_set_drvdata(pdev, dsi);
1555ef8187d7SThierry Reding 	pm_runtime_enable(&pdev->dev);
1556ef8187d7SThierry Reding 
1557dec72739SThierry Reding 	INIT_LIST_HEAD(&dsi->client.list);
1558dec72739SThierry Reding 	dsi->client.ops = &dsi_client_ops;
1559dec72739SThierry Reding 	dsi->client.dev = &pdev->dev;
1560dec72739SThierry Reding 
1561dec72739SThierry Reding 	err = host1x_client_register(&dsi->client);
1562dec72739SThierry Reding 	if (err < 0) {
1563dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to register host1x client: %d\n",
1564dec72739SThierry Reding 			err);
1565d2d0a9d2SThierry Reding 		goto unregister;
1566dec72739SThierry Reding 	}
1567dec72739SThierry Reding 
1568dec72739SThierry Reding 	return 0;
1569d2d0a9d2SThierry Reding 
1570d2d0a9d2SThierry Reding unregister:
1571d2d0a9d2SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1572d2d0a9d2SThierry Reding mipi_free:
1573d2d0a9d2SThierry Reding 	tegra_mipi_free(dsi->mipi);
1574d2d0a9d2SThierry Reding 	return err;
1575dec72739SThierry Reding }
1576dec72739SThierry Reding 
1577dec72739SThierry Reding static int tegra_dsi_remove(struct platform_device *pdev)
1578dec72739SThierry Reding {
1579dec72739SThierry Reding 	struct tegra_dsi *dsi = platform_get_drvdata(pdev);
1580dec72739SThierry Reding 	int err;
1581dec72739SThierry Reding 
1582ef8187d7SThierry Reding 	pm_runtime_disable(&pdev->dev);
1583ef8187d7SThierry Reding 
1584dec72739SThierry Reding 	err = host1x_client_unregister(&dsi->client);
1585dec72739SThierry Reding 	if (err < 0) {
1586dec72739SThierry Reding 		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
1587dec72739SThierry Reding 			err);
1588dec72739SThierry Reding 		return err;
1589dec72739SThierry Reding 	}
1590dec72739SThierry Reding 
1591328ec69eSThierry Reding 	tegra_output_remove(&dsi->output);
15925b901e78SThierry Reding 
1593dec72739SThierry Reding 	mipi_dsi_host_unregister(&dsi->host);
1594dec72739SThierry Reding 	tegra_mipi_free(dsi->mipi);
1595dec72739SThierry Reding 
1596ef8187d7SThierry Reding 	return 0;
1597ef8187d7SThierry Reding }
1598ef8187d7SThierry Reding 
1599ef8187d7SThierry Reding #ifdef CONFIG_PM
1600ef8187d7SThierry Reding static int tegra_dsi_suspend(struct device *dev)
1601ef8187d7SThierry Reding {
1602ef8187d7SThierry Reding 	struct tegra_dsi *dsi = dev_get_drvdata(dev);
1603ef8187d7SThierry Reding 	int err;
1604ef8187d7SThierry Reding 
160564230aa0SJon Hunter 	if (dsi->rst) {
1606ef8187d7SThierry Reding 		err = reset_control_assert(dsi->rst);
1607ef8187d7SThierry Reding 		if (err < 0) {
1608ef8187d7SThierry Reding 			dev_err(dev, "failed to assert reset: %d\n", err);
1609ef8187d7SThierry Reding 			return err;
1610ef8187d7SThierry Reding 		}
161164230aa0SJon Hunter 	}
1612ef8187d7SThierry Reding 
1613ef8187d7SThierry Reding 	usleep_range(1000, 2000);
1614ef8187d7SThierry Reding 
1615dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1616dec72739SThierry Reding 	clk_disable_unprepare(dsi->clk);
1617ef8187d7SThierry Reding 
1618ef8187d7SThierry Reding 	regulator_disable(dsi->vdd);
1619dec72739SThierry Reding 
1620dec72739SThierry Reding 	return 0;
1621dec72739SThierry Reding }
1622dec72739SThierry Reding 
1623ef8187d7SThierry Reding static int tegra_dsi_resume(struct device *dev)
1624ef8187d7SThierry Reding {
1625ef8187d7SThierry Reding 	struct tegra_dsi *dsi = dev_get_drvdata(dev);
1626ef8187d7SThierry Reding 	int err;
1627ef8187d7SThierry Reding 
1628ef8187d7SThierry Reding 	err = regulator_enable(dsi->vdd);
1629ef8187d7SThierry Reding 	if (err < 0) {
1630ef8187d7SThierry Reding 		dev_err(dsi->dev, "failed to enable VDD supply: %d\n", err);
1631ef8187d7SThierry Reding 		return err;
1632ef8187d7SThierry Reding 	}
1633ef8187d7SThierry Reding 
1634ef8187d7SThierry Reding 	err = clk_prepare_enable(dsi->clk);
1635ef8187d7SThierry Reding 	if (err < 0) {
1636ef8187d7SThierry Reding 		dev_err(dev, "cannot enable DSI clock: %d\n", err);
1637ef8187d7SThierry Reding 		goto disable_vdd;
1638ef8187d7SThierry Reding 	}
1639ef8187d7SThierry Reding 
1640ef8187d7SThierry Reding 	err = clk_prepare_enable(dsi->clk_lp);
1641ef8187d7SThierry Reding 	if (err < 0) {
1642ef8187d7SThierry Reding 		dev_err(dev, "cannot enable low-power clock: %d\n", err);
1643ef8187d7SThierry Reding 		goto disable_clk;
1644ef8187d7SThierry Reding 	}
1645ef8187d7SThierry Reding 
1646ef8187d7SThierry Reding 	usleep_range(1000, 2000);
1647ef8187d7SThierry Reding 
164864230aa0SJon Hunter 	if (dsi->rst) {
1649ef8187d7SThierry Reding 		err = reset_control_deassert(dsi->rst);
1650ef8187d7SThierry Reding 		if (err < 0) {
1651ef8187d7SThierry Reding 			dev_err(dev, "cannot assert reset: %d\n", err);
1652ef8187d7SThierry Reding 			goto disable_clk_lp;
1653ef8187d7SThierry Reding 		}
165464230aa0SJon Hunter 	}
1655ef8187d7SThierry Reding 
1656ef8187d7SThierry Reding 	return 0;
1657ef8187d7SThierry Reding 
1658ef8187d7SThierry Reding disable_clk_lp:
1659ef8187d7SThierry Reding 	clk_disable_unprepare(dsi->clk_lp);
1660ef8187d7SThierry Reding disable_clk:
1661ef8187d7SThierry Reding 	clk_disable_unprepare(dsi->clk);
1662ef8187d7SThierry Reding disable_vdd:
1663ef8187d7SThierry Reding 	regulator_disable(dsi->vdd);
1664ef8187d7SThierry Reding 	return err;
1665ef8187d7SThierry Reding }
1666ef8187d7SThierry Reding #endif
1667ef8187d7SThierry Reding 
1668ef8187d7SThierry Reding static const struct dev_pm_ops tegra_dsi_pm_ops = {
1669ef8187d7SThierry Reding 	SET_RUNTIME_PM_OPS(tegra_dsi_suspend, tegra_dsi_resume, NULL)
1670ef8187d7SThierry Reding };
1671ef8187d7SThierry Reding 
1672dec72739SThierry Reding static const struct of_device_id tegra_dsi_of_match[] = {
1673ddfb406bSThierry Reding 	{ .compatible = "nvidia,tegra210-dsi", },
1674c06c7930SThierry Reding 	{ .compatible = "nvidia,tegra132-dsi", },
16757d338587SThierry Reding 	{ .compatible = "nvidia,tegra124-dsi", },
1676dec72739SThierry Reding 	{ .compatible = "nvidia,tegra114-dsi", },
1677dec72739SThierry Reding 	{ },
1678dec72739SThierry Reding };
1679ef70728cSStephen Warren MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
1680dec72739SThierry Reding 
1681dec72739SThierry Reding struct platform_driver tegra_dsi_driver = {
1682dec72739SThierry Reding 	.driver = {
1683dec72739SThierry Reding 		.name = "tegra-dsi",
1684dec72739SThierry Reding 		.of_match_table = tegra_dsi_of_match,
1685ef8187d7SThierry Reding 		.pm = &tegra_dsi_pm_ops,
1686dec72739SThierry Reding 	},
1687dec72739SThierry Reding 	.probe = tegra_dsi_probe,
1688dec72739SThierry Reding 	.remove = tegra_dsi_remove,
1689dec72739SThierry Reding };
1690