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