aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2013-09-03 02:45:46 -0400
committerThierry Reding <treding@nvidia.com>2013-12-20 09:56:04 -0500
commitdec727399a4b36bec87b7b4d4c1b20025e69758a (patch)
tree23068d248a62dd94e0a71e35c2c3cce595a370ab /drivers
parentb5190022f77a41465c2202f621a5fa07c9aabb7b (diff)
drm/tegra: Add DSI support
This commit adds support for both DSI outputs found on Tegra. Only very minimal functionality is implemented, so advanced features like ganged mode won't work. Due to the lack of other test hardware, some sections of the driver are hardcoded to work with Dalmore. Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/tegra/Kconfig1
-rw-r--r--drivers/gpu/drm/tegra/Makefile2
-rw-r--r--drivers/gpu/drm/tegra/dc.h2
-rw-r--r--drivers/gpu/drm/tegra/drm.c10
-rw-r--r--drivers/gpu/drm/tegra/drm.h2
-rw-r--r--drivers/gpu/drm/tegra/dsi.c963
-rw-r--r--drivers/gpu/drm/tegra/dsi.h134
-rw-r--r--drivers/gpu/drm/tegra/mipi-phy.c137
-rw-r--r--drivers/gpu/drm/tegra/mipi-phy.h65
-rw-r--r--drivers/gpu/drm/tegra/output.c5
10 files changed, 1320 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 7a3e8ae90631..5acb2504efb1 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -6,6 +6,7 @@ config DRM_TEGRA
6 select TEGRA_HOST1X 6 select TEGRA_HOST1X
7 select DRM_KMS_HELPER 7 select DRM_KMS_HELPER
8 select DRM_KMS_FB_HELPER 8 select DRM_KMS_FB_HELPER
9 select DRM_MIPI_DSI
9 select DRM_PANEL 10 select DRM_PANEL
10 select FB_SYS_FILLRECT 11 select FB_SYS_FILLRECT
11 select FB_SYS_COPYAREA 12 select FB_SYS_COPYAREA
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index edc76abd58bb..8d220afbd85f 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -9,6 +9,8 @@ tegra-drm-y := \
9 output.o \ 9 output.o \
10 rgb.o \ 10 rgb.o \
11 hdmi.o \ 11 hdmi.o \
12 mipi-phy.o \
13 dsi.o \
12 gr2d.o \ 14 gr2d.o \
13 gr3d.o 15 gr3d.o
14 16
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 91bbda291470..788627a060d7 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -28,6 +28,7 @@
28#define DISP_CTRL_MODE_STOP (0 << 5) 28#define DISP_CTRL_MODE_STOP (0 << 5)
29#define DISP_CTRL_MODE_C_DISPLAY (1 << 5) 29#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
30#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) 30#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
31#define DISP_CTRL_MODE_MASK (3 << 5)
31#define DC_CMD_SIGNAL_RAISE 0x033 32#define DC_CMD_SIGNAL_RAISE 0x033
32#define DC_CMD_DISPLAY_POWER_CONTROL 0x036 33#define DC_CMD_DISPLAY_POWER_CONTROL 0x036
33#define PW0_ENABLE (1 << 0) 34#define PW0_ENABLE (1 << 0)
@@ -116,6 +117,7 @@
116 117
117#define DC_DISP_DISP_WIN_OPTIONS 0x402 118#define DC_DISP_DISP_WIN_OPTIONS 0x402
118#define HDMI_ENABLE (1 << 30) 119#define HDMI_ENABLE (1 << 30)
120#define DSI_ENABLE (1 << 29)
119 121
120#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 122#define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403
121#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) 123#define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24)
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 07eba596d458..08e9e3740c13 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -653,6 +653,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
653 { .compatible = "nvidia,tegra30-hdmi", }, 653 { .compatible = "nvidia,tegra30-hdmi", },
654 { .compatible = "nvidia,tegra30-gr2d", }, 654 { .compatible = "nvidia,tegra30-gr2d", },
655 { .compatible = "nvidia,tegra30-gr3d", }, 655 { .compatible = "nvidia,tegra30-gr3d", },
656 { .compatible = "nvidia,tegra114-dsi", },
656 { .compatible = "nvidia,tegra114-hdmi", }, 657 { .compatible = "nvidia,tegra114-hdmi", },
657 { .compatible = "nvidia,tegra114-gr3d", }, 658 { .compatible = "nvidia,tegra114-gr3d", },
658 { /* sentinel */ } 659 { /* sentinel */ }
@@ -677,10 +678,14 @@ static int __init host1x_drm_init(void)
677 if (err < 0) 678 if (err < 0)
678 goto unregister_host1x; 679 goto unregister_host1x;
679 680
680 err = platform_driver_register(&tegra_hdmi_driver); 681 err = platform_driver_register(&tegra_dsi_driver);
681 if (err < 0) 682 if (err < 0)
682 goto unregister_dc; 683 goto unregister_dc;
683 684
685 err = platform_driver_register(&tegra_hdmi_driver);
686 if (err < 0)
687 goto unregister_dsi;
688
684 err = platform_driver_register(&tegra_gr2d_driver); 689 err = platform_driver_register(&tegra_gr2d_driver);
685 if (err < 0) 690 if (err < 0)
686 goto unregister_hdmi; 691 goto unregister_hdmi;
@@ -695,6 +700,8 @@ unregister_gr2d:
695 platform_driver_unregister(&tegra_gr2d_driver); 700 platform_driver_unregister(&tegra_gr2d_driver);
696unregister_hdmi: 701unregister_hdmi:
697 platform_driver_unregister(&tegra_hdmi_driver); 702 platform_driver_unregister(&tegra_hdmi_driver);
703unregister_dsi:
704 platform_driver_unregister(&tegra_dsi_driver);
698unregister_dc: 705unregister_dc:
699 platform_driver_unregister(&tegra_dc_driver); 706 platform_driver_unregister(&tegra_dc_driver);
700unregister_host1x: 707unregister_host1x:
@@ -708,6 +715,7 @@ static void __exit host1x_drm_exit(void)
708 platform_driver_unregister(&tegra_gr3d_driver); 715 platform_driver_unregister(&tegra_gr3d_driver);
709 platform_driver_unregister(&tegra_gr2d_driver); 716 platform_driver_unregister(&tegra_gr2d_driver);
710 platform_driver_unregister(&tegra_hdmi_driver); 717 platform_driver_unregister(&tegra_hdmi_driver);
718 platform_driver_unregister(&tegra_dsi_driver);
711 platform_driver_unregister(&tegra_dc_driver); 719 platform_driver_unregister(&tegra_dc_driver);
712 host1x_driver_unregister(&host1x_drm_driver); 720 host1x_driver_unregister(&host1x_drm_driver);
713} 721}
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index bb8b1305606e..ddaa937836de 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -177,6 +177,7 @@ struct tegra_output_ops {
177enum tegra_output_type { 177enum tegra_output_type {
178 TEGRA_OUTPUT_RGB, 178 TEGRA_OUTPUT_RGB,
179 TEGRA_OUTPUT_HDMI, 179 TEGRA_OUTPUT_HDMI,
180 TEGRA_OUTPUT_DSI,
180}; 181};
181 182
182struct tegra_output { 183struct tegra_output {
@@ -267,6 +268,7 @@ extern void tegra_drm_fb_exit(struct drm_device *drm);
267extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); 268extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
268 269
269extern struct platform_driver tegra_dc_driver; 270extern struct platform_driver tegra_dc_driver;
271extern struct platform_driver tegra_dsi_driver;
270extern struct platform_driver tegra_hdmi_driver; 272extern struct platform_driver tegra_hdmi_driver;
271extern struct platform_driver tegra_gr2d_driver; 273extern struct platform_driver tegra_gr2d_driver;
272extern struct platform_driver tegra_gr3d_driver; 274extern struct platform_driver tegra_gr3d_driver;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
new file mode 100644
index 000000000000..84a73e32214f
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -0,0 +1,963 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <linux/clk.h>
24#include <linux/debugfs.h>
25#include <linux/host1x.h>
26#include <linux/module.h>
27#include <linux/of.h>
28#include <linux/platform_device.h>
29#include <linux/reset.h>
30
31#include <drm/drm_mipi_dsi.h>
32#include <drm/drm_panel.h>
33
34#include <video/mipi_display.h>
35
36#include "dc.h"
37#include "drm.h"
38#include "dsi.h"
39#include "mipi-phy.h"
40
41#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
42#define DSI_HOST_FIFO_DEPTH 64
43
44struct tegra_dsi {
45 struct host1x_client client;
46 struct tegra_output output;
47 struct device *dev;
48
49 void __iomem *regs;
50
51 struct reset_control *rst;
52 struct clk *clk_parent;
53 struct clk *clk_lp;
54 struct clk *clk;
55
56 struct drm_info_list *debugfs_files;
57 struct drm_minor *minor;
58 struct dentry *debugfs;
59
60 enum mipi_dsi_pixel_format format;
61 unsigned int lanes;
62
63 struct tegra_mipi_device *mipi;
64 struct mipi_dsi_host host;
65};
66
67static inline struct tegra_dsi *
68host1x_client_to_dsi(struct host1x_client *client)
69{
70 return container_of(client, struct tegra_dsi, client);
71}
72
73static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
74{
75 return container_of(host, struct tegra_dsi, host);
76}
77
78static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
79{
80 return container_of(output, struct tegra_dsi, output);
81}
82
83static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
84 unsigned long reg)
85{
86 return readl(dsi->regs + (reg << 2));
87}
88
89static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
90 unsigned long reg)
91{
92 writel(value, dsi->regs + (reg << 2));
93}
94
95static int tegra_dsi_show_regs(struct seq_file *s, void *data)
96{
97 struct drm_info_node *node = s->private;
98 struct tegra_dsi *dsi = node->info_ent->data;
99
100#define DUMP_REG(name) \
101 seq_printf(s, "%-32s %#05x %08lx\n", #name, name, \
102 tegra_dsi_readl(dsi, name))
103
104 DUMP_REG(DSI_INCR_SYNCPT);
105 DUMP_REG(DSI_INCR_SYNCPT_CONTROL);
106 DUMP_REG(DSI_INCR_SYNCPT_ERROR);
107 DUMP_REG(DSI_CTXSW);
108 DUMP_REG(DSI_RD_DATA);
109 DUMP_REG(DSI_WR_DATA);
110 DUMP_REG(DSI_POWER_CONTROL);
111 DUMP_REG(DSI_INT_ENABLE);
112 DUMP_REG(DSI_INT_STATUS);
113 DUMP_REG(DSI_INT_MASK);
114 DUMP_REG(DSI_HOST_CONTROL);
115 DUMP_REG(DSI_CONTROL);
116 DUMP_REG(DSI_SOL_DELAY);
117 DUMP_REG(DSI_MAX_THRESHOLD);
118 DUMP_REG(DSI_TRIGGER);
119 DUMP_REG(DSI_TX_CRC);
120 DUMP_REG(DSI_STATUS);
121
122 DUMP_REG(DSI_INIT_SEQ_CONTROL);
123 DUMP_REG(DSI_INIT_SEQ_DATA_0);
124 DUMP_REG(DSI_INIT_SEQ_DATA_1);
125 DUMP_REG(DSI_INIT_SEQ_DATA_2);
126 DUMP_REG(DSI_INIT_SEQ_DATA_3);
127 DUMP_REG(DSI_INIT_SEQ_DATA_4);
128 DUMP_REG(DSI_INIT_SEQ_DATA_5);
129 DUMP_REG(DSI_INIT_SEQ_DATA_6);
130 DUMP_REG(DSI_INIT_SEQ_DATA_7);
131
132 DUMP_REG(DSI_PKT_SEQ_0_LO);
133 DUMP_REG(DSI_PKT_SEQ_0_HI);
134 DUMP_REG(DSI_PKT_SEQ_1_LO);
135 DUMP_REG(DSI_PKT_SEQ_1_HI);
136 DUMP_REG(DSI_PKT_SEQ_2_LO);
137 DUMP_REG(DSI_PKT_SEQ_2_HI);
138 DUMP_REG(DSI_PKT_SEQ_3_LO);
139 DUMP_REG(DSI_PKT_SEQ_3_HI);
140 DUMP_REG(DSI_PKT_SEQ_4_LO);
141 DUMP_REG(DSI_PKT_SEQ_4_HI);
142 DUMP_REG(DSI_PKT_SEQ_5_LO);
143 DUMP_REG(DSI_PKT_SEQ_5_HI);
144
145 DUMP_REG(DSI_DCS_CMDS);
146
147 DUMP_REG(DSI_PKT_LEN_0_1);
148 DUMP_REG(DSI_PKT_LEN_2_3);
149 DUMP_REG(DSI_PKT_LEN_4_5);
150 DUMP_REG(DSI_PKT_LEN_6_7);
151
152 DUMP_REG(DSI_PHY_TIMING_0);
153 DUMP_REG(DSI_PHY_TIMING_1);
154 DUMP_REG(DSI_PHY_TIMING_2);
155 DUMP_REG(DSI_BTA_TIMING);
156
157 DUMP_REG(DSI_TIMEOUT_0);
158 DUMP_REG(DSI_TIMEOUT_1);
159 DUMP_REG(DSI_TO_TALLY);
160
161 DUMP_REG(DSI_PAD_CONTROL_0);
162 DUMP_REG(DSI_PAD_CONTROL_CD);
163 DUMP_REG(DSI_PAD_CD_STATUS);
164 DUMP_REG(DSI_VIDEO_MODE_CONTROL);
165 DUMP_REG(DSI_PAD_CONTROL_1);
166 DUMP_REG(DSI_PAD_CONTROL_2);
167 DUMP_REG(DSI_PAD_CONTROL_3);
168 DUMP_REG(DSI_PAD_CONTROL_4);
169
170 DUMP_REG(DSI_GANGED_MODE_CONTROL);
171 DUMP_REG(DSI_GANGED_MODE_START);
172 DUMP_REG(DSI_GANGED_MODE_SIZE);
173
174 DUMP_REG(DSI_RAW_DATA_BYTE_COUNT);
175 DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL);
176
177 DUMP_REG(DSI_INIT_SEQ_DATA_8);
178 DUMP_REG(DSI_INIT_SEQ_DATA_9);
179 DUMP_REG(DSI_INIT_SEQ_DATA_10);
180 DUMP_REG(DSI_INIT_SEQ_DATA_11);
181 DUMP_REG(DSI_INIT_SEQ_DATA_12);
182 DUMP_REG(DSI_INIT_SEQ_DATA_13);
183 DUMP_REG(DSI_INIT_SEQ_DATA_14);
184 DUMP_REG(DSI_INIT_SEQ_DATA_15);
185
186#undef DUMP_REG
187
188 return 0;
189}
190
191static struct drm_info_list debugfs_files[] = {
192 { "regs", tegra_dsi_show_regs, 0, NULL },
193};
194
195static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi,
196 struct drm_minor *minor)
197{
198 const char *name = dev_name(dsi->dev);
199 unsigned int i;
200 int err;
201
202 dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root);
203 if (!dsi->debugfs)
204 return -ENOMEM;
205
206 dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
207 GFP_KERNEL);
208 if (!dsi->debugfs_files) {
209 err = -ENOMEM;
210 goto remove;
211 }
212
213 for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
214 dsi->debugfs_files[i].data = dsi;
215
216 err = drm_debugfs_create_files(dsi->debugfs_files,
217 ARRAY_SIZE(debugfs_files),
218 dsi->debugfs, minor);
219 if (err < 0)
220 goto free;
221
222 dsi->minor = minor;
223
224 return 0;
225
226free:
227 kfree(dsi->debugfs_files);
228 dsi->debugfs_files = NULL;
229remove:
230 debugfs_remove(dsi->debugfs);
231 dsi->debugfs = NULL;
232
233 return err;
234}
235
236static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
237{
238 drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
239 dsi->minor);
240 dsi->minor = NULL;
241
242 kfree(dsi->debugfs_files);
243 dsi->debugfs_files = NULL;
244
245 debugfs_remove(dsi->debugfs);
246 dsi->debugfs = NULL;
247
248 return 0;
249}
250
251#define PKT_ID0(id) ((((id) & 0x3f) << 3) | (1 << 9))
252#define PKT_LEN0(len) (((len) & 0x07) << 0)
253#define PKT_ID1(id) ((((id) & 0x3f) << 13) | (1 << 19))
254#define PKT_LEN1(len) (((len) & 0x07) << 10)
255#define PKT_ID2(id) ((((id) & 0x3f) << 23) | (1 << 29))
256#define PKT_LEN2(len) (((len) & 0x07) << 20)
257
258#define PKT_LP (1 << 30)
259#define NUM_PKT_SEQ 12
260
261/* non-burst mode with sync-end */
262static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = {
263 [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
264 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
265 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
266 PKT_LP,
267 [ 1] = 0,
268 [ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
269 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
270 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
271 PKT_LP,
272 [ 3] = 0,
273 [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
274 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
275 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
276 PKT_LP,
277 [ 5] = 0,
278 [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
279 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
280 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
281 [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
282 PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
283 PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
284 [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
285 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
286 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
287 PKT_LP,
288 [ 9] = 0,
289 [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
290 PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
291 PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
292 [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
293 PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
294 PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
295};
296
297static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
298{
299 struct mipi_dphy_timing timing;
300 unsigned long value, period;
301 long rate;
302 int err;
303
304 rate = clk_get_rate(dsi->clk);
305 if (rate < 0)
306 return rate;
307
308 period = DIV_ROUND_CLOSEST(1000000000UL, rate * 2);
309
310 err = mipi_dphy_timing_get_default(&timing, period);
311 if (err < 0)
312 return err;
313
314 err = mipi_dphy_timing_validate(&timing, period);
315 if (err < 0) {
316 dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
317 return err;
318 }
319
320 /*
321 * The D-PHY timing fields below are expressed in byte-clock cycles,
322 * so multiply the period by 8.
323 */
324 period *= 8;
325
326 value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
327 DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
328 DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
329 DSI_TIMING_FIELD(timing.hsprepare, period, 1);
330 tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
331
332 value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
333 DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
334 DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
335 DSI_TIMING_FIELD(timing.lpx, period, 1);
336 tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
337
338 value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
339 DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
340 DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
341 tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
342
343 value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
344 DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
345 DSI_TIMING_FIELD(timing.tago, period, 1);
346 tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
347
348 return 0;
349}
350
351static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
352 unsigned int *mulp, unsigned int *divp)
353{
354 switch (format) {
355 case MIPI_DSI_FMT_RGB666_PACKED:
356 case MIPI_DSI_FMT_RGB888:
357 *mulp = 3;
358 *divp = 1;
359 break;
360
361 case MIPI_DSI_FMT_RGB565:
362 *mulp = 2;
363 *divp = 1;
364 break;
365
366 case MIPI_DSI_FMT_RGB666:
367 *mulp = 9;
368 *divp = 4;
369 break;
370
371 default:
372 return -EINVAL;
373 }
374
375 return 0;
376}
377
378static int tegra_output_dsi_enable(struct tegra_output *output)
379{
380 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
381 struct drm_display_mode *mode = &dc->base.mode;
382 unsigned int hact, hsw, hbp, hfp, i, mul, div;
383 struct tegra_dsi *dsi = to_dsi(output);
384 /* FIXME: don't hardcode this */
385 const u32 *pkt_seq = pkt_seq_vnb_syne;
386 unsigned long value;
387 int err;
388
389 err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
390 if (err < 0)
391 return err;
392
393 err = clk_enable(dsi->clk);
394 if (err < 0)
395 return err;
396
397 reset_control_deassert(dsi->rst);
398
399 value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(dsi->format) |
400 DSI_CONTROL_LANES(dsi->lanes - 1) |
401 DSI_CONTROL_SOURCE(dc->pipe);
402 tegra_dsi_writel(dsi, value, DSI_CONTROL);
403
404 tegra_dsi_writel(dsi, DSI_VIDEO_FIFO_DEPTH, DSI_MAX_THRESHOLD);
405
406 value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS |
407 DSI_HOST_CONTROL_ECC;
408 tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
409
410 value = tegra_dsi_readl(dsi, DSI_CONTROL);
411 value |= DSI_CONTROL_HS_CLK_CTRL;
412 value &= ~DSI_CONTROL_TX_TRIG(3);
413 value &= ~DSI_CONTROL_DCS_ENABLE;
414 value |= DSI_CONTROL_VIDEO_ENABLE;
415 value &= ~DSI_CONTROL_HOST_ENABLE;
416 tegra_dsi_writel(dsi, value, DSI_CONTROL);
417
418 err = tegra_dsi_set_phy_timing(dsi);
419 if (err < 0)
420 return err;
421
422 for (i = 0; i < NUM_PKT_SEQ; i++)
423 tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
424
425 /* horizontal active pixels */
426 hact = mode->hdisplay * mul / div;
427
428 /* horizontal sync width */
429 hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
430 hsw -= 10;
431
432 /* horizontal back porch */
433 hbp = (mode->htotal - mode->hsync_end) * mul / div;
434 hbp -= 14;
435
436 /* horizontal front porch */
437 hfp = (mode->hsync_start - mode->hdisplay) * mul / div;
438 hfp -= 8;
439
440 tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
441 tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
442 tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
443 tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
444
445 /* set SOL delay */
446 tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
447
448 /* enable display controller */
449 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
450 value |= DSI_ENABLE;
451 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
452
453 value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
454 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
455 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
456
457 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
458 value &= ~DISP_CTRL_MODE_MASK;
459 value |= DISP_CTRL_MODE_C_DISPLAY;
460 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
461
462 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
463 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
464
465 /* enable DSI controller */
466 value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
467 value |= DSI_POWER_CONTROL_ENABLE;
468 tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
469
470 return 0;
471}
472
473static int tegra_output_dsi_disable(struct tegra_output *output)
474{
475 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
476 struct tegra_dsi *dsi = to_dsi(output);
477 unsigned long value;
478
479 /* disable DSI controller */
480 value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
481 value &= DSI_POWER_CONTROL_ENABLE;
482 tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
483
484 /*
485 * FIXME: The output isn't attached to any CRTC when it's being
486 * disabled, so the following will never be executed.
487 */
488 if (dc) {
489 /* disable display controller */
490 value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
491 value &= ~DISP_CTRL_MODE_MASK;
492 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
493
494 value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
495 value &= ~DSI_ENABLE;
496 tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
497 }
498
499 clk_disable(dsi->clk);
500
501 return 0;
502}
503
504static int tegra_output_dsi_setup_clock(struct tegra_output *output,
505 struct clk *clk, unsigned long pclk)
506{
507 struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
508 struct drm_display_mode *mode = &dc->base.mode;
509 unsigned int timeout, mul, div, vrefresh;
510 struct tegra_dsi *dsi = to_dsi(output);
511 unsigned long bclk, plld, value;
512 struct clk *base;
513 int err;
514
515 err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
516 if (err < 0)
517 return err;
518
519 vrefresh = drm_mode_vrefresh(mode);
520
521 pclk = mode->htotal * mode->vtotal * vrefresh;
522 bclk = (pclk * mul) / (div * dsi->lanes);
523 plld = DIV_ROUND_UP(bclk * 8, 1000000);
524 pclk = (plld * 1000000) / 2;
525
526 err = clk_set_parent(clk, dsi->clk_parent);
527 if (err < 0) {
528 dev_err(dsi->dev, "failed to set parent clock: %d\n", err);
529 return err;
530 }
531
532 base = clk_get_parent(dsi->clk_parent);
533
534 /*
535 * This assumes that the parent clock is pll_d_out0 or pll_d2_out
536 * respectively, each of which divides the base pll_d by 2.
537 */
538 err = clk_set_rate(base, pclk * 2);
539 if (err < 0) {
540 dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
541 pclk * 2);
542 return err;
543 }
544
545 /*
546 * XXX: Move the below somewhere else so that we don't need to have
547 * access to the vrefresh in this function?
548 */
549
550 /* one frame high-speed transmission timeout */
551 timeout = (bclk / vrefresh) / 512;
552 value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
553 tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
554
555 /* 2 ms peripheral timeout for panel */
556 timeout = 2 * bclk / 512 * 1000;
557 value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
558 tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
559
560 value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
561 tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
562
563 return 0;
564}
565
566static int tegra_output_dsi_check_mode(struct tegra_output *output,
567 struct drm_display_mode *mode,
568 enum drm_mode_status *status)
569{
570 /*
571 * FIXME: For now, always assume that the mode is okay.
572 */
573
574 *status = MODE_OK;
575
576 return 0;
577}
578
579static const struct tegra_output_ops dsi_ops = {
580 .enable = tegra_output_dsi_enable,
581 .disable = tegra_output_dsi_disable,
582 .setup_clock = tegra_output_dsi_setup_clock,
583 .check_mode = tegra_output_dsi_check_mode,
584};
585
586static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
587{
588 unsigned long value;
589
590 value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
591 tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
592
593 return 0;
594}
595
596static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
597{
598 unsigned long value;
599
600 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
601 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
602 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
603 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
604 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
605
606 /* start calibration */
607 tegra_dsi_pad_enable(dsi);
608
609 value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
610 DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
611 DSI_PAD_OUT_CLK(0x0);
612 tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
613
614 return tegra_mipi_calibrate(dsi->mipi);
615}
616
617static int tegra_dsi_init(struct host1x_client *client)
618{
619 struct tegra_drm *tegra = dev_get_drvdata(client->parent);
620 struct tegra_dsi *dsi = host1x_client_to_dsi(client);
621 unsigned long value, i;
622 int err;
623
624 dsi->output.type = TEGRA_OUTPUT_DSI;
625 dsi->output.dev = client->dev;
626 dsi->output.ops = &dsi_ops;
627
628 err = tegra_output_init(tegra->drm, &dsi->output);
629 if (err < 0) {
630 dev_err(client->dev, "output setup failed: %d\n", err);
631 return err;
632 }
633
634 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
635 err = tegra_dsi_debugfs_init(dsi, tegra->drm->primary);
636 if (err < 0)
637 dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
638 }
639
640 /*
641 * enable high-speed mode, checksum generation, ECC generation and
642 * disable raw mode
643 */
644 value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
645 value |= DSI_HOST_CONTROL_ECC | DSI_HOST_CONTROL_CS |
646 DSI_HOST_CONTROL_HS;
647 value &= ~DSI_HOST_CONTROL_RAW;
648 tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
649
650 tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
651 tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
652
653 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
654
655 for (i = 0; i < 8; i++) {
656 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
657 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
658 }
659
660 for (i = 0; i < 12; i++)
661 tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
662
663 tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
664
665 err = tegra_dsi_pad_calibrate(dsi);
666 if (err < 0) {
667 dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
668 return err;
669 }
670
671 tegra_dsi_writel(dsi, DSI_POWER_CONTROL_ENABLE, DSI_POWER_CONTROL);
672 usleep_range(300, 1000);
673
674 return 0;
675}
676
677static int tegra_dsi_exit(struct host1x_client *client)
678{
679 struct tegra_dsi *dsi = host1x_client_to_dsi(client);
680 int err;
681
682 if (IS_ENABLED(CONFIG_DEBUG_FS)) {
683 err = tegra_dsi_debugfs_exit(dsi);
684 if (err < 0)
685 dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
686 }
687
688 err = tegra_output_disable(&dsi->output);
689 if (err < 0) {
690 dev_err(client->dev, "output failed to disable: %d\n", err);
691 return err;
692 }
693
694 err = tegra_output_exit(&dsi->output);
695 if (err < 0) {
696 dev_err(client->dev, "output cleanup failed: %d\n", err);
697 return err;
698 }
699
700 return 0;
701}
702
703static const struct host1x_client_ops dsi_client_ops = {
704 .init = tegra_dsi_init,
705 .exit = tegra_dsi_exit,
706};
707
708static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
709{
710 struct clk *parent;
711 int err;
712
713 parent = clk_get_parent(dsi->clk);
714 if (!parent)
715 return -EINVAL;
716
717 err = clk_set_parent(parent, dsi->clk_parent);
718 if (err < 0)
719 return err;
720
721 return 0;
722}
723
724static void tegra_dsi_initialize(struct tegra_dsi *dsi)
725{
726 unsigned int i;
727
728 tegra_dsi_writel(dsi, 0, DSI_POWER_CONTROL);
729
730 tegra_dsi_writel(dsi, 0, DSI_INT_ENABLE);
731 tegra_dsi_writel(dsi, 0, DSI_INT_STATUS);
732 tegra_dsi_writel(dsi, 0, DSI_INT_MASK);
733
734 tegra_dsi_writel(dsi, 0, DSI_HOST_CONTROL);
735 tegra_dsi_writel(dsi, 0, DSI_CONTROL);
736
737 tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
738 tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
739
740 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
741
742 for (i = 0; i < 8; i++) {
743 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
744 tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
745 }
746
747 for (i = 0; i < 12; i++)
748 tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
749
750 tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
751
752 for (i = 0; i < 4; i++)
753 tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1 + i);
754
755 tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_0);
756 tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_1);
757 tegra_dsi_writel(dsi, 0x000000ff, DSI_PHY_TIMING_2);
758 tegra_dsi_writel(dsi, 0x00000000, DSI_BTA_TIMING);
759
760 tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_0);
761 tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_1);
762 tegra_dsi_writel(dsi, 0, DSI_TO_TALLY);
763
764 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
765 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_CD);
766 tegra_dsi_writel(dsi, 0, DSI_PAD_CD_STATUS);
767 tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL);
768 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
769 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
770 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
771 tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
772
773 tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
774 tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
775 tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
776}
777
778static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
779 struct mipi_dsi_device *device)
780{
781 struct tegra_dsi *dsi = host_to_tegra(host);
782 struct tegra_output *output = &dsi->output;
783
784 dsi->format = device->format;
785 dsi->lanes = device->lanes;
786
787 output->panel = of_drm_find_panel(device->dev.of_node);
788 if (output->panel) {
789 if (output->connector.dev)
790 drm_helper_hpd_irq_event(output->connector.dev);
791 }
792
793 return 0;
794}
795
796static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
797 struct mipi_dsi_device *device)
798{
799 struct tegra_dsi *dsi = host_to_tegra(host);
800 struct tegra_output *output = &dsi->output;
801
802 if (output->panel && &device->dev == output->panel->dev) {
803 if (output->connector.dev)
804 drm_helper_hpd_irq_event(output->connector.dev);
805
806 output->panel = NULL;
807 }
808
809 return 0;
810}
811
812static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
813 .attach = tegra_dsi_host_attach,
814 .detach = tegra_dsi_host_detach,
815};
816
817static int tegra_dsi_probe(struct platform_device *pdev)
818{
819 struct tegra_dsi *dsi;
820 struct resource *regs;
821 int err;
822
823 dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
824 if (!dsi)
825 return -ENOMEM;
826
827 dsi->output.dev = dsi->dev = &pdev->dev;
828
829 err = tegra_output_probe(&dsi->output);
830 if (err < 0)
831 return err;
832
833 /*
834 * Assume these values by default. When a DSI peripheral driver
835 * attaches to the DSI host, the parameters will be taken from
836 * the attached device.
837 */
838 dsi->format = MIPI_DSI_FMT_RGB888;
839 dsi->lanes = 4;
840
841 dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
842 if (IS_ERR(dsi->rst))
843 return PTR_ERR(dsi->rst);
844
845 dsi->clk = devm_clk_get(&pdev->dev, NULL);
846 if (IS_ERR(dsi->clk)) {
847 dev_err(&pdev->dev, "cannot get DSI clock\n");
848 return PTR_ERR(dsi->clk);
849 }
850
851 err = clk_prepare_enable(dsi->clk);
852 if (err < 0) {
853 dev_err(&pdev->dev, "cannot enable DSI clock\n");
854 return err;
855 }
856
857 dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
858 if (IS_ERR(dsi->clk_lp)) {
859 dev_err(&pdev->dev, "cannot get low-power clock\n");
860 return PTR_ERR(dsi->clk_lp);
861 }
862
863 err = clk_prepare_enable(dsi->clk_lp);
864 if (err < 0) {
865 dev_err(&pdev->dev, "cannot enable low-power clock\n");
866 return err;
867 }
868
869 dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
870 if (IS_ERR(dsi->clk_parent)) {
871 dev_err(&pdev->dev, "cannot get parent clock\n");
872 return PTR_ERR(dsi->clk_parent);
873 }
874
875 err = clk_prepare_enable(dsi->clk_parent);
876 if (err < 0) {
877 dev_err(&pdev->dev, "cannot enable parent clock\n");
878 return err;
879 }
880
881 err = tegra_dsi_setup_clocks(dsi);
882 if (err < 0) {
883 dev_err(&pdev->dev, "cannot setup clocks\n");
884 return err;
885 }
886
887 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
888 dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
889 if (!dsi->regs)
890 return -EADDRNOTAVAIL;
891
892 tegra_dsi_initialize(dsi);
893
894 dsi->mipi = tegra_mipi_request(&pdev->dev);
895 if (IS_ERR(dsi->mipi))
896 return PTR_ERR(dsi->mipi);
897
898 dsi->host.ops = &tegra_dsi_host_ops;
899 dsi->host.dev = &pdev->dev;
900
901 err = mipi_dsi_host_register(&dsi->host);
902 if (err < 0) {
903 dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
904 return err;
905 }
906
907 INIT_LIST_HEAD(&dsi->client.list);
908 dsi->client.ops = &dsi_client_ops;
909 dsi->client.dev = &pdev->dev;
910
911 err = host1x_client_register(&dsi->client);
912 if (err < 0) {
913 dev_err(&pdev->dev, "failed to register host1x client: %d\n",
914 err);
915 return err;
916 }
917
918 platform_set_drvdata(pdev, dsi);
919
920 return 0;
921}
922
923static int tegra_dsi_remove(struct platform_device *pdev)
924{
925 struct tegra_dsi *dsi = platform_get_drvdata(pdev);
926 int err;
927
928 err = host1x_client_unregister(&dsi->client);
929 if (err < 0) {
930 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
931 err);
932 return err;
933 }
934
935 mipi_dsi_host_unregister(&dsi->host);
936 tegra_mipi_free(dsi->mipi);
937
938 clk_disable_unprepare(dsi->clk_parent);
939 clk_disable_unprepare(dsi->clk_lp);
940 clk_disable_unprepare(dsi->clk);
941
942 err = tegra_output_remove(&dsi->output);
943 if (err < 0) {
944 dev_err(&pdev->dev, "failed to remove output: %d\n", err);
945 return err;
946 }
947
948 return 0;
949}
950
951static const struct of_device_id tegra_dsi_of_match[] = {
952 { .compatible = "nvidia,tegra114-dsi", },
953 { },
954};
955
956struct platform_driver tegra_dsi_driver = {
957 .driver = {
958 .name = "tegra-dsi",
959 .of_match_table = tegra_dsi_of_match,
960 },
961 .probe = tegra_dsi_probe,
962 .remove = tegra_dsi_remove,
963};
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
new file mode 100644
index 000000000000..00e79c1f448c
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dsi.h
@@ -0,0 +1,134 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#ifndef DRM_TEGRA_DSI_H
24#define DRM_TEGRA_DSI_H
25
26#define DSI_INCR_SYNCPT 0x00
27#define DSI_INCR_SYNCPT_CONTROL 0x01
28#define DSI_INCR_SYNCPT_ERROR 0x02
29#define DSI_CTXSW 0x08
30#define DSI_RD_DATA 0x09
31#define DSI_WR_DATA 0x0a
32#define DSI_POWER_CONTROL 0x0b
33#define DSI_POWER_CONTROL_ENABLE (1 << 0)
34#define DSI_INT_ENABLE 0x0c
35#define DSI_INT_STATUS 0x0d
36#define DSI_INT_MASK 0x0e
37#define DSI_HOST_CONTROL 0x0f
38#define DSI_HOST_CONTROL_RAW (1 << 6)
39#define DSI_HOST_CONTROL_HS (1 << 5)
40#define DSI_HOST_CONTROL_BTA (1 << 2)
41#define DSI_HOST_CONTROL_CS (1 << 1)
42#define DSI_HOST_CONTROL_ECC (1 << 0)
43#define DSI_CONTROL 0x10
44#define DSI_CONTROL_HS_CLK_CTRL (1 << 20)
45#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16)
46#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12)
47#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8)
48#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4)
49#define DSI_CONTROL_DCS_ENABLE (1 << 3)
50#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2)
51#define DSI_CONTROL_VIDEO_ENABLE (1 << 1)
52#define DSI_CONTROL_HOST_ENABLE (1 << 0)
53#define DSI_SOL_DELAY 0x11
54#define DSI_MAX_THRESHOLD 0x12
55#define DSI_TRIGGER 0x13
56#define DSI_TX_CRC 0x14
57#define DSI_STATUS 0x15
58#define DSI_STATUS_IDLE (1 << 10)
59#define DSI_INIT_SEQ_CONTROL 0x1a
60#define DSI_INIT_SEQ_DATA_0 0x1b
61#define DSI_INIT_SEQ_DATA_1 0x1c
62#define DSI_INIT_SEQ_DATA_2 0x1d
63#define DSI_INIT_SEQ_DATA_3 0x1e
64#define DSI_INIT_SEQ_DATA_4 0x1f
65#define DSI_INIT_SEQ_DATA_5 0x20
66#define DSI_INIT_SEQ_DATA_6 0x21
67#define DSI_INIT_SEQ_DATA_7 0x22
68#define DSI_PKT_SEQ_0_LO 0x23
69#define DSI_PKT_SEQ_0_HI 0x24
70#define DSI_PKT_SEQ_1_LO 0x25
71#define DSI_PKT_SEQ_1_HI 0x26
72#define DSI_PKT_SEQ_2_LO 0x27
73#define DSI_PKT_SEQ_2_HI 0x28
74#define DSI_PKT_SEQ_3_LO 0x29
75#define DSI_PKT_SEQ_3_HI 0x2a
76#define DSI_PKT_SEQ_4_LO 0x2b
77#define DSI_PKT_SEQ_4_HI 0x2c
78#define DSI_PKT_SEQ_5_LO 0x2d
79#define DSI_PKT_SEQ_5_HI 0x2e
80#define DSI_DCS_CMDS 0x33
81#define DSI_PKT_LEN_0_1 0x34
82#define DSI_PKT_LEN_2_3 0x35
83#define DSI_PKT_LEN_4_5 0x36
84#define DSI_PKT_LEN_6_7 0x37
85#define DSI_PHY_TIMING_0 0x3c
86#define DSI_PHY_TIMING_1 0x3d
87#define DSI_PHY_TIMING_2 0x3e
88#define DSI_BTA_TIMING 0x3f
89
90#define DSI_TIMING_FIELD(value, period, hwinc) \
91 ((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff)
92
93#define DSI_TIMEOUT_0 0x44
94#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16)
95#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0)
96#define DSI_TIMEOUT_1 0x45
97#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16)
98#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0)
99#define DSI_TO_TALLY 0x46
100#define DSI_TALLY_TA(x) (((x) & 0xff) << 16)
101#define DSI_TALLY_LRX(x) (((x) & 0xff) << 8)
102#define DSI_TALLY_HTX(x) (((x) & 0xff) << 0)
103#define DSI_PAD_CONTROL_0 0x4b
104#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0)
105#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8)
106#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16)
107#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24)
108#define DSI_PAD_CONTROL_CD 0x4c
109#define DSI_PAD_CD_STATUS 0x4d
110#define DSI_VIDEO_MODE_CONTROL 0x4e
111#define DSI_PAD_CONTROL_1 0x4f
112#define DSI_PAD_CONTROL_2 0x50
113#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0)
114#define DSI_PAD_LP_DN(x) (((x) & 0x7) << 4)
115#define DSI_PAD_LP_UP(x) (((x) & 0x7) << 8)
116#define DSI_PAD_SLEW_DN(x) (((x) & 0x7) << 12)
117#define DSI_PAD_SLEW_UP(x) (((x) & 0x7) << 16)
118#define DSI_PAD_CONTROL_3 0x51
119#define DSI_PAD_CONTROL_4 0x52
120#define DSI_GANGED_MODE_CONTROL 0x53
121#define DSI_GANGED_MODE_START 0x54
122#define DSI_GANGED_MODE_SIZE 0x55
123#define DSI_RAW_DATA_BYTE_COUNT 0x56
124#define DSI_ULTRA_LOW_POWER_CONTROL 0x57
125#define DSI_INIT_SEQ_DATA_8 0x58
126#define DSI_INIT_SEQ_DATA_9 0x59
127#define DSI_INIT_SEQ_DATA_10 0x5a
128#define DSI_INIT_SEQ_DATA_11 0x5b
129#define DSI_INIT_SEQ_DATA_12 0x5c
130#define DSI_INIT_SEQ_DATA_13 0x5d
131#define DSI_INIT_SEQ_DATA_14 0x5e
132#define DSI_INIT_SEQ_DATA_15 0x5f
133
134#endif
diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c
new file mode 100644
index 000000000000..1d2ad267cfce
--- /dev/null
+++ b/drivers/gpu/drm/tegra/mipi-phy.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include <linux/kernel.h>
24
25#include "mipi-phy.h"
26
27/*
28 * Default D-PHY timings based on MIPI D-PHY specification. Derived from
29 * the valid ranges specified in Section 5.9 of the D-PHY specification
30 * with minor adjustments.
31 */
32int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
33 unsigned long period)
34{
35 timing->clkmiss = 0;
36 timing->clkpost = 70 + 52 * period;
37 timing->clkpre = 8;
38 timing->clkprepare = 65;
39 timing->clksettle = 95;
40 timing->clktermen = 0;
41 timing->clktrail = 80;
42 timing->clkzero = 260;
43 timing->dtermen = 0;
44 timing->eot = 0;
45 timing->hsexit = 120;
46 timing->hsprepare = 65 + 5 * period;
47 timing->hszero = 145 + 5 * period;
48 timing->hssettle = 85 + 6 * period;
49 timing->hsskip = 40;
50 timing->hstrail = max(8 * period, 60 + 4 * period);
51 timing->init = 100000;
52 timing->lpx = 60;
53 timing->taget = 5 * timing->lpx;
54 timing->tago = 4 * timing->lpx;
55 timing->tasure = 2 * timing->lpx;
56 timing->wakeup = 1000000;
57
58 return 0;
59}
60
61/*
62 * Validate D-PHY timing according to MIPI Alliance Specification for D-PHY,
63 * Section 5.9 "Global Operation Timing Parameters".
64 */
65int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
66 unsigned long period)
67{
68 if (timing->clkmiss > 60)
69 return -EINVAL;
70
71 if (timing->clkpost < (60 + 52 * period))
72 return -EINVAL;
73
74 if (timing->clkpre < 8)
75 return -EINVAL;
76
77 if (timing->clkprepare < 38 || timing->clkprepare > 95)
78 return -EINVAL;
79
80 if (timing->clksettle < 95 || timing->clksettle > 300)
81 return -EINVAL;
82
83 if (timing->clktermen > 38)
84 return -EINVAL;
85
86 if (timing->clktrail < 60)
87 return -EINVAL;
88
89 if (timing->clkprepare + timing->clkzero < 300)
90 return -EINVAL;
91
92 if (timing->dtermen > 35 + 4 * period)
93 return -EINVAL;
94
95 if (timing->eot > 105 + 12 * period)
96 return -EINVAL;
97
98 if (timing->hsexit < 100)
99 return -EINVAL;
100
101 if (timing->hsprepare < 40 + 4 * period ||
102 timing->hsprepare > 85 + 6 * period)
103 return -EINVAL;
104
105 if (timing->hsprepare + timing->hszero < 145 + 10 * period)
106 return -EINVAL;
107
108 if ((timing->hssettle < 85 + 6 * period) ||
109 (timing->hssettle > 145 + 10 * period))
110 return -EINVAL;
111
112 if (timing->hsskip < 40 || timing->hsskip > 55 + 4 * period)
113 return -EINVAL;
114
115 if (timing->hstrail < max(8 * period, 60 + 4 * period))
116 return -EINVAL;
117
118 if (timing->init < 100000)
119 return -EINVAL;
120
121 if (timing->lpx < 50)
122 return -EINVAL;
123
124 if (timing->taget != 5 * timing->lpx)
125 return -EINVAL;
126
127 if (timing->tago != 4 * timing->lpx)
128 return -EINVAL;
129
130 if (timing->tasure < timing->lpx || timing->tasure > 2 * timing->lpx)
131 return -EINVAL;
132
133 if (timing->wakeup < 1000000)
134 return -EINVAL;
135
136 return 0;
137}
diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h
new file mode 100644
index 000000000000..d3591694432d
--- /dev/null
+++ b/drivers/gpu/drm/tegra/mipi-phy.h
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2013 NVIDIA Corporation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#ifndef DRM_TEGRA_MIPI_PHY_H
24#define DRM_TEGRA_MIPI_PHY_H
25
26/*
27 * D-PHY timing parameters
28 *
29 * A detailed description of these parameters can be found in the MIPI
30 * Alliance Specification for D-PHY, Section 5.9 "Global Operation Timing
31 * Parameters".
32 *
33 * All parameters are specified in nanoseconds.
34 */
35struct mipi_dphy_timing {
36 unsigned int clkmiss;
37 unsigned int clkpost;
38 unsigned int clkpre;
39 unsigned int clkprepare;
40 unsigned int clksettle;
41 unsigned int clktermen;
42 unsigned int clktrail;
43 unsigned int clkzero;
44 unsigned int dtermen;
45 unsigned int eot;
46 unsigned int hsexit;
47 unsigned int hsprepare;
48 unsigned int hszero;
49 unsigned int hssettle;
50 unsigned int hsskip;
51 unsigned int hstrail;
52 unsigned int init;
53 unsigned int lpx;
54 unsigned int taget;
55 unsigned int tago;
56 unsigned int tasure;
57 unsigned int wakeup;
58};
59
60int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
61 unsigned long period);
62int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
63 unsigned long period);
64
65#endif
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 581dc5d37bed..f1b5030f55e3 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -284,6 +284,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
284 encoder = DRM_MODE_ENCODER_TMDS; 284 encoder = DRM_MODE_ENCODER_TMDS;
285 break; 285 break;
286 286
287 case TEGRA_OUTPUT_DSI:
288 connector = DRM_MODE_CONNECTOR_DSI;
289 encoder = DRM_MODE_ENCODER_DSI;
290 break;
291
287 default: 292 default:
288 connector = DRM_MODE_CONNECTOR_Unknown; 293 connector = DRM_MODE_CONNECTOR_Unknown;
289 encoder = DRM_MODE_ENCODER_NONE; 294 encoder = DRM_MODE_ENCODER_NONE;