15fc537bfSLinus Walleij // SPDX-License-Identifier: GPL-2.0 25fc537bfSLinus Walleij /* 35fc537bfSLinus Walleij * Copyright (C) 2018 Linus Walleij <linus.walleij@linaro.org> 45fc537bfSLinus Walleij * Parts of this file were based on the MCDE driver by Marcus Lorentzon 55fc537bfSLinus Walleij * (C) ST-Ericsson SA 2013 65fc537bfSLinus Walleij */ 75fc537bfSLinus Walleij #include <linux/clk.h> 85fc537bfSLinus Walleij #include <linux/delay.h> 95fc537bfSLinus Walleij #include <linux/dma-buf.h> 105fc537bfSLinus Walleij 115fc537bfSLinus Walleij #include <drm/drm_device.h> 125fc537bfSLinus Walleij #include <drm/drm_fb_cma_helper.h> 135fc537bfSLinus Walleij #include <drm/drm_fourcc.h> 145fc537bfSLinus Walleij #include <drm/drm_gem_cma_helper.h> 155fc537bfSLinus Walleij #include <drm/drm_gem_framebuffer_helper.h> 165fc537bfSLinus Walleij #include <drm/drm_mipi_dsi.h> 175fc537bfSLinus Walleij #include <drm/drm_simple_kms_helper.h> 185fc537bfSLinus Walleij #include <drm/drm_vblank.h> 195fc537bfSLinus Walleij #include <video/mipi_display.h> 205fc537bfSLinus Walleij 215fc537bfSLinus Walleij #include "mcde_drm.h" 225fc537bfSLinus Walleij #include "mcde_display_regs.h" 235fc537bfSLinus Walleij 245fc537bfSLinus Walleij enum mcde_fifo { 255fc537bfSLinus Walleij MCDE_FIFO_A, 265fc537bfSLinus Walleij MCDE_FIFO_B, 275fc537bfSLinus Walleij /* TODO: implement FIFO C0 and FIFO C1 */ 285fc537bfSLinus Walleij }; 295fc537bfSLinus Walleij 305fc537bfSLinus Walleij enum mcde_channel { 315fc537bfSLinus Walleij MCDE_CHANNEL_0 = 0, 325fc537bfSLinus Walleij MCDE_CHANNEL_1, 335fc537bfSLinus Walleij MCDE_CHANNEL_2, 345fc537bfSLinus Walleij MCDE_CHANNEL_3, 355fc537bfSLinus Walleij }; 365fc537bfSLinus Walleij 375fc537bfSLinus Walleij enum mcde_extsrc { 385fc537bfSLinus Walleij MCDE_EXTSRC_0 = 0, 395fc537bfSLinus Walleij MCDE_EXTSRC_1, 405fc537bfSLinus Walleij MCDE_EXTSRC_2, 415fc537bfSLinus Walleij MCDE_EXTSRC_3, 425fc537bfSLinus Walleij MCDE_EXTSRC_4, 435fc537bfSLinus Walleij MCDE_EXTSRC_5, 445fc537bfSLinus Walleij MCDE_EXTSRC_6, 455fc537bfSLinus Walleij MCDE_EXTSRC_7, 465fc537bfSLinus Walleij MCDE_EXTSRC_8, 475fc537bfSLinus Walleij MCDE_EXTSRC_9, 485fc537bfSLinus Walleij }; 495fc537bfSLinus Walleij 505fc537bfSLinus Walleij enum mcde_overlay { 515fc537bfSLinus Walleij MCDE_OVERLAY_0 = 0, 525fc537bfSLinus Walleij MCDE_OVERLAY_1, 535fc537bfSLinus Walleij MCDE_OVERLAY_2, 545fc537bfSLinus Walleij MCDE_OVERLAY_3, 555fc537bfSLinus Walleij MCDE_OVERLAY_4, 565fc537bfSLinus Walleij MCDE_OVERLAY_5, 575fc537bfSLinus Walleij }; 585fc537bfSLinus Walleij 595fc537bfSLinus Walleij enum mcde_dsi_formatter { 605fc537bfSLinus Walleij MCDE_DSI_FORMATTER_0 = 0, 615fc537bfSLinus Walleij MCDE_DSI_FORMATTER_1, 625fc537bfSLinus Walleij MCDE_DSI_FORMATTER_2, 635fc537bfSLinus Walleij }; 645fc537bfSLinus Walleij 655fc537bfSLinus Walleij void mcde_display_irq(struct mcde *mcde) 665fc537bfSLinus Walleij { 675fc537bfSLinus Walleij u32 mispp, misovl, mischnl; 68bb5ce9a0SDan Carpenter bool vblank = false; 695fc537bfSLinus Walleij 705fc537bfSLinus Walleij /* Handle display IRQs */ 715fc537bfSLinus Walleij mispp = readl(mcde->regs + MCDE_MISPP); 725fc537bfSLinus Walleij misovl = readl(mcde->regs + MCDE_MISOVL); 735fc537bfSLinus Walleij mischnl = readl(mcde->regs + MCDE_MISCHNL); 745fc537bfSLinus Walleij 755fc537bfSLinus Walleij /* 765fc537bfSLinus Walleij * Handle IRQs from the DSI link. All IRQs from the DSI links 775fc537bfSLinus Walleij * are just latched onto the MCDE IRQ line, so we need to traverse 785fc537bfSLinus Walleij * any active DSI masters and check if an IRQ is originating from 795fc537bfSLinus Walleij * them. 805fc537bfSLinus Walleij * 815fc537bfSLinus Walleij * TODO: Currently only one DSI link is supported. 825fc537bfSLinus Walleij */ 835fc537bfSLinus Walleij if (mcde_dsi_irq(mcde->mdsi)) { 845fc537bfSLinus Walleij u32 val; 855fc537bfSLinus Walleij 865fc537bfSLinus Walleij /* 875fc537bfSLinus Walleij * In oneshot mode we do not send continuous updates 885fc537bfSLinus Walleij * to the display, instead we only push out updates when 895fc537bfSLinus Walleij * the update function is called, then we disable the 905fc537bfSLinus Walleij * flow on the channel once we get the TE IRQ. 915fc537bfSLinus Walleij */ 925fc537bfSLinus Walleij if (mcde->oneshot_mode) { 935fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 945fc537bfSLinus Walleij if (--mcde->flow_active == 0) { 955fc537bfSLinus Walleij dev_dbg(mcde->dev, "TE0 IRQ\n"); 965fc537bfSLinus Walleij /* Disable FIFO A flow */ 975fc537bfSLinus Walleij val = readl(mcde->regs + MCDE_CRA0); 985fc537bfSLinus Walleij val &= ~MCDE_CRX0_FLOEN; 995fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_CRA0); 1005fc537bfSLinus Walleij } 1015fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 1025fc537bfSLinus Walleij } 1035fc537bfSLinus Walleij } 1045fc537bfSLinus Walleij 1055fc537bfSLinus Walleij /* Vblank from one of the channels */ 1065fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPA) { 1075fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl A vblank IRQ\n"); 1085fc537bfSLinus Walleij vblank = true; 1095fc537bfSLinus Walleij } 1105fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPB) { 1115fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl B vblank IRQ\n"); 1125fc537bfSLinus Walleij vblank = true; 1135fc537bfSLinus Walleij } 1145fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPC0) 1155fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C0 vblank IRQ\n"); 1165fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPC1) 1175fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C1 vblank IRQ\n"); 1185fc537bfSLinus Walleij if (mispp & MCDE_PP_VSCC0) 1195fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C0 TE IRQ\n"); 1205fc537bfSLinus Walleij if (mispp & MCDE_PP_VSCC1) 1215fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C1 TE IRQ\n"); 1225fc537bfSLinus Walleij writel(mispp, mcde->regs + MCDE_RISPP); 1235fc537bfSLinus Walleij 1245fc537bfSLinus Walleij if (vblank) 1255fc537bfSLinus Walleij drm_crtc_handle_vblank(&mcde->pipe.crtc); 1265fc537bfSLinus Walleij 1275fc537bfSLinus Walleij if (misovl) 1285fc537bfSLinus Walleij dev_info(mcde->dev, "some stray overlay IRQ %08x\n", misovl); 1295fc537bfSLinus Walleij writel(misovl, mcde->regs + MCDE_RISOVL); 1305fc537bfSLinus Walleij 1315fc537bfSLinus Walleij if (mischnl) 1325fc537bfSLinus Walleij dev_info(mcde->dev, "some stray channel error IRQ %08x\n", 1335fc537bfSLinus Walleij mischnl); 1345fc537bfSLinus Walleij writel(mischnl, mcde->regs + MCDE_RISCHNL); 1355fc537bfSLinus Walleij } 1365fc537bfSLinus Walleij 1375fc537bfSLinus Walleij void mcde_display_disable_irqs(struct mcde *mcde) 1385fc537bfSLinus Walleij { 1395fc537bfSLinus Walleij /* Disable all IRQs */ 1405fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCPP); 1415fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCOVL); 1425fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCCHNL); 1435fc537bfSLinus Walleij 1445fc537bfSLinus Walleij /* Clear any pending IRQs */ 1455fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); 1465fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISOVL); 1475fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISCHNL); 1485fc537bfSLinus Walleij } 1495fc537bfSLinus Walleij 1505fc537bfSLinus Walleij static int mcde_display_check(struct drm_simple_display_pipe *pipe, 1515fc537bfSLinus Walleij struct drm_plane_state *pstate, 1525fc537bfSLinus Walleij struct drm_crtc_state *cstate) 1535fc537bfSLinus Walleij { 1545fc537bfSLinus Walleij const struct drm_display_mode *mode = &cstate->mode; 1555fc537bfSLinus Walleij struct drm_framebuffer *old_fb = pipe->plane.state->fb; 1565fc537bfSLinus Walleij struct drm_framebuffer *fb = pstate->fb; 1575fc537bfSLinus Walleij 1585fc537bfSLinus Walleij if (fb) { 1595fc537bfSLinus Walleij u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); 1605fc537bfSLinus Walleij 1615fc537bfSLinus Walleij /* FB base address must be dword aligned. */ 1625fc537bfSLinus Walleij if (offset & 3) { 1635fc537bfSLinus Walleij DRM_DEBUG_KMS("FB not 32-bit aligned\n"); 1645fc537bfSLinus Walleij return -EINVAL; 1655fc537bfSLinus Walleij } 1665fc537bfSLinus Walleij 1675fc537bfSLinus Walleij /* 1685fc537bfSLinus Walleij * There's no pitch register, the mode's hdisplay 1695fc537bfSLinus Walleij * controls this. 1705fc537bfSLinus Walleij */ 1715fc537bfSLinus Walleij if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { 1725fc537bfSLinus Walleij DRM_DEBUG_KMS("can't handle pitches\n"); 1735fc537bfSLinus Walleij return -EINVAL; 1745fc537bfSLinus Walleij } 1755fc537bfSLinus Walleij 1765fc537bfSLinus Walleij /* 1775fc537bfSLinus Walleij * We can't change the FB format in a flicker-free 1785fc537bfSLinus Walleij * manner (and only update it during CRTC enable). 1795fc537bfSLinus Walleij */ 1805fc537bfSLinus Walleij if (old_fb && old_fb->format != fb->format) 1815fc537bfSLinus Walleij cstate->mode_changed = true; 1825fc537bfSLinus Walleij } 1835fc537bfSLinus Walleij 1845fc537bfSLinus Walleij return 0; 1855fc537bfSLinus Walleij } 1865fc537bfSLinus Walleij 1875fc537bfSLinus Walleij static int mcde_configure_extsrc(struct mcde *mcde, enum mcde_extsrc src, 1885fc537bfSLinus Walleij u32 format) 1895fc537bfSLinus Walleij { 1905fc537bfSLinus Walleij u32 val; 1915fc537bfSLinus Walleij u32 conf; 1925fc537bfSLinus Walleij u32 cr; 1935fc537bfSLinus Walleij 1945fc537bfSLinus Walleij switch (src) { 1955fc537bfSLinus Walleij case MCDE_EXTSRC_0: 1965fc537bfSLinus Walleij conf = MCDE_EXTSRC0CONF; 1975fc537bfSLinus Walleij cr = MCDE_EXTSRC0CR; 1985fc537bfSLinus Walleij break; 1995fc537bfSLinus Walleij case MCDE_EXTSRC_1: 2005fc537bfSLinus Walleij conf = MCDE_EXTSRC1CONF; 2015fc537bfSLinus Walleij cr = MCDE_EXTSRC1CR; 2025fc537bfSLinus Walleij break; 2035fc537bfSLinus Walleij case MCDE_EXTSRC_2: 2045fc537bfSLinus Walleij conf = MCDE_EXTSRC2CONF; 2055fc537bfSLinus Walleij cr = MCDE_EXTSRC2CR; 2065fc537bfSLinus Walleij break; 2075fc537bfSLinus Walleij case MCDE_EXTSRC_3: 2085fc537bfSLinus Walleij conf = MCDE_EXTSRC3CONF; 2095fc537bfSLinus Walleij cr = MCDE_EXTSRC3CR; 2105fc537bfSLinus Walleij break; 2115fc537bfSLinus Walleij case MCDE_EXTSRC_4: 2125fc537bfSLinus Walleij conf = MCDE_EXTSRC4CONF; 2135fc537bfSLinus Walleij cr = MCDE_EXTSRC4CR; 2145fc537bfSLinus Walleij break; 2155fc537bfSLinus Walleij case MCDE_EXTSRC_5: 2165fc537bfSLinus Walleij conf = MCDE_EXTSRC5CONF; 2175fc537bfSLinus Walleij cr = MCDE_EXTSRC5CR; 2185fc537bfSLinus Walleij break; 2195fc537bfSLinus Walleij case MCDE_EXTSRC_6: 2205fc537bfSLinus Walleij conf = MCDE_EXTSRC6CONF; 2215fc537bfSLinus Walleij cr = MCDE_EXTSRC6CR; 2225fc537bfSLinus Walleij break; 2235fc537bfSLinus Walleij case MCDE_EXTSRC_7: 2245fc537bfSLinus Walleij conf = MCDE_EXTSRC7CONF; 2255fc537bfSLinus Walleij cr = MCDE_EXTSRC7CR; 2265fc537bfSLinus Walleij break; 2275fc537bfSLinus Walleij case MCDE_EXTSRC_8: 2285fc537bfSLinus Walleij conf = MCDE_EXTSRC8CONF; 2295fc537bfSLinus Walleij cr = MCDE_EXTSRC8CR; 2305fc537bfSLinus Walleij break; 2315fc537bfSLinus Walleij case MCDE_EXTSRC_9: 2325fc537bfSLinus Walleij conf = MCDE_EXTSRC9CONF; 2335fc537bfSLinus Walleij cr = MCDE_EXTSRC9CR; 2345fc537bfSLinus Walleij break; 2355fc537bfSLinus Walleij } 2365fc537bfSLinus Walleij 2375fc537bfSLinus Walleij /* 2385fc537bfSLinus Walleij * Configure external source 0 one buffer (buffer 0) 2395fc537bfSLinus Walleij * primary overlay ID 0. 2405fc537bfSLinus Walleij * From mcde_hw.c ovly_update_registers() in the vendor tree 2415fc537bfSLinus Walleij */ 2425fc537bfSLinus Walleij val = 0 << MCDE_EXTSRCXCONF_BUF_ID_SHIFT; 2435fc537bfSLinus Walleij val |= 1 << MCDE_EXTSRCXCONF_BUF_NB_SHIFT; 2445fc537bfSLinus Walleij val |= 0 << MCDE_EXTSRCXCONF_PRI_OVLID_SHIFT; 2455fc537bfSLinus Walleij /* 2465fc537bfSLinus Walleij * MCDE has inverse semantics from DRM on RBG/BGR which is why 2475fc537bfSLinus Walleij * all the modes are inversed here. 2485fc537bfSLinus Walleij */ 2495fc537bfSLinus Walleij switch (format) { 2505fc537bfSLinus Walleij case DRM_FORMAT_ARGB8888: 2515fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 << 2525fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2535fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2545fc537bfSLinus Walleij break; 2555fc537bfSLinus Walleij case DRM_FORMAT_ABGR8888: 2565fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 << 2575fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2585fc537bfSLinus Walleij break; 2595fc537bfSLinus Walleij case DRM_FORMAT_XRGB8888: 2605fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 << 2615fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2625fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2635fc537bfSLinus Walleij break; 2645fc537bfSLinus Walleij case DRM_FORMAT_XBGR8888: 2655fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 << 2665fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2675fc537bfSLinus Walleij break; 2685fc537bfSLinus Walleij case DRM_FORMAT_RGB888: 2695fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB888 << 2705fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2715fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2725fc537bfSLinus Walleij break; 2735fc537bfSLinus Walleij case DRM_FORMAT_BGR888: 2745fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB888 << 2755fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2765fc537bfSLinus Walleij break; 2775fc537bfSLinus Walleij case DRM_FORMAT_ARGB4444: 2785fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 << 2795fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2805fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2815fc537bfSLinus Walleij break; 2825fc537bfSLinus Walleij case DRM_FORMAT_ABGR4444: 2835fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 << 2845fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2855fc537bfSLinus Walleij break; 2865fc537bfSLinus Walleij case DRM_FORMAT_XRGB4444: 2875fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB444 << 2885fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2895fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2905fc537bfSLinus Walleij break; 2915fc537bfSLinus Walleij case DRM_FORMAT_XBGR4444: 2925fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB444 << 2935fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2945fc537bfSLinus Walleij break; 2955fc537bfSLinus Walleij case DRM_FORMAT_XRGB1555: 2965fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 << 2975fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2985fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2995fc537bfSLinus Walleij break; 3005fc537bfSLinus Walleij case DRM_FORMAT_XBGR1555: 3015fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 << 3025fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3035fc537bfSLinus Walleij break; 3045fc537bfSLinus Walleij case DRM_FORMAT_RGB565: 3055fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB565 << 3065fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3075fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 3085fc537bfSLinus Walleij break; 3095fc537bfSLinus Walleij case DRM_FORMAT_BGR565: 3105fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB565 << 3115fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3125fc537bfSLinus Walleij break; 3135fc537bfSLinus Walleij case DRM_FORMAT_YUV422: 3145fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_YCBCR422 << 3155fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3165fc537bfSLinus Walleij break; 3175fc537bfSLinus Walleij default: 3185fc537bfSLinus Walleij dev_err(mcde->dev, "Unknown pixel format 0x%08x\n", 3195fc537bfSLinus Walleij format); 3205fc537bfSLinus Walleij return -EINVAL; 3215fc537bfSLinus Walleij } 3225fc537bfSLinus Walleij writel(val, mcde->regs + conf); 3235fc537bfSLinus Walleij 3245fc537bfSLinus Walleij /* Software select, primary */ 3255fc537bfSLinus Walleij val = MCDE_EXTSRCXCR_SEL_MOD_SOFTWARE_SEL; 3265fc537bfSLinus Walleij val |= MCDE_EXTSRCXCR_MULTIOVL_CTRL_PRIMARY; 3275fc537bfSLinus Walleij writel(val, mcde->regs + cr); 3285fc537bfSLinus Walleij 3295fc537bfSLinus Walleij return 0; 3305fc537bfSLinus Walleij } 3315fc537bfSLinus Walleij 3325fc537bfSLinus Walleij static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, 3335fc537bfSLinus Walleij enum mcde_extsrc src, 3345fc537bfSLinus Walleij enum mcde_channel ch, 3355fc537bfSLinus Walleij const struct drm_display_mode *mode, 3365fc537bfSLinus Walleij u32 format) 3375fc537bfSLinus Walleij { 3385fc537bfSLinus Walleij u32 val; 3395fc537bfSLinus Walleij u32 conf1; 3405fc537bfSLinus Walleij u32 conf2; 3415fc537bfSLinus Walleij u32 crop; 3425fc537bfSLinus Walleij u32 ljinc; 3435fc537bfSLinus Walleij u32 cr; 3445fc537bfSLinus Walleij u32 comp; 3455fc537bfSLinus Walleij 3465fc537bfSLinus Walleij switch (ovl) { 3475fc537bfSLinus Walleij case MCDE_OVERLAY_0: 3485fc537bfSLinus Walleij conf1 = MCDE_OVL0CONF; 3495fc537bfSLinus Walleij conf2 = MCDE_OVL0CONF2; 3505fc537bfSLinus Walleij crop = MCDE_OVL0CROP; 3515fc537bfSLinus Walleij ljinc = MCDE_OVL0LJINC; 3525fc537bfSLinus Walleij cr = MCDE_OVL0CR; 3535fc537bfSLinus Walleij comp = MCDE_OVL0COMP; 3545fc537bfSLinus Walleij break; 3555fc537bfSLinus Walleij case MCDE_OVERLAY_1: 3565fc537bfSLinus Walleij conf1 = MCDE_OVL1CONF; 3575fc537bfSLinus Walleij conf2 = MCDE_OVL1CONF2; 3585fc537bfSLinus Walleij crop = MCDE_OVL1CROP; 3595fc537bfSLinus Walleij ljinc = MCDE_OVL1LJINC; 3605fc537bfSLinus Walleij cr = MCDE_OVL1CR; 3615fc537bfSLinus Walleij comp = MCDE_OVL1COMP; 3625fc537bfSLinus Walleij break; 3635fc537bfSLinus Walleij case MCDE_OVERLAY_2: 3645fc537bfSLinus Walleij conf1 = MCDE_OVL2CONF; 3655fc537bfSLinus Walleij conf2 = MCDE_OVL2CONF2; 3665fc537bfSLinus Walleij crop = MCDE_OVL2CROP; 3675fc537bfSLinus Walleij ljinc = MCDE_OVL2LJINC; 3685fc537bfSLinus Walleij cr = MCDE_OVL2CR; 3695fc537bfSLinus Walleij comp = MCDE_OVL2COMP; 3705fc537bfSLinus Walleij break; 3715fc537bfSLinus Walleij case MCDE_OVERLAY_3: 3725fc537bfSLinus Walleij conf1 = MCDE_OVL3CONF; 3735fc537bfSLinus Walleij conf2 = MCDE_OVL3CONF2; 3745fc537bfSLinus Walleij crop = MCDE_OVL3CROP; 3755fc537bfSLinus Walleij ljinc = MCDE_OVL3LJINC; 3765fc537bfSLinus Walleij cr = MCDE_OVL3CR; 3775fc537bfSLinus Walleij comp = MCDE_OVL3COMP; 3785fc537bfSLinus Walleij break; 3795fc537bfSLinus Walleij case MCDE_OVERLAY_4: 3805fc537bfSLinus Walleij conf1 = MCDE_OVL4CONF; 3815fc537bfSLinus Walleij conf2 = MCDE_OVL4CONF2; 3825fc537bfSLinus Walleij crop = MCDE_OVL4CROP; 3835fc537bfSLinus Walleij ljinc = MCDE_OVL4LJINC; 3845fc537bfSLinus Walleij cr = MCDE_OVL4CR; 3855fc537bfSLinus Walleij comp = MCDE_OVL4COMP; 3865fc537bfSLinus Walleij break; 3875fc537bfSLinus Walleij case MCDE_OVERLAY_5: 3885fc537bfSLinus Walleij conf1 = MCDE_OVL5CONF; 3895fc537bfSLinus Walleij conf2 = MCDE_OVL5CONF2; 3905fc537bfSLinus Walleij crop = MCDE_OVL5CROP; 3915fc537bfSLinus Walleij ljinc = MCDE_OVL5LJINC; 3925fc537bfSLinus Walleij cr = MCDE_OVL5CR; 3935fc537bfSLinus Walleij comp = MCDE_OVL5COMP; 3945fc537bfSLinus Walleij break; 3955fc537bfSLinus Walleij } 3965fc537bfSLinus Walleij 3975fc537bfSLinus Walleij val = mode->hdisplay << MCDE_OVLXCONF_PPL_SHIFT; 3985fc537bfSLinus Walleij val |= mode->vdisplay << MCDE_OVLXCONF_LPF_SHIFT; 3995fc537bfSLinus Walleij /* Use external source 0 that we just configured */ 4005fc537bfSLinus Walleij val |= src << MCDE_OVLXCONF_EXTSRC_ID_SHIFT; 4015fc537bfSLinus Walleij writel(val, mcde->regs + conf1); 4025fc537bfSLinus Walleij 4035fc537bfSLinus Walleij val = MCDE_OVLXCONF2_BP_PER_PIXEL_ALPHA; 4045fc537bfSLinus Walleij val |= 0xff << MCDE_OVLXCONF2_ALPHAVALUE_SHIFT; 4055fc537bfSLinus Walleij /* OPQ: overlay is opaque */ 4065fc537bfSLinus Walleij switch (format) { 4075fc537bfSLinus Walleij case DRM_FORMAT_ARGB8888: 4085fc537bfSLinus Walleij case DRM_FORMAT_ABGR8888: 4095fc537bfSLinus Walleij case DRM_FORMAT_ARGB4444: 4105fc537bfSLinus Walleij case DRM_FORMAT_ABGR4444: 4115fc537bfSLinus Walleij case DRM_FORMAT_XRGB1555: 4125fc537bfSLinus Walleij case DRM_FORMAT_XBGR1555: 4135fc537bfSLinus Walleij /* No OPQ */ 4145fc537bfSLinus Walleij break; 4155fc537bfSLinus Walleij case DRM_FORMAT_XRGB8888: 4165fc537bfSLinus Walleij case DRM_FORMAT_XBGR8888: 4175fc537bfSLinus Walleij case DRM_FORMAT_RGB888: 4185fc537bfSLinus Walleij case DRM_FORMAT_BGR888: 4195fc537bfSLinus Walleij case DRM_FORMAT_RGB565: 4205fc537bfSLinus Walleij case DRM_FORMAT_BGR565: 4215fc537bfSLinus Walleij case DRM_FORMAT_YUV422: 4225fc537bfSLinus Walleij val |= MCDE_OVLXCONF2_OPQ; 4235fc537bfSLinus Walleij break; 4245fc537bfSLinus Walleij default: 4255fc537bfSLinus Walleij dev_err(mcde->dev, "Unknown pixel format 0x%08x\n", 4265fc537bfSLinus Walleij format); 4275fc537bfSLinus Walleij break; 4285fc537bfSLinus Walleij } 4295fc537bfSLinus Walleij /* The default watermark level for overlay 0 is 48 */ 4305fc537bfSLinus Walleij val |= 48 << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; 4315fc537bfSLinus Walleij writel(val, mcde->regs + conf2); 4325fc537bfSLinus Walleij 4335fc537bfSLinus Walleij /* Number of bytes to fetch per line */ 4345fc537bfSLinus Walleij writel(mcde->stride, mcde->regs + ljinc); 4355fc537bfSLinus Walleij /* No cropping */ 4365fc537bfSLinus Walleij writel(0, mcde->regs + crop); 4375fc537bfSLinus Walleij 4385fc537bfSLinus Walleij /* Set up overlay control register */ 4395fc537bfSLinus Walleij val = MCDE_OVLXCR_OVLEN; 4405fc537bfSLinus Walleij val |= MCDE_OVLXCR_COLCCTRL_DISABLED; 4415fc537bfSLinus Walleij val |= MCDE_OVLXCR_BURSTSIZE_8W << 4425fc537bfSLinus Walleij MCDE_OVLXCR_BURSTSIZE_SHIFT; 4435fc537bfSLinus Walleij val |= MCDE_OVLXCR_MAXOUTSTANDING_8_REQ << 4445fc537bfSLinus Walleij MCDE_OVLXCR_MAXOUTSTANDING_SHIFT; 4455fc537bfSLinus Walleij /* Not using rotation but set it up anyways */ 4465fc537bfSLinus Walleij val |= MCDE_OVLXCR_ROTBURSTSIZE_8W << 4475fc537bfSLinus Walleij MCDE_OVLXCR_ROTBURSTSIZE_SHIFT; 4485fc537bfSLinus Walleij writel(val, mcde->regs + cr); 4495fc537bfSLinus Walleij 4505fc537bfSLinus Walleij /* 4515fc537bfSLinus Walleij * Set up the overlay compositor to route the overlay out to 4525fc537bfSLinus Walleij * the desired channel 4535fc537bfSLinus Walleij */ 4545fc537bfSLinus Walleij val = ch << MCDE_OVLXCOMP_CH_ID_SHIFT; 4555fc537bfSLinus Walleij writel(val, mcde->regs + comp); 4565fc537bfSLinus Walleij } 4575fc537bfSLinus Walleij 4585fc537bfSLinus Walleij static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch, 4595fc537bfSLinus Walleij enum mcde_fifo fifo, 4605fc537bfSLinus Walleij const struct drm_display_mode *mode) 4615fc537bfSLinus Walleij { 4625fc537bfSLinus Walleij u32 val; 4635fc537bfSLinus Walleij u32 conf; 4645fc537bfSLinus Walleij u32 sync; 4655fc537bfSLinus Walleij u32 stat; 4665fc537bfSLinus Walleij u32 bgcol; 4675fc537bfSLinus Walleij u32 mux; 4685fc537bfSLinus Walleij 4695fc537bfSLinus Walleij switch (ch) { 4705fc537bfSLinus Walleij case MCDE_CHANNEL_0: 4715fc537bfSLinus Walleij conf = MCDE_CHNL0CONF; 4725fc537bfSLinus Walleij sync = MCDE_CHNL0SYNCHMOD; 4735fc537bfSLinus Walleij stat = MCDE_CHNL0STAT; 4745fc537bfSLinus Walleij bgcol = MCDE_CHNL0BCKGNDCOL; 4755fc537bfSLinus Walleij mux = MCDE_CHNL0MUXING; 4765fc537bfSLinus Walleij break; 4775fc537bfSLinus Walleij case MCDE_CHANNEL_1: 4785fc537bfSLinus Walleij conf = MCDE_CHNL1CONF; 4795fc537bfSLinus Walleij sync = MCDE_CHNL1SYNCHMOD; 4805fc537bfSLinus Walleij stat = MCDE_CHNL1STAT; 4815fc537bfSLinus Walleij bgcol = MCDE_CHNL1BCKGNDCOL; 4825fc537bfSLinus Walleij mux = MCDE_CHNL1MUXING; 4835fc537bfSLinus Walleij break; 4845fc537bfSLinus Walleij case MCDE_CHANNEL_2: 4855fc537bfSLinus Walleij conf = MCDE_CHNL2CONF; 4865fc537bfSLinus Walleij sync = MCDE_CHNL2SYNCHMOD; 4875fc537bfSLinus Walleij stat = MCDE_CHNL2STAT; 4885fc537bfSLinus Walleij bgcol = MCDE_CHNL2BCKGNDCOL; 4895fc537bfSLinus Walleij mux = MCDE_CHNL2MUXING; 4905fc537bfSLinus Walleij break; 4915fc537bfSLinus Walleij case MCDE_CHANNEL_3: 4925fc537bfSLinus Walleij conf = MCDE_CHNL3CONF; 4935fc537bfSLinus Walleij sync = MCDE_CHNL3SYNCHMOD; 4945fc537bfSLinus Walleij stat = MCDE_CHNL3STAT; 4955fc537bfSLinus Walleij bgcol = MCDE_CHNL3BCKGNDCOL; 4965fc537bfSLinus Walleij mux = MCDE_CHNL3MUXING; 4975fc537bfSLinus Walleij return; 4985fc537bfSLinus Walleij } 4995fc537bfSLinus Walleij 5005fc537bfSLinus Walleij /* Set up channel 0 sync (based on chnl_update_registers()) */ 501d920e8daSStephan Gerhold if (mcde->video_mode || mcde->te_sync) 5025fc537bfSLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 5035fc537bfSLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 504d920e8daSStephan Gerhold else 5055fc537bfSLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE 5065fc537bfSLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 507d920e8daSStephan Gerhold 508d920e8daSStephan Gerhold if (mcde->te_sync) 509d920e8daSStephan Gerhold val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 510d920e8daSStephan Gerhold << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 511d920e8daSStephan Gerhold else 5125fc537bfSLinus Walleij val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER 5135fc537bfSLinus Walleij << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 514d920e8daSStephan Gerhold 5155fc537bfSLinus Walleij writel(val, mcde->regs + sync); 5165fc537bfSLinus Walleij 5175fc537bfSLinus Walleij /* Set up pixels per line and lines per frame */ 5185fc537bfSLinus Walleij val = (mode->hdisplay - 1) << MCDE_CHNLXCONF_PPL_SHIFT; 5195fc537bfSLinus Walleij val |= (mode->vdisplay - 1) << MCDE_CHNLXCONF_LPF_SHIFT; 5205fc537bfSLinus Walleij writel(val, mcde->regs + conf); 5215fc537bfSLinus Walleij 5225fc537bfSLinus Walleij /* 5235fc537bfSLinus Walleij * Normalize color conversion: 5245fc537bfSLinus Walleij * black background, OLED conversion disable on channel 5255fc537bfSLinus Walleij */ 5265fc537bfSLinus Walleij val = MCDE_CHNLXSTAT_CHNLBLBCKGND_EN | 5275fc537bfSLinus Walleij MCDE_CHNLXSTAT_CHNLRD; 5285fc537bfSLinus Walleij writel(val, mcde->regs + stat); 5295fc537bfSLinus Walleij writel(0, mcde->regs + bgcol); 5305fc537bfSLinus Walleij 5315fc537bfSLinus Walleij /* Set up muxing: connect the channel to the desired FIFO */ 5325fc537bfSLinus Walleij switch (fifo) { 5335fc537bfSLinus Walleij case MCDE_FIFO_A: 5345fc537bfSLinus Walleij writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_A, 5355fc537bfSLinus Walleij mcde->regs + mux); 5365fc537bfSLinus Walleij break; 5375fc537bfSLinus Walleij case MCDE_FIFO_B: 5385fc537bfSLinus Walleij writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_B, 5395fc537bfSLinus Walleij mcde->regs + mux); 5405fc537bfSLinus Walleij break; 5415fc537bfSLinus Walleij } 5425fc537bfSLinus Walleij } 5435fc537bfSLinus Walleij 5445fc537bfSLinus Walleij static void mcde_configure_fifo(struct mcde *mcde, enum mcde_fifo fifo, 5455fc537bfSLinus Walleij enum mcde_dsi_formatter fmt, 5465fc537bfSLinus Walleij int fifo_wtrmrk) 5475fc537bfSLinus Walleij { 5485fc537bfSLinus Walleij u32 val; 5495fc537bfSLinus Walleij u32 ctrl; 5505fc537bfSLinus Walleij u32 cr0, cr1; 5515fc537bfSLinus Walleij 5525fc537bfSLinus Walleij switch (fifo) { 5535fc537bfSLinus Walleij case MCDE_FIFO_A: 5545fc537bfSLinus Walleij ctrl = MCDE_CTRLA; 5555fc537bfSLinus Walleij cr0 = MCDE_CRA0; 5565fc537bfSLinus Walleij cr1 = MCDE_CRA1; 5575fc537bfSLinus Walleij break; 5585fc537bfSLinus Walleij case MCDE_FIFO_B: 5595fc537bfSLinus Walleij ctrl = MCDE_CTRLB; 5605fc537bfSLinus Walleij cr0 = MCDE_CRB0; 5615fc537bfSLinus Walleij cr1 = MCDE_CRB1; 5625fc537bfSLinus Walleij break; 5635fc537bfSLinus Walleij } 5645fc537bfSLinus Walleij 5655fc537bfSLinus Walleij val = fifo_wtrmrk << MCDE_CTRLX_FIFOWTRMRK_SHIFT; 5665fc537bfSLinus Walleij /* We only support DSI formatting for now */ 5675fc537bfSLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << 5685fc537bfSLinus Walleij MCDE_CTRLX_FORMTYPE_SHIFT; 5695fc537bfSLinus Walleij 5705fc537bfSLinus Walleij /* Select the formatter to use for this FIFO */ 5715fc537bfSLinus Walleij val |= fmt << MCDE_CTRLX_FORMID_SHIFT; 5725fc537bfSLinus Walleij writel(val, mcde->regs + ctrl); 5735fc537bfSLinus Walleij 5745fc537bfSLinus Walleij /* Blend source with Alpha 0xff on FIFO */ 5755fc537bfSLinus Walleij val = MCDE_CRX0_BLENDEN | 5765fc537bfSLinus Walleij 0xff << MCDE_CRX0_ALPHABLEND_SHIFT; 5775fc537bfSLinus Walleij writel(val, mcde->regs + cr0); 5785fc537bfSLinus Walleij 5795fc537bfSLinus Walleij /* Set-up from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */ 5805fc537bfSLinus Walleij 5815fc537bfSLinus Walleij /* Use the MCDE clock for this FIFO */ 5825fc537bfSLinus Walleij val = MCDE_CRX1_CLKSEL_MCDECLK << MCDE_CRX1_CLKSEL_SHIFT; 5835fc537bfSLinus Walleij 5845fc537bfSLinus Walleij /* TODO: when adding DPI support add OUTBPP etc here */ 5855fc537bfSLinus Walleij writel(val, mcde->regs + cr1); 5865fc537bfSLinus Walleij }; 5875fc537bfSLinus Walleij 5885fc537bfSLinus Walleij static void mcde_configure_dsi_formatter(struct mcde *mcde, 5895fc537bfSLinus Walleij enum mcde_dsi_formatter fmt, 5905fc537bfSLinus Walleij u32 formatter_frame, 5915fc537bfSLinus Walleij int pkt_size) 5925fc537bfSLinus Walleij { 5935fc537bfSLinus Walleij u32 val; 5945fc537bfSLinus Walleij u32 conf0; 5955fc537bfSLinus Walleij u32 frame; 5965fc537bfSLinus Walleij u32 pkt; 5975fc537bfSLinus Walleij u32 sync; 5985fc537bfSLinus Walleij u32 cmdw; 5995fc537bfSLinus Walleij u32 delay0, delay1; 6005fc537bfSLinus Walleij 6015fc537bfSLinus Walleij switch (fmt) { 6025fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_0: 6035fc537bfSLinus Walleij conf0 = MCDE_DSIVID0CONF0; 6045fc537bfSLinus Walleij frame = MCDE_DSIVID0FRAME; 6055fc537bfSLinus Walleij pkt = MCDE_DSIVID0PKT; 6065fc537bfSLinus Walleij sync = MCDE_DSIVID0SYNC; 6075fc537bfSLinus Walleij cmdw = MCDE_DSIVID0CMDW; 6085fc537bfSLinus Walleij delay0 = MCDE_DSIVID0DELAY0; 6095fc537bfSLinus Walleij delay1 = MCDE_DSIVID0DELAY1; 6105fc537bfSLinus Walleij break; 6115fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_1: 6125fc537bfSLinus Walleij conf0 = MCDE_DSIVID1CONF0; 6135fc537bfSLinus Walleij frame = MCDE_DSIVID1FRAME; 6145fc537bfSLinus Walleij pkt = MCDE_DSIVID1PKT; 6155fc537bfSLinus Walleij sync = MCDE_DSIVID1SYNC; 6165fc537bfSLinus Walleij cmdw = MCDE_DSIVID1CMDW; 6175fc537bfSLinus Walleij delay0 = MCDE_DSIVID1DELAY0; 6185fc537bfSLinus Walleij delay1 = MCDE_DSIVID1DELAY1; 6195fc537bfSLinus Walleij break; 6205fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_2: 6215fc537bfSLinus Walleij conf0 = MCDE_DSIVID2CONF0; 6225fc537bfSLinus Walleij frame = MCDE_DSIVID2FRAME; 6235fc537bfSLinus Walleij pkt = MCDE_DSIVID2PKT; 6245fc537bfSLinus Walleij sync = MCDE_DSIVID2SYNC; 6255fc537bfSLinus Walleij cmdw = MCDE_DSIVID2CMDW; 6265fc537bfSLinus Walleij delay0 = MCDE_DSIVID2DELAY0; 6275fc537bfSLinus Walleij delay1 = MCDE_DSIVID2DELAY1; 6285fc537bfSLinus Walleij break; 6295fc537bfSLinus Walleij } 6305fc537bfSLinus Walleij 6315fc537bfSLinus Walleij /* 6325fc537bfSLinus Walleij * Enable formatter 6335fc537bfSLinus Walleij * 8 bit commands and DCS commands (notgen = not generic) 6345fc537bfSLinus Walleij */ 6355fc537bfSLinus Walleij val = MCDE_DSICONF0_CMD8 | MCDE_DSICONF0_DCSVID_NOTGEN; 6365fc537bfSLinus Walleij if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) 6375fc537bfSLinus Walleij val |= MCDE_DSICONF0_VID_MODE_VID; 6385fc537bfSLinus Walleij switch (mcde->mdsi->format) { 6395fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB888: 6405fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB888 << 6415fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 6425fc537bfSLinus Walleij break; 6435fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB666: 6445fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB666 << 6455fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 6465fc537bfSLinus Walleij break; 6475fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB666_PACKED: 6485fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB666_PACKED << 6495fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 6505fc537bfSLinus Walleij break; 6515fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB565: 6525fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB565 << 6535fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 6545fc537bfSLinus Walleij break; 6555fc537bfSLinus Walleij default: 6565fc537bfSLinus Walleij dev_err(mcde->dev, "unknown DSI format\n"); 6575fc537bfSLinus Walleij return; 6585fc537bfSLinus Walleij } 6595fc537bfSLinus Walleij writel(val, mcde->regs + conf0); 6605fc537bfSLinus Walleij 6615fc537bfSLinus Walleij writel(formatter_frame, mcde->regs + frame); 6625fc537bfSLinus Walleij writel(pkt_size, mcde->regs + pkt); 6635fc537bfSLinus Walleij writel(0, mcde->regs + sync); 6645fc537bfSLinus Walleij /* Define the MIPI command: we want to write into display memory */ 6655fc537bfSLinus Walleij val = MIPI_DCS_WRITE_MEMORY_CONTINUE << 6665fc537bfSLinus Walleij MCDE_DSIVIDXCMDW_CMDW_CONTINUE_SHIFT; 6675fc537bfSLinus Walleij val |= MIPI_DCS_WRITE_MEMORY_START << 6685fc537bfSLinus Walleij MCDE_DSIVIDXCMDW_CMDW_START_SHIFT; 6695fc537bfSLinus Walleij writel(val, mcde->regs + cmdw); 6705fc537bfSLinus Walleij 6715fc537bfSLinus Walleij /* 6725fc537bfSLinus Walleij * FIXME: the vendor driver has some hack around this value in 6735fc537bfSLinus Walleij * CMD mode with autotrig. 6745fc537bfSLinus Walleij */ 6755fc537bfSLinus Walleij writel(0, mcde->regs + delay0); 6765fc537bfSLinus Walleij writel(0, mcde->regs + delay1); 6775fc537bfSLinus Walleij } 6785fc537bfSLinus Walleij 6795fc537bfSLinus Walleij static void mcde_enable_fifo(struct mcde *mcde, enum mcde_fifo fifo) 6805fc537bfSLinus Walleij { 6815fc537bfSLinus Walleij u32 val; 6825fc537bfSLinus Walleij u32 cr; 6835fc537bfSLinus Walleij 6845fc537bfSLinus Walleij switch (fifo) { 6855fc537bfSLinus Walleij case MCDE_FIFO_A: 6865fc537bfSLinus Walleij cr = MCDE_CRA0; 6875fc537bfSLinus Walleij break; 6885fc537bfSLinus Walleij case MCDE_FIFO_B: 6895fc537bfSLinus Walleij cr = MCDE_CRB0; 6905fc537bfSLinus Walleij break; 6915fc537bfSLinus Walleij default: 6925fc537bfSLinus Walleij dev_err(mcde->dev, "cannot enable FIFO %c\n", 6935fc537bfSLinus Walleij 'A' + fifo); 6945fc537bfSLinus Walleij return; 6955fc537bfSLinus Walleij } 6965fc537bfSLinus Walleij 6975fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 6985fc537bfSLinus Walleij val = readl(mcde->regs + cr); 6995fc537bfSLinus Walleij val |= MCDE_CRX0_FLOEN; 7005fc537bfSLinus Walleij writel(val, mcde->regs + cr); 7015fc537bfSLinus Walleij mcde->flow_active++; 7025fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 7035fc537bfSLinus Walleij } 7045fc537bfSLinus Walleij 7055fc537bfSLinus Walleij static void mcde_disable_fifo(struct mcde *mcde, enum mcde_fifo fifo, 7065fc537bfSLinus Walleij bool wait_for_drain) 7075fc537bfSLinus Walleij { 7085fc537bfSLinus Walleij int timeout = 100; 7095fc537bfSLinus Walleij u32 val; 7105fc537bfSLinus Walleij u32 cr; 7115fc537bfSLinus Walleij 7125fc537bfSLinus Walleij switch (fifo) { 7135fc537bfSLinus Walleij case MCDE_FIFO_A: 7145fc537bfSLinus Walleij cr = MCDE_CRA0; 7155fc537bfSLinus Walleij break; 7165fc537bfSLinus Walleij case MCDE_FIFO_B: 7175fc537bfSLinus Walleij cr = MCDE_CRB0; 7185fc537bfSLinus Walleij break; 7195fc537bfSLinus Walleij default: 7205fc537bfSLinus Walleij dev_err(mcde->dev, "cannot disable FIFO %c\n", 7215fc537bfSLinus Walleij 'A' + fifo); 7225fc537bfSLinus Walleij return; 7235fc537bfSLinus Walleij } 7245fc537bfSLinus Walleij 7255fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 7265fc537bfSLinus Walleij val = readl(mcde->regs + cr); 7275fc537bfSLinus Walleij val &= ~MCDE_CRX0_FLOEN; 7285fc537bfSLinus Walleij writel(val, mcde->regs + cr); 7295fc537bfSLinus Walleij mcde->flow_active = 0; 7305fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 7315fc537bfSLinus Walleij 7325fc537bfSLinus Walleij if (!wait_for_drain) 7335fc537bfSLinus Walleij return; 7345fc537bfSLinus Walleij 7355fc537bfSLinus Walleij /* Check that we really drained and stopped the flow */ 7365fc537bfSLinus Walleij while (readl(mcde->regs + cr) & MCDE_CRX0_FLOEN) { 7375fc537bfSLinus Walleij usleep_range(1000, 1500); 7385fc537bfSLinus Walleij if (!--timeout) { 7395fc537bfSLinus Walleij dev_err(mcde->dev, 7405fc537bfSLinus Walleij "FIFO timeout while clearing FIFO %c\n", 7415fc537bfSLinus Walleij 'A' + fifo); 7425fc537bfSLinus Walleij return; 7435fc537bfSLinus Walleij } 7445fc537bfSLinus Walleij } 7455fc537bfSLinus Walleij } 7465fc537bfSLinus Walleij 7475fc537bfSLinus Walleij /* 7485fc537bfSLinus Walleij * This drains a pipe i.e. a FIFO connected to a certain channel 7495fc537bfSLinus Walleij */ 7505fc537bfSLinus Walleij static void mcde_drain_pipe(struct mcde *mcde, enum mcde_fifo fifo, 7515fc537bfSLinus Walleij enum mcde_channel ch) 7525fc537bfSLinus Walleij { 7535fc537bfSLinus Walleij u32 val; 7545fc537bfSLinus Walleij u32 ctrl; 7555fc537bfSLinus Walleij u32 synsw; 7565fc537bfSLinus Walleij 7575fc537bfSLinus Walleij switch (fifo) { 7585fc537bfSLinus Walleij case MCDE_FIFO_A: 7595fc537bfSLinus Walleij ctrl = MCDE_CTRLA; 7605fc537bfSLinus Walleij break; 7615fc537bfSLinus Walleij case MCDE_FIFO_B: 7625fc537bfSLinus Walleij ctrl = MCDE_CTRLB; 7635fc537bfSLinus Walleij break; 7645fc537bfSLinus Walleij } 7655fc537bfSLinus Walleij 7665fc537bfSLinus Walleij switch (ch) { 7675fc537bfSLinus Walleij case MCDE_CHANNEL_0: 7685fc537bfSLinus Walleij synsw = MCDE_CHNL0SYNCHSW; 7695fc537bfSLinus Walleij break; 7705fc537bfSLinus Walleij case MCDE_CHANNEL_1: 7715fc537bfSLinus Walleij synsw = MCDE_CHNL1SYNCHSW; 7725fc537bfSLinus Walleij break; 7735fc537bfSLinus Walleij case MCDE_CHANNEL_2: 7745fc537bfSLinus Walleij synsw = MCDE_CHNL2SYNCHSW; 7755fc537bfSLinus Walleij break; 7765fc537bfSLinus Walleij case MCDE_CHANNEL_3: 7775fc537bfSLinus Walleij synsw = MCDE_CHNL3SYNCHSW; 7785fc537bfSLinus Walleij return; 7795fc537bfSLinus Walleij } 7805fc537bfSLinus Walleij 7815fc537bfSLinus Walleij val = readl(mcde->regs + ctrl); 7825fc537bfSLinus Walleij if (!(val & MCDE_CTRLX_FIFOEMPTY)) { 7835fc537bfSLinus Walleij dev_err(mcde->dev, "Channel A FIFO not empty (handover)\n"); 7845fc537bfSLinus Walleij /* Attempt to clear the FIFO */ 7855fc537bfSLinus Walleij mcde_enable_fifo(mcde, fifo); 7865fc537bfSLinus Walleij /* Trigger a software sync out on respective channel (0-3) */ 7875fc537bfSLinus Walleij writel(MCDE_CHNLXSYNCHSW_SW_TRIG, mcde->regs + synsw); 7885fc537bfSLinus Walleij /* Disable FIFO A flow again */ 7895fc537bfSLinus Walleij mcde_disable_fifo(mcde, fifo, true); 7905fc537bfSLinus Walleij } 7915fc537bfSLinus Walleij } 7925fc537bfSLinus Walleij 7935fc537bfSLinus Walleij static int mcde_dsi_get_pkt_div(int ppl, int fifo_size) 7945fc537bfSLinus Walleij { 7955fc537bfSLinus Walleij /* 7965fc537bfSLinus Walleij * DSI command mode line packets should be split into an even number of 7975fc537bfSLinus Walleij * packets smaller than or equal to the fifo size. 7985fc537bfSLinus Walleij */ 7995fc537bfSLinus Walleij int div; 8005fc537bfSLinus Walleij const int max_div = DIV_ROUND_UP(MCDE_MAX_WIDTH, fifo_size); 8015fc537bfSLinus Walleij 8025fc537bfSLinus Walleij for (div = 1; div < max_div; div++) 8035fc537bfSLinus Walleij if (ppl % div == 0 && ppl / div <= fifo_size) 8045fc537bfSLinus Walleij return div; 8055fc537bfSLinus Walleij return 1; 8065fc537bfSLinus Walleij } 8075fc537bfSLinus Walleij 8085fc537bfSLinus Walleij static void mcde_display_enable(struct drm_simple_display_pipe *pipe, 8095fc537bfSLinus Walleij struct drm_crtc_state *cstate, 8105fc537bfSLinus Walleij struct drm_plane_state *plane_state) 8115fc537bfSLinus Walleij { 8125fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 8135fc537bfSLinus Walleij struct drm_plane *plane = &pipe->plane; 8145fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 8155fc537bfSLinus Walleij struct mcde *mcde = drm->dev_private; 8165fc537bfSLinus Walleij const struct drm_display_mode *mode = &cstate->mode; 8175fc537bfSLinus Walleij struct drm_framebuffer *fb = plane->state->fb; 8185fc537bfSLinus Walleij u32 format = fb->format->format; 8195fc537bfSLinus Walleij u32 formatter_ppl = mode->hdisplay; /* pixels per line */ 8205fc537bfSLinus Walleij u32 formatter_lpf = mode->vdisplay; /* lines per frame */ 8215fc537bfSLinus Walleij int pkt_size, fifo_wtrmrk; 822182c58abSSam Ravnborg int cpp = fb->format->cpp[0]; 8235fc537bfSLinus Walleij int formatter_cpp; 8245fc537bfSLinus Walleij struct drm_format_name_buf tmp; 8255fc537bfSLinus Walleij u32 formatter_frame; 8265fc537bfSLinus Walleij u32 pkt_div; 8275fc537bfSLinus Walleij u32 val; 8285fc537bfSLinus Walleij 8295fc537bfSLinus Walleij dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", 8305fc537bfSLinus Walleij mode->hdisplay, mode->vdisplay, 8315fc537bfSLinus Walleij drm_get_format_name(format, &tmp)); 8325fc537bfSLinus Walleij if (!mcde->mdsi) { 8335fc537bfSLinus Walleij /* TODO: deal with this for non-DSI output */ 8345fc537bfSLinus Walleij dev_err(drm->dev, "no DSI master attached!\n"); 8355fc537bfSLinus Walleij return; 8365fc537bfSLinus Walleij } 8375fc537bfSLinus Walleij 8385fc537bfSLinus Walleij dev_info(drm->dev, "output in %s mode, format %dbpp\n", 8395fc537bfSLinus Walleij (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? 8405fc537bfSLinus Walleij "VIDEO" : "CMD", 8415fc537bfSLinus Walleij mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format)); 8425fc537bfSLinus Walleij formatter_cpp = 8435fc537bfSLinus Walleij mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format) / 8; 8445fc537bfSLinus Walleij dev_info(drm->dev, "overlay CPP %d bytes, DSI CPP %d bytes\n", 8455fc537bfSLinus Walleij cpp, 8465fc537bfSLinus Walleij formatter_cpp); 8475fc537bfSLinus Walleij 8485fc537bfSLinus Walleij /* Calculations from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */ 8495fc537bfSLinus Walleij 8505fc537bfSLinus Walleij /* 8515fc537bfSLinus Walleij * Set up FIFO A watermark level: 8525fc537bfSLinus Walleij * 128 for LCD 32bpp video mode 8535fc537bfSLinus Walleij * 48 for LCD 32bpp command mode 8545fc537bfSLinus Walleij * 128 for LCD 16bpp video mode 8555fc537bfSLinus Walleij * 64 for LCD 16bpp command mode 8565fc537bfSLinus Walleij * 128 for HDMI 32bpp 8575fc537bfSLinus Walleij * 192 for HDMI 16bpp 8585fc537bfSLinus Walleij */ 8595fc537bfSLinus Walleij fifo_wtrmrk = mode->hdisplay; 8605fc537bfSLinus Walleij if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 8615fc537bfSLinus Walleij fifo_wtrmrk = min(fifo_wtrmrk, 128); 8625fc537bfSLinus Walleij pkt_div = 1; 8635fc537bfSLinus Walleij } else { 8645fc537bfSLinus Walleij fifo_wtrmrk = min(fifo_wtrmrk, 48); 8655fc537bfSLinus Walleij /* The FIFO is 640 entries deep on this v3 hardware */ 8665fc537bfSLinus Walleij pkt_div = mcde_dsi_get_pkt_div(mode->hdisplay, 640); 8675fc537bfSLinus Walleij } 8685fc537bfSLinus Walleij dev_dbg(drm->dev, "FIFO watermark after flooring: %d bytes\n", 8695fc537bfSLinus Walleij fifo_wtrmrk); 8705fc537bfSLinus Walleij dev_dbg(drm->dev, "Packet divisor: %d bytes\n", pkt_div); 8715fc537bfSLinus Walleij 8725fc537bfSLinus Walleij /* NOTE: pkt_div is 1 for video mode */ 8735fc537bfSLinus Walleij pkt_size = (formatter_ppl * formatter_cpp) / pkt_div; 8745fc537bfSLinus Walleij /* Commands CMD8 need one extra byte */ 8755fc537bfSLinus Walleij if (!(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)) 8765fc537bfSLinus Walleij pkt_size++; 8775fc537bfSLinus Walleij 8785fc537bfSLinus Walleij dev_dbg(drm->dev, "DSI packet size: %d * %d bytes per line\n", 8795fc537bfSLinus Walleij pkt_size, pkt_div); 8805fc537bfSLinus Walleij dev_dbg(drm->dev, "Overlay frame size: %u bytes\n", 8815fc537bfSLinus Walleij mode->hdisplay * mode->vdisplay * cpp); 8825fc537bfSLinus Walleij mcde->stride = mode->hdisplay * cpp; 8835fc537bfSLinus Walleij dev_dbg(drm->dev, "Overlay line stride: %u bytes\n", 8845fc537bfSLinus Walleij mcde->stride); 8855fc537bfSLinus Walleij /* NOTE: pkt_div is 1 for video mode */ 8865fc537bfSLinus Walleij formatter_frame = pkt_size * pkt_div * formatter_lpf; 8875fc537bfSLinus Walleij dev_dbg(drm->dev, "Formatter frame size: %u bytes\n", formatter_frame); 8885fc537bfSLinus Walleij 8895fc537bfSLinus Walleij /* Drain the FIFO A + channel 0 pipe so we have a clean slate */ 8905fc537bfSLinus Walleij mcde_drain_pipe(mcde, MCDE_FIFO_A, MCDE_CHANNEL_0); 8915fc537bfSLinus Walleij 8925fc537bfSLinus Walleij /* 8935fc537bfSLinus Walleij * We set up our display pipeline: 8945fc537bfSLinus Walleij * EXTSRC 0 -> OVERLAY 0 -> CHANNEL 0 -> FIFO A -> DSI FORMATTER 0 8955fc537bfSLinus Walleij * 8965fc537bfSLinus Walleij * First configure the external source (memory) on external source 0 8975fc537bfSLinus Walleij * using the desired bitstream/bitmap format 8985fc537bfSLinus Walleij */ 8995fc537bfSLinus Walleij mcde_configure_extsrc(mcde, MCDE_EXTSRC_0, format); 9005fc537bfSLinus Walleij 9015fc537bfSLinus Walleij /* 9025fc537bfSLinus Walleij * Configure overlay 0 according to format and mode and take input 9035fc537bfSLinus Walleij * from external source 0 and route the output of this overlay to 9045fc537bfSLinus Walleij * channel 0 9055fc537bfSLinus Walleij */ 9065fc537bfSLinus Walleij mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0, 9075fc537bfSLinus Walleij MCDE_CHANNEL_0, mode, format); 9085fc537bfSLinus Walleij 9095fc537bfSLinus Walleij /* 9105fc537bfSLinus Walleij * Configure pixel-per-line and line-per-frame for channel 0 and then 9115fc537bfSLinus Walleij * route channel 0 to FIFO A 9125fc537bfSLinus Walleij */ 9135fc537bfSLinus Walleij mcde_configure_channel(mcde, MCDE_CHANNEL_0, MCDE_FIFO_A, mode); 9145fc537bfSLinus Walleij 9155fc537bfSLinus Walleij /* Configure FIFO A to use DSI formatter 0 */ 9165fc537bfSLinus Walleij mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, 9175fc537bfSLinus Walleij fifo_wtrmrk); 9185fc537bfSLinus Walleij 9195fc537bfSLinus Walleij /* Configure the DSI formatter 0 for the DSI panel output */ 9205fc537bfSLinus Walleij mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, 9215fc537bfSLinus Walleij formatter_frame, pkt_size); 9225fc537bfSLinus Walleij 9235fc537bfSLinus Walleij if (mcde->te_sync) { 9245fc537bfSLinus Walleij if (mode->flags & DRM_MODE_FLAG_NVSYNC) 9255fc537bfSLinus Walleij val = MCDE_VSCRC_VSPOL; 9265fc537bfSLinus Walleij else 9275fc537bfSLinus Walleij val = 0; 9285fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_VSCRC0); 9295fc537bfSLinus Walleij /* Enable VSYNC capture on TE0 */ 9305fc537bfSLinus Walleij val = readl(mcde->regs + MCDE_CRC); 9315fc537bfSLinus Walleij val |= MCDE_CRC_SYCEN0; 9325fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_CRC); 933768859c2SStephan Gerhold } 9345fc537bfSLinus Walleij 9355fc537bfSLinus Walleij drm_crtc_vblank_on(crtc); 9365fc537bfSLinus Walleij 937d920e8daSStephan Gerhold if (mcde->video_mode) 938d920e8daSStephan Gerhold /* 939d920e8daSStephan Gerhold * Keep FIFO permanently enabled in video mode, 940d920e8daSStephan Gerhold * otherwise MCDE will stop feeding data to the panel. 941d920e8daSStephan Gerhold */ 942d920e8daSStephan Gerhold mcde_enable_fifo(mcde, MCDE_FIFO_A); 943d920e8daSStephan Gerhold 9445fc537bfSLinus Walleij dev_info(drm->dev, "MCDE display is enabled\n"); 9455fc537bfSLinus Walleij } 9465fc537bfSLinus Walleij 9475fc537bfSLinus Walleij static void mcde_display_disable(struct drm_simple_display_pipe *pipe) 9485fc537bfSLinus Walleij { 9495fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 9505fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 951fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 95297de8636SStephan Gerhold struct drm_pending_vblank_event *event; 9535fc537bfSLinus Walleij 9545fc537bfSLinus Walleij drm_crtc_vblank_off(crtc); 9555fc537bfSLinus Walleij 9565fc537bfSLinus Walleij /* Disable FIFO A flow */ 9575fc537bfSLinus Walleij mcde_disable_fifo(mcde, MCDE_FIFO_A, true); 9585fc537bfSLinus Walleij 95997de8636SStephan Gerhold event = crtc->state->event; 96097de8636SStephan Gerhold if (event) { 96197de8636SStephan Gerhold crtc->state->event = NULL; 96297de8636SStephan Gerhold 96397de8636SStephan Gerhold spin_lock_irq(&crtc->dev->event_lock); 96497de8636SStephan Gerhold drm_crtc_send_vblank_event(crtc, event); 96597de8636SStephan Gerhold spin_unlock_irq(&crtc->dev->event_lock); 96697de8636SStephan Gerhold } 96797de8636SStephan Gerhold 9685fc537bfSLinus Walleij dev_info(drm->dev, "MCDE display is disabled\n"); 9695fc537bfSLinus Walleij } 9705fc537bfSLinus Walleij 9715fc537bfSLinus Walleij static void mcde_display_send_one_frame(struct mcde *mcde) 9725fc537bfSLinus Walleij { 9735fc537bfSLinus Walleij /* Request a TE ACK */ 9745fc537bfSLinus Walleij if (mcde->te_sync) 9755fc537bfSLinus Walleij mcde_dsi_te_request(mcde->mdsi); 9765fc537bfSLinus Walleij 9775fc537bfSLinus Walleij /* Enable FIFO A flow */ 9785fc537bfSLinus Walleij mcde_enable_fifo(mcde, MCDE_FIFO_A); 9795fc537bfSLinus Walleij 9805fc537bfSLinus Walleij if (mcde->te_sync) { 9815fc537bfSLinus Walleij /* 9825fc537bfSLinus Walleij * If oneshot mode is enabled, the flow will be disabled 9835fc537bfSLinus Walleij * when the TE0 IRQ arrives in the interrupt handler. Otherwise 9845fc537bfSLinus Walleij * updates are continuously streamed to the display after this 9855fc537bfSLinus Walleij * point. 9865fc537bfSLinus Walleij */ 9875fc537bfSLinus Walleij dev_dbg(mcde->dev, "sent TE0 framebuffer update\n"); 9885fc537bfSLinus Walleij return; 9895fc537bfSLinus Walleij } 9905fc537bfSLinus Walleij 9915fc537bfSLinus Walleij /* Trigger a software sync out on channel 0 */ 9925fc537bfSLinus Walleij writel(MCDE_CHNLXSYNCHSW_SW_TRIG, 9935fc537bfSLinus Walleij mcde->regs + MCDE_CHNL0SYNCHSW); 9945fc537bfSLinus Walleij 9955fc537bfSLinus Walleij /* 9965fc537bfSLinus Walleij * Disable FIFO A flow again: since we are using TE sync we 9975fc537bfSLinus Walleij * need to wait for the FIFO to drain before we continue 9985fc537bfSLinus Walleij * so repeated calls to this function will not cause a mess 9995fc537bfSLinus Walleij * in the hardware by pushing updates will updates are going 10005fc537bfSLinus Walleij * on already. 10015fc537bfSLinus Walleij */ 10025fc537bfSLinus Walleij mcde_disable_fifo(mcde, MCDE_FIFO_A, true); 10035fc537bfSLinus Walleij 10045fc537bfSLinus Walleij dev_dbg(mcde->dev, "sent SW framebuffer update\n"); 10055fc537bfSLinus Walleij } 10065fc537bfSLinus Walleij 10075fc537bfSLinus Walleij static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) 10085fc537bfSLinus Walleij { 10095fc537bfSLinus Walleij /* Write bitmap base address to register */ 10105fc537bfSLinus Walleij writel(buffer_address, mcde->regs + MCDE_EXTSRCXA0); 10115fc537bfSLinus Walleij /* 10125fc537bfSLinus Walleij * Base address for next line this is probably only used 10135fc537bfSLinus Walleij * in interlace modes. 10145fc537bfSLinus Walleij */ 10155fc537bfSLinus Walleij writel(buffer_address + mcde->stride, mcde->regs + MCDE_EXTSRCXA1); 10165fc537bfSLinus Walleij } 10175fc537bfSLinus Walleij 10185fc537bfSLinus Walleij static void mcde_display_update(struct drm_simple_display_pipe *pipe, 10195fc537bfSLinus Walleij struct drm_plane_state *old_pstate) 10205fc537bfSLinus Walleij { 10215fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 10225fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1023fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 10245fc537bfSLinus Walleij struct drm_pending_vblank_event *event = crtc->state->event; 10255fc537bfSLinus Walleij struct drm_plane *plane = &pipe->plane; 10265fc537bfSLinus Walleij struct drm_plane_state *pstate = plane->state; 10275fc537bfSLinus Walleij struct drm_framebuffer *fb = pstate->fb; 10285fc537bfSLinus Walleij 10295fc537bfSLinus Walleij /* 10305fc537bfSLinus Walleij * Handle any pending event first, we need to arm the vblank 10315fc537bfSLinus Walleij * interrupt before sending any update to the display so we don't 10325fc537bfSLinus Walleij * miss the interrupt. 10335fc537bfSLinus Walleij */ 10345fc537bfSLinus Walleij if (event) { 10355fc537bfSLinus Walleij crtc->state->event = NULL; 10365fc537bfSLinus Walleij 10375fc537bfSLinus Walleij spin_lock_irq(&crtc->dev->event_lock); 10385fc537bfSLinus Walleij /* 10395fc537bfSLinus Walleij * Hardware must be on before we can arm any vblank event, 10405fc537bfSLinus Walleij * this is not a scanout controller where there is always 10415fc537bfSLinus Walleij * some periodic update going on, it is completely frozen 10425fc537bfSLinus Walleij * until we get an update. If MCDE output isn't yet enabled, 10435fc537bfSLinus Walleij * we just send a vblank dummy event back. 10445fc537bfSLinus Walleij */ 10455fc537bfSLinus Walleij if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) { 10465fc537bfSLinus Walleij dev_dbg(mcde->dev, "arm vblank event\n"); 10475fc537bfSLinus Walleij drm_crtc_arm_vblank_event(crtc, event); 10485fc537bfSLinus Walleij } else { 10495fc537bfSLinus Walleij dev_dbg(mcde->dev, "insert fake vblank event\n"); 10505fc537bfSLinus Walleij drm_crtc_send_vblank_event(crtc, event); 10515fc537bfSLinus Walleij } 10525fc537bfSLinus Walleij 10535fc537bfSLinus Walleij spin_unlock_irq(&crtc->dev->event_lock); 10545fc537bfSLinus Walleij } 10555fc537bfSLinus Walleij 10565fc537bfSLinus Walleij /* 10575fc537bfSLinus Walleij * We do not start sending framebuffer updates before the 10585fc537bfSLinus Walleij * display is enabled. Update events will however be dispatched 10595fc537bfSLinus Walleij * from the DRM core before the display is enabled. 10605fc537bfSLinus Walleij */ 10615fc537bfSLinus Walleij if (fb) { 10625fc537bfSLinus Walleij mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); 1063d920e8daSStephan Gerhold if (!mcde->video_mode) 10645fc537bfSLinus Walleij /* Send a single frame using software sync */ 10655fc537bfSLinus Walleij mcde_display_send_one_frame(mcde); 10665fc537bfSLinus Walleij dev_info_once(mcde->dev, "sent first display update\n"); 10675fc537bfSLinus Walleij } else { 10685fc537bfSLinus Walleij /* 10695fc537bfSLinus Walleij * If an update is receieved before the MCDE is enabled 10705fc537bfSLinus Walleij * (before mcde_display_enable() is called) we can't really 10715fc537bfSLinus Walleij * do much with that buffer. 10725fc537bfSLinus Walleij */ 10735fc537bfSLinus Walleij dev_info(mcde->dev, "ignored a display update\n"); 10745fc537bfSLinus Walleij } 10755fc537bfSLinus Walleij } 10765fc537bfSLinus Walleij 10775fc537bfSLinus Walleij static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) 10785fc537bfSLinus Walleij { 10795fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 10805fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1081fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 10825fc537bfSLinus Walleij u32 val; 10835fc537bfSLinus Walleij 10845fc537bfSLinus Walleij /* Enable all VBLANK IRQs */ 10855fc537bfSLinus Walleij val = MCDE_PP_VCMPA | 10865fc537bfSLinus Walleij MCDE_PP_VCMPB | 10875fc537bfSLinus Walleij MCDE_PP_VSCC0 | 10885fc537bfSLinus Walleij MCDE_PP_VSCC1 | 10895fc537bfSLinus Walleij MCDE_PP_VCMPC0 | 10905fc537bfSLinus Walleij MCDE_PP_VCMPC1; 10915fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_IMSCPP); 10925fc537bfSLinus Walleij 10935fc537bfSLinus Walleij return 0; 10945fc537bfSLinus Walleij } 10955fc537bfSLinus Walleij 10965fc537bfSLinus Walleij static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) 10975fc537bfSLinus Walleij { 10985fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 10995fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1100fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 11015fc537bfSLinus Walleij 11025fc537bfSLinus Walleij /* Disable all VBLANK IRQs */ 11035fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCPP); 11045fc537bfSLinus Walleij /* Clear any pending IRQs */ 11055fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); 11065fc537bfSLinus Walleij } 11075fc537bfSLinus Walleij 11085fc537bfSLinus Walleij static struct drm_simple_display_pipe_funcs mcde_display_funcs = { 11095fc537bfSLinus Walleij .check = mcde_display_check, 11105fc537bfSLinus Walleij .enable = mcde_display_enable, 11115fc537bfSLinus Walleij .disable = mcde_display_disable, 11125fc537bfSLinus Walleij .update = mcde_display_update, 1113768859c2SStephan Gerhold .enable_vblank = mcde_display_enable_vblank, 1114768859c2SStephan Gerhold .disable_vblank = mcde_display_disable_vblank, 11155fc537bfSLinus Walleij .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, 11165fc537bfSLinus Walleij }; 11175fc537bfSLinus Walleij 11185fc537bfSLinus Walleij int mcde_display_init(struct drm_device *drm) 11195fc537bfSLinus Walleij { 1120fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 11215fc537bfSLinus Walleij int ret; 11225fc537bfSLinus Walleij static const u32 formats[] = { 11235fc537bfSLinus Walleij DRM_FORMAT_ARGB8888, 11245fc537bfSLinus Walleij DRM_FORMAT_ABGR8888, 11255fc537bfSLinus Walleij DRM_FORMAT_XRGB8888, 11265fc537bfSLinus Walleij DRM_FORMAT_XBGR8888, 11275fc537bfSLinus Walleij DRM_FORMAT_RGB888, 11285fc537bfSLinus Walleij DRM_FORMAT_BGR888, 11295fc537bfSLinus Walleij DRM_FORMAT_ARGB4444, 11305fc537bfSLinus Walleij DRM_FORMAT_ABGR4444, 11315fc537bfSLinus Walleij DRM_FORMAT_XRGB4444, 11325fc537bfSLinus Walleij DRM_FORMAT_XBGR4444, 11335fc537bfSLinus Walleij /* These are actually IRGB1555 so intensity bit is lost */ 11345fc537bfSLinus Walleij DRM_FORMAT_XRGB1555, 11355fc537bfSLinus Walleij DRM_FORMAT_XBGR1555, 11365fc537bfSLinus Walleij DRM_FORMAT_RGB565, 11375fc537bfSLinus Walleij DRM_FORMAT_BGR565, 11385fc537bfSLinus Walleij DRM_FORMAT_YUV422, 11395fc537bfSLinus Walleij }; 11405fc537bfSLinus Walleij 11415fc537bfSLinus Walleij ret = drm_simple_display_pipe_init(drm, &mcde->pipe, 11425fc537bfSLinus Walleij &mcde_display_funcs, 11435fc537bfSLinus Walleij formats, ARRAY_SIZE(formats), 11445fc537bfSLinus Walleij NULL, 11455fc537bfSLinus Walleij mcde->connector); 11465fc537bfSLinus Walleij if (ret) 11475fc537bfSLinus Walleij return ret; 11485fc537bfSLinus Walleij 11495fc537bfSLinus Walleij return 0; 11505fc537bfSLinus Walleij } 11515fc537bfSLinus Walleij EXPORT_SYMBOL_GPL(mcde_display_init); 1152