summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2019-05-24 05:20:19 -0400
committerLinus Walleij <linus.walleij@linaro.org>2019-05-24 11:00:13 -0400
commit5fc537bfd00033a3f813330175f7f12c25957ebf (patch)
treea8b81e5553b856a584799235ebe5292f46ed43c7
parent9371ea5e5918f9d9afd9464b2c2718ea51baa239 (diff)
drm/mcde: Add new driver for ST-Ericsson MCDE
This adds a new DRM driver for the ST-Ericsson Multi Channel Display Engine, MCDE display controller. This hardware has three independent DSI hosts and can composit and display several memory buffers onto an LCD display. It was developed for several years inside of ST-Ericsson and shipped with a few million mobile phones from Sony and Samsung, as well as with the Snowball community development board. The driver is currently pretty rudimentary but supports a simple framebuffer so we can get penguins and graphics when using these SoCs. Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190524092019.19355-1-linus.walleij@linaro.org
-rw-r--r--Documentation/gpu/drivers.rst1
-rw-r--r--Documentation/gpu/mcde.rst8
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/mcde/Kconfig18
-rw-r--r--drivers/gpu/drm/mcde/Makefile3
-rw-r--r--drivers/gpu/drm/mcde/mcde_display.c1142
-rw-r--r--drivers/gpu/drm/mcde/mcde_display_regs.h518
-rw-r--r--drivers/gpu/drm/mcde/mcde_drm.h44
-rw-r--r--drivers/gpu/drm/mcde/mcde_drv.c572
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi.c1044
-rw-r--r--drivers/gpu/drm/mcde/mcde_dsi_regs.h385
13 files changed, 3745 insertions, 0 deletions
diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst
index 044a7025477c..4bfb7068e9f7 100644
--- a/Documentation/gpu/drivers.rst
+++ b/Documentation/gpu/drivers.rst
@@ -7,6 +7,7 @@ GPU Driver Documentation
7 amdgpu 7 amdgpu
8 amdgpu-dc 8 amdgpu-dc
9 i915 9 i915
10 mcde
10 meson 11 meson
11 pl111 12 pl111
12 tegra 13 tegra
diff --git a/Documentation/gpu/mcde.rst b/Documentation/gpu/mcde.rst
new file mode 100644
index 000000000000..c69e977defda
--- /dev/null
+++ b/Documentation/gpu/mcde.rst
@@ -0,0 +1,8 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3=======================================================
4 drm/mcde ST-Ericsson MCDE Multi-channel display engine
5=======================================================
6
7.. kernel-doc:: drivers/gpu/drm/mcde/mcde_drv.c
8 :doc: ST-Ericsson MCDE DRM Driver
diff --git a/MAINTAINERS b/MAINTAINERS
index 63da5ff1355c..dd1523b90c3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5128,6 +5128,13 @@ S: Maintained
5128F: drivers/gpu/drm/tinydrm/st7735r.c 5128F: drivers/gpu/drm/tinydrm/st7735r.c
5129F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt 5129F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt
5130 5130
5131DRM DRIVER FOR ST-ERICSSON MCDE
5132M: Linus Walleij <linus.walleij@linaro.org>
5133T: git git://anongit.freedesktop.org/drm/drm-misc
5134S: Maintained
5135F: drivers/gpu/drm/mcde/
5136F: Documentation/devicetree/bindings/display/ste,mcde.txt
5137
5131DRM DRIVER FOR TDFX VIDEO CARDS 5138DRM DRIVER FOR TDFX VIDEO CARDS
5132S: Orphan / Obsolete 5139S: Orphan / Obsolete
5133F: drivers/gpu/drm/tdfx/ 5140F: drivers/gpu/drm/tdfx/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index a461f078a0dd..edcfb05b2db8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -349,6 +349,8 @@ source "drivers/gpu/drm/panfrost/Kconfig"
349 349
350source "drivers/gpu/drm/aspeed/Kconfig" 350source "drivers/gpu/drm/aspeed/Kconfig"
351 351
352source "drivers/gpu/drm/mcde/Kconfig"
353
352# Keep legacy drivers last 354# Keep legacy drivers last
353 355
354menuconfig DRM_LEGACY 356menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 4c3dc4268b65..5fcc9bc9c97a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -118,3 +118,4 @@ obj-$(CONFIG_DRM_VBOXVIDEO) += vboxvideo/
118obj-$(CONFIG_DRM_LIMA) += lima/ 118obj-$(CONFIG_DRM_LIMA) += lima/
119obj-$(CONFIG_DRM_PANFROST) += panfrost/ 119obj-$(CONFIG_DRM_PANFROST) += panfrost/
120obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ 120obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
121obj-$(CONFIG_DRM_MCDE) += mcde/
diff --git a/drivers/gpu/drm/mcde/Kconfig b/drivers/gpu/drm/mcde/Kconfig
new file mode 100644
index 000000000000..b3990126562c
--- /dev/null
+++ b/drivers/gpu/drm/mcde/Kconfig
@@ -0,0 +1,18 @@
1config DRM_MCDE
2 tristate "DRM Support for ST-Ericsson MCDE (Multichannel Display Engine)"
3 depends on DRM
4 depends on CMA
5 depends on ARM || COMPILE_TEST
6 depends on OF
7 select MFD_SYSCON
8 select DRM_MIPI_DSI
9 select DRM_BRIDGE
10 select DRM_PANEL_BRIDGE
11 select DRM_KMS_HELPER
12 select DRM_KMS_CMA_HELPER
13 select DRM_GEM_CMA_HELPER
14 select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
15 help
16 Choose this option for DRM support for the ST-Ericsson MCDE
17 Multi-Channel Display Engine.
18 If M is selected the module will be called mcde_drm.
diff --git a/drivers/gpu/drm/mcde/Makefile b/drivers/gpu/drm/mcde/Makefile
new file mode 100644
index 000000000000..fe28f4e0fe46
--- /dev/null
+++ b/drivers/gpu/drm/mcde/Makefile
@@ -0,0 +1,3 @@
1mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_display.o
2
3obj-$(CONFIG_DRM_MCDE) += mcde_drm.o
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
new file mode 100644
index 000000000000..17dc46d554b0
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -0,0 +1,1142 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 Linus Walleij <linus.walleij@linaro.org>
4 * Parts of this file were based on the MCDE driver by Marcus Lorentzon
5 * (C) ST-Ericsson SA 2013
6 */
7#include <linux/clk.h>
8#include <linux/delay.h>
9#include <linux/dma-buf.h>
10
11#include <drm/drm_device.h>
12#include <drm/drm_fb_cma_helper.h>
13#include <drm/drm_fourcc.h>
14#include <drm/drm_gem_cma_helper.h>
15#include <drm/drm_gem_framebuffer_helper.h>
16#include <drm/drm_mipi_dsi.h>
17#include <drm/drm_simple_kms_helper.h>
18#include <drm/drm_vblank.h>
19#include <video/mipi_display.h>
20
21#include "mcde_drm.h"
22#include "mcde_display_regs.h"
23
24enum mcde_fifo {
25 MCDE_FIFO_A,
26 MCDE_FIFO_B,
27 /* TODO: implement FIFO C0 and FIFO C1 */
28};
29
30enum mcde_channel {
31 MCDE_CHANNEL_0 = 0,
32 MCDE_CHANNEL_1,
33 MCDE_CHANNEL_2,
34 MCDE_CHANNEL_3,
35};
36
37enum mcde_extsrc {
38 MCDE_EXTSRC_0 = 0,
39 MCDE_EXTSRC_1,
40 MCDE_EXTSRC_2,
41 MCDE_EXTSRC_3,
42 MCDE_EXTSRC_4,
43 MCDE_EXTSRC_5,
44 MCDE_EXTSRC_6,
45 MCDE_EXTSRC_7,
46 MCDE_EXTSRC_8,
47 MCDE_EXTSRC_9,
48};
49
50enum mcde_overlay {
51 MCDE_OVERLAY_0 = 0,
52 MCDE_OVERLAY_1,
53 MCDE_OVERLAY_2,
54 MCDE_OVERLAY_3,
55 MCDE_OVERLAY_4,
56 MCDE_OVERLAY_5,
57};
58
59enum mcde_dsi_formatter {
60 MCDE_DSI_FORMATTER_0 = 0,
61 MCDE_DSI_FORMATTER_1,
62 MCDE_DSI_FORMATTER_2,
63};
64
65void mcde_display_irq(struct mcde *mcde)
66{
67 u32 mispp, misovl, mischnl;
68 bool vblank;
69
70 /* Handle display IRQs */
71 mispp = readl(mcde->regs + MCDE_MISPP);
72 misovl = readl(mcde->regs + MCDE_MISOVL);
73 mischnl = readl(mcde->regs + MCDE_MISCHNL);
74
75 /*
76 * Handle IRQs from the DSI link. All IRQs from the DSI links
77 * are just latched onto the MCDE IRQ line, so we need to traverse
78 * any active DSI masters and check if an IRQ is originating from
79 * them.
80 *
81 * TODO: Currently only one DSI link is supported.
82 */
83 if (mcde_dsi_irq(mcde->mdsi)) {
84 u32 val;
85
86 /*
87 * In oneshot mode we do not send continuous updates
88 * to the display, instead we only push out updates when
89 * the update function is called, then we disable the
90 * flow on the channel once we get the TE IRQ.
91 */
92 if (mcde->oneshot_mode) {
93 spin_lock(&mcde->flow_lock);
94 if (--mcde->flow_active == 0) {
95 dev_dbg(mcde->dev, "TE0 IRQ\n");
96 /* Disable FIFO A flow */
97 val = readl(mcde->regs + MCDE_CRA0);
98 val &= ~MCDE_CRX0_FLOEN;
99 writel(val, mcde->regs + MCDE_CRA0);
100 }
101 spin_unlock(&mcde->flow_lock);
102 }
103 }
104
105 /* Vblank from one of the channels */
106 if (mispp & MCDE_PP_VCMPA) {
107 dev_dbg(mcde->dev, "chnl A vblank IRQ\n");
108 vblank = true;
109 }
110 if (mispp & MCDE_PP_VCMPB) {
111 dev_dbg(mcde->dev, "chnl B vblank IRQ\n");
112 vblank = true;
113 }
114 if (mispp & MCDE_PP_VCMPC0)
115 dev_dbg(mcde->dev, "chnl C0 vblank IRQ\n");
116 if (mispp & MCDE_PP_VCMPC1)
117 dev_dbg(mcde->dev, "chnl C1 vblank IRQ\n");
118 if (mispp & MCDE_PP_VSCC0)
119 dev_dbg(mcde->dev, "chnl C0 TE IRQ\n");
120 if (mispp & MCDE_PP_VSCC1)
121 dev_dbg(mcde->dev, "chnl C1 TE IRQ\n");
122 writel(mispp, mcde->regs + MCDE_RISPP);
123
124 if (vblank)
125 drm_crtc_handle_vblank(&mcde->pipe.crtc);
126
127 if (misovl)
128 dev_info(mcde->dev, "some stray overlay IRQ %08x\n", misovl);
129 writel(misovl, mcde->regs + MCDE_RISOVL);
130
131 if (mischnl)
132 dev_info(mcde->dev, "some stray channel error IRQ %08x\n",
133 mischnl);
134 writel(mischnl, mcde->regs + MCDE_RISCHNL);
135}
136
137void mcde_display_disable_irqs(struct mcde *mcde)
138{
139 /* Disable all IRQs */
140 writel(0, mcde->regs + MCDE_IMSCPP);
141 writel(0, mcde->regs + MCDE_IMSCOVL);
142 writel(0, mcde->regs + MCDE_IMSCCHNL);
143
144 /* Clear any pending IRQs */
145 writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP);
146 writel(0xFFFFFFFF, mcde->regs + MCDE_RISOVL);
147 writel(0xFFFFFFFF, mcde->regs + MCDE_RISCHNL);
148}
149
150static int mcde_display_check(struct drm_simple_display_pipe *pipe,
151 struct drm_plane_state *pstate,
152 struct drm_crtc_state *cstate)
153{
154 const struct drm_display_mode *mode = &cstate->mode;
155 struct drm_framebuffer *old_fb = pipe->plane.state->fb;
156 struct drm_framebuffer *fb = pstate->fb;
157
158 if (fb) {
159 u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0);
160
161 /* FB base address must be dword aligned. */
162 if (offset & 3) {
163 DRM_DEBUG_KMS("FB not 32-bit aligned\n");
164 return -EINVAL;
165 }
166
167 /*
168 * There's no pitch register, the mode's hdisplay
169 * controls this.
170 */
171 if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) {
172 DRM_DEBUG_KMS("can't handle pitches\n");
173 return -EINVAL;
174 }
175
176 /*
177 * We can't change the FB format in a flicker-free
178 * manner (and only update it during CRTC enable).
179 */
180 if (old_fb && old_fb->format != fb->format)
181 cstate->mode_changed = true;
182 }
183
184 return 0;
185}
186
187static int mcde_configure_extsrc(struct mcde *mcde, enum mcde_extsrc src,
188 u32 format)
189{
190 u32 val;
191 u32 conf;
192 u32 cr;
193
194 switch (src) {
195 case MCDE_EXTSRC_0:
196 conf = MCDE_EXTSRC0CONF;
197 cr = MCDE_EXTSRC0CR;
198 break;
199 case MCDE_EXTSRC_1:
200 conf = MCDE_EXTSRC1CONF;
201 cr = MCDE_EXTSRC1CR;
202 break;
203 case MCDE_EXTSRC_2:
204 conf = MCDE_EXTSRC2CONF;
205 cr = MCDE_EXTSRC2CR;
206 break;
207 case MCDE_EXTSRC_3:
208 conf = MCDE_EXTSRC3CONF;
209 cr = MCDE_EXTSRC3CR;
210 break;
211 case MCDE_EXTSRC_4:
212 conf = MCDE_EXTSRC4CONF;
213 cr = MCDE_EXTSRC4CR;
214 break;
215 case MCDE_EXTSRC_5:
216 conf = MCDE_EXTSRC5CONF;
217 cr = MCDE_EXTSRC5CR;
218 break;
219 case MCDE_EXTSRC_6:
220 conf = MCDE_EXTSRC6CONF;
221 cr = MCDE_EXTSRC6CR;
222 break;
223 case MCDE_EXTSRC_7:
224 conf = MCDE_EXTSRC7CONF;
225 cr = MCDE_EXTSRC7CR;
226 break;
227 case MCDE_EXTSRC_8:
228 conf = MCDE_EXTSRC8CONF;
229 cr = MCDE_EXTSRC8CR;
230 break;
231 case MCDE_EXTSRC_9:
232 conf = MCDE_EXTSRC9CONF;
233 cr = MCDE_EXTSRC9CR;
234 break;
235 }
236
237 /*
238 * Configure external source 0 one buffer (buffer 0)
239 * primary overlay ID 0.
240 * From mcde_hw.c ovly_update_registers() in the vendor tree
241 */
242 val = 0 << MCDE_EXTSRCXCONF_BUF_ID_SHIFT;
243 val |= 1 << MCDE_EXTSRCXCONF_BUF_NB_SHIFT;
244 val |= 0 << MCDE_EXTSRCXCONF_PRI_OVLID_SHIFT;
245 /*
246 * MCDE has inverse semantics from DRM on RBG/BGR which is why
247 * all the modes are inversed here.
248 */
249 switch (format) {
250 case DRM_FORMAT_ARGB8888:
251 val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 <<
252 MCDE_EXTSRCXCONF_BPP_SHIFT;
253 val |= MCDE_EXTSRCXCONF_BGR;
254 break;
255 case DRM_FORMAT_ABGR8888:
256 val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 <<
257 MCDE_EXTSRCXCONF_BPP_SHIFT;
258 break;
259 case DRM_FORMAT_XRGB8888:
260 val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 <<
261 MCDE_EXTSRCXCONF_BPP_SHIFT;
262 val |= MCDE_EXTSRCXCONF_BGR;
263 break;
264 case DRM_FORMAT_XBGR8888:
265 val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 <<
266 MCDE_EXTSRCXCONF_BPP_SHIFT;
267 break;
268 case DRM_FORMAT_RGB888:
269 val |= MCDE_EXTSRCXCONF_BPP_RGB888 <<
270 MCDE_EXTSRCXCONF_BPP_SHIFT;
271 val |= MCDE_EXTSRCXCONF_BGR;
272 break;
273 case DRM_FORMAT_BGR888:
274 val |= MCDE_EXTSRCXCONF_BPP_RGB888 <<
275 MCDE_EXTSRCXCONF_BPP_SHIFT;
276 break;
277 case DRM_FORMAT_ARGB4444:
278 val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 <<
279 MCDE_EXTSRCXCONF_BPP_SHIFT;
280 val |= MCDE_EXTSRCXCONF_BGR;
281 break;
282 case DRM_FORMAT_ABGR4444:
283 val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 <<
284 MCDE_EXTSRCXCONF_BPP_SHIFT;
285 break;
286 case DRM_FORMAT_XRGB4444:
287 val |= MCDE_EXTSRCXCONF_BPP_RGB444 <<
288 MCDE_EXTSRCXCONF_BPP_SHIFT;
289 val |= MCDE_EXTSRCXCONF_BGR;
290 break;
291 case DRM_FORMAT_XBGR4444:
292 val |= MCDE_EXTSRCXCONF_BPP_RGB444 <<
293 MCDE_EXTSRCXCONF_BPP_SHIFT;
294 break;
295 case DRM_FORMAT_XRGB1555:
296 val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 <<
297 MCDE_EXTSRCXCONF_BPP_SHIFT;
298 val |= MCDE_EXTSRCXCONF_BGR;
299 break;
300 case DRM_FORMAT_XBGR1555:
301 val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 <<
302 MCDE_EXTSRCXCONF_BPP_SHIFT;
303 break;
304 case DRM_FORMAT_RGB565:
305 val |= MCDE_EXTSRCXCONF_BPP_RGB565 <<
306 MCDE_EXTSRCXCONF_BPP_SHIFT;
307 val |= MCDE_EXTSRCXCONF_BGR;
308 break;
309 case DRM_FORMAT_BGR565:
310 val |= MCDE_EXTSRCXCONF_BPP_RGB565 <<
311 MCDE_EXTSRCXCONF_BPP_SHIFT;
312 break;
313 case DRM_FORMAT_YUV422:
314 val |= MCDE_EXTSRCXCONF_BPP_YCBCR422 <<
315 MCDE_EXTSRCXCONF_BPP_SHIFT;
316 break;
317 default:
318 dev_err(mcde->dev, "Unknown pixel format 0x%08x\n",
319 format);
320 return -EINVAL;
321 }
322 writel(val, mcde->regs + conf);
323
324 /* Software select, primary */
325 val = MCDE_EXTSRCXCR_SEL_MOD_SOFTWARE_SEL;
326 val |= MCDE_EXTSRCXCR_MULTIOVL_CTRL_PRIMARY;
327 writel(val, mcde->regs + cr);
328
329 return 0;
330}
331
332static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl,
333 enum mcde_extsrc src,
334 enum mcde_channel ch,
335 const struct drm_display_mode *mode,
336 u32 format)
337{
338 u32 val;
339 u32 conf1;
340 u32 conf2;
341 u32 crop;
342 u32 ljinc;
343 u32 cr;
344 u32 comp;
345
346 switch (ovl) {
347 case MCDE_OVERLAY_0:
348 conf1 = MCDE_OVL0CONF;
349 conf2 = MCDE_OVL0CONF2;
350 crop = MCDE_OVL0CROP;
351 ljinc = MCDE_OVL0LJINC;
352 cr = MCDE_OVL0CR;
353 comp = MCDE_OVL0COMP;
354 break;
355 case MCDE_OVERLAY_1:
356 conf1 = MCDE_OVL1CONF;
357 conf2 = MCDE_OVL1CONF2;
358 crop = MCDE_OVL1CROP;
359 ljinc = MCDE_OVL1LJINC;
360 cr = MCDE_OVL1CR;
361 comp = MCDE_OVL1COMP;
362 break;
363 case MCDE_OVERLAY_2:
364 conf1 = MCDE_OVL2CONF;
365 conf2 = MCDE_OVL2CONF2;
366 crop = MCDE_OVL2CROP;
367 ljinc = MCDE_OVL2LJINC;
368 cr = MCDE_OVL2CR;
369 comp = MCDE_OVL2COMP;
370 break;
371 case MCDE_OVERLAY_3:
372 conf1 = MCDE_OVL3CONF;
373 conf2 = MCDE_OVL3CONF2;
374 crop = MCDE_OVL3CROP;
375 ljinc = MCDE_OVL3LJINC;
376 cr = MCDE_OVL3CR;
377 comp = MCDE_OVL3COMP;
378 break;
379 case MCDE_OVERLAY_4:
380 conf1 = MCDE_OVL4CONF;
381 conf2 = MCDE_OVL4CONF2;
382 crop = MCDE_OVL4CROP;
383 ljinc = MCDE_OVL4LJINC;
384 cr = MCDE_OVL4CR;
385 comp = MCDE_OVL4COMP;
386 break;
387 case MCDE_OVERLAY_5:
388 conf1 = MCDE_OVL5CONF;
389 conf2 = MCDE_OVL5CONF2;
390 crop = MCDE_OVL5CROP;
391 ljinc = MCDE_OVL5LJINC;
392 cr = MCDE_OVL5CR;
393 comp = MCDE_OVL5COMP;
394 break;
395 }
396
397 val = mode->hdisplay << MCDE_OVLXCONF_PPL_SHIFT;
398 val |= mode->vdisplay << MCDE_OVLXCONF_LPF_SHIFT;
399 /* Use external source 0 that we just configured */
400 val |= src << MCDE_OVLXCONF_EXTSRC_ID_SHIFT;
401 writel(val, mcde->regs + conf1);
402
403 val = MCDE_OVLXCONF2_BP_PER_PIXEL_ALPHA;
404 val |= 0xff << MCDE_OVLXCONF2_ALPHAVALUE_SHIFT;
405 /* OPQ: overlay is opaque */
406 switch (format) {
407 case DRM_FORMAT_ARGB8888:
408 case DRM_FORMAT_ABGR8888:
409 case DRM_FORMAT_ARGB4444:
410 case DRM_FORMAT_ABGR4444:
411 case DRM_FORMAT_XRGB1555:
412 case DRM_FORMAT_XBGR1555:
413 /* No OPQ */
414 break;
415 case DRM_FORMAT_XRGB8888:
416 case DRM_FORMAT_XBGR8888:
417 case DRM_FORMAT_RGB888:
418 case DRM_FORMAT_BGR888:
419 case DRM_FORMAT_RGB565:
420 case DRM_FORMAT_BGR565:
421 case DRM_FORMAT_YUV422:
422 val |= MCDE_OVLXCONF2_OPQ;
423 break;
424 default:
425 dev_err(mcde->dev, "Unknown pixel format 0x%08x\n",
426 format);
427 break;
428 }
429 /* The default watermark level for overlay 0 is 48 */
430 val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT;
431 writel(val, mcde->regs + conf2);
432
433 /* Number of bytes to fetch per line */
434 writel(mcde->stride, mcde->regs + ljinc);
435 /* No cropping */
436 writel(0, mcde->regs + crop);
437
438 /* Set up overlay control register */
439 val = MCDE_OVLXCR_OVLEN;
440 val |= MCDE_OVLXCR_COLCCTRL_DISABLED;
441 val |= MCDE_OVLXCR_BURSTSIZE_8W <<
442 MCDE_OVLXCR_BURSTSIZE_SHIFT;
443 val |= MCDE_OVLXCR_MAXOUTSTANDING_8_REQ <<
444 MCDE_OVLXCR_MAXOUTSTANDING_SHIFT;
445 /* Not using rotation but set it up anyways */
446 val |= MCDE_OVLXCR_ROTBURSTSIZE_8W <<
447 MCDE_OVLXCR_ROTBURSTSIZE_SHIFT;
448 writel(val, mcde->regs + cr);
449
450 /*
451 * Set up the overlay compositor to route the overlay out to
452 * the desired channel
453 */
454 val = ch << MCDE_OVLXCOMP_CH_ID_SHIFT;
455 writel(val, mcde->regs + comp);
456}
457
458static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch,
459 enum mcde_fifo fifo,
460 const struct drm_display_mode *mode)
461{
462 u32 val;
463 u32 conf;
464 u32 sync;
465 u32 stat;
466 u32 bgcol;
467 u32 mux;
468
469 switch (ch) {
470 case MCDE_CHANNEL_0:
471 conf = MCDE_CHNL0CONF;
472 sync = MCDE_CHNL0SYNCHMOD;
473 stat = MCDE_CHNL0STAT;
474 bgcol = MCDE_CHNL0BCKGNDCOL;
475 mux = MCDE_CHNL0MUXING;
476 break;
477 case MCDE_CHANNEL_1:
478 conf = MCDE_CHNL1CONF;
479 sync = MCDE_CHNL1SYNCHMOD;
480 stat = MCDE_CHNL1STAT;
481 bgcol = MCDE_CHNL1BCKGNDCOL;
482 mux = MCDE_CHNL1MUXING;
483 break;
484 case MCDE_CHANNEL_2:
485 conf = MCDE_CHNL2CONF;
486 sync = MCDE_CHNL2SYNCHMOD;
487 stat = MCDE_CHNL2STAT;
488 bgcol = MCDE_CHNL2BCKGNDCOL;
489 mux = MCDE_CHNL2MUXING;
490 break;
491 case MCDE_CHANNEL_3:
492 conf = MCDE_CHNL3CONF;
493 sync = MCDE_CHNL3SYNCHMOD;
494 stat = MCDE_CHNL3STAT;
495 bgcol = MCDE_CHNL3BCKGNDCOL;
496 mux = MCDE_CHNL3MUXING;
497 return;
498 }
499
500 /* Set up channel 0 sync (based on chnl_update_registers()) */
501 if (mcde->te_sync) {
502 /*
503 * Turn on hardware TE0 synchronization
504 */
505 val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE
506 << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
507 val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0
508 << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
509 } else {
510 /*
511 * Set up sync source to software, out sync formatter
512 * Code mostly from mcde_hw.c chnl_update_registers()
513 */
514 val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE
515 << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT;
516 val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER
517 << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT;
518 }
519 writel(val, mcde->regs + sync);
520
521 /* Set up pixels per line and lines per frame */
522 val = (mode->hdisplay - 1) << MCDE_CHNLXCONF_PPL_SHIFT;
523 val |= (mode->vdisplay - 1) << MCDE_CHNLXCONF_LPF_SHIFT;
524 writel(val, mcde->regs + conf);
525
526 /*
527 * Normalize color conversion:
528 * black background, OLED conversion disable on channel
529 */
530 val = MCDE_CHNLXSTAT_CHNLBLBCKGND_EN |
531 MCDE_CHNLXSTAT_CHNLRD;
532 writel(val, mcde->regs + stat);
533 writel(0, mcde->regs + bgcol);
534
535 /* Set up muxing: connect the channel to the desired FIFO */
536 switch (fifo) {
537 case MCDE_FIFO_A:
538 writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_A,
539 mcde->regs + mux);
540 break;
541 case MCDE_FIFO_B:
542 writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_B,
543 mcde->regs + mux);
544 break;
545 }
546}
547
548static void mcde_configure_fifo(struct mcde *mcde, enum mcde_fifo fifo,
549 enum mcde_dsi_formatter fmt,
550 int fifo_wtrmrk)
551{
552 u32 val;
553 u32 ctrl;
554 u32 cr0, cr1;
555
556 switch (fifo) {
557 case MCDE_FIFO_A:
558 ctrl = MCDE_CTRLA;
559 cr0 = MCDE_CRA0;
560 cr1 = MCDE_CRA1;
561 break;
562 case MCDE_FIFO_B:
563 ctrl = MCDE_CTRLB;
564 cr0 = MCDE_CRB0;
565 cr1 = MCDE_CRB1;
566 break;
567 }
568
569 val = fifo_wtrmrk << MCDE_CTRLX_FIFOWTRMRK_SHIFT;
570 /* We only support DSI formatting for now */
571 val |= MCDE_CTRLX_FORMTYPE_DSI <<
572 MCDE_CTRLX_FORMTYPE_SHIFT;
573
574 /* Select the formatter to use for this FIFO */
575 val |= fmt << MCDE_CTRLX_FORMID_SHIFT;
576 writel(val, mcde->regs + ctrl);
577
578 /* Blend source with Alpha 0xff on FIFO */
579 val = MCDE_CRX0_BLENDEN |
580 0xff << MCDE_CRX0_ALPHABLEND_SHIFT;
581 writel(val, mcde->regs + cr0);
582
583 /* Set-up from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */
584
585 /* Use the MCDE clock for this FIFO */
586 val = MCDE_CRX1_CLKSEL_MCDECLK << MCDE_CRX1_CLKSEL_SHIFT;
587
588 /* TODO: when adding DPI support add OUTBPP etc here */
589 writel(val, mcde->regs + cr1);
590};
591
592static void mcde_configure_dsi_formatter(struct mcde *mcde,
593 enum mcde_dsi_formatter fmt,
594 u32 formatter_frame,
595 int pkt_size)
596{
597 u32 val;
598 u32 conf0;
599 u32 frame;
600 u32 pkt;
601 u32 sync;
602 u32 cmdw;
603 u32 delay0, delay1;
604
605 switch (fmt) {
606 case MCDE_DSI_FORMATTER_0:
607 conf0 = MCDE_DSIVID0CONF0;
608 frame = MCDE_DSIVID0FRAME;
609 pkt = MCDE_DSIVID0PKT;
610 sync = MCDE_DSIVID0SYNC;
611 cmdw = MCDE_DSIVID0CMDW;
612 delay0 = MCDE_DSIVID0DELAY0;
613 delay1 = MCDE_DSIVID0DELAY1;
614 break;
615 case MCDE_DSI_FORMATTER_1:
616 conf0 = MCDE_DSIVID1CONF0;
617 frame = MCDE_DSIVID1FRAME;
618 pkt = MCDE_DSIVID1PKT;
619 sync = MCDE_DSIVID1SYNC;
620 cmdw = MCDE_DSIVID1CMDW;
621 delay0 = MCDE_DSIVID1DELAY0;
622 delay1 = MCDE_DSIVID1DELAY1;
623 break;
624 case MCDE_DSI_FORMATTER_2:
625 conf0 = MCDE_DSIVID2CONF0;
626 frame = MCDE_DSIVID2FRAME;
627 pkt = MCDE_DSIVID2PKT;
628 sync = MCDE_DSIVID2SYNC;
629 cmdw = MCDE_DSIVID2CMDW;
630 delay0 = MCDE_DSIVID2DELAY0;
631 delay1 = MCDE_DSIVID2DELAY1;
632 break;
633 }
634
635 /*
636 * Enable formatter
637 * 8 bit commands and DCS commands (notgen = not generic)
638 */
639 val = MCDE_DSICONF0_CMD8 | MCDE_DSICONF0_DCSVID_NOTGEN;
640 if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)
641 val |= MCDE_DSICONF0_VID_MODE_VID;
642 switch (mcde->mdsi->format) {
643 case MIPI_DSI_FMT_RGB888:
644 val |= MCDE_DSICONF0_PACKING_RGB888 <<
645 MCDE_DSICONF0_PACKING_SHIFT;
646 break;
647 case MIPI_DSI_FMT_RGB666:
648 val |= MCDE_DSICONF0_PACKING_RGB666 <<
649 MCDE_DSICONF0_PACKING_SHIFT;
650 break;
651 case MIPI_DSI_FMT_RGB666_PACKED:
652 val |= MCDE_DSICONF0_PACKING_RGB666_PACKED <<
653 MCDE_DSICONF0_PACKING_SHIFT;
654 break;
655 case MIPI_DSI_FMT_RGB565:
656 val |= MCDE_DSICONF0_PACKING_RGB565 <<
657 MCDE_DSICONF0_PACKING_SHIFT;
658 break;
659 default:
660 dev_err(mcde->dev, "unknown DSI format\n");
661 return;
662 }
663 writel(val, mcde->regs + conf0);
664
665 writel(formatter_frame, mcde->regs + frame);
666 writel(pkt_size, mcde->regs + pkt);
667 writel(0, mcde->regs + sync);
668 /* Define the MIPI command: we want to write into display memory */
669 val = MIPI_DCS_WRITE_MEMORY_CONTINUE <<
670 MCDE_DSIVIDXCMDW_CMDW_CONTINUE_SHIFT;
671 val |= MIPI_DCS_WRITE_MEMORY_START <<
672 MCDE_DSIVIDXCMDW_CMDW_START_SHIFT;
673 writel(val, mcde->regs + cmdw);
674
675 /*
676 * FIXME: the vendor driver has some hack around this value in
677 * CMD mode with autotrig.
678 */
679 writel(0, mcde->regs + delay0);
680 writel(0, mcde->regs + delay1);
681}
682
683static void mcde_enable_fifo(struct mcde *mcde, enum mcde_fifo fifo)
684{
685 u32 val;
686 u32 cr;
687
688 switch (fifo) {
689 case MCDE_FIFO_A:
690 cr = MCDE_CRA0;
691 break;
692 case MCDE_FIFO_B:
693 cr = MCDE_CRB0;
694 break;
695 default:
696 dev_err(mcde->dev, "cannot enable FIFO %c\n",
697 'A' + fifo);
698 return;
699 }
700
701 spin_lock(&mcde->flow_lock);
702 val = readl(mcde->regs + cr);
703 val |= MCDE_CRX0_FLOEN;
704 writel(val, mcde->regs + cr);
705 mcde->flow_active++;
706 spin_unlock(&mcde->flow_lock);
707}
708
709static void mcde_disable_fifo(struct mcde *mcde, enum mcde_fifo fifo,
710 bool wait_for_drain)
711{
712 int timeout = 100;
713 u32 val;
714 u32 cr;
715
716 switch (fifo) {
717 case MCDE_FIFO_A:
718 cr = MCDE_CRA0;
719 break;
720 case MCDE_FIFO_B:
721 cr = MCDE_CRB0;
722 break;
723 default:
724 dev_err(mcde->dev, "cannot disable FIFO %c\n",
725 'A' + fifo);
726 return;
727 }
728
729 spin_lock(&mcde->flow_lock);
730 val = readl(mcde->regs + cr);
731 val &= ~MCDE_CRX0_FLOEN;
732 writel(val, mcde->regs + cr);
733 mcde->flow_active = 0;
734 spin_unlock(&mcde->flow_lock);
735
736 if (!wait_for_drain)
737 return;
738
739 /* Check that we really drained and stopped the flow */
740 while (readl(mcde->regs + cr) & MCDE_CRX0_FLOEN) {
741 usleep_range(1000, 1500);
742 if (!--timeout) {
743 dev_err(mcde->dev,
744 "FIFO timeout while clearing FIFO %c\n",
745 'A' + fifo);
746 return;
747 }
748 }
749}
750
751/*
752 * This drains a pipe i.e. a FIFO connected to a certain channel
753 */
754static void mcde_drain_pipe(struct mcde *mcde, enum mcde_fifo fifo,
755 enum mcde_channel ch)
756{
757 u32 val;
758 u32 ctrl;
759 u32 synsw;
760
761 switch (fifo) {
762 case MCDE_FIFO_A:
763 ctrl = MCDE_CTRLA;
764 break;
765 case MCDE_FIFO_B:
766 ctrl = MCDE_CTRLB;
767 break;
768 }
769
770 switch (ch) {
771 case MCDE_CHANNEL_0:
772 synsw = MCDE_CHNL0SYNCHSW;
773 break;
774 case MCDE_CHANNEL_1:
775 synsw = MCDE_CHNL1SYNCHSW;
776 break;
777 case MCDE_CHANNEL_2:
778 synsw = MCDE_CHNL2SYNCHSW;
779 break;
780 case MCDE_CHANNEL_3:
781 synsw = MCDE_CHNL3SYNCHSW;
782 return;
783 }
784
785 val = readl(mcde->regs + ctrl);
786 if (!(val & MCDE_CTRLX_FIFOEMPTY)) {
787 dev_err(mcde->dev, "Channel A FIFO not empty (handover)\n");
788 /* Attempt to clear the FIFO */
789 mcde_enable_fifo(mcde, fifo);
790 /* Trigger a software sync out on respective channel (0-3) */
791 writel(MCDE_CHNLXSYNCHSW_SW_TRIG, mcde->regs + synsw);
792 /* Disable FIFO A flow again */
793 mcde_disable_fifo(mcde, fifo, true);
794 }
795}
796
797static int mcde_dsi_get_pkt_div(int ppl, int fifo_size)
798{
799 /*
800 * DSI command mode line packets should be split into an even number of
801 * packets smaller than or equal to the fifo size.
802 */
803 int div;
804 const int max_div = DIV_ROUND_UP(MCDE_MAX_WIDTH, fifo_size);
805
806 for (div = 1; div < max_div; div++)
807 if (ppl % div == 0 && ppl / div <= fifo_size)
808 return div;
809 return 1;
810}
811
812static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
813 struct drm_crtc_state *cstate,
814 struct drm_plane_state *plane_state)
815{
816 struct drm_crtc *crtc = &pipe->crtc;
817 struct drm_plane *plane = &pipe->plane;
818 struct drm_device *drm = crtc->dev;
819 struct mcde *mcde = drm->dev_private;
820 const struct drm_display_mode *mode = &cstate->mode;
821 struct drm_framebuffer *fb = plane->state->fb;
822 u32 format = fb->format->format;
823 u32 formatter_ppl = mode->hdisplay; /* pixels per line */
824 u32 formatter_lpf = mode->vdisplay; /* lines per frame */
825 int pkt_size, fifo_wtrmrk;
826 int cpp = drm_format_plane_cpp(format, 0);
827 int formatter_cpp;
828 struct drm_format_name_buf tmp;
829 u32 formatter_frame;
830 u32 pkt_div;
831 u32 val;
832
833 dev_info(drm->dev, "enable MCDE, %d x %d format %s\n",
834 mode->hdisplay, mode->vdisplay,
835 drm_get_format_name(format, &tmp));
836 if (!mcde->mdsi) {
837 /* TODO: deal with this for non-DSI output */
838 dev_err(drm->dev, "no DSI master attached!\n");
839 return;
840 }
841
842 dev_info(drm->dev, "output in %s mode, format %dbpp\n",
843 (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ?
844 "VIDEO" : "CMD",
845 mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format));
846 formatter_cpp =
847 mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format) / 8;
848 dev_info(drm->dev, "overlay CPP %d bytes, DSI CPP %d bytes\n",
849 cpp,
850 formatter_cpp);
851
852 /* Calculations from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */
853
854 /*
855 * Set up FIFO A watermark level:
856 * 128 for LCD 32bpp video mode
857 * 48 for LCD 32bpp command mode
858 * 128 for LCD 16bpp video mode
859 * 64 for LCD 16bpp command mode
860 * 128 for HDMI 32bpp
861 * 192 for HDMI 16bpp
862 */
863 fifo_wtrmrk = mode->hdisplay;
864 if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
865 fifo_wtrmrk = min(fifo_wtrmrk, 128);
866 pkt_div = 1;
867 } else {
868 fifo_wtrmrk = min(fifo_wtrmrk, 48);
869 /* The FIFO is 640 entries deep on this v3 hardware */
870 pkt_div = mcde_dsi_get_pkt_div(mode->hdisplay, 640);
871 }
872 dev_dbg(drm->dev, "FIFO watermark after flooring: %d bytes\n",
873 fifo_wtrmrk);
874 dev_dbg(drm->dev, "Packet divisor: %d bytes\n", pkt_div);
875
876 /* NOTE: pkt_div is 1 for video mode */
877 pkt_size = (formatter_ppl * formatter_cpp) / pkt_div;
878 /* Commands CMD8 need one extra byte */
879 if (!(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO))
880 pkt_size++;
881
882 dev_dbg(drm->dev, "DSI packet size: %d * %d bytes per line\n",
883 pkt_size, pkt_div);
884 dev_dbg(drm->dev, "Overlay frame size: %u bytes\n",
885 mode->hdisplay * mode->vdisplay * cpp);
886 mcde->stride = mode->hdisplay * cpp;
887 dev_dbg(drm->dev, "Overlay line stride: %u bytes\n",
888 mcde->stride);
889 /* NOTE: pkt_div is 1 for video mode */
890 formatter_frame = pkt_size * pkt_div * formatter_lpf;
891 dev_dbg(drm->dev, "Formatter frame size: %u bytes\n", formatter_frame);
892
893 /* Drain the FIFO A + channel 0 pipe so we have a clean slate */
894 mcde_drain_pipe(mcde, MCDE_FIFO_A, MCDE_CHANNEL_0);
895
896 /*
897 * We set up our display pipeline:
898 * EXTSRC 0 -> OVERLAY 0 -> CHANNEL 0 -> FIFO A -> DSI FORMATTER 0
899 *
900 * First configure the external source (memory) on external source 0
901 * using the desired bitstream/bitmap format
902 */
903 mcde_configure_extsrc(mcde, MCDE_EXTSRC_0, format);
904
905 /*
906 * Configure overlay 0 according to format and mode and take input
907 * from external source 0 and route the output of this overlay to
908 * channel 0
909 */
910 mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0,
911 MCDE_CHANNEL_0, mode, format);
912
913 /*
914 * Configure pixel-per-line and line-per-frame for channel 0 and then
915 * route channel 0 to FIFO A
916 */
917 mcde_configure_channel(mcde, MCDE_CHANNEL_0, MCDE_FIFO_A, mode);
918
919 /* Configure FIFO A to use DSI formatter 0 */
920 mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0,
921 fifo_wtrmrk);
922
923 /* Configure the DSI formatter 0 for the DSI panel output */
924 mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0,
925 formatter_frame, pkt_size);
926
927 if (mcde->te_sync) {
928 if (mode->flags & DRM_MODE_FLAG_NVSYNC)
929 val = MCDE_VSCRC_VSPOL;
930 else
931 val = 0;
932 writel(val, mcde->regs + MCDE_VSCRC0);
933 /* Enable VSYNC capture on TE0 */
934 val = readl(mcde->regs + MCDE_CRC);
935 val |= MCDE_CRC_SYCEN0;
936 writel(val, mcde->regs + MCDE_CRC);
937
938 drm_crtc_vblank_on(crtc);
939 }
940
941 dev_info(drm->dev, "MCDE display is enabled\n");
942}
943
944static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
945{
946 struct drm_crtc *crtc = &pipe->crtc;
947 struct drm_device *drm = crtc->dev;
948 struct mcde *mcde = drm->dev_private;
949
950 if (mcde->te_sync)
951 drm_crtc_vblank_off(crtc);
952
953 /* Disable FIFO A flow */
954 mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
955
956 dev_info(drm->dev, "MCDE display is disabled\n");
957}
958
959static void mcde_display_send_one_frame(struct mcde *mcde)
960{
961 /* Request a TE ACK */
962 if (mcde->te_sync)
963 mcde_dsi_te_request(mcde->mdsi);
964
965 /* Enable FIFO A flow */
966 mcde_enable_fifo(mcde, MCDE_FIFO_A);
967
968 if (mcde->te_sync) {
969 /*
970 * If oneshot mode is enabled, the flow will be disabled
971 * when the TE0 IRQ arrives in the interrupt handler. Otherwise
972 * updates are continuously streamed to the display after this
973 * point.
974 */
975 dev_dbg(mcde->dev, "sent TE0 framebuffer update\n");
976 return;
977 }
978
979 /* Trigger a software sync out on channel 0 */
980 writel(MCDE_CHNLXSYNCHSW_SW_TRIG,
981 mcde->regs + MCDE_CHNL0SYNCHSW);
982
983 /*
984 * Disable FIFO A flow again: since we are using TE sync we
985 * need to wait for the FIFO to drain before we continue
986 * so repeated calls to this function will not cause a mess
987 * in the hardware by pushing updates will updates are going
988 * on already.
989 */
990 mcde_disable_fifo(mcde, MCDE_FIFO_A, true);
991
992 dev_dbg(mcde->dev, "sent SW framebuffer update\n");
993}
994
995static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address)
996{
997 /* Write bitmap base address to register */
998 writel(buffer_address, mcde->regs + MCDE_EXTSRCXA0);
999 /*
1000 * Base address for next line this is probably only used
1001 * in interlace modes.
1002 */
1003 writel(buffer_address + mcde->stride, mcde->regs + MCDE_EXTSRCXA1);
1004}
1005
1006static void mcde_display_update(struct drm_simple_display_pipe *pipe,
1007 struct drm_plane_state *old_pstate)
1008{
1009 struct drm_crtc *crtc = &pipe->crtc;
1010 struct drm_device *drm = crtc->dev;
1011 struct mcde *mcde = drm->dev_private;
1012 struct drm_pending_vblank_event *event = crtc->state->event;
1013 struct drm_plane *plane = &pipe->plane;
1014 struct drm_plane_state *pstate = plane->state;
1015 struct drm_framebuffer *fb = pstate->fb;
1016
1017 /*
1018 * Handle any pending event first, we need to arm the vblank
1019 * interrupt before sending any update to the display so we don't
1020 * miss the interrupt.
1021 */
1022 if (event) {
1023 crtc->state->event = NULL;
1024
1025 spin_lock_irq(&crtc->dev->event_lock);
1026 /*
1027 * Hardware must be on before we can arm any vblank event,
1028 * this is not a scanout controller where there is always
1029 * some periodic update going on, it is completely frozen
1030 * until we get an update. If MCDE output isn't yet enabled,
1031 * we just send a vblank dummy event back.
1032 */
1033 if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) {
1034 dev_dbg(mcde->dev, "arm vblank event\n");
1035 drm_crtc_arm_vblank_event(crtc, event);
1036 } else {
1037 dev_dbg(mcde->dev, "insert fake vblank event\n");
1038 drm_crtc_send_vblank_event(crtc, event);
1039 }
1040
1041 spin_unlock_irq(&crtc->dev->event_lock);
1042 }
1043
1044 /*
1045 * We do not start sending framebuffer updates before the
1046 * display is enabled. Update events will however be dispatched
1047 * from the DRM core before the display is enabled.
1048 */
1049 if (fb) {
1050 mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0));
1051 /* Send a single frame using software sync */
1052 mcde_display_send_one_frame(mcde);
1053 dev_info_once(mcde->dev, "sent first display update\n");
1054 } else {
1055 /*
1056 * If an update is receieved before the MCDE is enabled
1057 * (before mcde_display_enable() is called) we can't really
1058 * do much with that buffer.
1059 */
1060 dev_info(mcde->dev, "ignored a display update\n");
1061 }
1062}
1063
1064static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe)
1065{
1066 struct drm_crtc *crtc = &pipe->crtc;
1067 struct drm_device *drm = crtc->dev;
1068 struct mcde *mcde = drm->dev_private;
1069 u32 val;
1070
1071 /* Enable all VBLANK IRQs */
1072 val = MCDE_PP_VCMPA |
1073 MCDE_PP_VCMPB |
1074 MCDE_PP_VSCC0 |
1075 MCDE_PP_VSCC1 |
1076 MCDE_PP_VCMPC0 |
1077 MCDE_PP_VCMPC1;
1078 writel(val, mcde->regs + MCDE_IMSCPP);
1079
1080 return 0;
1081}
1082
1083static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe)
1084{
1085 struct drm_crtc *crtc = &pipe->crtc;
1086 struct drm_device *drm = crtc->dev;
1087 struct mcde *mcde = drm->dev_private;
1088
1089 /* Disable all VBLANK IRQs */
1090 writel(0, mcde->regs + MCDE_IMSCPP);
1091 /* Clear any pending IRQs */
1092 writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP);
1093}
1094
1095static struct drm_simple_display_pipe_funcs mcde_display_funcs = {
1096 .check = mcde_display_check,
1097 .enable = mcde_display_enable,
1098 .disable = mcde_display_disable,
1099 .update = mcde_display_update,
1100 .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
1101};
1102
1103int mcde_display_init(struct drm_device *drm)
1104{
1105 struct mcde *mcde = drm->dev_private;
1106 int ret;
1107 static const u32 formats[] = {
1108 DRM_FORMAT_ARGB8888,
1109 DRM_FORMAT_ABGR8888,
1110 DRM_FORMAT_XRGB8888,
1111 DRM_FORMAT_XBGR8888,
1112 DRM_FORMAT_RGB888,
1113 DRM_FORMAT_BGR888,
1114 DRM_FORMAT_ARGB4444,
1115 DRM_FORMAT_ABGR4444,
1116 DRM_FORMAT_XRGB4444,
1117 DRM_FORMAT_XBGR4444,
1118 /* These are actually IRGB1555 so intensity bit is lost */
1119 DRM_FORMAT_XRGB1555,
1120 DRM_FORMAT_XBGR1555,
1121 DRM_FORMAT_RGB565,
1122 DRM_FORMAT_BGR565,
1123 DRM_FORMAT_YUV422,
1124 };
1125
1126 /* Provide vblank only when we have TE enabled */
1127 if (mcde->te_sync) {
1128 mcde_display_funcs.enable_vblank = mcde_display_enable_vblank;
1129 mcde_display_funcs.disable_vblank = mcde_display_disable_vblank;
1130 }
1131
1132 ret = drm_simple_display_pipe_init(drm, &mcde->pipe,
1133 &mcde_display_funcs,
1134 formats, ARRAY_SIZE(formats),
1135 NULL,
1136 mcde->connector);
1137 if (ret)
1138 return ret;
1139
1140 return 0;
1141}
1142EXPORT_SYMBOL_GPL(mcde_display_init);
diff --git a/drivers/gpu/drm/mcde/mcde_display_regs.h b/drivers/gpu/drm/mcde/mcde_display_regs.h
new file mode 100644
index 000000000000..d3ac7ef5ff9a
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_display_regs.h
@@ -0,0 +1,518 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __DRM_MCDE_DISPLAY_REGS
3#define __DRM_MCDE_DISPLAY_REGS
4
5/* PP (pixel processor) interrupts */
6#define MCDE_IMSCPP 0x00000104
7#define MCDE_RISPP 0x00000114
8#define MCDE_MISPP 0x00000124
9#define MCDE_SISPP 0x00000134
10
11#define MCDE_PP_VCMPA BIT(0)
12#define MCDE_PP_VCMPB BIT(1)
13#define MCDE_PP_VSCC0 BIT(2)
14#define MCDE_PP_VSCC1 BIT(3)
15#define MCDE_PP_VCMPC0 BIT(4)
16#define MCDE_PP_VCMPC1 BIT(5)
17#define MCDE_PP_ROTFD_A BIT(6)
18#define MCDE_PP_ROTFD_B BIT(7)
19
20/* Overlay interrupts */
21#define MCDE_IMSCOVL 0x00000108
22#define MCDE_RISOVL 0x00000118
23#define MCDE_MISOVL 0x00000128
24#define MCDE_SISOVL 0x00000138
25
26/* Channel interrupts */
27#define MCDE_IMSCCHNL 0x0000010C
28#define MCDE_RISCHNL 0x0000011C
29#define MCDE_MISCHNL 0x0000012C
30#define MCDE_SISCHNL 0x0000013C
31
32/* X = 0..9 */
33#define MCDE_EXTSRCXA0 0x00000200
34#define MCDE_EXTSRCXA0_GROUPOFFSET 0x20
35#define MCDE_EXTSRCXA0_BASEADDRESS0_SHIFT 3
36#define MCDE_EXTSRCXA0_BASEADDRESS0_MASK 0xFFFFFFF8
37
38#define MCDE_EXTSRCXA1 0x00000204
39#define MCDE_EXTSRCXA1_GROUPOFFSET 0x20
40#define MCDE_EXTSRCXA1_BASEADDRESS1_SHIFT 3
41#define MCDE_EXTSRCXA1_BASEADDRESS1_MASK 0xFFFFFFF8
42
43/* External sources 0..9 */
44#define MCDE_EXTSRC0CONF 0x0000020C
45#define MCDE_EXTSRC1CONF 0x0000022C
46#define MCDE_EXTSRC2CONF 0x0000024C
47#define MCDE_EXTSRC3CONF 0x0000026C
48#define MCDE_EXTSRC4CONF 0x0000028C
49#define MCDE_EXTSRC5CONF 0x000002AC
50#define MCDE_EXTSRC6CONF 0x000002CC
51#define MCDE_EXTSRC7CONF 0x000002EC
52#define MCDE_EXTSRC8CONF 0x0000030C
53#define MCDE_EXTSRC9CONF 0x0000032C
54#define MCDE_EXTSRCXCONF_GROUPOFFSET 0x20
55#define MCDE_EXTSRCXCONF_BUF_ID_SHIFT 0
56#define MCDE_EXTSRCXCONF_BUF_ID_MASK 0x00000003
57#define MCDE_EXTSRCXCONF_BUF_NB_SHIFT 2
58#define MCDE_EXTSRCXCONF_BUF_NB_MASK 0x0000000C
59#define MCDE_EXTSRCXCONF_PRI_OVLID_SHIFT 4
60#define MCDE_EXTSRCXCONF_PRI_OVLID_MASK 0x000000F0
61#define MCDE_EXTSRCXCONF_BPP_SHIFT 8
62#define MCDE_EXTSRCXCONF_BPP_MASK 0x00000F00
63#define MCDE_EXTSRCXCONF_BPP_1BPP_PAL 0
64#define MCDE_EXTSRCXCONF_BPP_2BPP_PAL 1
65#define MCDE_EXTSRCXCONF_BPP_4BPP_PAL 2
66#define MCDE_EXTSRCXCONF_BPP_8BPP_PAL 3
67#define MCDE_EXTSRCXCONF_BPP_RGB444 4
68#define MCDE_EXTSRCXCONF_BPP_ARGB4444 5
69#define MCDE_EXTSRCXCONF_BPP_IRGB1555 6
70#define MCDE_EXTSRCXCONF_BPP_RGB565 7
71#define MCDE_EXTSRCXCONF_BPP_RGB888 8
72#define MCDE_EXTSRCXCONF_BPP_XRGB8888 9
73#define MCDE_EXTSRCXCONF_BPP_ARGB8888 10
74#define MCDE_EXTSRCXCONF_BPP_YCBCR422 11
75#define MCDE_EXTSRCXCONF_BGR BIT(12)
76#define MCDE_EXTSRCXCONF_BEBO BIT(13)
77#define MCDE_EXTSRCXCONF_BEPO BIT(14)
78#define MCDE_EXTSRCXCONF_TUNNELING_BUFFER_HEIGHT_SHIFT 16
79#define MCDE_EXTSRCXCONF_TUNNELING_BUFFER_HEIGHT_MASK 0x0FFF0000
80
81/* External sources 0..9 */
82#define MCDE_EXTSRC0CR 0x00000210
83#define MCDE_EXTSRC1CR 0x00000230
84#define MCDE_EXTSRC2CR 0x00000250
85#define MCDE_EXTSRC3CR 0x00000270
86#define MCDE_EXTSRC4CR 0x00000290
87#define MCDE_EXTSRC5CR 0x000002B0
88#define MCDE_EXTSRC6CR 0x000002D0
89#define MCDE_EXTSRC7CR 0x000002F0
90#define MCDE_EXTSRC8CR 0x00000310
91#define MCDE_EXTSRC9CR 0x00000330
92#define MCDE_EXTSRCXCR_SEL_MOD_SHIFT 0
93#define MCDE_EXTSRCXCR_SEL_MOD_MASK 0x00000003
94#define MCDE_EXTSRCXCR_SEL_MOD_EXTERNAL_SEL 0
95#define MCDE_EXTSRCXCR_SEL_MOD_AUTO_TOGGLE 1
96#define MCDE_EXTSRCXCR_SEL_MOD_SOFTWARE_SEL 2
97#define MCDE_EXTSRCXCR_MULTIOVL_CTRL_PRIMARY BIT(2) /* 0 = all */
98#define MCDE_EXTSRCXCR_FS_DIV_DISABLE BIT(3)
99#define MCDE_EXTSRCXCR_FORCE_FS_DIV BIT(4)
100
101/* Only external source 6 has a second address register */
102#define MCDE_EXTSRC6A2 0x000002C8
103
104/* 6 overlays */
105#define MCDE_OVL0CR 0x00000400
106#define MCDE_OVL1CR 0x00000420
107#define MCDE_OVL2CR 0x00000440
108#define MCDE_OVL3CR 0x00000460
109#define MCDE_OVL4CR 0x00000480
110#define MCDE_OVL5CR 0x000004A0
111#define MCDE_OVLXCR_OVLEN BIT(0)
112#define MCDE_OVLXCR_COLCCTRL_DISABLED 0
113#define MCDE_OVLXCR_COLCCTRL_ENABLED_NO_SAT (1 << 1)
114#define MCDE_OVLXCR_COLCCTRL_ENABLED_SAT (2 << 1)
115#define MCDE_OVLXCR_CKEYGEN BIT(3)
116#define MCDE_OVLXCR_ALPHAPMEN BIT(4)
117#define MCDE_OVLXCR_OVLF BIT(5)
118#define MCDE_OVLXCR_OVLR BIT(6)
119#define MCDE_OVLXCR_OVLB BIT(7)
120#define MCDE_OVLXCR_FETCH_ROPC_SHIFT 8
121#define MCDE_OVLXCR_FETCH_ROPC_MASK 0x0000FF00
122#define MCDE_OVLXCR_STBPRIO_SHIFT 16
123#define MCDE_OVLXCR_STBPRIO_MASK 0x000F0000
124#define MCDE_OVLXCR_BURSTSIZE_SHIFT 20
125#define MCDE_OVLXCR_BURSTSIZE_MASK 0x00F00000
126#define MCDE_OVLXCR_BURSTSIZE_1W 0
127#define MCDE_OVLXCR_BURSTSIZE_2W 1
128#define MCDE_OVLXCR_BURSTSIZE_4W 2
129#define MCDE_OVLXCR_BURSTSIZE_8W 3
130#define MCDE_OVLXCR_BURSTSIZE_16W 4
131#define MCDE_OVLXCR_BURSTSIZE_HW_1W 8
132#define MCDE_OVLXCR_BURSTSIZE_HW_2W 9
133#define MCDE_OVLXCR_BURSTSIZE_HW_4W 10
134#define MCDE_OVLXCR_BURSTSIZE_HW_8W 11
135#define MCDE_OVLXCR_BURSTSIZE_HW_16W 12
136#define MCDE_OVLXCR_MAXOUTSTANDING_SHIFT 24
137#define MCDE_OVLXCR_MAXOUTSTANDING_MASK 0x0F000000
138#define MCDE_OVLXCR_MAXOUTSTANDING_1_REQ 0
139#define MCDE_OVLXCR_MAXOUTSTANDING_2_REQ 1
140#define MCDE_OVLXCR_MAXOUTSTANDING_4_REQ 2
141#define MCDE_OVLXCR_MAXOUTSTANDING_8_REQ 3
142#define MCDE_OVLXCR_MAXOUTSTANDING_16_REQ 4
143#define MCDE_OVLXCR_ROTBURSTSIZE_SHIFT 28
144#define MCDE_OVLXCR_ROTBURSTSIZE_MASK 0xF0000000
145#define MCDE_OVLXCR_ROTBURSTSIZE_1W 0
146#define MCDE_OVLXCR_ROTBURSTSIZE_2W 1
147#define MCDE_OVLXCR_ROTBURSTSIZE_4W 2
148#define MCDE_OVLXCR_ROTBURSTSIZE_8W 3
149#define MCDE_OVLXCR_ROTBURSTSIZE_16W 4
150#define MCDE_OVLXCR_ROTBURSTSIZE_HW_1W 8
151#define MCDE_OVLXCR_ROTBURSTSIZE_HW_2W 9
152#define MCDE_OVLXCR_ROTBURSTSIZE_HW_4W 10
153#define MCDE_OVLXCR_ROTBURSTSIZE_HW_8W 11
154#define MCDE_OVLXCR_ROTBURSTSIZE_HW_16W 12
155
156#define MCDE_OVL0CONF 0x00000404
157#define MCDE_OVL1CONF 0x00000424
158#define MCDE_OVL2CONF 0x00000444
159#define MCDE_OVL3CONF 0x00000464
160#define MCDE_OVL4CONF 0x00000484
161#define MCDE_OVL5CONF 0x000004A4
162#define MCDE_OVLXCONF_PPL_SHIFT 0
163#define MCDE_OVLXCONF_PPL_MASK 0x000007FF
164#define MCDE_OVLXCONF_EXTSRC_ID_SHIFT 11
165#define MCDE_OVLXCONF_EXTSRC_ID_MASK 0x00007800
166#define MCDE_OVLXCONF_LPF_SHIFT 16
167#define MCDE_OVLXCONF_LPF_MASK 0x07FF0000
168
169#define MCDE_OVL0CONF2 0x00000408
170#define MCDE_OVL1CONF2 0x00000428
171#define MCDE_OVL2CONF2 0x00000448
172#define MCDE_OVL3CONF2 0x00000468
173#define MCDE_OVL4CONF2 0x00000488
174#define MCDE_OVL5CONF2 0x000004A8
175#define MCDE_OVLXCONF2_BP_PER_PIXEL_ALPHA 0
176#define MCDE_OVLXCONF2_BP_CONSTANT_ALPHA BIT(0)
177#define MCDE_OVLXCONF2_ALPHAVALUE_SHIFT 1
178#define MCDE_OVLXCONF2_ALPHAVALUE_MASK 0x000001FE
179#define MCDE_OVLXCONF2_OPQ BIT(9)
180#define MCDE_OVLXCONF2_PIXOFF_SHIFT 10
181#define MCDE_OVLXCONF2_PIXOFF_MASK 0x0000FC00
182#define MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16
183#define MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000
184
185#define MCDE_OVL0LJINC 0x0000040C
186#define MCDE_OVL1LJINC 0x0000042C
187#define MCDE_OVL2LJINC 0x0000044C
188#define MCDE_OVL3LJINC 0x0000046C
189#define MCDE_OVL4LJINC 0x0000048C
190#define MCDE_OVL5LJINC 0x000004AC
191
192#define MCDE_OVL0CROP 0x00000410
193#define MCDE_OVL1CROP 0x00000430
194#define MCDE_OVL2CROP 0x00000450
195#define MCDE_OVL3CROP 0x00000470
196#define MCDE_OVL4CROP 0x00000490
197#define MCDE_OVL5CROP 0x000004B0
198#define MCDE_OVLXCROP_TMRGN_SHIFT 0
199#define MCDE_OVLXCROP_TMRGN_MASK 0x003FFFFF
200#define MCDE_OVLXCROP_LMRGN_SHIFT 22
201#define MCDE_OVLXCROP_LMRGN_MASK 0xFFC00000
202
203#define MCDE_OVL0COMP 0x00000414
204#define MCDE_OVL1COMP 0x00000434
205#define MCDE_OVL2COMP 0x00000454
206#define MCDE_OVL3COMP 0x00000474
207#define MCDE_OVL4COMP 0x00000494
208#define MCDE_OVL5COMP 0x000004B4
209#define MCDE_OVLXCOMP_XPOS_SHIFT 0
210#define MCDE_OVLXCOMP_XPOS_MASK 0x000007FF
211#define MCDE_OVLXCOMP_CH_ID_SHIFT 11
212#define MCDE_OVLXCOMP_CH_ID_MASK 0x00007800
213#define MCDE_OVLXCOMP_YPOS_SHIFT 16
214#define MCDE_OVLXCOMP_YPOS_MASK 0x07FF0000
215#define MCDE_OVLXCOMP_Z_SHIFT 27
216#define MCDE_OVLXCOMP_Z_MASK 0x78000000
217
218#define MCDE_CRC 0x00000C00
219#define MCDE_CRC_C1EN BIT(2)
220#define MCDE_CRC_C2EN BIT(3)
221#define MCDE_CRC_SYCEN0 BIT(7)
222#define MCDE_CRC_SYCEN1 BIT(8)
223#define MCDE_CRC_SIZE1 BIT(9)
224#define MCDE_CRC_SIZE2 BIT(10)
225#define MCDE_CRC_YUVCONVC1EN BIT(15)
226#define MCDE_CRC_CS1EN BIT(16)
227#define MCDE_CRC_CS2EN BIT(17)
228#define MCDE_CRC_CS1POL BIT(19)
229#define MCDE_CRC_CS2POL BIT(20)
230#define MCDE_CRC_CD1POL BIT(21)
231#define MCDE_CRC_CD2POL BIT(22)
232#define MCDE_CRC_WR1POL BIT(23)
233#define MCDE_CRC_WR2POL BIT(24)
234#define MCDE_CRC_RD1POL BIT(25)
235#define MCDE_CRC_RD2POL BIT(26)
236#define MCDE_CRC_SYNCCTRL_SHIFT 29
237#define MCDE_CRC_SYNCCTRL_MASK 0x60000000
238#define MCDE_CRC_SYNCCTRL_NO_SYNC 0
239#define MCDE_CRC_SYNCCTRL_DBI0 1
240#define MCDE_CRC_SYNCCTRL_DBI1 2
241#define MCDE_CRC_SYNCCTRL_PING_PONG 3
242#define MCDE_CRC_CLAMPC1EN BIT(31)
243
244#define MCDE_VSCRC0 0x00000C5C
245#define MCDE_VSCRC1 0x00000C60
246#define MCDE_VSCRC_VSPMIN_MASK 0x00000FFF
247#define MCDE_VSCRC_VSPMAX_SHIFT 12
248#define MCDE_VSCRC_VSPMAX_MASK 0x00FFF000
249#define MCDE_VSCRC_VSPDIV_SHIFT 24
250#define MCDE_VSCRC_VSPDIV_MASK 0x07000000
251#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_1 0
252#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_2 1
253#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_4 2
254#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_8 3
255#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_16 4
256#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_32 5
257#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_64 6
258#define MCDE_VSCRC_VSPDIV_MCDECLK_DIV_128 7
259#define MCDE_VSCRC_VSPOL BIT(27) /* 0 active high, 1 active low */
260#define MCDE_VSCRC_VSSEL BIT(28) /* 0 VSYNC0, 1 VSYNC1 */
261#define MCDE_VSCRC_VSDBL BIT(29)
262
263/* Channel config 0..3 */
264#define MCDE_CHNL0CONF 0x00000600
265#define MCDE_CHNL1CONF 0x00000620
266#define MCDE_CHNL2CONF 0x00000640
267#define MCDE_CHNL3CONF 0x00000660
268#define MCDE_CHNLXCONF_PPL_SHIFT 0
269#define MCDE_CHNLXCONF_PPL_MASK 0x000007FF
270#define MCDE_CHNLXCONF_LPF_SHIFT 16
271#define MCDE_CHNLXCONF_LPF_MASK 0x07FF0000
272#define MCDE_MAX_WIDTH 2048
273
274/* Channel status 0..3 */
275#define MCDE_CHNL0STAT 0x00000604
276#define MCDE_CHNL1STAT 0x00000624
277#define MCDE_CHNL2STAT 0x00000644
278#define MCDE_CHNL3STAT 0x00000664
279#define MCDE_CHNLXSTAT_CHNLRD BIT(0)
280#define MCDE_CHNLXSTAT_CHNLA BIT(1)
281#define MCDE_CHNLXSTAT_CHNLBLBCKGND_EN BIT(16)
282#define MCDE_CHNLXSTAT_PPLX2_V422 BIT(17)
283#define MCDE_CHNLXSTAT_LPFX2_V422 BIT(18)
284
285/* Sync settings for channel 0..3 */
286#define MCDE_CHNL0SYNCHMOD 0x00000608
287#define MCDE_CHNL1SYNCHMOD 0x00000628
288#define MCDE_CHNL2SYNCHMOD 0x00000648
289#define MCDE_CHNL3SYNCHMOD 0x00000668
290
291#define MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT 0
292#define MCDE_CHNLXSYNCHMOD_SRC_SYNCH_MASK 0x00000003
293#define MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 0
294#define MCDE_CHNLXSYNCHMOD_SRC_SYNCH_NO_SYNCH 1
295#define MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE 2
296#define MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT 2
297#define MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C
298#define MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0
299#define MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 1
300#define MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE1 2
301
302/* Software sync triggers for channel 0..3 */
303#define MCDE_CHNL0SYNCHSW 0x0000060C
304#define MCDE_CHNL1SYNCHSW 0x0000062C
305#define MCDE_CHNL2SYNCHSW 0x0000064C
306#define MCDE_CHNL3SYNCHSW 0x0000066C
307#define MCDE_CHNLXSYNCHSW_SW_TRIG BIT(0)
308
309#define MCDE_CHNL0BCKGNDCOL 0x00000610
310#define MCDE_CHNL1BCKGNDCOL 0x00000630
311#define MCDE_CHNL2BCKGNDCOL 0x00000650
312#define MCDE_CHNL3BCKGNDCOL 0x00000670
313#define MCDE_CHNLXBCKGNDCOL_B_SHIFT 0
314#define MCDE_CHNLXBCKGNDCOL_B_MASK 0x000000FF
315#define MCDE_CHNLXBCKGNDCOL_G_SHIFT 8
316#define MCDE_CHNLXBCKGNDCOL_G_MASK 0x0000FF00
317#define MCDE_CHNLXBCKGNDCOL_R_SHIFT 16
318#define MCDE_CHNLXBCKGNDCOL_R_MASK 0x00FF0000
319
320#define MCDE_CHNL0MUXING 0x00000614
321#define MCDE_CHNL1MUXING 0x00000634
322#define MCDE_CHNL2MUXING 0x00000654
323#define MCDE_CHNL3MUXING 0x00000674
324#define MCDE_CHNLXMUXING_FIFO_ID_FIFO_A 0
325#define MCDE_CHNLXMUXING_FIFO_ID_FIFO_B 1
326#define MCDE_CHNLXMUXING_FIFO_ID_FIFO_C0 2
327#define MCDE_CHNLXMUXING_FIFO_ID_FIFO_C1 3
328
329/* Pixel processing control registers for channel A B, */
330#define MCDE_CRA0 0x00000800
331#define MCDE_CRB0 0x00000A00
332#define MCDE_CRX0_FLOEN BIT(0)
333#define MCDE_CRX0_POWEREN BIT(1)
334#define MCDE_CRX0_BLENDEN BIT(2)
335#define MCDE_CRX0_AFLICKEN BIT(3)
336#define MCDE_CRX0_PALEN BIT(4)
337#define MCDE_CRX0_DITHEN BIT(5)
338#define MCDE_CRX0_GAMEN BIT(6)
339#define MCDE_CRX0_KEYCTRL_SHIFT 7
340#define MCDE_CRX0_KEYCTRL_MASK 0x00000380
341#define MCDE_CRX0_KEYCTRL_OFF 0
342#define MCDE_CRX0_KEYCTRL_ALPHA_RGB 1
343#define MCDE_CRX0_KEYCTRL_RGB 2
344#define MCDE_CRX0_KEYCTRL_FALPHA_FRGB 4
345#define MCDE_CRX0_KEYCTRL_FRGB 5
346#define MCDE_CRX0_BLENDCTRL BIT(10)
347#define MCDE_CRX0_FLICKMODE_SHIFT 11
348#define MCDE_CRX0_FLICKMODE_MASK 0x00001800
349#define MCDE_CRX0_FLICKMODE_FORCE_FILTER_0 0
350#define MCDE_CRX0_FLICKMODE_ADAPTIVE 1
351#define MCDE_CRX0_FLICKMODE_TEST_MODE 2
352#define MCDE_CRX0_FLOCKFORMAT_RGB BIT(13) /* 0 = YCVCR */
353#define MCDE_CRX0_PALMODE_GAMMA BIT(14) /* 0 = palette */
354#define MCDE_CRX0_OLEDEN BIT(15)
355#define MCDE_CRX0_ALPHABLEND_SHIFT 16
356#define MCDE_CRX0_ALPHABLEND_MASK 0x00FF0000
357#define MCDE_CRX0_ROTEN BIT(24)
358
359#define MCDE_CRA1 0x00000804
360#define MCDE_CRB1 0x00000A04
361#define MCDE_CRX1_PCD_SHIFT 0
362#define MCDE_CRX1_PCD_MASK 0x000003FF
363#define MCDE_CRX1_CLKSEL_SHIFT 10
364#define MCDE_CRX1_CLKSEL_MASK 0x00001C00
365#define MCDE_CRX1_CLKSEL_CLKPLL72 0
366#define MCDE_CRX1_CLKSEL_CLKPLL27 2
367#define MCDE_CRX1_CLKSEL_TV1CLK 3
368#define MCDE_CRX1_CLKSEL_TV2CLK 4
369#define MCDE_CRX1_CLKSEL_MCDECLK 5
370#define MCDE_CRX1_CDWIN_SHIFT 13
371#define MCDE_CRX1_CDWIN_MASK 0x0001E000
372#define MCDE_CRX1_CDWIN_8BPP_C1 0
373#define MCDE_CRX1_CDWIN_12BPP_C1 1
374#define MCDE_CRX1_CDWIN_12BPP_C2 2
375#define MCDE_CRX1_CDWIN_16BPP_C1 3
376#define MCDE_CRX1_CDWIN_16BPP_C2 4
377#define MCDE_CRX1_CDWIN_16BPP_C3 5
378#define MCDE_CRX1_CDWIN_18BPP_C1 6
379#define MCDE_CRX1_CDWIN_18BPP_C2 7
380#define MCDE_CRX1_CDWIN_24BPP 8
381#define MCDE_CRX1_OUTBPP_SHIFT 25
382#define MCDE_CRX1_OUTBPP_MASK 0x1E000000
383#define MCDE_CRX1_OUTBPP_MONO1 0
384#define MCDE_CRX1_OUTBPP_MONO2 1
385#define MCDE_CRX1_OUTBPP_MONO4 2
386#define MCDE_CRX1_OUTBPP_MONO8 3
387#define MCDE_CRX1_OUTBPP_8BPP 4
388#define MCDE_CRX1_OUTBPP_12BPP 5
389#define MCDE_CRX1_OUTBPP_15BPP 6
390#define MCDE_CRX1_OUTBPP_16BPP 7
391#define MCDE_CRX1_OUTBPP_18BPP 8
392#define MCDE_CRX1_OUTBPP_24BPP 9
393#define MCDE_CRX1_BCD BIT(29)
394#define MCDE_CRA1_CLKTYPE_TVXCLKSEL1 BIT(30) /* 0 = TVXCLKSEL1 */
395
396#define MCDE_COLKEYA 0x00000808
397#define MCDE_COLKEYB 0x00000A08
398
399#define MCDE_FCOLKEYA 0x0000080C
400#define MCDE_FCOLKEYB 0x00000A0C
401
402#define MCDE_RGBCONV1A 0x00000810
403#define MCDE_RGBCONV1B 0x00000A10
404
405#define MCDE_RGBCONV2A 0x00000814
406#define MCDE_RGBCONV2B 0x00000A14
407
408#define MCDE_RGBCONV3A 0x00000818
409#define MCDE_RGBCONV3B 0x00000A18
410
411#define MCDE_RGBCONV4A 0x0000081C
412#define MCDE_RGBCONV4B 0x00000A1C
413
414#define MCDE_RGBCONV5A 0x00000820
415#define MCDE_RGBCONV5B 0x00000A20
416
417#define MCDE_RGBCONV6A 0x00000824
418#define MCDE_RGBCONV6B 0x00000A24
419
420/* Rotation */
421#define MCDE_ROTACONF 0x0000087C
422#define MCDE_ROTBCONF 0x00000A7C
423
424#define MCDE_SYNCHCONFA 0x00000880
425#define MCDE_SYNCHCONFB 0x00000A80
426
427/* Channel A+B control registers */
428#define MCDE_CTRLA 0x00000884
429#define MCDE_CTRLB 0x00000A84
430#define MCDE_CTRLX_FIFOWTRMRK_SHIFT 0
431#define MCDE_CTRLX_FIFOWTRMRK_MASK 0x000003FF
432#define MCDE_CTRLX_FIFOEMPTY BIT(12)
433#define MCDE_CTRLX_FIFOFULL BIT(13)
434#define MCDE_CTRLX_FORMID_SHIFT 16
435#define MCDE_CTRLX_FORMID_MASK 0x00070000
436#define MCDE_CTRLX_FORMID_DSI0VID 0
437#define MCDE_CTRLX_FORMID_DSI0CMD 1
438#define MCDE_CTRLX_FORMID_DSI1VID 2
439#define MCDE_CTRLX_FORMID_DSI1CMD 3
440#define MCDE_CTRLX_FORMID_DSI2VID 4
441#define MCDE_CTRLX_FORMID_DSI2CMD 5
442#define MCDE_CTRLX_FORMID_DPIA 0
443#define MCDE_CTRLX_FORMID_DPIB 1
444#define MCDE_CTRLX_FORMTYPE_SHIFT 20
445#define MCDE_CTRLX_FORMTYPE_MASK 0x00700000
446#define MCDE_CTRLX_FORMTYPE_DPITV 0
447#define MCDE_CTRLX_FORMTYPE_DBI 1
448#define MCDE_CTRLX_FORMTYPE_DSI 2
449
450#define MCDE_DSIVID0CONF0 0x00000E00
451#define MCDE_DSICMD0CONF0 0x00000E20
452#define MCDE_DSIVID1CONF0 0x00000E40
453#define MCDE_DSICMD1CONF0 0x00000E60
454#define MCDE_DSIVID2CONF0 0x00000E80
455#define MCDE_DSICMD2CONF0 0x00000EA0
456#define MCDE_DSICONF0_BLANKING_SHIFT 0
457#define MCDE_DSICONF0_BLANKING_MASK 0x000000FF
458#define MCDE_DSICONF0_VID_MODE_CMD 0
459#define MCDE_DSICONF0_VID_MODE_VID BIT(12)
460#define MCDE_DSICONF0_CMD8 BIT(13)
461#define MCDE_DSICONF0_BIT_SWAP BIT(16)
462#define MCDE_DSICONF0_BYTE_SWAP BIT(17)
463#define MCDE_DSICONF0_DCSVID_NOTGEN BIT(18)
464#define MCDE_DSICONF0_PACKING_SHIFT 20
465#define MCDE_DSICONF0_PACKING_MASK 0x00700000
466#define MCDE_DSICONF0_PACKING_RGB565 0
467#define MCDE_DSICONF0_PACKING_RGB666 1
468#define MCDE_DSICONF0_PACKING_RGB666_PACKED 2
469#define MCDE_DSICONF0_PACKING_RGB888 3
470#define MCDE_DSICONF0_PACKING_HDTV 4
471
472#define MCDE_DSIVID0FRAME 0x00000E04
473#define MCDE_DSICMD0FRAME 0x00000E24
474#define MCDE_DSIVID1FRAME 0x00000E44
475#define MCDE_DSICMD1FRAME 0x00000E64
476#define MCDE_DSIVID2FRAME 0x00000E84
477#define MCDE_DSICMD2FRAME 0x00000EA4
478
479#define MCDE_DSIVID0PKT 0x00000E08
480#define MCDE_DSICMD0PKT 0x00000E28
481#define MCDE_DSIVID1PKT 0x00000E48
482#define MCDE_DSICMD1PKT 0x00000E68
483#define MCDE_DSIVID2PKT 0x00000E88
484#define MCDE_DSICMD2PKT 0x00000EA8
485
486#define MCDE_DSIVID0SYNC 0x00000E0C
487#define MCDE_DSICMD0SYNC 0x00000E2C
488#define MCDE_DSIVID1SYNC 0x00000E4C
489#define MCDE_DSICMD1SYNC 0x00000E6C
490#define MCDE_DSIVID2SYNC 0x00000E8C
491#define MCDE_DSICMD2SYNC 0x00000EAC
492
493#define MCDE_DSIVID0CMDW 0x00000E10
494#define MCDE_DSICMD0CMDW 0x00000E30
495#define MCDE_DSIVID1CMDW 0x00000E50
496#define MCDE_DSICMD1CMDW 0x00000E70
497#define MCDE_DSIVID2CMDW 0x00000E90
498#define MCDE_DSICMD2CMDW 0x00000EB0
499#define MCDE_DSIVIDXCMDW_CMDW_CONTINUE_SHIFT 0
500#define MCDE_DSIVIDXCMDW_CMDW_CONTINUE_MASK 0x0000FFFF
501#define MCDE_DSIVIDXCMDW_CMDW_START_SHIFT 16
502#define MCDE_DSIVIDXCMDW_CMDW_START_MASK 0xFFFF0000
503
504#define MCDE_DSIVID0DELAY0 0x00000E14
505#define MCDE_DSICMD0DELAY0 0x00000E34
506#define MCDE_DSIVID1DELAY0 0x00000E54
507#define MCDE_DSICMD1DELAY0 0x00000E74
508#define MCDE_DSIVID2DELAY0 0x00000E94
509#define MCDE_DSICMD2DELAY0 0x00000EB4
510
511#define MCDE_DSIVID0DELAY1 0x00000E18
512#define MCDE_DSICMD0DELAY1 0x00000E38
513#define MCDE_DSIVID1DELAY1 0x00000E58
514#define MCDE_DSICMD1DELAY1 0x00000E78
515#define MCDE_DSIVID2DELAY1 0x00000E98
516#define MCDE_DSICMD2DELAY1 0x00000EB8
517
518#endif /* __DRM_MCDE_DISPLAY_REGS */
diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h
new file mode 100644
index 000000000000..dab4db021231
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_drm.h
@@ -0,0 +1,44 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2018 Linus Walleij <linus.walleij@linaro.org>
4 * Parts of this file were based on the MCDE driver by Marcus Lorentzon
5 * (C) ST-Ericsson SA 2013
6 */
7#include <drm/drm_simple_kms_helper.h>
8
9#ifndef _MCDE_DRM_H_
10#define _MCDE_DRM_H_
11
12struct mcde {
13 struct drm_device drm;
14 struct device *dev;
15 struct drm_panel *panel;
16 struct drm_bridge *bridge;
17 struct drm_connector *connector;
18 struct drm_simple_display_pipe pipe;
19 struct mipi_dsi_device *mdsi;
20 s16 stride;
21 bool te_sync;
22 bool oneshot_mode;
23 unsigned int flow_active;
24 spinlock_t flow_lock; /* Locks the channel flow control */
25
26 void __iomem *regs;
27
28 struct clk *mcde_clk;
29 struct clk *lcd_clk;
30 struct clk *hdmi_clk;
31
32 struct regulator *epod;
33 struct regulator *vana;
34};
35
36bool mcde_dsi_irq(struct mipi_dsi_device *mdsi);
37void mcde_dsi_te_request(struct mipi_dsi_device *mdsi);
38extern struct platform_driver mcde_dsi_driver;
39
40void mcde_display_irq(struct mcde *mcde);
41void mcde_display_disable_irqs(struct mcde *mcde);
42int mcde_display_init(struct drm_device *drm);
43
44#endif /* _MCDE_DRM_H_ */
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
new file mode 100644
index 000000000000..baf63fb6850a
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -0,0 +1,572 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 Linus Walleij <linus.walleij@linaro.org>
4 * Parts of this file were based on the MCDE driver by Marcus Lorentzon
5 * (C) ST-Ericsson SA 2013
6 */
7
8/**
9 * DOC: ST-Ericsson MCDE Driver
10 *
11 * The MCDE (short for multi-channel display engine) is a graphics
12 * controller found in the Ux500 chipsets, such as NovaThor U8500.
13 * It was initially conceptualized by ST Microelectronics for the
14 * successor of the Nomadik line, STn8500 but productified in the
15 * ST-Ericsson U8500 where is was used for mass-market deployments
16 * in Android phones from Samsung and Sony Ericsson.
17 *
18 * It can do 1080p30 on SDTV CCIR656, DPI-2, DBI-2 or DSI for
19 * panels with or without frame buffering and can convert most
20 * input formats including most variants of RGB and YUV.
21 *
22 * The hardware has four display pipes, and the layout is a little
23 * bit like this:
24 *
25 * Memory -> Overlay -> Channel -> FIFO -> 5 formatters -> DSI/DPI
26 * External 0..5 0..3 A,B, 3 x DSI bridge
27 * source 0..9 C0,C1 2 x DPI
28 *
29 * FIFOs A and B are for LCD and HDMI while FIFO CO/C1 are for
30 * panels with embedded buffer.
31 * 3 of the formatters are for DSI.
32 * 2 of the formatters are for DPI.
33 *
34 * Behind the formatters are the DSI or DPI ports that route to
35 * the external pins of the chip. As there are 3 DSI ports and one
36 * DPI port, it is possible to configure up to 4 display pipelines
37 * (effectively using channels 0..3) for concurrent use.
38 *
39 * In the current DRM/KMS setup, we use one external source, one overlay,
40 * one FIFO and one formatter which we connect to the simple CMA framebuffer
41 * helpers. We then provide a bridge to the DSI port, and on the DSI port
42 * bridge we connect hang a panel bridge or other bridge. This may be subject
43 * to change as we exploit more of the hardware capabilities.
44 *
45 * TODO:
46 * - Enabled damaged rectangles using drm_plane_enable_fb_damage_clips()
47 * so we can selectively just transmit the damaged area to a
48 * command-only display.
49 * - Enable mixing of more planes, possibly at the cost of moving away
50 * from using the simple framebuffer pipeline.
51 * - Enable output to bridges such as the AV8100 HDMI encoder from
52 * the DSI bridge.
53 */
54
55#include <linux/clk.h>
56#include <linux/component.h>
57#include <linux/dma-buf.h>
58#include <linux/irq.h>
59#include <linux/io.h>
60#include <linux/module.h>
61#include <linux/of_platform.h>
62#include <linux/platform_device.h>
63#include <linux/regulator/consumer.h>
64#include <linux/slab.h>
65
66#include <drm/drm_atomic_helper.h>
67#include <drm/drm_bridge.h>
68#include <drm/drm_drv.h>
69#include <drm/drm_fb_cma_helper.h>
70#include <drm/drm_fb_helper.h>
71#include <drm/drm_gem.h>
72#include <drm/drm_gem_cma_helper.h>
73#include <drm/drm_gem_framebuffer_helper.h>
74#include <drm/drm_of.h>
75#include <drm/drm_probe_helper.h>
76#include <drm/drm_panel.h>
77#include <drm/drm_vblank.h>
78
79#include "mcde_drm.h"
80
81#define DRIVER_DESC "DRM module for MCDE"
82
83#define MCDE_CR 0x00000000
84#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_SHIFT 0
85#define MCDE_CR_IFIFOEMPTYLINECOUNT_V422_MASK 0x0000003F
86#define MCDE_CR_IFIFOCTRLEN BIT(15)
87#define MCDE_CR_UFRECOVERY_MODE_V422 BIT(16)
88#define MCDE_CR_WRAP_MODE_V422_SHIFT BIT(17)
89#define MCDE_CR_AUTOCLKG_EN BIT(30)
90#define MCDE_CR_MCDEEN BIT(31)
91
92#define MCDE_CONF0 0x00000004
93#define MCDE_CONF0_SYNCMUX0 BIT(0)
94#define MCDE_CONF0_SYNCMUX1 BIT(1)
95#define MCDE_CONF0_SYNCMUX2 BIT(2)
96#define MCDE_CONF0_SYNCMUX3 BIT(3)
97#define MCDE_CONF0_SYNCMUX4 BIT(4)
98#define MCDE_CONF0_SYNCMUX5 BIT(5)
99#define MCDE_CONF0_SYNCMUX6 BIT(6)
100#define MCDE_CONF0_SYNCMUX7 BIT(7)
101#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12
102#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000
103#define MCDE_CONF0_OUTMUX0_SHIFT 16
104#define MCDE_CONF0_OUTMUX0_MASK 0x00070000
105#define MCDE_CONF0_OUTMUX1_SHIFT 19
106#define MCDE_CONF0_OUTMUX1_MASK 0x00380000
107#define MCDE_CONF0_OUTMUX2_SHIFT 22
108#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000
109#define MCDE_CONF0_OUTMUX3_SHIFT 25
110#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000
111#define MCDE_CONF0_OUTMUX4_SHIFT 28
112#define MCDE_CONF0_OUTMUX4_MASK 0x70000000
113
114#define MCDE_SSP 0x00000008
115#define MCDE_AIS 0x00000100
116#define MCDE_IMSCERR 0x00000110
117#define MCDE_RISERR 0x00000120
118#define MCDE_MISERR 0x00000130
119#define MCDE_SISERR 0x00000140
120
121#define MCDE_PID 0x000001FC
122#define MCDE_PID_METALFIX_VERSION_SHIFT 0
123#define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF
124#define MCDE_PID_DEVELOPMENT_VERSION_SHIFT 8
125#define MCDE_PID_DEVELOPMENT_VERSION_MASK 0x0000FF00
126#define MCDE_PID_MINOR_VERSION_SHIFT 16
127#define MCDE_PID_MINOR_VERSION_MASK 0x00FF0000
128#define MCDE_PID_MAJOR_VERSION_SHIFT 24
129#define MCDE_PID_MAJOR_VERSION_MASK 0xFF000000
130
131static const struct drm_mode_config_funcs mcde_mode_config_funcs = {
132 .fb_create = drm_gem_fb_create_with_dirty,
133 .atomic_check = drm_atomic_helper_check,
134 .atomic_commit = drm_atomic_helper_commit,
135};
136
137static const struct drm_mode_config_helper_funcs mcde_mode_config_helpers = {
138 /*
139 * Using this function is necessary to commit atomic updates
140 * that need the CRTC to be enabled before a commit, as is
141 * the case with e.g. DSI displays.
142 */
143 .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
144};
145
146static irqreturn_t mcde_irq(int irq, void *data)
147{
148 struct mcde *mcde = data;
149 u32 val;
150
151 val = readl(mcde->regs + MCDE_MISERR);
152
153 mcde_display_irq(mcde);
154
155 if (val)
156 dev_info(mcde->dev, "some error IRQ\n");
157 writel(val, mcde->regs + MCDE_RISERR);
158
159 return IRQ_HANDLED;
160}
161
162static int mcde_modeset_init(struct drm_device *drm)
163{
164 struct drm_mode_config *mode_config;
165 struct mcde *mcde = drm->dev_private;
166 int ret;
167
168 if (!mcde->bridge) {
169 dev_err(drm->dev, "no display output bridge yet\n");
170 return -EPROBE_DEFER;
171 }
172
173 mode_config = &drm->mode_config;
174 mode_config->funcs = &mcde_mode_config_funcs;
175 mode_config->helper_private = &mcde_mode_config_helpers;
176 /* This hardware can do 1080p */
177 mode_config->min_width = 1;
178 mode_config->max_width = 1920;
179 mode_config->min_height = 1;
180 mode_config->max_height = 1080;
181
182 /*
183 * Currently we only support vblank handling on the DSI bridge, using
184 * TE synchronization. If TE sync is not set up, it is still possible
185 * to push out a single update on demand, but this is hard for DRM to
186 * exploit.
187 */
188 if (mcde->te_sync) {
189 ret = drm_vblank_init(drm, 1);
190 if (ret) {
191 dev_err(drm->dev, "failed to init vblank\n");
192 goto out_config;
193 }
194 }
195
196 ret = mcde_display_init(drm);
197 if (ret) {
198 dev_err(drm->dev, "failed to init display\n");
199 goto out_config;
200 }
201
202 /*
203 * Attach the DSI bridge
204 *
205 * TODO: when adding support for the DPI bridge or several DSI bridges,
206 * we selectively connect the bridge(s) here instead of this simple
207 * attachment.
208 */
209 ret = drm_simple_display_pipe_attach_bridge(&mcde->pipe,
210 mcde->bridge);
211 if (ret) {
212 dev_err(drm->dev, "failed to attach display output bridge\n");
213 goto out_config;
214 }
215
216 drm_mode_config_reset(drm);
217 drm_kms_helper_poll_init(drm);
218 drm_fbdev_generic_setup(drm, 32);
219
220 return 0;
221
222out_config:
223 drm_mode_config_cleanup(drm);
224 return ret;
225}
226
227static void mcde_release(struct drm_device *drm)
228{
229 struct mcde *mcde = drm->dev_private;
230
231 drm_mode_config_cleanup(drm);
232 drm_dev_fini(drm);
233 kfree(mcde);
234}
235
236DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
237
238static struct drm_driver mcde_drm_driver = {
239 .driver_features =
240 DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
241 .release = mcde_release,
242 .lastclose = drm_fb_helper_lastclose,
243 .ioctls = NULL,
244 .fops = &drm_fops,
245 .name = "mcde",
246 .desc = DRIVER_DESC,
247 .date = "20180529",
248 .major = 1,
249 .minor = 0,
250 .patchlevel = 0,
251 .dumb_create = drm_gem_cma_dumb_create,
252 .gem_free_object_unlocked = drm_gem_cma_free_object,
253 .gem_vm_ops = &drm_gem_cma_vm_ops,
254
255 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
256 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
257 .gem_prime_import = drm_gem_prime_import,
258 .gem_prime_export = drm_gem_prime_export,
259 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
260 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
261 .gem_prime_vmap = drm_gem_cma_prime_vmap,
262 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
263 .gem_prime_mmap = drm_gem_cma_prime_mmap,
264};
265
266static int mcde_drm_bind(struct device *dev)
267{
268 struct drm_device *drm = dev_get_drvdata(dev);
269 int ret;
270
271 drm_mode_config_init(drm);
272
273 ret = component_bind_all(drm->dev, drm);
274 if (ret) {
275 dev_err(dev, "can't bind component devices\n");
276 return ret;
277 }
278
279 ret = mcde_modeset_init(drm);
280 if (ret)
281 goto unbind;
282
283 ret = drm_dev_register(drm, 0);
284 if (ret < 0)
285 goto unbind;
286
287 return 0;
288
289unbind:
290 component_unbind_all(drm->dev, drm);
291 return ret;
292}
293
294static void mcde_drm_unbind(struct device *dev)
295{
296 struct drm_device *drm = dev_get_drvdata(dev);
297
298 drm_dev_unregister(drm);
299 drm_atomic_helper_shutdown(drm);
300 component_unbind_all(drm->dev, drm);
301}
302
303static const struct component_master_ops mcde_drm_comp_ops = {
304 .bind = mcde_drm_bind,
305 .unbind = mcde_drm_unbind,
306};
307
308static struct platform_driver *const mcde_component_drivers[] = {
309 &mcde_dsi_driver,
310};
311
312static int mcde_compare_dev(struct device *dev, void *data)
313{
314 return dev == data;
315}
316
317static int mcde_probe(struct platform_device *pdev)
318{
319 struct device *dev = &pdev->dev;
320 struct drm_device *drm;
321 struct mcde *mcde;
322 struct component_match *match;
323 struct resource *res;
324 u32 pid;
325 u32 val;
326 int irq;
327 int ret;
328 int i;
329
330 mcde = kzalloc(sizeof(*mcde), GFP_KERNEL);
331 if (!mcde)
332 return -ENOMEM;
333 mcde->dev = dev;
334
335 ret = drm_dev_init(&mcde->drm, &mcde_drm_driver, dev);
336 if (ret) {
337 kfree(mcde);
338 return ret;
339 }
340 drm = &mcde->drm;
341 drm->dev_private = mcde;
342 platform_set_drvdata(pdev, drm);
343
344 /* Enable use of the TE signal and interrupt */
345 mcde->te_sync = true;
346 /* Enable continuous updates: this is what Linux' framebuffer expects */
347 mcde->oneshot_mode = false;
348 drm->dev_private = mcde;
349
350 /* First obtain and turn on the main power */
351 mcde->epod = devm_regulator_get(dev, "epod");
352 if (IS_ERR(mcde->epod)) {
353 ret = PTR_ERR(mcde->epod);
354 dev_err(dev, "can't get EPOD regulator\n");
355 goto dev_unref;
356 }
357 ret = regulator_enable(mcde->epod);
358 if (ret) {
359 dev_err(dev, "can't enable EPOD regulator\n");
360 goto dev_unref;
361 }
362 mcde->vana = devm_regulator_get(dev, "vana");
363 if (IS_ERR(mcde->vana)) {
364 ret = PTR_ERR(mcde->vana);
365 dev_err(dev, "can't get VANA regulator\n");
366 goto regulator_epod_off;
367 }
368 ret = regulator_enable(mcde->vana);
369 if (ret) {
370 dev_err(dev, "can't enable VANA regulator\n");
371 goto regulator_epod_off;
372 }
373 /*
374 * The vendor code uses ESRAM (onchip RAM) and need to activate
375 * the v-esram34 regulator, but we don't use that yet
376 */
377
378 /* Clock the silicon so we can access the registers */
379 mcde->mcde_clk = devm_clk_get(dev, "mcde");
380 if (IS_ERR(mcde->mcde_clk)) {
381 dev_err(dev, "unable to get MCDE main clock\n");
382 ret = PTR_ERR(mcde->mcde_clk);
383 goto regulator_off;
384 }
385 ret = clk_prepare_enable(mcde->mcde_clk);
386 if (ret) {
387 dev_err(dev, "failed to enable MCDE main clock\n");
388 goto regulator_off;
389 }
390 dev_info(dev, "MCDE clk rate %lu Hz\n", clk_get_rate(mcde->mcde_clk));
391
392 mcde->lcd_clk = devm_clk_get(dev, "lcd");
393 if (IS_ERR(mcde->lcd_clk)) {
394 dev_err(dev, "unable to get LCD clock\n");
395 ret = PTR_ERR(mcde->lcd_clk);
396 goto clk_disable;
397 }
398 mcde->hdmi_clk = devm_clk_get(dev, "hdmi");
399 if (IS_ERR(mcde->hdmi_clk)) {
400 dev_err(dev, "unable to get HDMI clock\n");
401 ret = PTR_ERR(mcde->hdmi_clk);
402 goto clk_disable;
403 }
404
405 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
406 mcde->regs = devm_ioremap_resource(dev, res);
407 if (IS_ERR(mcde->regs)) {
408 dev_err(dev, "no MCDE regs\n");
409 ret = -EINVAL;
410 goto clk_disable;
411 }
412
413 irq = platform_get_irq(pdev, 0);
414 if (!irq) {
415 ret = -EINVAL;
416 goto clk_disable;
417 }
418
419 ret = devm_request_irq(dev, irq, mcde_irq, 0, "mcde", mcde);
420 if (ret) {
421 dev_err(dev, "failed to request irq %d\n", ret);
422 goto clk_disable;
423 }
424
425 /*
426 * Check hardware revision, we only support U8500v2 version
427 * as this was the only version used for mass market deployment,
428 * but surely you can add more versions if you have them and
429 * need them.
430 */
431 pid = readl(mcde->regs + MCDE_PID);
432 dev_info(dev, "found MCDE HW revision %d.%d (dev %d, metal fix %d)\n",
433 (pid & MCDE_PID_MAJOR_VERSION_MASK)
434 >> MCDE_PID_MAJOR_VERSION_SHIFT,
435 (pid & MCDE_PID_MINOR_VERSION_MASK)
436 >> MCDE_PID_MINOR_VERSION_SHIFT,
437 (pid & MCDE_PID_DEVELOPMENT_VERSION_MASK)
438 >> MCDE_PID_DEVELOPMENT_VERSION_SHIFT,
439 (pid & MCDE_PID_METALFIX_VERSION_MASK)
440 >> MCDE_PID_METALFIX_VERSION_SHIFT);
441 if (pid != 0x03000800) {
442 dev_err(dev, "unsupported hardware revision\n");
443 ret = -ENODEV;
444 goto clk_disable;
445 }
446
447 /* Set up the main control, watermark level at 7 */
448 val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT;
449 /* 24 bits DPI: connect LSB Ch B to D[0:7] */
450 val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT;
451 /* TV out: connect LSB Ch B to D[8:15] */
452 val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT;
453 /* Don't care about this muxing */
454 val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT;
455 /* 24 bits DPI: connect MID Ch B to D[24:31] */
456 val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT;
457 /* 5: 24 bits DPI: connect MSB Ch B to D[32:39] */
458 val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT;
459 /* Syncmux bits zero: DPI channel A and B on output pins A and B resp */
460 writel(val, mcde->regs + MCDE_CONF0);
461
462 /* Enable automatic clock gating */
463 val = readl(mcde->regs + MCDE_CR);
464 val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN;
465 writel(val, mcde->regs + MCDE_CR);
466
467 /* Clear any pending interrupts */
468 mcde_display_disable_irqs(mcde);
469 writel(0, mcde->regs + MCDE_IMSCERR);
470 writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR);
471
472 /* Spawn child devices for the DSI ports */
473 devm_of_platform_populate(dev);
474
475 /* Create something that will match the subdrivers when we bind */
476 for (i = 0; i < ARRAY_SIZE(mcde_component_drivers); i++) {
477 struct device_driver *drv = &mcde_component_drivers[i]->driver;
478 struct device *p = NULL, *d;
479
480 while ((d = bus_find_device(&platform_bus_type, p, drv,
481 (void *)platform_bus_type.match))) {
482 put_device(p);
483 component_match_add(dev, &match, mcde_compare_dev, d);
484 p = d;
485 }
486 put_device(p);
487 }
488 if (IS_ERR(match)) {
489 dev_err(dev, "could not create component match\n");
490 ret = PTR_ERR(match);
491 goto clk_disable;
492 }
493 ret = component_master_add_with_match(&pdev->dev, &mcde_drm_comp_ops,
494 match);
495 if (ret) {
496 dev_err(dev, "failed to add component master\n");
497 goto clk_disable;
498 }
499 return 0;
500
501clk_disable:
502 clk_disable_unprepare(mcde->mcde_clk);
503regulator_off:
504 regulator_disable(mcde->vana);
505regulator_epod_off:
506 regulator_disable(mcde->epod);
507dev_unref:
508 drm_dev_put(drm);
509 return ret;
510
511}
512
513static int mcde_remove(struct platform_device *pdev)
514{
515 struct drm_device *drm = platform_get_drvdata(pdev);
516 struct mcde *mcde = drm->dev_private;
517
518 component_master_del(&pdev->dev, &mcde_drm_comp_ops);
519 clk_disable_unprepare(mcde->mcde_clk);
520 regulator_disable(mcde->vana);
521 regulator_disable(mcde->epod);
522 drm_dev_put(drm);
523
524 return 0;
525}
526
527static const struct of_device_id mcde_of_match[] = {
528 {
529 .compatible = "ste,mcde",
530 },
531 {},
532};
533
534static struct platform_driver mcde_driver = {
535 .driver = {
536 .name = "mcde",
537 .of_match_table = of_match_ptr(mcde_of_match),
538 },
539 .probe = mcde_probe,
540 .remove = mcde_remove,
541};
542
543static struct platform_driver *const component_drivers[] = {
544 &mcde_dsi_driver,
545};
546
547static int __init mcde_drm_register(void)
548{
549 int ret;
550
551 ret = platform_register_drivers(component_drivers,
552 ARRAY_SIZE(component_drivers));
553 if (ret)
554 return ret;
555
556 return platform_driver_register(&mcde_driver);
557}
558
559static void __exit mcde_drm_unregister(void)
560{
561 platform_unregister_drivers(component_drivers,
562 ARRAY_SIZE(component_drivers));
563 platform_driver_unregister(&mcde_driver);
564}
565
566module_init(mcde_drm_register);
567module_exit(mcde_drm_unregister);
568
569MODULE_ALIAS("platform:mcde-drm");
570MODULE_DESCRIPTION(DRIVER_DESC);
571MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
572MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
new file mode 100644
index 000000000000..456b43482448
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -0,0 +1,1044 @@
1// SPDX-License-Identifier: GPL-2.0+
2#include <linux/clk.h>
3#include <linux/component.h>
4#include <linux/delay.h>
5#include <linux/io.h>
6#include <linux/mfd/syscon.h>
7#include <linux/module.h>
8#include <linux/of.h>
9#include <linux/platform_device.h>
10#include <linux/regmap.h>
11#include <linux/regulator/consumer.h>
12#include <video/mipi_display.h>
13
14#include <drm/drm_atomic_helper.h>
15#include <drm/drm_bridge.h>
16#include <drm/drm_device.h>
17#include <drm/drm_drv.h>
18#include <drm/drm_encoder.h>
19#include <drm/drm_mipi_dsi.h>
20#include <drm/drm_modeset_helper_vtables.h>
21#include <drm/drm_of.h>
22#include <drm/drm_panel.h>
23#include <drm/drm_print.h>
24#include <drm/drm_probe_helper.h>
25
26#include "mcde_drm.h"
27#include "mcde_dsi_regs.h"
28
29#define DSI_DEFAULT_LP_FREQ_HZ 19200000
30#define DSI_DEFAULT_HS_FREQ_HZ 420160000
31
32/* PRCMU DSI reset registers */
33#define PRCM_DSI_SW_RESET 0x324
34#define PRCM_DSI_SW_RESET_DSI0_SW_RESETN BIT(0)
35#define PRCM_DSI_SW_RESET_DSI1_SW_RESETN BIT(1)
36#define PRCM_DSI_SW_RESET_DSI2_SW_RESETN BIT(2)
37
38struct mcde_dsi {
39 struct device *dev;
40 struct mcde *mcde;
41 struct drm_bridge bridge;
42 struct drm_connector connector;
43 struct drm_panel *panel;
44 struct drm_bridge *bridge_out;
45 struct mipi_dsi_host dsi_host;
46 struct mipi_dsi_device *mdsi;
47 struct clk *hs_clk;
48 struct clk *lp_clk;
49 unsigned long hs_freq;
50 unsigned long lp_freq;
51 bool unused;
52
53 void __iomem *regs;
54 struct regmap *prcmu;
55};
56
57static inline struct mcde_dsi *bridge_to_mcde_dsi(struct drm_bridge *bridge)
58{
59 return container_of(bridge, struct mcde_dsi, bridge);
60}
61
62static inline struct mcde_dsi *host_to_mcde_dsi(struct mipi_dsi_host *h)
63{
64 return container_of(h, struct mcde_dsi, dsi_host);
65}
66
67static inline struct mcde_dsi *connector_to_mcde_dsi(struct drm_connector *c)
68{
69 return container_of(c, struct mcde_dsi, connector);
70}
71
72bool mcde_dsi_irq(struct mipi_dsi_device *mdsi)
73{
74 struct mcde_dsi *d;
75 u32 val;
76 bool te_received = false;
77
78 d = host_to_mcde_dsi(mdsi->host);
79
80 dev_dbg(d->dev, "%s called\n", __func__);
81
82 val = readl(d->regs + DSI_DIRECT_CMD_STS_FLAG);
83 if (val)
84 dev_dbg(d->dev, "DSI_DIRECT_CMD_STS_FLAG = %08x\n", val);
85 if (val & DSI_DIRECT_CMD_STS_WRITE_COMPLETED)
86 dev_dbg(d->dev, "direct command write completed\n");
87 if (val & DSI_DIRECT_CMD_STS_TE_RECEIVED) {
88 te_received = true;
89 dev_dbg(d->dev, "direct command TE received\n");
90 }
91 if (val & DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED)
92 dev_err(d->dev, "direct command ACK ERR received\n");
93 if (val & DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR)
94 dev_err(d->dev, "direct command read ERR received\n");
95 /* Mask off the ACK value and clear status */
96 writel(val, d->regs + DSI_DIRECT_CMD_STS_CLR);
97
98 val = readl(d->regs + DSI_CMD_MODE_STS_FLAG);
99 if (val)
100 dev_dbg(d->dev, "DSI_CMD_MODE_STS_FLAG = %08x\n", val);
101 if (val & DSI_CMD_MODE_STS_ERR_NO_TE)
102 /* This happens all the time (safe to ignore) */
103 dev_dbg(d->dev, "CMD mode no TE\n");
104 if (val & DSI_CMD_MODE_STS_ERR_TE_MISS)
105 /* This happens all the time (safe to ignore) */
106 dev_dbg(d->dev, "CMD mode TE miss\n");
107 if (val & DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN)
108 dev_err(d->dev, "CMD mode SD1 underrun\n");
109 if (val & DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN)
110 dev_err(d->dev, "CMD mode SD2 underrun\n");
111 if (val & DSI_CMD_MODE_STS_ERR_UNWANTED_RD)
112 dev_err(d->dev, "CMD mode unwanted RD\n");
113 writel(val, d->regs + DSI_CMD_MODE_STS_CLR);
114
115 val = readl(d->regs + DSI_DIRECT_CMD_RD_STS_FLAG);
116 if (val)
117 dev_dbg(d->dev, "DSI_DIRECT_CMD_RD_STS_FLAG = %08x\n", val);
118 writel(val, d->regs + DSI_DIRECT_CMD_RD_STS_CLR);
119
120 val = readl(d->regs + DSI_TG_STS_FLAG);
121 if (val)
122 dev_dbg(d->dev, "DSI_TG_STS_FLAG = %08x\n", val);
123 writel(val, d->regs + DSI_TG_STS_CLR);
124
125 val = readl(d->regs + DSI_VID_MODE_STS_FLAG);
126 if (val)
127 dev_err(d->dev, "some video mode error status\n");
128 writel(val, d->regs + DSI_VID_MODE_STS_CLR);
129
130 return te_received;
131}
132
133static int mcde_dsi_host_attach(struct mipi_dsi_host *host,
134 struct mipi_dsi_device *mdsi)
135{
136 struct mcde_dsi *d = host_to_mcde_dsi(host);
137
138 if (mdsi->lanes < 1 || mdsi->lanes > 2) {
139 DRM_ERROR("dsi device params invalid, 1 or 2 lanes supported\n");
140 return -EINVAL;
141 }
142
143 dev_info(d->dev, "attached DSI device with %d lanes\n", mdsi->lanes);
144 /* MIPI_DSI_FMT_RGB88 etc */
145 dev_info(d->dev, "format %08x, %dbpp\n", mdsi->format,
146 mipi_dsi_pixel_format_to_bpp(mdsi->format));
147 dev_info(d->dev, "mode flags: %08lx\n", mdsi->mode_flags);
148
149 d->mdsi = mdsi;
150 if (d->mcde)
151 d->mcde->mdsi = mdsi;
152
153 return 0;
154}
155
156static int mcde_dsi_host_detach(struct mipi_dsi_host *host,
157 struct mipi_dsi_device *mdsi)
158{
159 struct mcde_dsi *d = host_to_mcde_dsi(host);
160
161 d->mdsi = NULL;
162 if (d->mcde)
163 d->mcde->mdsi = NULL;
164
165 return 0;
166}
167
168#define MCDE_DSI_HOST_IS_READ(type) \
169 ((type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || \
170 (type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || \
171 (type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM) || \
172 (type == MIPI_DSI_DCS_READ))
173
174static ssize_t mcde_dsi_host_transfer(struct mipi_dsi_host *host,
175 const struct mipi_dsi_msg *msg)
176{
177 struct mcde_dsi *d = host_to_mcde_dsi(host);
178 const u32 loop_delay_us = 10; /* us */
179 const u8 *tx = msg->tx_buf;
180 u32 loop_counter;
181 size_t txlen;
182 u32 val;
183 int ret;
184 int i;
185
186 txlen = msg->tx_len;
187 if (txlen > 12) {
188 dev_err(d->dev,
189 "dunno how to write more than 12 bytes yet\n");
190 return -EIO;
191 }
192
193 dev_dbg(d->dev,
194 "message to channel %d, %u bytes",
195 msg->channel,
196 txlen);
197
198 /* Command "nature" */
199 if (MCDE_DSI_HOST_IS_READ(msg->type))
200 /* MCTL_MAIN_DATA_CTL already set up */
201 val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ;
202 else
203 val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE;
204 /*
205 * More than 2 bytes will not fit in a single packet, so it's
206 * time to set the "long not short" bit. One byte is used by
207 * the MIPI DCS command leaving just one byte for the payload
208 * in a short package.
209 */
210 if (mipi_dsi_packet_format_is_long(msg->type))
211 val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT;
212 val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT;
213 /* Add one to the length for the MIPI DCS command */
214 val |= txlen
215 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT;
216 val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN;
217 val |= msg->type << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT;
218 writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS);
219
220 /* MIPI DCS command is part of the data */
221 if (txlen > 0) {
222 val = 0;
223 for (i = 0; i < 4 && i < txlen; i++)
224 val |= tx[i] << (i & 3) * 8;
225 }
226 writel(val, d->regs + DSI_DIRECT_CMD_WRDAT0);
227 if (txlen > 4) {
228 val = 0;
229 for (i = 0; i < 4 && (i + 4) < txlen; i++)
230 val |= tx[i + 4] << (i & 3) * 8;
231 writel(val, d->regs + DSI_DIRECT_CMD_WRDAT1);
232 }
233 if (txlen > 8) {
234 val = 0;
235 for (i = 0; i < 4 && (i + 8) < txlen; i++)
236 val |= tx[i + 8] << (i & 3) * 8;
237 writel(val, d->regs + DSI_DIRECT_CMD_WRDAT2);
238 }
239 if (txlen > 12) {
240 val = 0;
241 for (i = 0; i < 4 && (i + 12) < txlen; i++)
242 val |= tx[i + 12] << (i & 3) * 8;
243 writel(val, d->regs + DSI_DIRECT_CMD_WRDAT3);
244 }
245
246 writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR);
247 writel(~0, d->regs + DSI_CMD_MODE_STS_CLR);
248 /* Send command */
249 writel(1, d->regs + DSI_DIRECT_CMD_SEND);
250
251 loop_counter = 1000 * 1000 / loop_delay_us;
252 while (!(readl(d->regs + DSI_DIRECT_CMD_STS) &
253 DSI_DIRECT_CMD_STS_WRITE_COMPLETED)
254 && --loop_counter)
255 usleep_range(loop_delay_us, (loop_delay_us * 3) / 2);
256
257 if (!loop_counter) {
258 dev_err(d->dev, "DSI write timeout!\n");
259 return -ETIME;
260 }
261
262 val = readl(d->regs + DSI_DIRECT_CMD_STS);
263 if (val & DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED) {
264 val >>= DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT;
265 dev_err(d->dev, "error during transmission: %04x\n",
266 val);
267 return -EIO;
268 }
269
270 if (!MCDE_DSI_HOST_IS_READ(msg->type)) {
271 /* Return number of bytes written */
272 if (mipi_dsi_packet_format_is_long(msg->type))
273 ret = 4 + txlen;
274 else
275 ret = 4;
276 } else {
277 /* OK this is a read command, get the response */
278 u32 rdsz;
279 u32 rddat;
280 u8 *rx = msg->rx_buf;
281
282 rdsz = readl(d->regs + DSI_DIRECT_CMD_RD_PROPERTY);
283 rdsz &= DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK;
284 rddat = readl(d->regs + DSI_DIRECT_CMD_RDDAT);
285 for (i = 0; i < 4 && i < rdsz; i++)
286 rx[i] = (rddat >> (i * 8)) & 0xff;
287 ret = rdsz;
288 }
289
290 writel(~0, d->regs + DSI_DIRECT_CMD_STS_CLR);
291 writel(~0, d->regs + DSI_CMD_MODE_STS_CLR);
292
293 return ret;
294}
295
296static const struct mipi_dsi_host_ops mcde_dsi_host_ops = {
297 .attach = mcde_dsi_host_attach,
298 .detach = mcde_dsi_host_detach,
299 .transfer = mcde_dsi_host_transfer,
300};
301
302/* This sends a direct (short) command to request TE */
303void mcde_dsi_te_request(struct mipi_dsi_device *mdsi)
304{
305 struct mcde_dsi *d;
306 u32 val;
307
308 d = host_to_mcde_dsi(mdsi->host);
309
310 /* Command "nature" TE request */
311 val = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TE_REQ;
312 val |= 0 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT;
313 val |= 2 << DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT;
314 val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN;
315 val |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 <<
316 DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT;
317 writel(val, d->regs + DSI_DIRECT_CMD_MAIN_SETTINGS);
318
319 /* Clear TE reveived and error status bits and enables them */
320 writel(DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR |
321 DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR,
322 d->regs + DSI_DIRECT_CMD_STS_CLR);
323 val = readl(d->regs + DSI_DIRECT_CMD_STS_CTL);
324 val |= DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN;
325 val |= DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN;
326 writel(val, d->regs + DSI_DIRECT_CMD_STS_CTL);
327
328 /* Clear and enable no TE or TE missing status */
329 writel(DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR |
330 DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR,
331 d->regs + DSI_CMD_MODE_STS_CLR);
332 val = readl(d->regs + DSI_CMD_MODE_STS_CTL);
333 val |= DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN;
334 val |= DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN;
335 writel(val, d->regs + DSI_CMD_MODE_STS_CTL);
336
337 /* Send this TE request command */
338 writel(1, d->regs + DSI_DIRECT_CMD_SEND);
339}
340
341static void mcde_dsi_setup_video_mode(struct mcde_dsi *d,
342 const struct drm_display_mode *mode)
343{
344 u8 bpp = mipi_dsi_pixel_format_to_bpp(d->mdsi->format);
345 u64 bpl;
346 u32 hfp;
347 u32 hbp;
348 u32 hsa;
349 u32 blkline_pck, line_duration;
350 u32 blkeol_pck, blkeol_duration;
351 u32 val;
352
353 val = 0;
354 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
355 val |= DSI_VID_MAIN_CTL_BURST_MODE;
356 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
357 val |= DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE;
358 val |= DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL;
359 }
360 /* RGB header and pixel mode */
361 switch (d->mdsi->format) {
362 case MIPI_DSI_FMT_RGB565:
363 val |= MIPI_DSI_PACKED_PIXEL_STREAM_16 <<
364 DSI_VID_MAIN_CTL_HEADER_SHIFT;
365 val |= DSI_VID_MAIN_CTL_VID_PIXEL_MODE_16BITS;
366 break;
367 case MIPI_DSI_FMT_RGB666_PACKED:
368 val |= MIPI_DSI_PACKED_PIXEL_STREAM_18 <<
369 DSI_VID_MAIN_CTL_HEADER_SHIFT;
370 val |= DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS;
371 break;
372 case MIPI_DSI_FMT_RGB666:
373 val |= MIPI_DSI_PIXEL_STREAM_3BYTE_18
374 << DSI_VID_MAIN_CTL_HEADER_SHIFT;
375 val |= DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS_LOOSE;
376 break;
377 case MIPI_DSI_FMT_RGB888:
378 val |= MIPI_DSI_PACKED_PIXEL_STREAM_24 <<
379 DSI_VID_MAIN_CTL_HEADER_SHIFT;
380 val |= DSI_VID_MAIN_CTL_VID_PIXEL_MODE_24BITS;
381 break;
382 default:
383 dev_err(d->dev, "unknown pixel mode\n");
384 return;
385 }
386
387 /* TODO: TVG could be enabled here */
388
389 /* Send blanking packet */
390 val |= DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0;
391 /* Send EOL packet */
392 val |= DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0;
393 /* Recovery mode 1 */
394 val |= 1 << DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT;
395 /* All other fields zero */
396 writel(val, d->regs + DSI_VID_MAIN_CTL);
397
398 /* Vertical frame parameters are pretty straight-forward */
399 val = mode->vdisplay << DSI_VID_VSIZE_VSA_LENGTH_SHIFT;
400 /* vertical front porch */
401 val |= (mode->vsync_start - mode->vdisplay)
402 << DSI_VID_VSIZE_VFP_LENGTH_SHIFT;
403 /* vertical sync active */
404 val |= (mode->vsync_end - mode->vsync_start)
405 << DSI_VID_VSIZE_VACT_LENGTH_SHIFT;
406 /* vertical back porch */
407 val |= (mode->vtotal - mode->vsync_end)
408 << DSI_VID_VSIZE_VBP_LENGTH_SHIFT;
409 writel(val, d->regs + DSI_VID_VSIZE);
410
411 /*
412 * Horizontal frame parameters:
413 * horizontal resolution is given in pixels and must be re-calculated
414 * into bytes since this is what the hardware expects.
415 *
416 * 6 + 2 is HFP header + checksum
417 */
418 hfp = (mode->hsync_start - mode->hdisplay) * bpp - 6 - 2;
419 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
420 /*
421 * 6 is HBP header + checksum
422 * 4 is RGB header + checksum
423 */
424 hbp = (mode->htotal - mode->hsync_end) * bpp - 4 - 6;
425 /*
426 * 6 is HBP header + checksum
427 * 4 is HSW packet bytes
428 * 4 is RGB header + checksum
429 */
430 hsa = (mode->hsync_end - mode->hsync_start) * bpp - 4 - 4 - 6;
431 } else {
432 /*
433 * HBP includes both back porch and sync
434 * 6 is HBP header + checksum
435 * 4 is HSW packet bytes
436 * 4 is RGB header + checksum
437 */
438 hbp = (mode->htotal - mode->hsync_start) * bpp - 4 - 4 - 6;
439 /* HSA is not considered in this mode and set to 0 */
440 hsa = 0;
441 }
442 dev_dbg(d->dev, "hfp: %u, hbp: %u, hsa: %u\n",
443 hfp, hbp, hsa);
444
445 /* Frame parameters: horizontal sync active */
446 val = hsa << DSI_VID_HSIZE1_HSA_LENGTH_SHIFT;
447 /* horizontal back porch */
448 val |= hbp << DSI_VID_HSIZE1_HBP_LENGTH_SHIFT;
449 /* horizontal front porch */
450 val |= hfp << DSI_VID_HSIZE1_HFP_LENGTH_SHIFT;
451 writel(val, d->regs + DSI_VID_HSIZE1);
452
453 /* RGB data length (bytes on one scanline) */
454 val = mode->hdisplay * (bpp / 8);
455 writel(val, d->regs + DSI_VID_HSIZE2);
456
457 /* TODO: further adjustments for TVG mode here */
458
459 /*
460 * EOL packet length from bits per line calculations: pixel clock
461 * is given in kHz, calculate the time between two pixels in
462 * picoseconds.
463 */
464 bpl = mode->clock * mode->htotal;
465 bpl *= (d->hs_freq / 8);
466 do_div(bpl, 1000000); /* microseconds */
467 do_div(bpl, 1000000); /* seconds */
468 bpl *= d->mdsi->lanes;
469 dev_dbg(d->dev, "calculated bytes per line: %llu\n", bpl);
470 /*
471 * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes
472 * 4 is short packet for vsync/hsync
473 */
474 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
475 /* Fixme: isn't the hsync width in pixels? */
476 blkline_pck = bpl - (mode->hsync_end - mode->hsync_start) - 6;
477 val = blkline_pck << DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT;
478 writel(val, d->regs + DSI_VID_BLKSIZE2);
479 } else {
480 blkline_pck = bpl - 4 - 6;
481 val = blkline_pck << DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT;
482 writel(val, d->regs + DSI_VID_BLKSIZE1);
483 }
484
485 line_duration = (blkline_pck + 6) / d->mdsi->lanes;
486 dev_dbg(d->dev, "line duration %u\n", line_duration);
487 val = line_duration << DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT;
488 /*
489 * This is the time to perform LP->HS on D-PHY
490 * FIXME: nowhere to get this from: DT property on the DSI?
491 */
492 val |= 0 << DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT;
493 writel(val, d->regs + DSI_VID_DPHY_TIME);
494
495 /* Calculate block end of line */
496 blkeol_pck = bpl - mode->hdisplay * bpp - 6;
497 blkeol_duration = (blkeol_pck + 6) / d->mdsi->lanes;
498 dev_dbg(d->dev, "blkeol pck: %u, duration: %u\n",
499 blkeol_pck, blkeol_duration);
500
501 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
502 /* Set up EOL clock for burst mode */
503 val = readl(d->regs + DSI_VID_BLKSIZE1);
504 val |= blkeol_pck << DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT;
505 writel(val, d->regs + DSI_VID_BLKSIZE1);
506 writel(blkeol_pck, d->regs + DSI_VID_VCA_SETTING2);
507
508 writel(blkeol_duration, d->regs + DSI_VID_PCK_TIME);
509 writel(blkeol_duration - 6, d->regs + DSI_VID_VCA_SETTING1);
510 }
511
512 /* Maximum line limit */
513 val = readl(d->regs + DSI_VID_VCA_SETTING2);
514 val |= blkline_pck <<
515 DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT;
516 writel(val, d->regs + DSI_VID_VCA_SETTING2);
517
518 /* Put IF1 into video mode */
519 val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
520 val |= DSI_MCTL_MAIN_DATA_CTL_IF1_MODE;
521 writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
522
523 /* Disable command mode on IF1 */
524 val = readl(d->regs + DSI_CMD_MODE_CTL);
525 val &= ~DSI_CMD_MODE_CTL_IF1_LP_EN;
526 writel(val, d->regs + DSI_CMD_MODE_CTL);
527
528 /* Enable some error interrupts */
529 val = readl(d->regs + DSI_VID_MODE_STS_CTL);
530 val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC;
531 val |= DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA;
532 writel(val, d->regs + DSI_VID_MODE_STS_CTL);
533
534 /* Enable video mode */
535 val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
536 val |= DSI_MCTL_MAIN_DATA_CTL_VID_EN;
537 writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
538}
539
540static void mcde_dsi_start(struct mcde_dsi *d)
541{
542 unsigned long hs_freq;
543 u32 val;
544 int i;
545
546 /* No integration mode */
547 writel(0, d->regs + DSI_MCTL_INTEGRATION_MODE);
548
549 /* Enable the DSI port, from drivers/video/mcde/dsilink_v2.c */
550 val = DSI_MCTL_MAIN_DATA_CTL_LINK_EN |
551 DSI_MCTL_MAIN_DATA_CTL_BTA_EN |
552 DSI_MCTL_MAIN_DATA_CTL_READ_EN |
553 DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN;
554 if (d->mdsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
555 val |= DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN;
556 writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
557
558 /* Set a high command timeout, clear other fields */
559 val = 0x3ff << DSI_CMD_MODE_CTL_TE_TIMEOUT_SHIFT;
560 writel(val, d->regs + DSI_CMD_MODE_CTL);
561
562 /*
563 * UI_X4 is described as "unit interval times four"
564 * I guess since DSI packets are 4 bytes wide, one unit
565 * is one byte.
566 */
567 hs_freq = clk_get_rate(d->hs_clk);
568 hs_freq /= 1000000; /* MHz */
569 val = 4000 / hs_freq;
570 dev_dbg(d->dev, "UI value: %d\n", val);
571 val <<= DSI_MCTL_DPHY_STATIC_UI_X4_SHIFT;
572 val &= DSI_MCTL_DPHY_STATIC_UI_X4_MASK;
573 writel(val, d->regs + DSI_MCTL_DPHY_STATIC);
574
575 /*
576 * Enable clocking: 0x0f (something?) between each burst,
577 * enable the second lane if needed, enable continuous clock if
578 * needed, enable switch into ULPM (ultra-low power mode) on
579 * all the lines.
580 */
581 val = 0x0f << DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_SHIFT;
582 if (d->mdsi->lanes == 2)
583 val |= DSI_MCTL_MAIN_PHY_CTL_LANE2_EN;
584 if (!(d->mdsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
585 val |= DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS;
586 val |= DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN |
587 DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN |
588 DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN;
589 writel(val, d->regs + DSI_MCTL_MAIN_PHY_CTL);
590
591 val = (1 << DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_SHIFT) |
592 (1 << DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_SHIFT);
593 writel(val, d->regs + DSI_MCTL_ULPOUT_TIME);
594
595 writel(DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_90,
596 d->regs + DSI_DPHY_LANES_TRIM);
597
598 /* High PHY timeout */
599 val = (0x0f << DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_SHIFT) |
600 (0x3fff << DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_SHIFT) |
601 (0x3fff << DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_SHIFT);
602 writel(val, d->regs + DSI_MCTL_DPHY_TIMEOUT);
603
604 val = DSI_MCTL_MAIN_EN_PLL_START |
605 DSI_MCTL_MAIN_EN_CKLANE_EN |
606 DSI_MCTL_MAIN_EN_DAT1_EN |
607 DSI_MCTL_MAIN_EN_IF1_EN;
608 if (d->mdsi->lanes == 2)
609 val |= DSI_MCTL_MAIN_EN_DAT2_EN;
610 writel(val, d->regs + DSI_MCTL_MAIN_EN);
611
612 /* Wait for the PLL to lock and the clock and data lines to come up */
613 i = 0;
614 val = DSI_MCTL_MAIN_STS_PLL_LOCK |
615 DSI_MCTL_MAIN_STS_CLKLANE_READY |
616 DSI_MCTL_MAIN_STS_DAT1_READY;
617 if (d->mdsi->lanes == 2)
618 val |= DSI_MCTL_MAIN_STS_DAT2_READY;
619 while ((readl(d->regs + DSI_MCTL_MAIN_STS) & val) != val) {
620 /* Sleep for a millisecond */
621 usleep_range(1000, 1500);
622 if (i++ == 100) {
623 dev_warn(d->dev, "DSI lanes did not start up\n");
624 return;
625 }
626 }
627
628 /* TODO needed? */
629
630 /* Command mode, clear IF1 ID */
631 val = readl(d->regs + DSI_CMD_MODE_CTL);
632 /*
633 * If we enable low-power mode here, with
634 * val |= DSI_CMD_MODE_CTL_IF1_LP_EN
635 * then display updates become really slow.
636 */
637 val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK;
638 writel(val, d->regs + DSI_CMD_MODE_CTL);
639
640 /* Wait for DSI PHY to initialize */
641 usleep_range(100, 200);
642 dev_info(d->dev, "DSI link enabled\n");
643}
644
645
646static void mcde_dsi_bridge_enable(struct drm_bridge *bridge)
647{
648 struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
649
650 dev_info(d->dev, "enable DSI master\n");
651};
652
653static void mcde_dsi_bridge_mode_set(struct drm_bridge *bridge,
654 const struct drm_display_mode *mode,
655 const struct drm_display_mode *adj)
656{
657 struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
658 unsigned long pixel_clock_hz = mode->clock * 1000;
659 unsigned long hs_freq, lp_freq;
660 u32 val;
661 int ret;
662
663 if (!d->mdsi) {
664 dev_err(d->dev, "no DSI device attached to encoder!\n");
665 return;
666 }
667
668 dev_info(d->dev, "set DSI master to %dx%d %lu Hz %s mode\n",
669 mode->hdisplay, mode->vdisplay, pixel_clock_hz,
670 (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? "VIDEO" : "CMD"
671 );
672
673 /* Copy maximum clock frequencies */
674 if (d->mdsi->lp_rate)
675 lp_freq = d->mdsi->lp_rate;
676 else
677 lp_freq = DSI_DEFAULT_LP_FREQ_HZ;
678 if (d->mdsi->hs_rate)
679 hs_freq = d->mdsi->hs_rate;
680 else
681 hs_freq = DSI_DEFAULT_HS_FREQ_HZ;
682
683 /* Enable LP (Low Power, Energy Save, ES) and HS (High Speed) clocks */
684 d->lp_freq = clk_round_rate(d->lp_clk, lp_freq);
685 ret = clk_set_rate(d->lp_clk, d->lp_freq);
686 if (ret)
687 dev_err(d->dev, "failed to set LP clock rate %lu Hz\n",
688 d->lp_freq);
689
690 d->hs_freq = clk_round_rate(d->hs_clk, hs_freq);
691 ret = clk_set_rate(d->hs_clk, d->hs_freq);
692 if (ret)
693 dev_err(d->dev, "failed to set HS clock rate %lu Hz\n",
694 d->hs_freq);
695
696 /* Start clocks */
697 ret = clk_prepare_enable(d->lp_clk);
698 if (ret)
699 dev_err(d->dev, "failed to enable LP clock\n");
700 else
701 dev_info(d->dev, "DSI LP clock rate %lu Hz\n",
702 d->lp_freq);
703 ret = clk_prepare_enable(d->hs_clk);
704 if (ret)
705 dev_err(d->dev, "failed to enable HS clock\n");
706 else
707 dev_info(d->dev, "DSI HS clock rate %lu Hz\n",
708 d->hs_freq);
709
710 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
711 mcde_dsi_setup_video_mode(d, mode);
712 } else {
713 /* Command mode, clear IF1 ID */
714 val = readl(d->regs + DSI_CMD_MODE_CTL);
715 /*
716 * If we enable low-power mode here with
717 * val |= DSI_CMD_MODE_CTL_IF1_LP_EN
718 * the display updates become really slow.
719 */
720 val &= ~DSI_CMD_MODE_CTL_IF1_ID_MASK;
721 writel(val, d->regs + DSI_CMD_MODE_CTL);
722 }
723}
724
725static void mcde_dsi_wait_for_command_mode_stop(struct mcde_dsi *d)
726{
727 u32 val;
728 int i;
729
730 /*
731 * Wait until we get out of command mode
732 * CSM = Command State Machine
733 */
734 i = 0;
735 val = DSI_CMD_MODE_STS_CSM_RUNNING;
736 while ((readl(d->regs + DSI_CMD_MODE_STS) & val) == val) {
737 /* Sleep for a millisecond */
738 usleep_range(1000, 2000);
739 if (i++ == 100) {
740 dev_warn(d->dev,
741 "could not get out of command mode\n");
742 return;
743 }
744 }
745}
746
747static void mcde_dsi_wait_for_video_mode_stop(struct mcde_dsi *d)
748{
749 u32 val;
750 int i;
751
752 /* Wait until we get out og video mode */
753 i = 0;
754 val = DSI_VID_MODE_STS_VSG_RUNNING;
755 while ((readl(d->regs + DSI_VID_MODE_STS) & val) == val) {
756 /* Sleep for a millisecond */
757 usleep_range(1000, 2000);
758 if (i++ == 100) {
759 dev_warn(d->dev,
760 "could not get out of video mode\n");
761 return;
762 }
763 }
764}
765
766static void mcde_dsi_bridge_disable(struct drm_bridge *bridge)
767{
768 struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
769 u32 val;
770
771 /* Disable all error interrupts */
772 writel(0, d->regs + DSI_VID_MODE_STS_CTL);
773
774 if (d->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
775 /* Stop video mode */
776 val = readl(d->regs + DSI_MCTL_MAIN_DATA_CTL);
777 val &= ~DSI_MCTL_MAIN_DATA_CTL_VID_EN;
778 writel(val, d->regs + DSI_MCTL_MAIN_DATA_CTL);
779 mcde_dsi_wait_for_video_mode_stop(d);
780 } else {
781 /* Stop command mode */
782 mcde_dsi_wait_for_command_mode_stop(d);
783 }
784
785 /* Stop clocks */
786 clk_disable_unprepare(d->hs_clk);
787 clk_disable_unprepare(d->lp_clk);
788}
789
790/*
791 * This connector needs no special handling, just use the default
792 * helpers for everything. It's pretty dummy.
793 */
794static const struct drm_connector_funcs mcde_dsi_connector_funcs = {
795 .reset = drm_atomic_helper_connector_reset,
796 .fill_modes = drm_helper_probe_single_connector_modes,
797 .destroy = drm_connector_cleanup,
798 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
799 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
800};
801
802static int mcde_dsi_get_modes(struct drm_connector *connector)
803{
804 struct mcde_dsi *d = connector_to_mcde_dsi(connector);
805
806 /* Just pass the question to the panel */
807 if (d->panel)
808 return drm_panel_get_modes(d->panel);
809
810 /* TODO: deal with bridges */
811
812 return 0;
813}
814
815static const struct drm_connector_helper_funcs
816mcde_dsi_connector_helper_funcs = {
817 .get_modes = mcde_dsi_get_modes,
818};
819
820static int mcde_dsi_bridge_attach(struct drm_bridge *bridge)
821{
822 struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
823 struct drm_device *drm = bridge->dev;
824 int ret;
825
826 drm_connector_helper_add(&d->connector,
827 &mcde_dsi_connector_helper_funcs);
828
829 if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
830 dev_err(d->dev, "we need atomic updates\n");
831 return -ENOTSUPP;
832 }
833
834 ret = drm_connector_init(drm, &d->connector,
835 &mcde_dsi_connector_funcs,
836 DRM_MODE_CONNECTOR_DSI);
837 if (ret) {
838 dev_err(d->dev, "failed to initialize DSI bridge connector\n");
839 return ret;
840 }
841 d->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
842 /* The encoder in the bridge attached to the DSI bridge */
843 drm_connector_attach_encoder(&d->connector, bridge->encoder);
844 /* Then we attach the DSI bridge to the output (panel etc) bridge */
845 ret = drm_bridge_attach(bridge->encoder, d->bridge_out, bridge);
846 if (ret) {
847 dev_err(d->dev, "failed to attach the DSI bridge\n");
848 return ret;
849 }
850 d->connector.status = connector_status_connected;
851
852 return 0;
853}
854
855static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
856 .attach = mcde_dsi_bridge_attach,
857 .mode_set = mcde_dsi_bridge_mode_set,
858 .disable = mcde_dsi_bridge_disable,
859 .enable = mcde_dsi_bridge_enable,
860};
861
862static int mcde_dsi_bind(struct device *dev, struct device *master,
863 void *data)
864{
865 struct drm_device *drm = data;
866 struct mcde *mcde = drm->dev_private;
867 struct mcde_dsi *d = dev_get_drvdata(dev);
868 struct device_node *child;
869 struct drm_panel *panel = NULL;
870 struct drm_bridge *bridge = NULL;
871
872 if (!of_get_available_child_count(dev->of_node)) {
873 dev_info(dev, "unused DSI interface\n");
874 d->unused = true;
875 return 0;
876 }
877 d->mcde = mcde;
878 /* If the display attached before binding, set this up */
879 if (d->mdsi)
880 d->mcde->mdsi = d->mdsi;
881
882 /* Obtain the clocks */
883 d->hs_clk = devm_clk_get(dev, "hs");
884 if (IS_ERR(d->hs_clk)) {
885 dev_err(dev, "unable to get HS clock\n");
886 return PTR_ERR(d->hs_clk);
887 }
888
889 d->lp_clk = devm_clk_get(dev, "lp");
890 if (IS_ERR(d->lp_clk)) {
891 dev_err(dev, "unable to get LP clock\n");
892 return PTR_ERR(d->lp_clk);
893 }
894
895 /* Assert RESET through the PRCMU, active low */
896 /* FIXME: which DSI block? */
897 regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
898 PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
899
900 usleep_range(100, 200);
901
902 /* De-assert RESET again */
903 regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
904 PRCM_DSI_SW_RESET_DSI0_SW_RESETN,
905 PRCM_DSI_SW_RESET_DSI0_SW_RESETN);
906
907 /* Start up the hardware */
908 mcde_dsi_start(d);
909
910 /* Look for a panel as a child to this node */
911 for_each_available_child_of_node(dev->of_node, child) {
912 panel = of_drm_find_panel(child);
913 if (IS_ERR(panel)) {
914 dev_err(dev, "failed to find panel try bridge (%lu)\n",
915 PTR_ERR(panel));
916 bridge = of_drm_find_bridge(child);
917 if (IS_ERR(bridge)) {
918 dev_err(dev, "failed to find bridge (%lu)\n",
919 PTR_ERR(bridge));
920 return PTR_ERR(bridge);
921 }
922 }
923 }
924 if (panel) {
925 bridge = drm_panel_bridge_add(panel,
926 DRM_MODE_CONNECTOR_DSI);
927 if (IS_ERR(bridge)) {
928 dev_err(dev, "error adding panel bridge\n");
929 return PTR_ERR(bridge);
930 }
931 dev_info(dev, "connected to panel\n");
932 d->panel = panel;
933 } else if (bridge) {
934 /* TODO: AV8100 HDMI encoder goes here for example */
935 dev_info(dev, "connected to non-panel bridge (unsupported)\n");
936 return -ENODEV;
937 } else {
938 dev_err(dev, "no panel or bridge\n");
939 return -ENODEV;
940 }
941
942 d->bridge_out = bridge;
943
944 /* Create a bridge for this DSI channel */
945 d->bridge.funcs = &mcde_dsi_bridge_funcs;
946 d->bridge.of_node = dev->of_node;
947 drm_bridge_add(&d->bridge);
948
949 /* TODO: first come first serve, use a list */
950 mcde->bridge = &d->bridge;
951
952 dev_info(dev, "initialized MCDE DSI bridge\n");
953
954 return 0;
955}
956
957static void mcde_dsi_unbind(struct device *dev, struct device *master,
958 void *data)
959{
960 struct mcde_dsi *d = dev_get_drvdata(dev);
961
962 if (d->panel)
963 drm_panel_bridge_remove(d->bridge_out);
964 regmap_update_bits(d->prcmu, PRCM_DSI_SW_RESET,
965 PRCM_DSI_SW_RESET_DSI0_SW_RESETN, 0);
966}
967
968static const struct component_ops mcde_dsi_component_ops = {
969 .bind = mcde_dsi_bind,
970 .unbind = mcde_dsi_unbind,
971};
972
973static int mcde_dsi_probe(struct platform_device *pdev)
974{
975 struct device *dev = &pdev->dev;
976 struct mcde_dsi *d;
977 struct mipi_dsi_host *host;
978 struct resource *res;
979 u32 dsi_id;
980 int ret;
981
982 d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
983 if (!d)
984 return -ENOMEM;
985 d->dev = dev;
986 platform_set_drvdata(pdev, d);
987
988 /* Get a handle on the PRCMU so we can do reset */
989 d->prcmu =
990 syscon_regmap_lookup_by_compatible("stericsson,db8500-prcmu");
991 if (IS_ERR(d->prcmu)) {
992 dev_err(dev, "no PRCMU regmap\n");
993 return PTR_ERR(d->prcmu);
994 }
995
996 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
997 d->regs = devm_ioremap_resource(dev, res);
998 if (IS_ERR(d->regs)) {
999 dev_err(dev, "no DSI regs\n");
1000 return PTR_ERR(d->regs);
1001 }
1002
1003 dsi_id = readl(d->regs + DSI_ID_REG);
1004 dev_info(dev, "HW revision 0x%08x\n", dsi_id);
1005
1006 host = &d->dsi_host;
1007 host->dev = dev;
1008 host->ops = &mcde_dsi_host_ops;
1009 ret = mipi_dsi_host_register(host);
1010 if (ret < 0) {
1011 dev_err(dev, "failed to register DSI host: %d\n", ret);
1012 return ret;
1013 }
1014 dev_info(dev, "registered DSI host\n");
1015
1016 platform_set_drvdata(pdev, d);
1017 return component_add(dev, &mcde_dsi_component_ops);
1018}
1019
1020static int mcde_dsi_remove(struct platform_device *pdev)
1021{
1022 struct mcde_dsi *d = platform_get_drvdata(pdev);
1023
1024 component_del(&pdev->dev, &mcde_dsi_component_ops);
1025 mipi_dsi_host_unregister(&d->dsi_host);
1026
1027 return 0;
1028}
1029
1030static const struct of_device_id mcde_dsi_of_match[] = {
1031 {
1032 .compatible = "ste,mcde-dsi",
1033 },
1034 {},
1035};
1036
1037struct platform_driver mcde_dsi_driver = {
1038 .driver = {
1039 .name = "mcde-dsi",
1040 .of_match_table = of_match_ptr(mcde_dsi_of_match),
1041 },
1042 .probe = mcde_dsi_probe,
1043 .remove = mcde_dsi_remove,
1044};
diff --git a/drivers/gpu/drm/mcde/mcde_dsi_regs.h b/drivers/gpu/drm/mcde/mcde_dsi_regs.h
new file mode 100644
index 000000000000..c9253321a3be
--- /dev/null
+++ b/drivers/gpu/drm/mcde/mcde_dsi_regs.h
@@ -0,0 +1,385 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __DRM_MCDE_DSI_REGS
3#define __DRM_MCDE_DSI_REGS
4
5#define DSI_MCTL_INTEGRATION_MODE 0x00000000
6
7#define DSI_MCTL_MAIN_DATA_CTL 0x00000004
8#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN BIT(0)
9#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE BIT(1)
10#define DSI_MCTL_MAIN_DATA_CTL_VID_EN BIT(2)
11#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL BIT(3)
12#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL BIT(4)
13#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN BIT(5)
14#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN BIT(6)
15#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN BIT(7)
16#define DSI_MCTL_MAIN_DATA_CTL_READ_EN BIT(8)
17#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN BIT(9)
18#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC BIT(10)
19#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM BIT(11)
20#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN BIT(12)
21#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN BIT(13)
22#define DSI_MCTL_MAIN_DATA_CTL_DLX_REMAP_EN BIT(14)
23#define DSI_MCTL_MAIN_DATA_CTL_TE_POLLING_EN BIT(15)
24
25#define DSI_MCTL_MAIN_PHY_CTL 0x00000008
26#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN BIT(0)
27#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE BIT(1)
28#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS BIT(2)
29#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN BIT(3)
30#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN BIT(4)
31#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN BIT(5)
32#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_SHIFT 6
33#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_MASK 0x000003C0
34#define DSI_MCTL_MAIN_PHY_CTL_CLOCK_FORCE_STOP_MODE BIT(10)
35
36#define DSI_MCTL_PLL_CTL 0x0000000C
37#define DSI_MCTL_LANE_STS 0x00000010
38
39#define DSI_MCTL_DPHY_TIMEOUT 0x00000014
40#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_SHIFT 0
41#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_MASK 0x0000000F
42#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_SHIFT 4
43#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_MASK 0x0003FFF0
44#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_SHIFT 18
45#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_MASK 0xFFFC0000
46
47#define DSI_MCTL_ULPOUT_TIME 0x00000018
48#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_SHIFT 0
49#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_MASK 0x000001FF
50#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_SHIFT 9
51#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_MASK 0x0003FE00
52
53#define DSI_MCTL_DPHY_STATIC 0x0000001C
54#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK BIT(0)
55#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK BIT(1)
56#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1 BIT(2)
57#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1 BIT(3)
58#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2 BIT(4)
59#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2 BIT(5)
60#define DSI_MCTL_DPHY_STATIC_UI_X4_SHIFT 6
61#define DSI_MCTL_DPHY_STATIC_UI_X4_MASK 0x00000FC0
62
63#define DSI_MCTL_MAIN_EN 0x00000020
64#define DSI_MCTL_MAIN_EN_PLL_START BIT(0)
65#define DSI_MCTL_MAIN_EN_CKLANE_EN BIT(3)
66#define DSI_MCTL_MAIN_EN_DAT1_EN BIT(4)
67#define DSI_MCTL_MAIN_EN_DAT2_EN BIT(5)
68#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ BIT(6)
69#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ BIT(7)
70#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ BIT(8)
71#define DSI_MCTL_MAIN_EN_IF1_EN BIT(9)
72#define DSI_MCTL_MAIN_EN_IF2_EN BIT(10)
73
74#define DSI_MCTL_MAIN_STS 0x00000024
75#define DSI_MCTL_MAIN_STS_PLL_LOCK BIT(0)
76#define DSI_MCTL_MAIN_STS_CLKLANE_READY BIT(1)
77#define DSI_MCTL_MAIN_STS_DAT1_READY BIT(2)
78#define DSI_MCTL_MAIN_STS_DAT2_READY BIT(3)
79#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR BIT(4)
80#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR BIT(5)
81#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK BIT(6)
82#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK BIT(7)
83
84#define DSI_MCTL_DPHY_ERR 0x00000028
85#define DSI_INT_VID_RDDATA 0x00000030
86#define DSI_INT_VID_GNT 0x00000034
87#define DSI_INT_CMD_RDDATA 0x00000038
88#define DSI_INT_CMD_GNT 0x0000003C
89#define DSI_INT_INTERRUPT_CTL 0x00000040
90
91#define DSI_CMD_MODE_CTL 0x00000050
92#define DSI_CMD_MODE_CTL_IF1_ID_SHIFT 0
93#define DSI_CMD_MODE_CTL_IF1_ID_MASK 0x00000003
94#define DSI_CMD_MODE_CTL_IF2_ID_SHIFT 2
95#define DSI_CMD_MODE_CTL_IF2_ID_MASK 0x0000000C
96#define DSI_CMD_MODE_CTL_IF1_LP_EN BIT(4)
97#define DSI_CMD_MODE_CTL_IF2_LP_EN BIT(5)
98#define DSI_CMD_MODE_CTL_ARB_MODE BIT(6)
99#define DSI_CMD_MODE_CTL_ARB_PRI BIT(7)
100#define DSI_CMD_MODE_CTL_FIL_VALUE_SHIFT 8
101#define DSI_CMD_MODE_CTL_FIL_VALUE_MASK 0x0000FF00
102#define DSI_CMD_MODE_CTL_TE_TIMEOUT_SHIFT 16
103#define DSI_CMD_MODE_CTL_TE_TIMEOUT_MASK 0x03FF0000
104
105#define DSI_CMD_MODE_STS 0x00000054
106#define DSI_CMD_MODE_STS_ERR_NO_TE BIT(0)
107#define DSI_CMD_MODE_STS_ERR_TE_MISS BIT(1)
108#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN BIT(2)
109#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN BIT(3)
110#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD BIT(4)
111#define DSI_CMD_MODE_STS_CSM_RUNNING BIT(5)
112
113#define DSI_DIRECT_CMD_SEND 0x00000060
114
115#define DSI_DIRECT_CMD_MAIN_SETTINGS 0x00000064
116#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_SHIFT 0
117#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_MASK 0x00000007
118#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE 0
119#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ 1
120#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TE_REQ 4
121#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TRIG_REQ 5
122#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_BTA_REQ 6
123#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT BIT(3)
124#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT 8
125#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_MASK 0x00003F00
126#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_TURN_ON_PERIPHERAL 50
127#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHUT_DOWN_PERIPHERAL 34
128#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_0 3
129#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_1 19
130#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_2 35
131#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_LONG_WRITE 41
132#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_0 5
133#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 21
134#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_LONG_WRITE 57
135#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_READ 6
136#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SET_MAX_PKT_SIZE 55
137#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT 14
138#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT 16
139#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN BIT(21)
140#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_SHIFT 24
141#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_MASK 0x0F000000
142
143#define DSI_DIRECT_CMD_STS 0x00000068
144#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION BIT(0)
145#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED BIT(1)
146#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED BIT(2)
147#define DSI_DIRECT_CMD_STS_READ_COMPLETED BIT(3)
148#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED_SHIFT BIT(4)
149#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED BIT(5)
150#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED BIT(6)
151#define DSI_DIRECT_CMD_STS_TE_RECEIVED BIT(7)
152#define DSI_DIRECT_CMD_STS_BTA_COMPLETED BIT(8)
153#define DSI_DIRECT_CMD_STS_BTA_FINISHED BIT(9)
154#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR BIT(10)
155#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_MASK 0x00007800
156#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_SHIFT 11
157#define DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT 16
158#define DSI_DIRECT_CMD_STS_ACK_VAL_MASK 0xFFFF0000
159
160#define DSI_DIRECT_CMD_RD_INIT 0x0000006C
161#define DSI_DIRECT_CMD_RD_INIT_RESET_SHIFT 0
162#define DSI_DIRECT_CMD_RD_INIT_RESET_MASK 0xFFFFFFFF
163
164#define DSI_DIRECT_CMD_WRDAT0 0x00000070
165#define DSI_DIRECT_CMD_WRDAT1 0x00000074
166#define DSI_DIRECT_CMD_WRDAT2 0x00000078
167#define DSI_DIRECT_CMD_WRDAT3 0x0000007C
168
169#define DSI_DIRECT_CMD_RDDAT 0x00000080
170
171#define DSI_DIRECT_CMD_RD_PROPERTY 0x00000084
172#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_SHIFT 0
173#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK 0x0000FFFF
174#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_SHIFT 16
175#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_MASK 0x00030000
176#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_SHIFT 18
177#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_MASK 0x00040000
178
179#define DSI_DIRECT_CMD_RD_STS 0x00000088
180
181#define DSI_VID_MAIN_CTL 0x00000090
182#define DSI_VID_MAIN_CTL_START_MODE_SHIFT 0
183#define DSI_VID_MAIN_CTL_START_MODE_MASK 0x00000003
184#define DSI_VID_MAIN_CTL_STOP_MODE_SHIFT 2
185#define DSI_VID_MAIN_CTL_STOP_MODE_MASK 0x0000000C
186#define DSI_VID_MAIN_CTL_VID_ID_SHIFT 4
187#define DSI_VID_MAIN_CTL_VID_ID_MASK 0x00000030
188#define DSI_VID_MAIN_CTL_HEADER_SHIFT 6
189#define DSI_VID_MAIN_CTL_HEADER_MASK 0x00000FC0
190#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_16BITS 0
191#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS BIT(12)
192#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS_LOOSE BIT(13)
193#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_24BITS (BIT(12) | BIT(13))
194#define DSI_VID_MAIN_CTL_BURST_MODE BIT(14)
195#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE BIT(15)
196#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL BIT(16)
197#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_NULL 0
198#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING BIT(17)
199#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0 BIT(18)
200#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_1 (BIT(17) | BIT(18))
201#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_NULL 0
202#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_BLANKING BIT(19)
203#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 BIT(20)
204#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_1 (BIT(19) | BIT(20))
205#define DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT 21
206#define DSI_VID_MAIN_CTL_RECOVERY_MODE_MASK 0x00600000
207
208#define DSI_VID_VSIZE 0x00000094
209#define DSI_VID_VSIZE_VSA_LENGTH_SHIFT 0
210#define DSI_VID_VSIZE_VSA_LENGTH_MASK 0x0000003F
211#define DSI_VID_VSIZE_VBP_LENGTH_SHIFT 6
212#define DSI_VID_VSIZE_VBP_LENGTH_MASK 0x00000FC0
213#define DSI_VID_VSIZE_VFP_LENGTH_SHIFT 12
214#define DSI_VID_VSIZE_VFP_LENGTH_MASK 0x000FF000
215#define DSI_VID_VSIZE_VACT_LENGTH_SHIFT 20
216#define DSI_VID_VSIZE_VACT_LENGTH_MASK 0x7FF00000
217
218#define DSI_VID_HSIZE1 0x00000098
219#define DSI_VID_HSIZE1_HSA_LENGTH_SHIFT 0
220#define DSI_VID_HSIZE1_HSA_LENGTH_MASK 0x000003FF
221#define DSI_VID_HSIZE1_HBP_LENGTH_SHIFT 10
222#define DSI_VID_HSIZE1_HBP_LENGTH_MASK 0x000FFC00
223#define DSI_VID_HSIZE1_HFP_LENGTH_SHIFT 20
224#define DSI_VID_HSIZE1_HFP_LENGTH_MASK 0x7FF00000
225
226#define DSI_VID_HSIZE2 0x0000009C
227#define DSI_VID_HSIZE2_RGB_SIZE_SHIFT 0
228#define DSI_VID_HSIZE2_RGB_SIZE_MASK 0x00001FFF
229
230#define DSI_VID_BLKSIZE1 0x000000A0
231#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT 0
232#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK 0x00001FFF
233#define DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT 13
234#define DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK 0x03FFE000
235
236#define DSI_VID_BLKSIZE2 0x000000A4
237#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT 0
238#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_MASK 0x00001FFF
239
240#define DSI_VID_PCK_TIME 0x000000A8
241#define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0
242
243#define DSI_VID_DPHY_TIME 0x000000AC
244#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0
245#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_MASK 0x00001FFF
246#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT 13
247#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_MASK 0x00FFE000
248
249#define DSI_VID_MODE_STS 0x000000BC
250#define DSI_VID_MODE_STS_VSG_RUNNING BIT(0)
251
252#define DSI_VID_VCA_SETTING1 0x000000C0
253#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT 0
254#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK 0x0000FFFF
255#define DSI_VID_VCA_SETTING1_BURST_LP BIT(16)
256
257#define DSI_VID_VCA_SETTING2 0x000000C4
258#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT 0
259#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK 0x0000FFFF
260#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT 16
261#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK 0xFFFF0000
262
263#define DSI_CMD_MODE_STS_CTL 0x000000F4
264#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN BIT(0)
265#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN BIT(1)
266#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN BIT(2)
267#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN BIT(3)
268#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN BIT(4)
269#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN BIT(5)
270#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE BIT(16)
271#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE BIT(17)
272#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE BIT(18)
273#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE BIT(19)
274#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE BIT(20)
275#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE BIT(21)
276
277#define DSI_DIRECT_CMD_STS_CTL 0x000000F8
278#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN BIT(0)
279#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN BIT(1)
280#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN BIT(2)
281#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN BIT(3)
282#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN BIT(4)
283#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN BIT(5)
284#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN BIT(6)
285#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN BIT(7)
286#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN BIT(8)
287#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN BIT(9)
288#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN BIT(10)
289#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE BIT(16)
290#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE BIT(17)
291#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE BIT(18)
292#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE BIT(19)
293#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE BIT(20)
294#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE BIT(21)
295#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE BIT(22)
296#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE BIT(23)
297#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE BIT(24)
298#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE BIT(25)
299#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE BIT(26)
300
301#define DSI_VID_MODE_STS_CTL 0x00000100
302#define DSI_VID_MODE_STS_CTL_VSG_RUNNING BIT(0)
303#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA BIT(1)
304#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC BIT(2)
305#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC BIT(3)
306#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH BIT(4)
307#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT BIT(5)
308#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE BIT(6)
309#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE BIT(7)
310#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD BIT(8)
311#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH BIT(9)
312#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE BIT(16)
313#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE BIT(17)
314#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE BIT(18)
315#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE BIT(19)
316#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE BIT(20)
317#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE BIT(21)
318#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE BIT(22)
319#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE BIT(23)
320#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE BIT(24)
321#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE BIT(25)
322#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE BIT(26)
323
324#define DSI_TG_STS_CTL 0x00000104
325#define DSI_MCTL_DHPY_ERR_CTL 0x00000108
326#define DSI_MCTL_MAIN_STS_CLR 0x00000110
327
328#define DSI_CMD_MODE_STS_CLR 0x00000114
329#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR BIT(0)
330#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR BIT(1)
331#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR BIT(2)
332#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR BIT(3)
333#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR BIT(4)
334#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR BIT(5)
335
336#define DSI_DIRECT_CMD_STS_CLR 0x00000118
337#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR BIT(0)
338#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR BIT(1)
339#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR BIT(2)
340#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR BIT(3)
341#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR BIT(4)
342#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR BIT(5)
343#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR BIT(6)
344#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR BIT(7)
345#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR BIT(8)
346#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR BIT(9)
347#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR BIT(10)
348
349#define DSI_DIRECT_CMD_RD_STS_CLR 0x0000011C
350#define DSI_VID_MODE_STS_CLR 0x00000120
351#define DSI_TG_STS_CLR 0x00000124
352#define DSI_MCTL_DPHY_ERR_CLR 0x00000128
353#define DSI_MCTL_MAIN_STS_FLAG 0x00000130
354#define DSI_CMD_MODE_STS_FLAG 0x00000134
355#define DSI_DIRECT_CMD_STS_FLAG 0x00000138
356#define DSI_DIRECT_CMD_RD_STS_FLAG 0x0000013C
357#define DSI_VID_MODE_STS_FLAG 0x00000140
358#define DSI_TG_STS_FLAG 0x00000144
359
360#define DSI_DPHY_LANES_TRIM 0x00000150
361#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_SHIFT 0
362#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_MASK 0x00000003
363#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1 BIT(2)
364#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1 BIT(3)
365#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1 BIT(4)
366#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1 BIT(5)
367#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_SHIFT 6
368#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_MASK 0x000000C0
369#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_SHIFT 8
370#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_MASK 0x00000300
371#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_SHIFT 10
372#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_MASK 0x00000C00
373#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_81 0
374#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_90 BIT(12)
375#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK BIT(13)
376#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK BIT(14)
377#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK BIT(15)
378#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2 BIT(16)
379#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2 BIT(18)
380#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2 BIT(19)
381#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2 BIT(20)
382
383#define DSI_ID_REG 0x00000FF0
384
385#endif /* __DRM_MCDE_DSI_REGS */