Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+3745
+1
Documentation/gpu/drivers.rst
··· 7 7 amdgpu 8 8 amdgpu-dc 9 9 i915 10 + mcde 10 11 meson 11 12 pl111 12 13 tegra
+8
Documentation/gpu/mcde.rst
··· 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
+7
MAINTAINERS
··· 5128 5128 F: drivers/gpu/drm/tinydrm/st7735r.c 5129 5129 F: Documentation/devicetree/bindings/display/sitronix,st7735r.txt 5130 5130 5131 + DRM DRIVER FOR ST-ERICSSON MCDE 5132 + M: Linus Walleij <linus.walleij@linaro.org> 5133 + T: git git://anongit.freedesktop.org/drm/drm-misc 5134 + S: Maintained 5135 + F: drivers/gpu/drm/mcde/ 5136 + F: Documentation/devicetree/bindings/display/ste,mcde.txt 5137 + 5131 5138 DRM DRIVER FOR TDFX VIDEO CARDS 5132 5139 S: Orphan / Obsolete 5133 5140 F: drivers/gpu/drm/tdfx/
+2
drivers/gpu/drm/Kconfig
··· 349 349 350 350 source "drivers/gpu/drm/aspeed/Kconfig" 351 351 352 + source "drivers/gpu/drm/mcde/Kconfig" 353 + 352 354 # Keep legacy drivers last 353 355 354 356 menuconfig DRM_LEGACY
+1
drivers/gpu/drm/Makefile
··· 118 118 obj-$(CONFIG_DRM_LIMA) += lima/ 119 119 obj-$(CONFIG_DRM_PANFROST) += panfrost/ 120 120 obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/ 121 + obj-$(CONFIG_DRM_MCDE) += mcde/
+18
drivers/gpu/drm/mcde/Kconfig
··· 1 + config 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.
+3
drivers/gpu/drm/mcde/Makefile
··· 1 + mcde_drm-y += mcde_drv.o mcde_dsi.o mcde_display.o 2 + 3 + obj-$(CONFIG_DRM_MCDE) += mcde_drm.o
+1142
drivers/gpu/drm/mcde/mcde_display.c
··· 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 + 24 + enum mcde_fifo { 25 + MCDE_FIFO_A, 26 + MCDE_FIFO_B, 27 + /* TODO: implement FIFO C0 and FIFO C1 */ 28 + }; 29 + 30 + enum mcde_channel { 31 + MCDE_CHANNEL_0 = 0, 32 + MCDE_CHANNEL_1, 33 + MCDE_CHANNEL_2, 34 + MCDE_CHANNEL_3, 35 + }; 36 + 37 + enum 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 + 50 + enum 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 + 59 + enum mcde_dsi_formatter { 60 + MCDE_DSI_FORMATTER_0 = 0, 61 + MCDE_DSI_FORMATTER_1, 62 + MCDE_DSI_FORMATTER_2, 63 + }; 64 + 65 + void 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 + 137 + void 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 + 150 + static 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 + 187 + static 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 + 332 + static 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 + 458 + static 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 + 548 + static 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 + 592 + static 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 + 683 + static 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 + 709 + static 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 + */ 754 + static 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 + 797 + static 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 + 812 + static 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 + 944 + static 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 + 959 + static 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 + 995 + static 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 + 1006 + static 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 + 1064 + static 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 + 1083 + static 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 + 1095 + static 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 + 1103 + int 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 + } 1142 + EXPORT_SYMBOL_GPL(mcde_display_init);
+518
drivers/gpu/drm/mcde/mcde_display_regs.h
··· 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 */
+44
drivers/gpu/drm/mcde/mcde_drm.h
··· 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 + 12 + struct 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 + 36 + bool mcde_dsi_irq(struct mipi_dsi_device *mdsi); 37 + void mcde_dsi_te_request(struct mipi_dsi_device *mdsi); 38 + extern struct platform_driver mcde_dsi_driver; 39 + 40 + void mcde_display_irq(struct mcde *mcde); 41 + void mcde_display_disable_irqs(struct mcde *mcde); 42 + int mcde_display_init(struct drm_device *drm); 43 + 44 + #endif /* _MCDE_DRM_H_ */
+572
drivers/gpu/drm/mcde/mcde_drv.c
··· 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 + 131 + static 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 + 137 + static 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 + 146 + static 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 + 162 + static 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 + 222 + out_config: 223 + drm_mode_config_cleanup(drm); 224 + return ret; 225 + } 226 + 227 + static 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 + 236 + DEFINE_DRM_GEM_CMA_FOPS(drm_fops); 237 + 238 + static 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 + 266 + static 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 + 289 + unbind: 290 + component_unbind_all(drm->dev, drm); 291 + return ret; 292 + } 293 + 294 + static 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 + 303 + static const struct component_master_ops mcde_drm_comp_ops = { 304 + .bind = mcde_drm_bind, 305 + .unbind = mcde_drm_unbind, 306 + }; 307 + 308 + static struct platform_driver *const mcde_component_drivers[] = { 309 + &mcde_dsi_driver, 310 + }; 311 + 312 + static int mcde_compare_dev(struct device *dev, void *data) 313 + { 314 + return dev == data; 315 + } 316 + 317 + static 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 + 501 + clk_disable: 502 + clk_disable_unprepare(mcde->mcde_clk); 503 + regulator_off: 504 + regulator_disable(mcde->vana); 505 + regulator_epod_off: 506 + regulator_disable(mcde->epod); 507 + dev_unref: 508 + drm_dev_put(drm); 509 + return ret; 510 + 511 + } 512 + 513 + static 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 + 527 + static const struct of_device_id mcde_of_match[] = { 528 + { 529 + .compatible = "ste,mcde", 530 + }, 531 + {}, 532 + }; 533 + 534 + static 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 + 543 + static struct platform_driver *const component_drivers[] = { 544 + &mcde_dsi_driver, 545 + }; 546 + 547 + static 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 + 559 + static 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 + 566 + module_init(mcde_drm_register); 567 + module_exit(mcde_drm_unregister); 568 + 569 + MODULE_ALIAS("platform:mcde-drm"); 570 + MODULE_DESCRIPTION(DRIVER_DESC); 571 + MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 572 + MODULE_LICENSE("GPL");
+1044
drivers/gpu/drm/mcde/mcde_dsi.c
··· 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 + 38 + struct 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 + 57 + static inline struct mcde_dsi *bridge_to_mcde_dsi(struct drm_bridge *bridge) 58 + { 59 + return container_of(bridge, struct mcde_dsi, bridge); 60 + } 61 + 62 + static 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 + 67 + static inline struct mcde_dsi *connector_to_mcde_dsi(struct drm_connector *c) 68 + { 69 + return container_of(c, struct mcde_dsi, connector); 70 + } 71 + 72 + bool 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 + 133 + static 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 + 156 + static 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 + 174 + static 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 + 296 + static 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 */ 303 + void 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 + 341 + static 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 + 540 + static 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 + 646 + static 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 + 653 + static 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 + 725 + static 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 + 747 + static 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 + 766 + static 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 + */ 794 + static 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 + 802 + static 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 + 815 + static const struct drm_connector_helper_funcs 816 + mcde_dsi_connector_helper_funcs = { 817 + .get_modes = mcde_dsi_get_modes, 818 + }; 819 + 820 + static 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 + 855 + static 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 + 862 + static 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 + 957 + static 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 + 968 + static const struct component_ops mcde_dsi_component_ops = { 969 + .bind = mcde_dsi_bind, 970 + .unbind = mcde_dsi_unbind, 971 + }; 972 + 973 + static 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 + 1020 + static 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 + 1030 + static const struct of_device_id mcde_dsi_of_match[] = { 1031 + { 1032 + .compatible = "ste,mcde-dsi", 1033 + }, 1034 + {}, 1035 + }; 1036 + 1037 + struct 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 + };
+385
drivers/gpu/drm/mcde/mcde_dsi_regs.h
··· 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 */