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> 10c4842d4dSLinus Walleij #include <linux/regulator/consumer.h> 11d795fd32SLinus Walleij #include <linux/media-bus-format.h> 125fc537bfSLinus Walleij 135fc537bfSLinus Walleij #include <drm/drm_device.h> 145fc537bfSLinus Walleij #include <drm/drm_fb_cma_helper.h> 155fc537bfSLinus Walleij #include <drm/drm_fourcc.h> 165fc537bfSLinus Walleij #include <drm/drm_gem_cma_helper.h> 175fc537bfSLinus Walleij #include <drm/drm_gem_framebuffer_helper.h> 185fc537bfSLinus Walleij #include <drm/drm_mipi_dsi.h> 195fc537bfSLinus Walleij #include <drm/drm_simple_kms_helper.h> 20d795fd32SLinus Walleij #include <drm/drm_bridge.h> 215fc537bfSLinus Walleij #include <drm/drm_vblank.h> 225fc537bfSLinus Walleij #include <video/mipi_display.h> 235fc537bfSLinus Walleij 245fc537bfSLinus Walleij #include "mcde_drm.h" 255fc537bfSLinus Walleij #include "mcde_display_regs.h" 265fc537bfSLinus Walleij 275fc537bfSLinus Walleij enum mcde_fifo { 285fc537bfSLinus Walleij MCDE_FIFO_A, 295fc537bfSLinus Walleij MCDE_FIFO_B, 305fc537bfSLinus Walleij /* TODO: implement FIFO C0 and FIFO C1 */ 315fc537bfSLinus Walleij }; 325fc537bfSLinus Walleij 335fc537bfSLinus Walleij enum mcde_channel { 345fc537bfSLinus Walleij MCDE_CHANNEL_0 = 0, 355fc537bfSLinus Walleij MCDE_CHANNEL_1, 365fc537bfSLinus Walleij MCDE_CHANNEL_2, 375fc537bfSLinus Walleij MCDE_CHANNEL_3, 385fc537bfSLinus Walleij }; 395fc537bfSLinus Walleij 405fc537bfSLinus Walleij enum mcde_extsrc { 415fc537bfSLinus Walleij MCDE_EXTSRC_0 = 0, 425fc537bfSLinus Walleij MCDE_EXTSRC_1, 435fc537bfSLinus Walleij MCDE_EXTSRC_2, 445fc537bfSLinus Walleij MCDE_EXTSRC_3, 455fc537bfSLinus Walleij MCDE_EXTSRC_4, 465fc537bfSLinus Walleij MCDE_EXTSRC_5, 475fc537bfSLinus Walleij MCDE_EXTSRC_6, 485fc537bfSLinus Walleij MCDE_EXTSRC_7, 495fc537bfSLinus Walleij MCDE_EXTSRC_8, 505fc537bfSLinus Walleij MCDE_EXTSRC_9, 515fc537bfSLinus Walleij }; 525fc537bfSLinus Walleij 535fc537bfSLinus Walleij enum mcde_overlay { 545fc537bfSLinus Walleij MCDE_OVERLAY_0 = 0, 555fc537bfSLinus Walleij MCDE_OVERLAY_1, 565fc537bfSLinus Walleij MCDE_OVERLAY_2, 575fc537bfSLinus Walleij MCDE_OVERLAY_3, 585fc537bfSLinus Walleij MCDE_OVERLAY_4, 595fc537bfSLinus Walleij MCDE_OVERLAY_5, 605fc537bfSLinus Walleij }; 615fc537bfSLinus Walleij 62d795fd32SLinus Walleij enum mcde_formatter { 635fc537bfSLinus Walleij MCDE_DSI_FORMATTER_0 = 0, 645fc537bfSLinus Walleij MCDE_DSI_FORMATTER_1, 655fc537bfSLinus Walleij MCDE_DSI_FORMATTER_2, 66d795fd32SLinus Walleij MCDE_DSI_FORMATTER_3, 67d795fd32SLinus Walleij MCDE_DSI_FORMATTER_4, 68d795fd32SLinus Walleij MCDE_DSI_FORMATTER_5, 69d795fd32SLinus Walleij MCDE_DPI_FORMATTER_0, 70d795fd32SLinus Walleij MCDE_DPI_FORMATTER_1, 715fc537bfSLinus Walleij }; 725fc537bfSLinus Walleij 735fc537bfSLinus Walleij void mcde_display_irq(struct mcde *mcde) 745fc537bfSLinus Walleij { 755fc537bfSLinus Walleij u32 mispp, misovl, mischnl; 76bb5ce9a0SDan Carpenter bool vblank = false; 775fc537bfSLinus Walleij 785fc537bfSLinus Walleij /* Handle display IRQs */ 795fc537bfSLinus Walleij mispp = readl(mcde->regs + MCDE_MISPP); 805fc537bfSLinus Walleij misovl = readl(mcde->regs + MCDE_MISOVL); 815fc537bfSLinus Walleij mischnl = readl(mcde->regs + MCDE_MISCHNL); 825fc537bfSLinus Walleij 835fc537bfSLinus Walleij /* 845fc537bfSLinus Walleij * Handle IRQs from the DSI link. All IRQs from the DSI links 855fc537bfSLinus Walleij * are just latched onto the MCDE IRQ line, so we need to traverse 865fc537bfSLinus Walleij * any active DSI masters and check if an IRQ is originating from 875fc537bfSLinus Walleij * them. 885fc537bfSLinus Walleij * 895fc537bfSLinus Walleij * TODO: Currently only one DSI link is supported. 905fc537bfSLinus Walleij */ 91d795fd32SLinus Walleij if (!mcde->dpi_output && mcde_dsi_irq(mcde->mdsi)) { 925fc537bfSLinus Walleij u32 val; 935fc537bfSLinus Walleij 945fc537bfSLinus Walleij /* 955fc537bfSLinus Walleij * In oneshot mode we do not send continuous updates 965fc537bfSLinus Walleij * to the display, instead we only push out updates when 975fc537bfSLinus Walleij * the update function is called, then we disable the 985fc537bfSLinus Walleij * flow on the channel once we get the TE IRQ. 995fc537bfSLinus Walleij */ 100709c2773SLinus Walleij if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { 1015fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 1025fc537bfSLinus Walleij if (--mcde->flow_active == 0) { 1035fc537bfSLinus Walleij dev_dbg(mcde->dev, "TE0 IRQ\n"); 1045fc537bfSLinus Walleij /* Disable FIFO A flow */ 1055fc537bfSLinus Walleij val = readl(mcde->regs + MCDE_CRA0); 1065fc537bfSLinus Walleij val &= ~MCDE_CRX0_FLOEN; 1075fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_CRA0); 1085fc537bfSLinus Walleij } 1095fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 1105fc537bfSLinus Walleij } 1115fc537bfSLinus Walleij } 1125fc537bfSLinus Walleij 1135fc537bfSLinus Walleij /* Vblank from one of the channels */ 1145fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPA) { 1155fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl A vblank IRQ\n"); 1165fc537bfSLinus Walleij vblank = true; 1175fc537bfSLinus Walleij } 1185fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPB) { 1195fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl B vblank IRQ\n"); 1205fc537bfSLinus Walleij vblank = true; 1215fc537bfSLinus Walleij } 1225fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPC0) 1235fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C0 vblank IRQ\n"); 1245fc537bfSLinus Walleij if (mispp & MCDE_PP_VCMPC1) 1255fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C1 vblank IRQ\n"); 1265fc537bfSLinus Walleij if (mispp & MCDE_PP_VSCC0) 1275fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C0 TE IRQ\n"); 1285fc537bfSLinus Walleij if (mispp & MCDE_PP_VSCC1) 1295fc537bfSLinus Walleij dev_dbg(mcde->dev, "chnl C1 TE IRQ\n"); 1305fc537bfSLinus Walleij writel(mispp, mcde->regs + MCDE_RISPP); 1315fc537bfSLinus Walleij 1325fc537bfSLinus Walleij if (vblank) 1335fc537bfSLinus Walleij drm_crtc_handle_vblank(&mcde->pipe.crtc); 1345fc537bfSLinus Walleij 1355fc537bfSLinus Walleij if (misovl) 1365fc537bfSLinus Walleij dev_info(mcde->dev, "some stray overlay IRQ %08x\n", misovl); 1375fc537bfSLinus Walleij writel(misovl, mcde->regs + MCDE_RISOVL); 1385fc537bfSLinus Walleij 1395fc537bfSLinus Walleij if (mischnl) 1405fc537bfSLinus Walleij dev_info(mcde->dev, "some stray channel error IRQ %08x\n", 1415fc537bfSLinus Walleij mischnl); 1425fc537bfSLinus Walleij writel(mischnl, mcde->regs + MCDE_RISCHNL); 1435fc537bfSLinus Walleij } 1445fc537bfSLinus Walleij 1455fc537bfSLinus Walleij void mcde_display_disable_irqs(struct mcde *mcde) 1465fc537bfSLinus Walleij { 1475fc537bfSLinus Walleij /* Disable all IRQs */ 1485fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCPP); 1495fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCOVL); 1505fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCCHNL); 1515fc537bfSLinus Walleij 1525fc537bfSLinus Walleij /* Clear any pending IRQs */ 1535fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); 1545fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISOVL); 1555fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISCHNL); 1565fc537bfSLinus Walleij } 1575fc537bfSLinus Walleij 1585fc537bfSLinus Walleij static int mcde_display_check(struct drm_simple_display_pipe *pipe, 1595fc537bfSLinus Walleij struct drm_plane_state *pstate, 1605fc537bfSLinus Walleij struct drm_crtc_state *cstate) 1615fc537bfSLinus Walleij { 1625fc537bfSLinus Walleij const struct drm_display_mode *mode = &cstate->mode; 1635fc537bfSLinus Walleij struct drm_framebuffer *old_fb = pipe->plane.state->fb; 1645fc537bfSLinus Walleij struct drm_framebuffer *fb = pstate->fb; 1655fc537bfSLinus Walleij 1665fc537bfSLinus Walleij if (fb) { 1675fc537bfSLinus Walleij u32 offset = drm_fb_cma_get_gem_addr(fb, pstate, 0); 1685fc537bfSLinus Walleij 1695fc537bfSLinus Walleij /* FB base address must be dword aligned. */ 1705fc537bfSLinus Walleij if (offset & 3) { 1715fc537bfSLinus Walleij DRM_DEBUG_KMS("FB not 32-bit aligned\n"); 1725fc537bfSLinus Walleij return -EINVAL; 1735fc537bfSLinus Walleij } 1745fc537bfSLinus Walleij 1755fc537bfSLinus Walleij /* 1765fc537bfSLinus Walleij * There's no pitch register, the mode's hdisplay 1775fc537bfSLinus Walleij * controls this. 1785fc537bfSLinus Walleij */ 1795fc537bfSLinus Walleij if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { 1805fc537bfSLinus Walleij DRM_DEBUG_KMS("can't handle pitches\n"); 1815fc537bfSLinus Walleij return -EINVAL; 1825fc537bfSLinus Walleij } 1835fc537bfSLinus Walleij 1845fc537bfSLinus Walleij /* 1855fc537bfSLinus Walleij * We can't change the FB format in a flicker-free 1865fc537bfSLinus Walleij * manner (and only update it during CRTC enable). 1875fc537bfSLinus Walleij */ 1885fc537bfSLinus Walleij if (old_fb && old_fb->format != fb->format) 1895fc537bfSLinus Walleij cstate->mode_changed = true; 1905fc537bfSLinus Walleij } 1915fc537bfSLinus Walleij 1925fc537bfSLinus Walleij return 0; 1935fc537bfSLinus Walleij } 1945fc537bfSLinus Walleij 1955fc537bfSLinus Walleij static int mcde_configure_extsrc(struct mcde *mcde, enum mcde_extsrc src, 1965fc537bfSLinus Walleij u32 format) 1975fc537bfSLinus Walleij { 1985fc537bfSLinus Walleij u32 val; 1995fc537bfSLinus Walleij u32 conf; 2005fc537bfSLinus Walleij u32 cr; 2015fc537bfSLinus Walleij 2025fc537bfSLinus Walleij switch (src) { 2035fc537bfSLinus Walleij case MCDE_EXTSRC_0: 2045fc537bfSLinus Walleij conf = MCDE_EXTSRC0CONF; 2055fc537bfSLinus Walleij cr = MCDE_EXTSRC0CR; 2065fc537bfSLinus Walleij break; 2075fc537bfSLinus Walleij case MCDE_EXTSRC_1: 2085fc537bfSLinus Walleij conf = MCDE_EXTSRC1CONF; 2095fc537bfSLinus Walleij cr = MCDE_EXTSRC1CR; 2105fc537bfSLinus Walleij break; 2115fc537bfSLinus Walleij case MCDE_EXTSRC_2: 2125fc537bfSLinus Walleij conf = MCDE_EXTSRC2CONF; 2135fc537bfSLinus Walleij cr = MCDE_EXTSRC2CR; 2145fc537bfSLinus Walleij break; 2155fc537bfSLinus Walleij case MCDE_EXTSRC_3: 2165fc537bfSLinus Walleij conf = MCDE_EXTSRC3CONF; 2175fc537bfSLinus Walleij cr = MCDE_EXTSRC3CR; 2185fc537bfSLinus Walleij break; 2195fc537bfSLinus Walleij case MCDE_EXTSRC_4: 2205fc537bfSLinus Walleij conf = MCDE_EXTSRC4CONF; 2215fc537bfSLinus Walleij cr = MCDE_EXTSRC4CR; 2225fc537bfSLinus Walleij break; 2235fc537bfSLinus Walleij case MCDE_EXTSRC_5: 2245fc537bfSLinus Walleij conf = MCDE_EXTSRC5CONF; 2255fc537bfSLinus Walleij cr = MCDE_EXTSRC5CR; 2265fc537bfSLinus Walleij break; 2275fc537bfSLinus Walleij case MCDE_EXTSRC_6: 2285fc537bfSLinus Walleij conf = MCDE_EXTSRC6CONF; 2295fc537bfSLinus Walleij cr = MCDE_EXTSRC6CR; 2305fc537bfSLinus Walleij break; 2315fc537bfSLinus Walleij case MCDE_EXTSRC_7: 2325fc537bfSLinus Walleij conf = MCDE_EXTSRC7CONF; 2335fc537bfSLinus Walleij cr = MCDE_EXTSRC7CR; 2345fc537bfSLinus Walleij break; 2355fc537bfSLinus Walleij case MCDE_EXTSRC_8: 2365fc537bfSLinus Walleij conf = MCDE_EXTSRC8CONF; 2375fc537bfSLinus Walleij cr = MCDE_EXTSRC8CR; 2385fc537bfSLinus Walleij break; 2395fc537bfSLinus Walleij case MCDE_EXTSRC_9: 2405fc537bfSLinus Walleij conf = MCDE_EXTSRC9CONF; 2415fc537bfSLinus Walleij cr = MCDE_EXTSRC9CR; 2425fc537bfSLinus Walleij break; 2435fc537bfSLinus Walleij } 2445fc537bfSLinus Walleij 2455fc537bfSLinus Walleij /* 2465fc537bfSLinus Walleij * Configure external source 0 one buffer (buffer 0) 2475fc537bfSLinus Walleij * primary overlay ID 0. 2485fc537bfSLinus Walleij * From mcde_hw.c ovly_update_registers() in the vendor tree 2495fc537bfSLinus Walleij */ 2505fc537bfSLinus Walleij val = 0 << MCDE_EXTSRCXCONF_BUF_ID_SHIFT; 2515fc537bfSLinus Walleij val |= 1 << MCDE_EXTSRCXCONF_BUF_NB_SHIFT; 2525fc537bfSLinus Walleij val |= 0 << MCDE_EXTSRCXCONF_PRI_OVLID_SHIFT; 25377f512bdSLinus Walleij 2545fc537bfSLinus Walleij switch (format) { 2555fc537bfSLinus Walleij case DRM_FORMAT_ARGB8888: 2565fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 << 2575fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2585fc537bfSLinus Walleij break; 2595fc537bfSLinus Walleij case DRM_FORMAT_ABGR8888: 2605fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB8888 << 2615fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 26277f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2635fc537bfSLinus Walleij break; 2645fc537bfSLinus Walleij case DRM_FORMAT_XRGB8888: 2655fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 << 2665fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2675fc537bfSLinus Walleij break; 2685fc537bfSLinus Walleij case DRM_FORMAT_XBGR8888: 2695fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_XRGB8888 << 2705fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 27177f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2725fc537bfSLinus Walleij break; 2735fc537bfSLinus Walleij case DRM_FORMAT_RGB888: 2745fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB888 << 2755fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2765fc537bfSLinus Walleij break; 2775fc537bfSLinus Walleij case DRM_FORMAT_BGR888: 2785fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB888 << 2795fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 28077f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2815fc537bfSLinus Walleij break; 2825fc537bfSLinus Walleij case DRM_FORMAT_ARGB4444: 2835fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 << 2845fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2855fc537bfSLinus Walleij break; 2865fc537bfSLinus Walleij case DRM_FORMAT_ABGR4444: 2875fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_ARGB4444 << 2885fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 28977f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2905fc537bfSLinus Walleij break; 2915fc537bfSLinus Walleij case DRM_FORMAT_XRGB4444: 2925fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB444 << 2935fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 2945fc537bfSLinus Walleij break; 2955fc537bfSLinus Walleij case DRM_FORMAT_XBGR4444: 2965fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB444 << 2975fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 29877f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 2995fc537bfSLinus Walleij break; 3005fc537bfSLinus Walleij case DRM_FORMAT_XRGB1555: 3015fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 << 3025fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3035fc537bfSLinus Walleij break; 3045fc537bfSLinus Walleij case DRM_FORMAT_XBGR1555: 3055fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_IRGB1555 << 3065fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 30777f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 3085fc537bfSLinus Walleij break; 3095fc537bfSLinus Walleij case DRM_FORMAT_RGB565: 3105fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB565 << 3115fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3125fc537bfSLinus Walleij break; 3135fc537bfSLinus Walleij case DRM_FORMAT_BGR565: 3145fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_RGB565 << 3155fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 31677f512bdSLinus Walleij val |= MCDE_EXTSRCXCONF_BGR; 3175fc537bfSLinus Walleij break; 3185fc537bfSLinus Walleij case DRM_FORMAT_YUV422: 3195fc537bfSLinus Walleij val |= MCDE_EXTSRCXCONF_BPP_YCBCR422 << 3205fc537bfSLinus Walleij MCDE_EXTSRCXCONF_BPP_SHIFT; 3215fc537bfSLinus Walleij break; 3225fc537bfSLinus Walleij default: 3235fc537bfSLinus Walleij dev_err(mcde->dev, "Unknown pixel format 0x%08x\n", 3245fc537bfSLinus Walleij format); 3255fc537bfSLinus Walleij return -EINVAL; 3265fc537bfSLinus Walleij } 3275fc537bfSLinus Walleij writel(val, mcde->regs + conf); 3285fc537bfSLinus Walleij 3295fc537bfSLinus Walleij /* Software select, primary */ 3305fc537bfSLinus Walleij val = MCDE_EXTSRCXCR_SEL_MOD_SOFTWARE_SEL; 3315fc537bfSLinus Walleij val |= MCDE_EXTSRCXCR_MULTIOVL_CTRL_PRIMARY; 3325fc537bfSLinus Walleij writel(val, mcde->regs + cr); 3335fc537bfSLinus Walleij 3345fc537bfSLinus Walleij return 0; 3355fc537bfSLinus Walleij } 3365fc537bfSLinus Walleij 3375fc537bfSLinus Walleij static void mcde_configure_overlay(struct mcde *mcde, enum mcde_overlay ovl, 3385fc537bfSLinus Walleij enum mcde_extsrc src, 3395fc537bfSLinus Walleij enum mcde_channel ch, 3405fc537bfSLinus Walleij const struct drm_display_mode *mode, 34144c3867aSLinus Walleij u32 format, int cpp) 3425fc537bfSLinus Walleij { 3435fc537bfSLinus Walleij u32 val; 3445fc537bfSLinus Walleij u32 conf1; 3455fc537bfSLinus Walleij u32 conf2; 3465fc537bfSLinus Walleij u32 crop; 3475fc537bfSLinus Walleij u32 ljinc; 3485fc537bfSLinus Walleij u32 cr; 3495fc537bfSLinus Walleij u32 comp; 35044c3867aSLinus Walleij u32 pixel_fetcher_watermark; 3515fc537bfSLinus Walleij 3525fc537bfSLinus Walleij switch (ovl) { 3535fc537bfSLinus Walleij case MCDE_OVERLAY_0: 3545fc537bfSLinus Walleij conf1 = MCDE_OVL0CONF; 3555fc537bfSLinus Walleij conf2 = MCDE_OVL0CONF2; 3565fc537bfSLinus Walleij crop = MCDE_OVL0CROP; 3575fc537bfSLinus Walleij ljinc = MCDE_OVL0LJINC; 3585fc537bfSLinus Walleij cr = MCDE_OVL0CR; 3595fc537bfSLinus Walleij comp = MCDE_OVL0COMP; 3605fc537bfSLinus Walleij break; 3615fc537bfSLinus Walleij case MCDE_OVERLAY_1: 3625fc537bfSLinus Walleij conf1 = MCDE_OVL1CONF; 3635fc537bfSLinus Walleij conf2 = MCDE_OVL1CONF2; 3645fc537bfSLinus Walleij crop = MCDE_OVL1CROP; 3655fc537bfSLinus Walleij ljinc = MCDE_OVL1LJINC; 3665fc537bfSLinus Walleij cr = MCDE_OVL1CR; 3675fc537bfSLinus Walleij comp = MCDE_OVL1COMP; 3685fc537bfSLinus Walleij break; 3695fc537bfSLinus Walleij case MCDE_OVERLAY_2: 3705fc537bfSLinus Walleij conf1 = MCDE_OVL2CONF; 3715fc537bfSLinus Walleij conf2 = MCDE_OVL2CONF2; 3725fc537bfSLinus Walleij crop = MCDE_OVL2CROP; 3735fc537bfSLinus Walleij ljinc = MCDE_OVL2LJINC; 3745fc537bfSLinus Walleij cr = MCDE_OVL2CR; 3755fc537bfSLinus Walleij comp = MCDE_OVL2COMP; 3765fc537bfSLinus Walleij break; 3775fc537bfSLinus Walleij case MCDE_OVERLAY_3: 3785fc537bfSLinus Walleij conf1 = MCDE_OVL3CONF; 3795fc537bfSLinus Walleij conf2 = MCDE_OVL3CONF2; 3805fc537bfSLinus Walleij crop = MCDE_OVL3CROP; 3815fc537bfSLinus Walleij ljinc = MCDE_OVL3LJINC; 3825fc537bfSLinus Walleij cr = MCDE_OVL3CR; 3835fc537bfSLinus Walleij comp = MCDE_OVL3COMP; 3845fc537bfSLinus Walleij break; 3855fc537bfSLinus Walleij case MCDE_OVERLAY_4: 3865fc537bfSLinus Walleij conf1 = MCDE_OVL4CONF; 3875fc537bfSLinus Walleij conf2 = MCDE_OVL4CONF2; 3885fc537bfSLinus Walleij crop = MCDE_OVL4CROP; 3895fc537bfSLinus Walleij ljinc = MCDE_OVL4LJINC; 3905fc537bfSLinus Walleij cr = MCDE_OVL4CR; 3915fc537bfSLinus Walleij comp = MCDE_OVL4COMP; 3925fc537bfSLinus Walleij break; 3935fc537bfSLinus Walleij case MCDE_OVERLAY_5: 3945fc537bfSLinus Walleij conf1 = MCDE_OVL5CONF; 3955fc537bfSLinus Walleij conf2 = MCDE_OVL5CONF2; 3965fc537bfSLinus Walleij crop = MCDE_OVL5CROP; 3975fc537bfSLinus Walleij ljinc = MCDE_OVL5LJINC; 3985fc537bfSLinus Walleij cr = MCDE_OVL5CR; 3995fc537bfSLinus Walleij comp = MCDE_OVL5COMP; 4005fc537bfSLinus Walleij break; 4015fc537bfSLinus Walleij } 4025fc537bfSLinus Walleij 4035fc537bfSLinus Walleij val = mode->hdisplay << MCDE_OVLXCONF_PPL_SHIFT; 4045fc537bfSLinus Walleij val |= mode->vdisplay << MCDE_OVLXCONF_LPF_SHIFT; 4055fc537bfSLinus Walleij /* Use external source 0 that we just configured */ 4065fc537bfSLinus Walleij val |= src << MCDE_OVLXCONF_EXTSRC_ID_SHIFT; 4075fc537bfSLinus Walleij writel(val, mcde->regs + conf1); 4085fc537bfSLinus Walleij 4095fc537bfSLinus Walleij val = MCDE_OVLXCONF2_BP_PER_PIXEL_ALPHA; 4105fc537bfSLinus Walleij val |= 0xff << MCDE_OVLXCONF2_ALPHAVALUE_SHIFT; 4115fc537bfSLinus Walleij /* OPQ: overlay is opaque */ 4125fc537bfSLinus Walleij switch (format) { 4135fc537bfSLinus Walleij case DRM_FORMAT_ARGB8888: 4145fc537bfSLinus Walleij case DRM_FORMAT_ABGR8888: 4155fc537bfSLinus Walleij case DRM_FORMAT_ARGB4444: 4165fc537bfSLinus Walleij case DRM_FORMAT_ABGR4444: 4175fc537bfSLinus Walleij case DRM_FORMAT_XRGB1555: 4185fc537bfSLinus Walleij case DRM_FORMAT_XBGR1555: 4195fc537bfSLinus Walleij /* No OPQ */ 4205fc537bfSLinus Walleij break; 4215fc537bfSLinus Walleij case DRM_FORMAT_XRGB8888: 4225fc537bfSLinus Walleij case DRM_FORMAT_XBGR8888: 4235fc537bfSLinus Walleij case DRM_FORMAT_RGB888: 4245fc537bfSLinus Walleij case DRM_FORMAT_BGR888: 4255fc537bfSLinus Walleij case DRM_FORMAT_RGB565: 4265fc537bfSLinus Walleij case DRM_FORMAT_BGR565: 4275fc537bfSLinus Walleij case DRM_FORMAT_YUV422: 4285fc537bfSLinus Walleij val |= MCDE_OVLXCONF2_OPQ; 4295fc537bfSLinus Walleij break; 4305fc537bfSLinus Walleij default: 4315fc537bfSLinus Walleij dev_err(mcde->dev, "Unknown pixel format 0x%08x\n", 4325fc537bfSLinus Walleij format); 4335fc537bfSLinus Walleij break; 4345fc537bfSLinus Walleij } 43544c3867aSLinus Walleij 43644c3867aSLinus Walleij /* 43744c3867aSLinus Walleij * Pixel fetch watermark level is max 0x1FFF pixels. 43844c3867aSLinus Walleij * Two basic rules should be followed: 43944c3867aSLinus Walleij * 1. The value should be at least 256 bits. 44044c3867aSLinus Walleij * 2. The sum of all active overlays pixelfetch watermark level 44144c3867aSLinus Walleij * multiplied with bits per pixel, should be lower than the 44244c3867aSLinus Walleij * size of input_fifo_size in bits. 44344c3867aSLinus Walleij * 3. The value should be a multiple of a line (256 bits). 44444c3867aSLinus Walleij */ 44544c3867aSLinus Walleij switch (cpp) { 44644c3867aSLinus Walleij case 2: 44744c3867aSLinus Walleij pixel_fetcher_watermark = 128; 44844c3867aSLinus Walleij break; 44944c3867aSLinus Walleij case 3: 45044c3867aSLinus Walleij pixel_fetcher_watermark = 96; 45144c3867aSLinus Walleij break; 45244c3867aSLinus Walleij case 4: 45344c3867aSLinus Walleij pixel_fetcher_watermark = 48; 45444c3867aSLinus Walleij break; 45544c3867aSLinus Walleij default: 45644c3867aSLinus Walleij pixel_fetcher_watermark = 48; 45744c3867aSLinus Walleij break; 45844c3867aSLinus Walleij } 45944c3867aSLinus Walleij dev_dbg(mcde->dev, "pixel fetcher watermark level %d pixels\n", 46044c3867aSLinus Walleij pixel_fetcher_watermark); 46144c3867aSLinus Walleij val |= pixel_fetcher_watermark << MCDE_OVLXCONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT; 4625fc537bfSLinus Walleij writel(val, mcde->regs + conf2); 4635fc537bfSLinus Walleij 4645fc537bfSLinus Walleij /* Number of bytes to fetch per line */ 4655fc537bfSLinus Walleij writel(mcde->stride, mcde->regs + ljinc); 4665fc537bfSLinus Walleij /* No cropping */ 4675fc537bfSLinus Walleij writel(0, mcde->regs + crop); 4685fc537bfSLinus Walleij 4695fc537bfSLinus Walleij /* Set up overlay control register */ 4705fc537bfSLinus Walleij val = MCDE_OVLXCR_OVLEN; 4715fc537bfSLinus Walleij val |= MCDE_OVLXCR_COLCCTRL_DISABLED; 4725fc537bfSLinus Walleij val |= MCDE_OVLXCR_BURSTSIZE_8W << 4735fc537bfSLinus Walleij MCDE_OVLXCR_BURSTSIZE_SHIFT; 4745fc537bfSLinus Walleij val |= MCDE_OVLXCR_MAXOUTSTANDING_8_REQ << 4755fc537bfSLinus Walleij MCDE_OVLXCR_MAXOUTSTANDING_SHIFT; 4765fc537bfSLinus Walleij /* Not using rotation but set it up anyways */ 4775fc537bfSLinus Walleij val |= MCDE_OVLXCR_ROTBURSTSIZE_8W << 4785fc537bfSLinus Walleij MCDE_OVLXCR_ROTBURSTSIZE_SHIFT; 4795fc537bfSLinus Walleij writel(val, mcde->regs + cr); 4805fc537bfSLinus Walleij 4815fc537bfSLinus Walleij /* 4825fc537bfSLinus Walleij * Set up the overlay compositor to route the overlay out to 4835fc537bfSLinus Walleij * the desired channel 4845fc537bfSLinus Walleij */ 4855fc537bfSLinus Walleij val = ch << MCDE_OVLXCOMP_CH_ID_SHIFT; 4865fc537bfSLinus Walleij writel(val, mcde->regs + comp); 4875fc537bfSLinus Walleij } 4885fc537bfSLinus Walleij 4895fc537bfSLinus Walleij static void mcde_configure_channel(struct mcde *mcde, enum mcde_channel ch, 4905fc537bfSLinus Walleij enum mcde_fifo fifo, 4915fc537bfSLinus Walleij const struct drm_display_mode *mode) 4925fc537bfSLinus Walleij { 4935fc537bfSLinus Walleij u32 val; 4945fc537bfSLinus Walleij u32 conf; 4955fc537bfSLinus Walleij u32 sync; 4965fc537bfSLinus Walleij u32 stat; 4975fc537bfSLinus Walleij u32 bgcol; 4985fc537bfSLinus Walleij u32 mux; 4995fc537bfSLinus Walleij 5005fc537bfSLinus Walleij switch (ch) { 5015fc537bfSLinus Walleij case MCDE_CHANNEL_0: 5025fc537bfSLinus Walleij conf = MCDE_CHNL0CONF; 5035fc537bfSLinus Walleij sync = MCDE_CHNL0SYNCHMOD; 5045fc537bfSLinus Walleij stat = MCDE_CHNL0STAT; 5055fc537bfSLinus Walleij bgcol = MCDE_CHNL0BCKGNDCOL; 5065fc537bfSLinus Walleij mux = MCDE_CHNL0MUXING; 5075fc537bfSLinus Walleij break; 5085fc537bfSLinus Walleij case MCDE_CHANNEL_1: 5095fc537bfSLinus Walleij conf = MCDE_CHNL1CONF; 5105fc537bfSLinus Walleij sync = MCDE_CHNL1SYNCHMOD; 5115fc537bfSLinus Walleij stat = MCDE_CHNL1STAT; 5125fc537bfSLinus Walleij bgcol = MCDE_CHNL1BCKGNDCOL; 5135fc537bfSLinus Walleij mux = MCDE_CHNL1MUXING; 5145fc537bfSLinus Walleij break; 5155fc537bfSLinus Walleij case MCDE_CHANNEL_2: 5165fc537bfSLinus Walleij conf = MCDE_CHNL2CONF; 5175fc537bfSLinus Walleij sync = MCDE_CHNL2SYNCHMOD; 5185fc537bfSLinus Walleij stat = MCDE_CHNL2STAT; 5195fc537bfSLinus Walleij bgcol = MCDE_CHNL2BCKGNDCOL; 5205fc537bfSLinus Walleij mux = MCDE_CHNL2MUXING; 5215fc537bfSLinus Walleij break; 5225fc537bfSLinus Walleij case MCDE_CHANNEL_3: 5235fc537bfSLinus Walleij conf = MCDE_CHNL3CONF; 5245fc537bfSLinus Walleij sync = MCDE_CHNL3SYNCHMOD; 5255fc537bfSLinus Walleij stat = MCDE_CHNL3STAT; 5265fc537bfSLinus Walleij bgcol = MCDE_CHNL3BCKGNDCOL; 5275fc537bfSLinus Walleij mux = MCDE_CHNL3MUXING; 5285fc537bfSLinus Walleij return; 5295fc537bfSLinus Walleij } 5305fc537bfSLinus Walleij 5315fc537bfSLinus Walleij /* Set up channel 0 sync (based on chnl_update_registers()) */ 532709c2773SLinus Walleij switch (mcde->flow_mode) { 533709c2773SLinus Walleij case MCDE_COMMAND_ONESHOT_FLOW: 534709c2773SLinus Walleij /* Oneshot is achieved with software sync */ 5355fc537bfSLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SOFTWARE 5365fc537bfSLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 537709c2773SLinus Walleij break; 538709c2773SLinus Walleij case MCDE_COMMAND_TE_FLOW: 539709c2773SLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 540709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 541d920e8daSStephan Gerhold val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 542d920e8daSStephan Gerhold << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 543709c2773SLinus Walleij break; 544709c2773SLinus Walleij case MCDE_COMMAND_BTA_TE_FLOW: 545709c2773SLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 546709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 547709c2773SLinus Walleij /* 548709c2773SLinus Walleij * TODO: 549709c2773SLinus Walleij * The vendor driver uses the formatter as sync source 550709c2773SLinus Walleij * for BTA TE mode. Test to use TE if you have a panel 551709c2773SLinus Walleij * that uses this mode. 552709c2773SLinus Walleij */ 5535fc537bfSLinus Walleij val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER 5545fc537bfSLinus Walleij << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 555709c2773SLinus Walleij break; 556709c2773SLinus Walleij case MCDE_VIDEO_TE_FLOW: 557709c2773SLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 558709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 559709c2773SLinus Walleij val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_TE0 560709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 561709c2773SLinus Walleij break; 562709c2773SLinus Walleij case MCDE_VIDEO_FORMATTER_FLOW: 563d795fd32SLinus Walleij case MCDE_DPI_FORMATTER_FLOW: 564709c2773SLinus Walleij val = MCDE_CHNLXSYNCHMOD_SRC_SYNCH_HARDWARE 565709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_SRC_SYNCH_SHIFT; 566709c2773SLinus Walleij val |= MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_FORMATTER 567709c2773SLinus Walleij << MCDE_CHNLXSYNCHMOD_OUT_SYNCH_SRC_SHIFT; 568709c2773SLinus Walleij break; 569709c2773SLinus Walleij default: 570709c2773SLinus Walleij dev_err(mcde->dev, "unknown flow mode %d\n", 571709c2773SLinus Walleij mcde->flow_mode); 572*3a78f064SLinus Walleij return; 573709c2773SLinus Walleij } 574d920e8daSStephan Gerhold 5755fc537bfSLinus Walleij writel(val, mcde->regs + sync); 5765fc537bfSLinus Walleij 5775fc537bfSLinus Walleij /* Set up pixels per line and lines per frame */ 5785fc537bfSLinus Walleij val = (mode->hdisplay - 1) << MCDE_CHNLXCONF_PPL_SHIFT; 5795fc537bfSLinus Walleij val |= (mode->vdisplay - 1) << MCDE_CHNLXCONF_LPF_SHIFT; 5805fc537bfSLinus Walleij writel(val, mcde->regs + conf); 5815fc537bfSLinus Walleij 5825fc537bfSLinus Walleij /* 5835fc537bfSLinus Walleij * Normalize color conversion: 5845fc537bfSLinus Walleij * black background, OLED conversion disable on channel 5855fc537bfSLinus Walleij */ 5865fc537bfSLinus Walleij val = MCDE_CHNLXSTAT_CHNLBLBCKGND_EN | 5875fc537bfSLinus Walleij MCDE_CHNLXSTAT_CHNLRD; 5885fc537bfSLinus Walleij writel(val, mcde->regs + stat); 5895fc537bfSLinus Walleij writel(0, mcde->regs + bgcol); 5905fc537bfSLinus Walleij 5915fc537bfSLinus Walleij /* Set up muxing: connect the channel to the desired FIFO */ 5925fc537bfSLinus Walleij switch (fifo) { 5935fc537bfSLinus Walleij case MCDE_FIFO_A: 5945fc537bfSLinus Walleij writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_A, 5955fc537bfSLinus Walleij mcde->regs + mux); 5965fc537bfSLinus Walleij break; 5975fc537bfSLinus Walleij case MCDE_FIFO_B: 5985fc537bfSLinus Walleij writel(MCDE_CHNLXMUXING_FIFO_ID_FIFO_B, 5995fc537bfSLinus Walleij mcde->regs + mux); 6005fc537bfSLinus Walleij break; 6015fc537bfSLinus Walleij } 602d795fd32SLinus Walleij 603d795fd32SLinus Walleij /* 604d795fd32SLinus Walleij * If using DPI configure the sync event. 605d795fd32SLinus Walleij * TODO: this is for LCD only, it does not cover TV out. 606d795fd32SLinus Walleij */ 607d795fd32SLinus Walleij if (mcde->dpi_output) { 608d795fd32SLinus Walleij u32 stripwidth; 609d795fd32SLinus Walleij 610d795fd32SLinus Walleij stripwidth = 0xF000 / (mode->vdisplay * 4); 611d795fd32SLinus Walleij dev_info(mcde->dev, "stripwidth: %d\n", stripwidth); 612d795fd32SLinus Walleij 613d795fd32SLinus Walleij val = MCDE_SYNCHCONF_HWREQVEVENT_ACTIVE_VIDEO | 614d795fd32SLinus Walleij (mode->hdisplay - 1 - stripwidth) << MCDE_SYNCHCONF_HWREQVCNT_SHIFT | 615d795fd32SLinus Walleij MCDE_SYNCHCONF_SWINTVEVENT_ACTIVE_VIDEO | 616d795fd32SLinus Walleij (mode->hdisplay - 1 - stripwidth) << MCDE_SYNCHCONF_SWINTVCNT_SHIFT; 617d795fd32SLinus Walleij 618d795fd32SLinus Walleij switch (fifo) { 619d795fd32SLinus Walleij case MCDE_FIFO_A: 620d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_SYNCHCONFA); 621d795fd32SLinus Walleij break; 622d795fd32SLinus Walleij case MCDE_FIFO_B: 623d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_SYNCHCONFB); 624d795fd32SLinus Walleij break; 625d795fd32SLinus Walleij } 626d795fd32SLinus Walleij } 6275fc537bfSLinus Walleij } 6285fc537bfSLinus Walleij 6295fc537bfSLinus Walleij static void mcde_configure_fifo(struct mcde *mcde, enum mcde_fifo fifo, 630d795fd32SLinus Walleij enum mcde_formatter fmt, 6315fc537bfSLinus Walleij int fifo_wtrmrk) 6325fc537bfSLinus Walleij { 6335fc537bfSLinus Walleij u32 val; 6345fc537bfSLinus Walleij u32 ctrl; 6355fc537bfSLinus Walleij u32 cr0, cr1; 6365fc537bfSLinus Walleij 6375fc537bfSLinus Walleij switch (fifo) { 6385fc537bfSLinus Walleij case MCDE_FIFO_A: 6395fc537bfSLinus Walleij ctrl = MCDE_CTRLA; 6405fc537bfSLinus Walleij cr0 = MCDE_CRA0; 6415fc537bfSLinus Walleij cr1 = MCDE_CRA1; 6425fc537bfSLinus Walleij break; 6435fc537bfSLinus Walleij case MCDE_FIFO_B: 6445fc537bfSLinus Walleij ctrl = MCDE_CTRLB; 6455fc537bfSLinus Walleij cr0 = MCDE_CRB0; 6465fc537bfSLinus Walleij cr1 = MCDE_CRB1; 6475fc537bfSLinus Walleij break; 6485fc537bfSLinus Walleij } 6495fc537bfSLinus Walleij 6505fc537bfSLinus Walleij val = fifo_wtrmrk << MCDE_CTRLX_FIFOWTRMRK_SHIFT; 6515fc537bfSLinus Walleij 652d795fd32SLinus Walleij /* 653d795fd32SLinus Walleij * Select the formatter to use for this FIFO 654d795fd32SLinus Walleij * 655d795fd32SLinus Walleij * The register definitions imply that different IDs should be used 656d795fd32SLinus Walleij * by the DSI formatters depending on if they are in VID or CMD 657d795fd32SLinus Walleij * mode, and the manual says they are dedicated but identical. 658d795fd32SLinus Walleij * The vendor code uses them as it seems fit. 659d795fd32SLinus Walleij */ 660d795fd32SLinus Walleij switch (fmt) { 661d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_0: 662d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 663d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI0VID << MCDE_CTRLX_FORMID_SHIFT; 664d795fd32SLinus Walleij break; 665d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_1: 666d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 667d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI0CMD << MCDE_CTRLX_FORMID_SHIFT; 668d795fd32SLinus Walleij break; 669d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_2: 670d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 671d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI1VID << MCDE_CTRLX_FORMID_SHIFT; 672d795fd32SLinus Walleij break; 673d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_3: 674d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 675d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI1CMD << MCDE_CTRLX_FORMID_SHIFT; 676d795fd32SLinus Walleij break; 677d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_4: 678d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 679d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI2VID << MCDE_CTRLX_FORMID_SHIFT; 680d795fd32SLinus Walleij break; 681d795fd32SLinus Walleij case MCDE_DSI_FORMATTER_5: 682d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DSI << MCDE_CTRLX_FORMTYPE_SHIFT; 683d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DSI2CMD << MCDE_CTRLX_FORMID_SHIFT; 684d795fd32SLinus Walleij break; 685d795fd32SLinus Walleij case MCDE_DPI_FORMATTER_0: 686d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DPITV << MCDE_CTRLX_FORMTYPE_SHIFT; 687d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DPIA << MCDE_CTRLX_FORMID_SHIFT; 688d795fd32SLinus Walleij break; 689d795fd32SLinus Walleij case MCDE_DPI_FORMATTER_1: 690d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMTYPE_DPITV << MCDE_CTRLX_FORMTYPE_SHIFT; 691d795fd32SLinus Walleij val |= MCDE_CTRLX_FORMID_DPIB << MCDE_CTRLX_FORMID_SHIFT; 692d795fd32SLinus Walleij break; 693d795fd32SLinus Walleij } 6945fc537bfSLinus Walleij writel(val, mcde->regs + ctrl); 6955fc537bfSLinus Walleij 6965fc537bfSLinus Walleij /* Blend source with Alpha 0xff on FIFO */ 6975fc537bfSLinus Walleij val = MCDE_CRX0_BLENDEN | 6985fc537bfSLinus Walleij 0xff << MCDE_CRX0_ALPHABLEND_SHIFT; 6995fc537bfSLinus Walleij writel(val, mcde->regs + cr0); 7005fc537bfSLinus Walleij 701d795fd32SLinus Walleij spin_lock(&mcde->fifo_crx1_lock); 702d795fd32SLinus Walleij val = readl(mcde->regs + cr1); 703d795fd32SLinus Walleij /* 704d795fd32SLinus Walleij * Set-up from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() 705d795fd32SLinus Walleij * FIXME: a different clock needs to be selected for TV out. 706d795fd32SLinus Walleij */ 707d795fd32SLinus Walleij if (mcde->dpi_output) { 708d795fd32SLinus Walleij struct drm_connector *connector = drm_panel_bridge_connector(mcde->bridge); 709d795fd32SLinus Walleij u32 bus_format; 7105fc537bfSLinus Walleij 711d795fd32SLinus Walleij /* Assume RGB888 24 bit if we have no further info */ 712d795fd32SLinus Walleij if (!connector->display_info.num_bus_formats) { 713d795fd32SLinus Walleij dev_info(mcde->dev, "panel does not specify bus format, assume RGB888\n"); 714d795fd32SLinus Walleij bus_format = MEDIA_BUS_FMT_RGB888_1X24; 715d795fd32SLinus Walleij } else { 716d795fd32SLinus Walleij bus_format = connector->display_info.bus_formats[0]; 717d795fd32SLinus Walleij } 718d795fd32SLinus Walleij 719d795fd32SLinus Walleij /* 720d795fd32SLinus Walleij * Set up the CDWIN and OUTBPP for the LCD 721d795fd32SLinus Walleij * 722d795fd32SLinus Walleij * FIXME: fill this in if you know the correspondance between the MIPI 723d795fd32SLinus Walleij * DPI specification and the media bus formats. 724d795fd32SLinus Walleij */ 725d795fd32SLinus Walleij val &= ~MCDE_CRX1_CDWIN_MASK; 726d795fd32SLinus Walleij val &= ~MCDE_CRX1_OUTBPP_MASK; 727d795fd32SLinus Walleij switch (bus_format) { 728d795fd32SLinus Walleij case MEDIA_BUS_FMT_RGB888_1X24: 729d795fd32SLinus Walleij val |= MCDE_CRX1_CDWIN_24BPP << MCDE_CRX1_CDWIN_SHIFT; 730d795fd32SLinus Walleij val |= MCDE_CRX1_OUTBPP_24BPP << MCDE_CRX1_OUTBPP_SHIFT; 731d795fd32SLinus Walleij break; 732d795fd32SLinus Walleij default: 733d795fd32SLinus Walleij dev_err(mcde->dev, "unknown bus format, assume RGB888\n"); 734d795fd32SLinus Walleij val |= MCDE_CRX1_CDWIN_24BPP << MCDE_CRX1_CDWIN_SHIFT; 735d795fd32SLinus Walleij val |= MCDE_CRX1_OUTBPP_24BPP << MCDE_CRX1_OUTBPP_SHIFT; 736d795fd32SLinus Walleij break; 737d795fd32SLinus Walleij } 738d795fd32SLinus Walleij } else { 739d795fd32SLinus Walleij /* Use the MCDE clock for DSI */ 740d795fd32SLinus Walleij val &= ~MCDE_CRX1_CLKSEL_MASK; 7415fc537bfSLinus Walleij val = MCDE_CRX1_CLKSEL_MCDECLK << MCDE_CRX1_CLKSEL_SHIFT; 742d795fd32SLinus Walleij } 7435fc537bfSLinus Walleij writel(val, mcde->regs + cr1); 744d795fd32SLinus Walleij spin_unlock(&mcde->fifo_crx1_lock); 7455fc537bfSLinus Walleij }; 7465fc537bfSLinus Walleij 7475fc537bfSLinus Walleij static void mcde_configure_dsi_formatter(struct mcde *mcde, 748d795fd32SLinus Walleij enum mcde_formatter fmt, 7495fc537bfSLinus Walleij u32 formatter_frame, 7505fc537bfSLinus Walleij int pkt_size) 7515fc537bfSLinus Walleij { 7525fc537bfSLinus Walleij u32 val; 7535fc537bfSLinus Walleij u32 conf0; 7545fc537bfSLinus Walleij u32 frame; 7555fc537bfSLinus Walleij u32 pkt; 7565fc537bfSLinus Walleij u32 sync; 7575fc537bfSLinus Walleij u32 cmdw; 7585fc537bfSLinus Walleij u32 delay0, delay1; 7595fc537bfSLinus Walleij 7605fc537bfSLinus Walleij switch (fmt) { 7615fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_0: 7625fc537bfSLinus Walleij conf0 = MCDE_DSIVID0CONF0; 7635fc537bfSLinus Walleij frame = MCDE_DSIVID0FRAME; 7645fc537bfSLinus Walleij pkt = MCDE_DSIVID0PKT; 7655fc537bfSLinus Walleij sync = MCDE_DSIVID0SYNC; 7665fc537bfSLinus Walleij cmdw = MCDE_DSIVID0CMDW; 7675fc537bfSLinus Walleij delay0 = MCDE_DSIVID0DELAY0; 7685fc537bfSLinus Walleij delay1 = MCDE_DSIVID0DELAY1; 7695fc537bfSLinus Walleij break; 7705fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_1: 7715fc537bfSLinus Walleij conf0 = MCDE_DSIVID1CONF0; 7725fc537bfSLinus Walleij frame = MCDE_DSIVID1FRAME; 7735fc537bfSLinus Walleij pkt = MCDE_DSIVID1PKT; 7745fc537bfSLinus Walleij sync = MCDE_DSIVID1SYNC; 7755fc537bfSLinus Walleij cmdw = MCDE_DSIVID1CMDW; 7765fc537bfSLinus Walleij delay0 = MCDE_DSIVID1DELAY0; 7775fc537bfSLinus Walleij delay1 = MCDE_DSIVID1DELAY1; 7785fc537bfSLinus Walleij break; 7795fc537bfSLinus Walleij case MCDE_DSI_FORMATTER_2: 7805fc537bfSLinus Walleij conf0 = MCDE_DSIVID2CONF0; 7815fc537bfSLinus Walleij frame = MCDE_DSIVID2FRAME; 7825fc537bfSLinus Walleij pkt = MCDE_DSIVID2PKT; 7835fc537bfSLinus Walleij sync = MCDE_DSIVID2SYNC; 7845fc537bfSLinus Walleij cmdw = MCDE_DSIVID2CMDW; 7855fc537bfSLinus Walleij delay0 = MCDE_DSIVID2DELAY0; 7865fc537bfSLinus Walleij delay1 = MCDE_DSIVID2DELAY1; 7875fc537bfSLinus Walleij break; 788d795fd32SLinus Walleij default: 789d795fd32SLinus Walleij dev_err(mcde->dev, "tried to configure a non-DSI formatter as DSI\n"); 790d795fd32SLinus Walleij return; 7915fc537bfSLinus Walleij } 7925fc537bfSLinus Walleij 7935fc537bfSLinus Walleij /* 7945fc537bfSLinus Walleij * Enable formatter 7955fc537bfSLinus Walleij * 8 bit commands and DCS commands (notgen = not generic) 7965fc537bfSLinus Walleij */ 7975fc537bfSLinus Walleij val = MCDE_DSICONF0_CMD8 | MCDE_DSICONF0_DCSVID_NOTGEN; 7985fc537bfSLinus Walleij if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) 7995fc537bfSLinus Walleij val |= MCDE_DSICONF0_VID_MODE_VID; 8005fc537bfSLinus Walleij switch (mcde->mdsi->format) { 8015fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB888: 8025fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB888 << 8035fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 8045fc537bfSLinus Walleij break; 8055fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB666: 8065fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB666 << 8075fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 8085fc537bfSLinus Walleij break; 8095fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB666_PACKED: 81077f512bdSLinus Walleij dev_err(mcde->dev, 81177f512bdSLinus Walleij "we cannot handle the packed RGB666 format\n"); 81277f512bdSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB666 << 8135fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 8145fc537bfSLinus Walleij break; 8155fc537bfSLinus Walleij case MIPI_DSI_FMT_RGB565: 8165fc537bfSLinus Walleij val |= MCDE_DSICONF0_PACKING_RGB565 << 8175fc537bfSLinus Walleij MCDE_DSICONF0_PACKING_SHIFT; 8185fc537bfSLinus Walleij break; 8195fc537bfSLinus Walleij default: 8205fc537bfSLinus Walleij dev_err(mcde->dev, "unknown DSI format\n"); 8215fc537bfSLinus Walleij return; 8225fc537bfSLinus Walleij } 8235fc537bfSLinus Walleij writel(val, mcde->regs + conf0); 8245fc537bfSLinus Walleij 8255fc537bfSLinus Walleij writel(formatter_frame, mcde->regs + frame); 8265fc537bfSLinus Walleij writel(pkt_size, mcde->regs + pkt); 8275fc537bfSLinus Walleij writel(0, mcde->regs + sync); 8285fc537bfSLinus Walleij /* Define the MIPI command: we want to write into display memory */ 8295fc537bfSLinus Walleij val = MIPI_DCS_WRITE_MEMORY_CONTINUE << 8305fc537bfSLinus Walleij MCDE_DSIVIDXCMDW_CMDW_CONTINUE_SHIFT; 8315fc537bfSLinus Walleij val |= MIPI_DCS_WRITE_MEMORY_START << 8325fc537bfSLinus Walleij MCDE_DSIVIDXCMDW_CMDW_START_SHIFT; 8335fc537bfSLinus Walleij writel(val, mcde->regs + cmdw); 8345fc537bfSLinus Walleij 8355fc537bfSLinus Walleij /* 8365fc537bfSLinus Walleij * FIXME: the vendor driver has some hack around this value in 8375fc537bfSLinus Walleij * CMD mode with autotrig. 8385fc537bfSLinus Walleij */ 8395fc537bfSLinus Walleij writel(0, mcde->regs + delay0); 8405fc537bfSLinus Walleij writel(0, mcde->regs + delay1); 8415fc537bfSLinus Walleij } 8425fc537bfSLinus Walleij 8435fc537bfSLinus Walleij static void mcde_enable_fifo(struct mcde *mcde, enum mcde_fifo fifo) 8445fc537bfSLinus Walleij { 8455fc537bfSLinus Walleij u32 val; 8465fc537bfSLinus Walleij u32 cr; 8475fc537bfSLinus Walleij 8485fc537bfSLinus Walleij switch (fifo) { 8495fc537bfSLinus Walleij case MCDE_FIFO_A: 8505fc537bfSLinus Walleij cr = MCDE_CRA0; 8515fc537bfSLinus Walleij break; 8525fc537bfSLinus Walleij case MCDE_FIFO_B: 8535fc537bfSLinus Walleij cr = MCDE_CRB0; 8545fc537bfSLinus Walleij break; 8555fc537bfSLinus Walleij default: 8565fc537bfSLinus Walleij dev_err(mcde->dev, "cannot enable FIFO %c\n", 8575fc537bfSLinus Walleij 'A' + fifo); 8585fc537bfSLinus Walleij return; 8595fc537bfSLinus Walleij } 8605fc537bfSLinus Walleij 8615fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 8625fc537bfSLinus Walleij val = readl(mcde->regs + cr); 8635fc537bfSLinus Walleij val |= MCDE_CRX0_FLOEN; 8645fc537bfSLinus Walleij writel(val, mcde->regs + cr); 8655fc537bfSLinus Walleij mcde->flow_active++; 8665fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 8675fc537bfSLinus Walleij } 8685fc537bfSLinus Walleij 8695fc537bfSLinus Walleij static void mcde_disable_fifo(struct mcde *mcde, enum mcde_fifo fifo, 8705fc537bfSLinus Walleij bool wait_for_drain) 8715fc537bfSLinus Walleij { 8725fc537bfSLinus Walleij int timeout = 100; 8735fc537bfSLinus Walleij u32 val; 8745fc537bfSLinus Walleij u32 cr; 8755fc537bfSLinus Walleij 8765fc537bfSLinus Walleij switch (fifo) { 8775fc537bfSLinus Walleij case MCDE_FIFO_A: 8785fc537bfSLinus Walleij cr = MCDE_CRA0; 8795fc537bfSLinus Walleij break; 8805fc537bfSLinus Walleij case MCDE_FIFO_B: 8815fc537bfSLinus Walleij cr = MCDE_CRB0; 8825fc537bfSLinus Walleij break; 8835fc537bfSLinus Walleij default: 8845fc537bfSLinus Walleij dev_err(mcde->dev, "cannot disable FIFO %c\n", 8855fc537bfSLinus Walleij 'A' + fifo); 8865fc537bfSLinus Walleij return; 8875fc537bfSLinus Walleij } 8885fc537bfSLinus Walleij 8895fc537bfSLinus Walleij spin_lock(&mcde->flow_lock); 8905fc537bfSLinus Walleij val = readl(mcde->regs + cr); 8915fc537bfSLinus Walleij val &= ~MCDE_CRX0_FLOEN; 8925fc537bfSLinus Walleij writel(val, mcde->regs + cr); 8935fc537bfSLinus Walleij mcde->flow_active = 0; 8945fc537bfSLinus Walleij spin_unlock(&mcde->flow_lock); 8955fc537bfSLinus Walleij 8965fc537bfSLinus Walleij if (!wait_for_drain) 8975fc537bfSLinus Walleij return; 8985fc537bfSLinus Walleij 8995fc537bfSLinus Walleij /* Check that we really drained and stopped the flow */ 9005fc537bfSLinus Walleij while (readl(mcde->regs + cr) & MCDE_CRX0_FLOEN) { 9015fc537bfSLinus Walleij usleep_range(1000, 1500); 9025fc537bfSLinus Walleij if (!--timeout) { 9035fc537bfSLinus Walleij dev_err(mcde->dev, 9045fc537bfSLinus Walleij "FIFO timeout while clearing FIFO %c\n", 9055fc537bfSLinus Walleij 'A' + fifo); 9065fc537bfSLinus Walleij return; 9075fc537bfSLinus Walleij } 9085fc537bfSLinus Walleij } 9095fc537bfSLinus Walleij } 9105fc537bfSLinus Walleij 9115fc537bfSLinus Walleij /* 9125fc537bfSLinus Walleij * This drains a pipe i.e. a FIFO connected to a certain channel 9135fc537bfSLinus Walleij */ 9145fc537bfSLinus Walleij static void mcde_drain_pipe(struct mcde *mcde, enum mcde_fifo fifo, 9155fc537bfSLinus Walleij enum mcde_channel ch) 9165fc537bfSLinus Walleij { 9175fc537bfSLinus Walleij u32 val; 9185fc537bfSLinus Walleij u32 ctrl; 9195fc537bfSLinus Walleij u32 synsw; 9205fc537bfSLinus Walleij 9215fc537bfSLinus Walleij switch (fifo) { 9225fc537bfSLinus Walleij case MCDE_FIFO_A: 9235fc537bfSLinus Walleij ctrl = MCDE_CTRLA; 9245fc537bfSLinus Walleij break; 9255fc537bfSLinus Walleij case MCDE_FIFO_B: 9265fc537bfSLinus Walleij ctrl = MCDE_CTRLB; 9275fc537bfSLinus Walleij break; 9285fc537bfSLinus Walleij } 9295fc537bfSLinus Walleij 9305fc537bfSLinus Walleij switch (ch) { 9315fc537bfSLinus Walleij case MCDE_CHANNEL_0: 9325fc537bfSLinus Walleij synsw = MCDE_CHNL0SYNCHSW; 9335fc537bfSLinus Walleij break; 9345fc537bfSLinus Walleij case MCDE_CHANNEL_1: 9355fc537bfSLinus Walleij synsw = MCDE_CHNL1SYNCHSW; 9365fc537bfSLinus Walleij break; 9375fc537bfSLinus Walleij case MCDE_CHANNEL_2: 9385fc537bfSLinus Walleij synsw = MCDE_CHNL2SYNCHSW; 9395fc537bfSLinus Walleij break; 9405fc537bfSLinus Walleij case MCDE_CHANNEL_3: 9415fc537bfSLinus Walleij synsw = MCDE_CHNL3SYNCHSW; 9425fc537bfSLinus Walleij return; 9435fc537bfSLinus Walleij } 9445fc537bfSLinus Walleij 9455fc537bfSLinus Walleij val = readl(mcde->regs + ctrl); 9465fc537bfSLinus Walleij if (!(val & MCDE_CTRLX_FIFOEMPTY)) { 9475fc537bfSLinus Walleij dev_err(mcde->dev, "Channel A FIFO not empty (handover)\n"); 9485fc537bfSLinus Walleij /* Attempt to clear the FIFO */ 9495fc537bfSLinus Walleij mcde_enable_fifo(mcde, fifo); 9505fc537bfSLinus Walleij /* Trigger a software sync out on respective channel (0-3) */ 9515fc537bfSLinus Walleij writel(MCDE_CHNLXSYNCHSW_SW_TRIG, mcde->regs + synsw); 9525fc537bfSLinus Walleij /* Disable FIFO A flow again */ 9535fc537bfSLinus Walleij mcde_disable_fifo(mcde, fifo, true); 9545fc537bfSLinus Walleij } 9555fc537bfSLinus Walleij } 9565fc537bfSLinus Walleij 9575fc537bfSLinus Walleij static int mcde_dsi_get_pkt_div(int ppl, int fifo_size) 9585fc537bfSLinus Walleij { 9595fc537bfSLinus Walleij /* 9605fc537bfSLinus Walleij * DSI command mode line packets should be split into an even number of 9615fc537bfSLinus Walleij * packets smaller than or equal to the fifo size. 9625fc537bfSLinus Walleij */ 9635fc537bfSLinus Walleij int div; 9645fc537bfSLinus Walleij const int max_div = DIV_ROUND_UP(MCDE_MAX_WIDTH, fifo_size); 9655fc537bfSLinus Walleij 9665fc537bfSLinus Walleij for (div = 1; div < max_div; div++) 9675fc537bfSLinus Walleij if (ppl % div == 0 && ppl / div <= fifo_size) 9685fc537bfSLinus Walleij return div; 9695fc537bfSLinus Walleij return 1; 9705fc537bfSLinus Walleij } 9715fc537bfSLinus Walleij 972d795fd32SLinus Walleij static void mcde_setup_dpi(struct mcde *mcde, const struct drm_display_mode *mode, 973d795fd32SLinus Walleij int *fifo_wtrmrk_lvl) 974d795fd32SLinus Walleij { 975d795fd32SLinus Walleij struct drm_connector *connector = drm_panel_bridge_connector(mcde->bridge); 976d795fd32SLinus Walleij u32 hsw, hfp, hbp; 977d795fd32SLinus Walleij u32 vsw, vfp, vbp; 978d795fd32SLinus Walleij u32 val; 979d795fd32SLinus Walleij 980d795fd32SLinus Walleij /* FIXME: we only support LCD, implement TV out */ 981d795fd32SLinus Walleij hsw = mode->hsync_end - mode->hsync_start; 982d795fd32SLinus Walleij hfp = mode->hsync_start - mode->hdisplay; 983d795fd32SLinus Walleij hbp = mode->htotal - mode->hsync_end; 984d795fd32SLinus Walleij vsw = mode->vsync_end - mode->vsync_start; 985d795fd32SLinus Walleij vfp = mode->vsync_start - mode->vdisplay; 986d795fd32SLinus Walleij vbp = mode->vtotal - mode->vsync_end; 987d795fd32SLinus Walleij 988d795fd32SLinus Walleij dev_info(mcde->dev, "output on DPI LCD from channel A\n"); 989d795fd32SLinus Walleij /* Display actual values */ 990d795fd32SLinus Walleij dev_info(mcde->dev, "HSW: %d, HFP: %d, HBP: %d, VSW: %d, VFP: %d, VBP: %d\n", 991d795fd32SLinus Walleij hsw, hfp, hbp, vsw, vfp, vbp); 992d795fd32SLinus Walleij 993d795fd32SLinus Walleij /* 994d795fd32SLinus Walleij * The pixel fetcher is 128 64-bit words deep = 1024 bytes. 995d795fd32SLinus Walleij * One overlay of 32bpp (4 cpp) assumed, fetch 160 pixels. 996d795fd32SLinus Walleij * 160 * 4 = 640 bytes. 997d795fd32SLinus Walleij */ 998d795fd32SLinus Walleij *fifo_wtrmrk_lvl = 640; 999d795fd32SLinus Walleij 1000d795fd32SLinus Walleij /* Set up the main control, watermark level at 7 */ 1001d795fd32SLinus Walleij val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; 1002d795fd32SLinus Walleij 1003d795fd32SLinus Walleij /* 1004d795fd32SLinus Walleij * This sets up the internal silicon muxing of the DPI 1005d795fd32SLinus Walleij * lines. This is how the silicon connects out to the 1006d795fd32SLinus Walleij * external pins, then the pins need to be further 1007d795fd32SLinus Walleij * configured into "alternate functions" using pin control 1008d795fd32SLinus Walleij * to actually get the signals out. 1009d795fd32SLinus Walleij * 1010d795fd32SLinus Walleij * FIXME: this is hardcoded to the only setting found in 1011d795fd32SLinus Walleij * the wild. If we need to use different settings for 1012d795fd32SLinus Walleij * different DPI displays, make this parameterizable from 1013d795fd32SLinus Walleij * the device tree. 1014d795fd32SLinus Walleij */ 1015d795fd32SLinus Walleij /* 24 bits DPI: connect Ch A LSB to D[0:7] */ 1016d795fd32SLinus Walleij val |= 0 << MCDE_CONF0_OUTMUX0_SHIFT; 1017d795fd32SLinus Walleij /* 24 bits DPI: connect Ch A MID to D[8:15] */ 1018d795fd32SLinus Walleij val |= 1 << MCDE_CONF0_OUTMUX1_SHIFT; 1019d795fd32SLinus Walleij /* Don't care about this muxing */ 1020d795fd32SLinus Walleij val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; 1021d795fd32SLinus Walleij /* Don't care about this muxing */ 1022d795fd32SLinus Walleij val |= 0 << MCDE_CONF0_OUTMUX3_SHIFT; 1023d795fd32SLinus Walleij /* 24 bits DPI: connect Ch A MSB to D[32:39] */ 1024d795fd32SLinus Walleij val |= 2 << MCDE_CONF0_OUTMUX4_SHIFT; 1025d795fd32SLinus Walleij /* Syncmux bits zero: DPI channel A */ 1026d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_CONF0); 1027d795fd32SLinus Walleij 1028d795fd32SLinus Walleij /* This hammers us into LCD mode */ 1029d795fd32SLinus Walleij writel(0, mcde->regs + MCDE_TVCRA); 1030d795fd32SLinus Walleij 1031d795fd32SLinus Walleij /* Front porch and sync width */ 1032d795fd32SLinus Walleij val = (vsw << MCDE_TVBL1_BEL1_SHIFT); 1033d795fd32SLinus Walleij val |= (vfp << MCDE_TVBL1_BSL1_SHIFT); 1034d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_TVBL1A); 1035d795fd32SLinus Walleij /* The vendor driver sets the same value into TVBL2A */ 1036d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_TVBL2A); 1037d795fd32SLinus Walleij 1038d795fd32SLinus Walleij /* Vertical back porch */ 1039d795fd32SLinus Walleij val = (vbp << MCDE_TVDVO_DVO1_SHIFT); 1040d795fd32SLinus Walleij /* The vendor drivers sets the same value into TVDVOA */ 1041d795fd32SLinus Walleij val |= (vbp << MCDE_TVDVO_DVO2_SHIFT); 1042d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_TVDVOA); 1043d795fd32SLinus Walleij 1044d795fd32SLinus Walleij /* Horizontal back porch, as 0 = 1 cycle we need to subtract 1 */ 1045d795fd32SLinus Walleij writel((hbp - 1), mcde->regs + MCDE_TVTIM1A); 1046d795fd32SLinus Walleij 1047d795fd32SLinus Walleij /* Horizongal sync width and horizonal front porch, 0 = 1 cycle */ 1048d795fd32SLinus Walleij val = ((hsw - 1) << MCDE_TVLBALW_LBW_SHIFT); 1049d795fd32SLinus Walleij val |= ((hfp - 1) << MCDE_TVLBALW_ALW_SHIFT); 1050d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_TVLBALWA); 1051d795fd32SLinus Walleij 1052d795fd32SLinus Walleij /* Blank some TV registers we don't use */ 1053d795fd32SLinus Walleij writel(0, mcde->regs + MCDE_TVISLA); 1054d795fd32SLinus Walleij writel(0, mcde->regs + MCDE_TVBLUA); 1055d795fd32SLinus Walleij 1056d795fd32SLinus Walleij /* Set up sync inversion etc */ 1057d795fd32SLinus Walleij val = 0; 1058d795fd32SLinus Walleij if (mode->flags & DRM_MODE_FLAG_NHSYNC) 1059d795fd32SLinus Walleij val |= MCDE_LCDTIM1B_IHS; 1060d795fd32SLinus Walleij if (mode->flags & DRM_MODE_FLAG_NVSYNC) 1061d795fd32SLinus Walleij val |= MCDE_LCDTIM1B_IVS; 1062d795fd32SLinus Walleij if (connector->display_info.bus_flags & DRM_BUS_FLAG_DE_LOW) 1063d795fd32SLinus Walleij val |= MCDE_LCDTIM1B_IOE; 1064d795fd32SLinus Walleij if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 1065d795fd32SLinus Walleij val |= MCDE_LCDTIM1B_IPC; 1066d795fd32SLinus Walleij writel(val, mcde->regs + MCDE_LCDTIM1A); 1067d795fd32SLinus Walleij } 1068d795fd32SLinus Walleij 1069bfbc5e3bSLinus Walleij static void mcde_setup_dsi(struct mcde *mcde, const struct drm_display_mode *mode, 1070bfbc5e3bSLinus Walleij int cpp, int *fifo_wtrmrk_lvl, int *dsi_formatter_frame, 1071bfbc5e3bSLinus Walleij int *dsi_pkt_size) 10725fc537bfSLinus Walleij { 10735fc537bfSLinus Walleij u32 formatter_ppl = mode->hdisplay; /* pixels per line */ 10745fc537bfSLinus Walleij u32 formatter_lpf = mode->vdisplay; /* lines per frame */ 1075bfbc5e3bSLinus Walleij int formatter_frame; 10765fc537bfSLinus Walleij int formatter_cpp; 1077bfbc5e3bSLinus Walleij int fifo_wtrmrk; 10785fc537bfSLinus Walleij u32 pkt_div; 1079bfbc5e3bSLinus Walleij int pkt_size; 10805fc537bfSLinus Walleij u32 val; 1081c4842d4dSLinus Walleij 1082bfbc5e3bSLinus Walleij dev_info(mcde->dev, "output in %s mode, format %dbpp\n", 10835fc537bfSLinus Walleij (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) ? 10845fc537bfSLinus Walleij "VIDEO" : "CMD", 10855fc537bfSLinus Walleij mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format)); 10865fc537bfSLinus Walleij formatter_cpp = 10875fc537bfSLinus Walleij mipi_dsi_pixel_format_to_bpp(mcde->mdsi->format) / 8; 1088bfbc5e3bSLinus Walleij dev_info(mcde->dev, "Overlay CPP: %d bytes, DSI formatter CPP %d bytes\n", 1089bfbc5e3bSLinus Walleij cpp, formatter_cpp); 1090bfbc5e3bSLinus Walleij 1091bfbc5e3bSLinus Walleij /* Set up the main control, watermark level at 7 */ 1092bfbc5e3bSLinus Walleij val = 7 << MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT; 1093bfbc5e3bSLinus Walleij 1094bfbc5e3bSLinus Walleij /* 1095bfbc5e3bSLinus Walleij * This is the internal silicon muxing of the DPI 1096bfbc5e3bSLinus Walleij * (parallell display) lines. Since we are not using 1097bfbc5e3bSLinus Walleij * this at all (we are using DSI) these are just 1098bfbc5e3bSLinus Walleij * dummy values from the vendor tree. 1099bfbc5e3bSLinus Walleij */ 1100bfbc5e3bSLinus Walleij val |= 3 << MCDE_CONF0_OUTMUX0_SHIFT; 1101bfbc5e3bSLinus Walleij val |= 3 << MCDE_CONF0_OUTMUX1_SHIFT; 1102bfbc5e3bSLinus Walleij val |= 0 << MCDE_CONF0_OUTMUX2_SHIFT; 1103bfbc5e3bSLinus Walleij val |= 4 << MCDE_CONF0_OUTMUX3_SHIFT; 1104bfbc5e3bSLinus Walleij val |= 5 << MCDE_CONF0_OUTMUX4_SHIFT; 1105bfbc5e3bSLinus Walleij writel(val, mcde->regs + MCDE_CONF0); 11065fc537bfSLinus Walleij 11075fc537bfSLinus Walleij /* Calculations from mcde_fmtr_dsi.c, fmtr_dsi_enable_video() */ 11085fc537bfSLinus Walleij 11095fc537bfSLinus Walleij /* 11105fc537bfSLinus Walleij * Set up FIFO A watermark level: 11115fc537bfSLinus Walleij * 128 for LCD 32bpp video mode 11125fc537bfSLinus Walleij * 48 for LCD 32bpp command mode 11135fc537bfSLinus Walleij * 128 for LCD 16bpp video mode 11145fc537bfSLinus Walleij * 64 for LCD 16bpp command mode 11155fc537bfSLinus Walleij * 128 for HDMI 32bpp 11165fc537bfSLinus Walleij * 192 for HDMI 16bpp 11175fc537bfSLinus Walleij */ 11185fc537bfSLinus Walleij fifo_wtrmrk = mode->hdisplay; 11195fc537bfSLinus Walleij if (mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO) { 11205fc537bfSLinus Walleij fifo_wtrmrk = min(fifo_wtrmrk, 128); 11215fc537bfSLinus Walleij pkt_div = 1; 11225fc537bfSLinus Walleij } else { 11235fc537bfSLinus Walleij fifo_wtrmrk = min(fifo_wtrmrk, 48); 11245fc537bfSLinus Walleij /* The FIFO is 640 entries deep on this v3 hardware */ 11255fc537bfSLinus Walleij pkt_div = mcde_dsi_get_pkt_div(mode->hdisplay, 640); 11265fc537bfSLinus Walleij } 1127bfbc5e3bSLinus Walleij dev_dbg(mcde->dev, "FIFO watermark after flooring: %d bytes\n", 11285fc537bfSLinus Walleij fifo_wtrmrk); 1129bfbc5e3bSLinus Walleij dev_dbg(mcde->dev, "Packet divisor: %d bytes\n", pkt_div); 11305fc537bfSLinus Walleij 11315fc537bfSLinus Walleij /* NOTE: pkt_div is 1 for video mode */ 11325fc537bfSLinus Walleij pkt_size = (formatter_ppl * formatter_cpp) / pkt_div; 11335fc537bfSLinus Walleij /* Commands CMD8 need one extra byte */ 11345fc537bfSLinus Walleij if (!(mcde->mdsi->mode_flags & MIPI_DSI_MODE_VIDEO)) 11355fc537bfSLinus Walleij pkt_size++; 11365fc537bfSLinus Walleij 1137bfbc5e3bSLinus Walleij dev_dbg(mcde->dev, "DSI packet size: %d * %d bytes per line\n", 11385fc537bfSLinus Walleij pkt_size, pkt_div); 1139bfbc5e3bSLinus Walleij dev_dbg(mcde->dev, "Overlay frame size: %u bytes\n", 11405fc537bfSLinus Walleij mode->hdisplay * mode->vdisplay * cpp); 1141bfbc5e3bSLinus Walleij /* NOTE: pkt_div is 1 for video mode */ 1142bfbc5e3bSLinus Walleij formatter_frame = pkt_size * pkt_div * formatter_lpf; 1143bfbc5e3bSLinus Walleij dev_dbg(mcde->dev, "Formatter frame size: %u bytes\n", formatter_frame); 1144bfbc5e3bSLinus Walleij 1145bfbc5e3bSLinus Walleij *fifo_wtrmrk_lvl = fifo_wtrmrk; 1146bfbc5e3bSLinus Walleij *dsi_pkt_size = pkt_size; 1147bfbc5e3bSLinus Walleij *dsi_formatter_frame = formatter_frame; 1148bfbc5e3bSLinus Walleij } 1149bfbc5e3bSLinus Walleij 1150bfbc5e3bSLinus Walleij static void mcde_display_enable(struct drm_simple_display_pipe *pipe, 1151bfbc5e3bSLinus Walleij struct drm_crtc_state *cstate, 1152bfbc5e3bSLinus Walleij struct drm_plane_state *plane_state) 1153bfbc5e3bSLinus Walleij { 1154bfbc5e3bSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 1155bfbc5e3bSLinus Walleij struct drm_plane *plane = &pipe->plane; 1156bfbc5e3bSLinus Walleij struct drm_device *drm = crtc->dev; 1157bfbc5e3bSLinus Walleij struct mcde *mcde = to_mcde(drm); 1158bfbc5e3bSLinus Walleij const struct drm_display_mode *mode = &cstate->mode; 1159bfbc5e3bSLinus Walleij struct drm_framebuffer *fb = plane->state->fb; 1160bfbc5e3bSLinus Walleij u32 format = fb->format->format; 1161bfbc5e3bSLinus Walleij int dsi_pkt_size; 1162bfbc5e3bSLinus Walleij int fifo_wtrmrk; 1163bfbc5e3bSLinus Walleij int cpp = fb->format->cpp[0]; 1164bfbc5e3bSLinus Walleij struct drm_format_name_buf tmp; 1165bfbc5e3bSLinus Walleij u32 dsi_formatter_frame; 1166bfbc5e3bSLinus Walleij u32 val; 1167bfbc5e3bSLinus Walleij int ret; 1168bfbc5e3bSLinus Walleij 1169bfbc5e3bSLinus Walleij /* This powers up the entire MCDE block and the DSI hardware */ 1170bfbc5e3bSLinus Walleij ret = regulator_enable(mcde->epod); 1171bfbc5e3bSLinus Walleij if (ret) { 1172bfbc5e3bSLinus Walleij dev_err(drm->dev, "can't re-enable EPOD regulator\n"); 1173bfbc5e3bSLinus Walleij return; 1174bfbc5e3bSLinus Walleij } 1175bfbc5e3bSLinus Walleij 1176bfbc5e3bSLinus Walleij dev_info(drm->dev, "enable MCDE, %d x %d format %s\n", 1177bfbc5e3bSLinus Walleij mode->hdisplay, mode->vdisplay, 1178bfbc5e3bSLinus Walleij drm_get_format_name(format, &tmp)); 1179bfbc5e3bSLinus Walleij 1180bfbc5e3bSLinus Walleij 1181bfbc5e3bSLinus Walleij /* Clear any pending interrupts */ 1182bfbc5e3bSLinus Walleij mcde_display_disable_irqs(mcde); 1183bfbc5e3bSLinus Walleij writel(0, mcde->regs + MCDE_IMSCERR); 1184bfbc5e3bSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISERR); 1185bfbc5e3bSLinus Walleij 1186d795fd32SLinus Walleij if (mcde->dpi_output) 1187d795fd32SLinus Walleij mcde_setup_dpi(mcde, mode, &fifo_wtrmrk); 1188d795fd32SLinus Walleij else 1189bfbc5e3bSLinus Walleij mcde_setup_dsi(mcde, mode, cpp, &fifo_wtrmrk, 1190bfbc5e3bSLinus Walleij &dsi_formatter_frame, &dsi_pkt_size); 1191bfbc5e3bSLinus Walleij 11925fc537bfSLinus Walleij mcde->stride = mode->hdisplay * cpp; 11935fc537bfSLinus Walleij dev_dbg(drm->dev, "Overlay line stride: %u bytes\n", 11945fc537bfSLinus Walleij mcde->stride); 11955fc537bfSLinus Walleij 11965fc537bfSLinus Walleij /* Drain the FIFO A + channel 0 pipe so we have a clean slate */ 11975fc537bfSLinus Walleij mcde_drain_pipe(mcde, MCDE_FIFO_A, MCDE_CHANNEL_0); 11985fc537bfSLinus Walleij 11995fc537bfSLinus Walleij /* 12005fc537bfSLinus Walleij * We set up our display pipeline: 12015fc537bfSLinus Walleij * EXTSRC 0 -> OVERLAY 0 -> CHANNEL 0 -> FIFO A -> DSI FORMATTER 0 12025fc537bfSLinus Walleij * 12035fc537bfSLinus Walleij * First configure the external source (memory) on external source 0 12045fc537bfSLinus Walleij * using the desired bitstream/bitmap format 12055fc537bfSLinus Walleij */ 12065fc537bfSLinus Walleij mcde_configure_extsrc(mcde, MCDE_EXTSRC_0, format); 12075fc537bfSLinus Walleij 12085fc537bfSLinus Walleij /* 12095fc537bfSLinus Walleij * Configure overlay 0 according to format and mode and take input 12105fc537bfSLinus Walleij * from external source 0 and route the output of this overlay to 12115fc537bfSLinus Walleij * channel 0 12125fc537bfSLinus Walleij */ 12135fc537bfSLinus Walleij mcde_configure_overlay(mcde, MCDE_OVERLAY_0, MCDE_EXTSRC_0, 121444c3867aSLinus Walleij MCDE_CHANNEL_0, mode, format, cpp); 12155fc537bfSLinus Walleij 12165fc537bfSLinus Walleij /* 12175fc537bfSLinus Walleij * Configure pixel-per-line and line-per-frame for channel 0 and then 12185fc537bfSLinus Walleij * route channel 0 to FIFO A 12195fc537bfSLinus Walleij */ 12205fc537bfSLinus Walleij mcde_configure_channel(mcde, MCDE_CHANNEL_0, MCDE_FIFO_A, mode); 12215fc537bfSLinus Walleij 1222d795fd32SLinus Walleij if (mcde->dpi_output) { 1223d795fd32SLinus Walleij unsigned long lcd_freq; 1224d795fd32SLinus Walleij 1225d795fd32SLinus Walleij /* Configure FIFO A to use DPI formatter 0 */ 1226d795fd32SLinus Walleij mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DPI_FORMATTER_0, 1227d795fd32SLinus Walleij fifo_wtrmrk); 1228d795fd32SLinus Walleij 1229d795fd32SLinus Walleij /* Set up and enable the LCD clock */ 1230d795fd32SLinus Walleij lcd_freq = clk_round_rate(mcde->fifoa_clk, mode->clock * 1000); 1231d795fd32SLinus Walleij ret = clk_set_rate(mcde->fifoa_clk, lcd_freq); 1232d795fd32SLinus Walleij if (ret) 1233d795fd32SLinus Walleij dev_err(mcde->dev, "failed to set LCD clock rate %lu Hz\n", 1234d795fd32SLinus Walleij lcd_freq); 1235d795fd32SLinus Walleij ret = clk_prepare_enable(mcde->fifoa_clk); 1236d795fd32SLinus Walleij if (ret) { 1237d795fd32SLinus Walleij dev_err(mcde->dev, "failed to enable FIFO A DPI clock\n"); 1238d795fd32SLinus Walleij return; 1239d795fd32SLinus Walleij } 1240d795fd32SLinus Walleij dev_info(mcde->dev, "LCD FIFO A clk rate %lu Hz\n", 1241d795fd32SLinus Walleij clk_get_rate(mcde->fifoa_clk)); 1242d795fd32SLinus Walleij } else { 12435fc537bfSLinus Walleij /* Configure FIFO A to use DSI formatter 0 */ 12445fc537bfSLinus Walleij mcde_configure_fifo(mcde, MCDE_FIFO_A, MCDE_DSI_FORMATTER_0, 12455fc537bfSLinus Walleij fifo_wtrmrk); 12465fc537bfSLinus Walleij 124742bac89aSLinus Walleij /* 124842bac89aSLinus Walleij * This brings up the DSI bridge which is tightly connected 124942bac89aSLinus Walleij * to the MCDE DSI formatter. 125042bac89aSLinus Walleij */ 125142bac89aSLinus Walleij mcde_dsi_enable(mcde->bridge); 125242bac89aSLinus Walleij 12535fc537bfSLinus Walleij /* Configure the DSI formatter 0 for the DSI panel output */ 12545fc537bfSLinus Walleij mcde_configure_dsi_formatter(mcde, MCDE_DSI_FORMATTER_0, 1255bfbc5e3bSLinus Walleij dsi_formatter_frame, dsi_pkt_size); 1256d795fd32SLinus Walleij } 12575fc537bfSLinus Walleij 1258709c2773SLinus Walleij switch (mcde->flow_mode) { 1259709c2773SLinus Walleij case MCDE_COMMAND_TE_FLOW: 1260709c2773SLinus Walleij case MCDE_COMMAND_BTA_TE_FLOW: 1261709c2773SLinus Walleij case MCDE_VIDEO_TE_FLOW: 1262d795fd32SLinus Walleij /* We are using TE in some combination */ 12635fc537bfSLinus Walleij if (mode->flags & DRM_MODE_FLAG_NVSYNC) 12645fc537bfSLinus Walleij val = MCDE_VSCRC_VSPOL; 12655fc537bfSLinus Walleij else 12665fc537bfSLinus Walleij val = 0; 12675fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_VSCRC0); 12685fc537bfSLinus Walleij /* Enable VSYNC capture on TE0 */ 12695fc537bfSLinus Walleij val = readl(mcde->regs + MCDE_CRC); 12705fc537bfSLinus Walleij val |= MCDE_CRC_SYCEN0; 12715fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_CRC); 1272709c2773SLinus Walleij break; 1273709c2773SLinus Walleij default: 1274709c2773SLinus Walleij /* No TE capture */ 1275709c2773SLinus Walleij break; 1276768859c2SStephan Gerhold } 12775fc537bfSLinus Walleij 12785fc537bfSLinus Walleij drm_crtc_vblank_on(crtc); 12795fc537bfSLinus Walleij 1280d920e8daSStephan Gerhold /* 128142bac89aSLinus Walleij * If we're using oneshot mode we don't start the flow 128242bac89aSLinus Walleij * until each time the display is given an update, and 128342bac89aSLinus Walleij * then we disable it immediately after. For all other 128442bac89aSLinus Walleij * modes (command or video) we start the FIFO flow 128542bac89aSLinus Walleij * right here. This is necessary for the hardware to 128642bac89aSLinus Walleij * behave right. 1287d920e8daSStephan Gerhold */ 128842bac89aSLinus Walleij if (mcde->flow_mode != MCDE_COMMAND_ONESHOT_FLOW) { 1289d920e8daSStephan Gerhold mcde_enable_fifo(mcde, MCDE_FIFO_A); 1290709c2773SLinus Walleij dev_dbg(mcde->dev, "started MCDE video FIFO flow\n"); 1291709c2773SLinus Walleij } 1292d920e8daSStephan Gerhold 129342bac89aSLinus Walleij /* Enable MCDE with automatic clock gating */ 1294c4842d4dSLinus Walleij val = readl(mcde->regs + MCDE_CR); 1295c4842d4dSLinus Walleij val |= MCDE_CR_MCDEEN | MCDE_CR_AUTOCLKG_EN; 1296c4842d4dSLinus Walleij writel(val, mcde->regs + MCDE_CR); 1297c4842d4dSLinus Walleij 12985fc537bfSLinus Walleij dev_info(drm->dev, "MCDE display is enabled\n"); 12995fc537bfSLinus Walleij } 13005fc537bfSLinus Walleij 13015fc537bfSLinus Walleij static void mcde_display_disable(struct drm_simple_display_pipe *pipe) 13025fc537bfSLinus Walleij { 13035fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 13045fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1305fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 130697de8636SStephan Gerhold struct drm_pending_vblank_event *event; 1307c4842d4dSLinus Walleij int ret; 13085fc537bfSLinus Walleij 13095fc537bfSLinus Walleij drm_crtc_vblank_off(crtc); 13105fc537bfSLinus Walleij 13115fc537bfSLinus Walleij /* Disable FIFO A flow */ 13125fc537bfSLinus Walleij mcde_disable_fifo(mcde, MCDE_FIFO_A, true); 13135fc537bfSLinus Walleij 1314d795fd32SLinus Walleij if (mcde->dpi_output) { 1315d795fd32SLinus Walleij clk_disable_unprepare(mcde->fifoa_clk); 1316d795fd32SLinus Walleij } else { 131742bac89aSLinus Walleij /* This disables the DSI bridge */ 131842bac89aSLinus Walleij mcde_dsi_disable(mcde->bridge); 1319d795fd32SLinus Walleij } 132042bac89aSLinus Walleij 132197de8636SStephan Gerhold event = crtc->state->event; 132297de8636SStephan Gerhold if (event) { 132397de8636SStephan Gerhold crtc->state->event = NULL; 132497de8636SStephan Gerhold 132597de8636SStephan Gerhold spin_lock_irq(&crtc->dev->event_lock); 132697de8636SStephan Gerhold drm_crtc_send_vblank_event(crtc, event); 132797de8636SStephan Gerhold spin_unlock_irq(&crtc->dev->event_lock); 132897de8636SStephan Gerhold } 132997de8636SStephan Gerhold 1330c4842d4dSLinus Walleij ret = regulator_disable(mcde->epod); 1331c4842d4dSLinus Walleij if (ret) 1332c4842d4dSLinus Walleij dev_err(drm->dev, "can't disable EPOD regulator\n"); 1333c4842d4dSLinus Walleij /* Make sure we are powered down (before we may power up again) */ 1334c4842d4dSLinus Walleij usleep_range(50000, 70000); 1335c4842d4dSLinus Walleij 13365fc537bfSLinus Walleij dev_info(drm->dev, "MCDE display is disabled\n"); 13375fc537bfSLinus Walleij } 13385fc537bfSLinus Walleij 1339ea66a9beSLinus Walleij static void mcde_start_flow(struct mcde *mcde) 13405fc537bfSLinus Walleij { 1341709c2773SLinus Walleij /* Request a TE ACK only in TE+BTA mode */ 1342709c2773SLinus Walleij if (mcde->flow_mode == MCDE_COMMAND_BTA_TE_FLOW) 13435fc537bfSLinus Walleij mcde_dsi_te_request(mcde->mdsi); 13445fc537bfSLinus Walleij 13455fc537bfSLinus Walleij /* Enable FIFO A flow */ 13465fc537bfSLinus Walleij mcde_enable_fifo(mcde, MCDE_FIFO_A); 13475fc537bfSLinus Walleij 13485fc537bfSLinus Walleij /* 13495fc537bfSLinus Walleij * If oneshot mode is enabled, the flow will be disabled 13505fc537bfSLinus Walleij * when the TE0 IRQ arrives in the interrupt handler. Otherwise 13515fc537bfSLinus Walleij * updates are continuously streamed to the display after this 13525fc537bfSLinus Walleij * point. 13535fc537bfSLinus Walleij */ 13545fc537bfSLinus Walleij 1355709c2773SLinus Walleij if (mcde->flow_mode == MCDE_COMMAND_ONESHOT_FLOW) { 13565fc537bfSLinus Walleij /* Trigger a software sync out on channel 0 */ 13575fc537bfSLinus Walleij writel(MCDE_CHNLXSYNCHSW_SW_TRIG, 13585fc537bfSLinus Walleij mcde->regs + MCDE_CHNL0SYNCHSW); 13595fc537bfSLinus Walleij 13605fc537bfSLinus Walleij /* 13615fc537bfSLinus Walleij * Disable FIFO A flow again: since we are using TE sync we 13625fc537bfSLinus Walleij * need to wait for the FIFO to drain before we continue 13635fc537bfSLinus Walleij * so repeated calls to this function will not cause a mess 13645fc537bfSLinus Walleij * in the hardware by pushing updates will updates are going 13655fc537bfSLinus Walleij * on already. 13665fc537bfSLinus Walleij */ 13675fc537bfSLinus Walleij mcde_disable_fifo(mcde, MCDE_FIFO_A, true); 1368709c2773SLinus Walleij } 13695fc537bfSLinus Walleij 1370709c2773SLinus Walleij dev_dbg(mcde->dev, "started MCDE FIFO flow\n"); 13715fc537bfSLinus Walleij } 13725fc537bfSLinus Walleij 13735fc537bfSLinus Walleij static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) 13745fc537bfSLinus Walleij { 13755fc537bfSLinus Walleij /* Write bitmap base address to register */ 13765fc537bfSLinus Walleij writel(buffer_address, mcde->regs + MCDE_EXTSRCXA0); 13775fc537bfSLinus Walleij /* 13785fc537bfSLinus Walleij * Base address for next line this is probably only used 13795fc537bfSLinus Walleij * in interlace modes. 13805fc537bfSLinus Walleij */ 13815fc537bfSLinus Walleij writel(buffer_address + mcde->stride, mcde->regs + MCDE_EXTSRCXA1); 13825fc537bfSLinus Walleij } 13835fc537bfSLinus Walleij 13845fc537bfSLinus Walleij static void mcde_display_update(struct drm_simple_display_pipe *pipe, 13855fc537bfSLinus Walleij struct drm_plane_state *old_pstate) 13865fc537bfSLinus Walleij { 13875fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 13885fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1389fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 13905fc537bfSLinus Walleij struct drm_pending_vblank_event *event = crtc->state->event; 13915fc537bfSLinus Walleij struct drm_plane *plane = &pipe->plane; 13925fc537bfSLinus Walleij struct drm_plane_state *pstate = plane->state; 13935fc537bfSLinus Walleij struct drm_framebuffer *fb = pstate->fb; 13945fc537bfSLinus Walleij 13955fc537bfSLinus Walleij /* 13965fc537bfSLinus Walleij * Handle any pending event first, we need to arm the vblank 13975fc537bfSLinus Walleij * interrupt before sending any update to the display so we don't 13985fc537bfSLinus Walleij * miss the interrupt. 13995fc537bfSLinus Walleij */ 14005fc537bfSLinus Walleij if (event) { 14015fc537bfSLinus Walleij crtc->state->event = NULL; 14025fc537bfSLinus Walleij 14035fc537bfSLinus Walleij spin_lock_irq(&crtc->dev->event_lock); 14045fc537bfSLinus Walleij /* 14055fc537bfSLinus Walleij * Hardware must be on before we can arm any vblank event, 14065fc537bfSLinus Walleij * this is not a scanout controller where there is always 14075fc537bfSLinus Walleij * some periodic update going on, it is completely frozen 14085fc537bfSLinus Walleij * until we get an update. If MCDE output isn't yet enabled, 14095fc537bfSLinus Walleij * we just send a vblank dummy event back. 14105fc537bfSLinus Walleij */ 14115fc537bfSLinus Walleij if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) { 14125fc537bfSLinus Walleij dev_dbg(mcde->dev, "arm vblank event\n"); 14135fc537bfSLinus Walleij drm_crtc_arm_vblank_event(crtc, event); 14145fc537bfSLinus Walleij } else { 14155fc537bfSLinus Walleij dev_dbg(mcde->dev, "insert fake vblank event\n"); 14165fc537bfSLinus Walleij drm_crtc_send_vblank_event(crtc, event); 14175fc537bfSLinus Walleij } 14185fc537bfSLinus Walleij 14195fc537bfSLinus Walleij spin_unlock_irq(&crtc->dev->event_lock); 14205fc537bfSLinus Walleij } 14215fc537bfSLinus Walleij 14225fc537bfSLinus Walleij /* 14235fc537bfSLinus Walleij * We do not start sending framebuffer updates before the 14245fc537bfSLinus Walleij * display is enabled. Update events will however be dispatched 14255fc537bfSLinus Walleij * from the DRM core before the display is enabled. 14265fc537bfSLinus Walleij */ 14275fc537bfSLinus Walleij if (fb) { 14285fc537bfSLinus Walleij mcde_set_extsrc(mcde, drm_fb_cma_get_gem_addr(fb, pstate, 0)); 1429709c2773SLinus Walleij dev_info_once(mcde->dev, "first update of display contents\n"); 143042bac89aSLinus Walleij /* 143142bac89aSLinus Walleij * Usually the flow is already active, unless we are in 143242bac89aSLinus Walleij * oneshot mode, then we need to kick the flow right here. 143342bac89aSLinus Walleij */ 143442bac89aSLinus Walleij if (mcde->flow_active == 0) 1435ea66a9beSLinus Walleij mcde_start_flow(mcde); 14365fc537bfSLinus Walleij } else { 14375fc537bfSLinus Walleij /* 14385fc537bfSLinus Walleij * If an update is receieved before the MCDE is enabled 14395fc537bfSLinus Walleij * (before mcde_display_enable() is called) we can't really 14405fc537bfSLinus Walleij * do much with that buffer. 14415fc537bfSLinus Walleij */ 14425fc537bfSLinus Walleij dev_info(mcde->dev, "ignored a display update\n"); 14435fc537bfSLinus Walleij } 14445fc537bfSLinus Walleij } 14455fc537bfSLinus Walleij 14465fc537bfSLinus Walleij static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) 14475fc537bfSLinus Walleij { 14485fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 14495fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1450fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 14515fc537bfSLinus Walleij u32 val; 14525fc537bfSLinus Walleij 14535fc537bfSLinus Walleij /* Enable all VBLANK IRQs */ 14545fc537bfSLinus Walleij val = MCDE_PP_VCMPA | 14555fc537bfSLinus Walleij MCDE_PP_VCMPB | 14565fc537bfSLinus Walleij MCDE_PP_VSCC0 | 14575fc537bfSLinus Walleij MCDE_PP_VSCC1 | 14585fc537bfSLinus Walleij MCDE_PP_VCMPC0 | 14595fc537bfSLinus Walleij MCDE_PP_VCMPC1; 14605fc537bfSLinus Walleij writel(val, mcde->regs + MCDE_IMSCPP); 14615fc537bfSLinus Walleij 14625fc537bfSLinus Walleij return 0; 14635fc537bfSLinus Walleij } 14645fc537bfSLinus Walleij 14655fc537bfSLinus Walleij static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) 14665fc537bfSLinus Walleij { 14675fc537bfSLinus Walleij struct drm_crtc *crtc = &pipe->crtc; 14685fc537bfSLinus Walleij struct drm_device *drm = crtc->dev; 1469fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 14705fc537bfSLinus Walleij 14715fc537bfSLinus Walleij /* Disable all VBLANK IRQs */ 14725fc537bfSLinus Walleij writel(0, mcde->regs + MCDE_IMSCPP); 14735fc537bfSLinus Walleij /* Clear any pending IRQs */ 14745fc537bfSLinus Walleij writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); 14755fc537bfSLinus Walleij } 14765fc537bfSLinus Walleij 14775fc537bfSLinus Walleij static struct drm_simple_display_pipe_funcs mcde_display_funcs = { 14785fc537bfSLinus Walleij .check = mcde_display_check, 14795fc537bfSLinus Walleij .enable = mcde_display_enable, 14805fc537bfSLinus Walleij .disable = mcde_display_disable, 14815fc537bfSLinus Walleij .update = mcde_display_update, 1482768859c2SStephan Gerhold .enable_vblank = mcde_display_enable_vblank, 1483768859c2SStephan Gerhold .disable_vblank = mcde_display_disable_vblank, 14845fc537bfSLinus Walleij .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb, 14855fc537bfSLinus Walleij }; 14865fc537bfSLinus Walleij 14875fc537bfSLinus Walleij int mcde_display_init(struct drm_device *drm) 14885fc537bfSLinus Walleij { 1489fd7ee85cSDaniel Vetter struct mcde *mcde = to_mcde(drm); 14905fc537bfSLinus Walleij int ret; 14915fc537bfSLinus Walleij static const u32 formats[] = { 14925fc537bfSLinus Walleij DRM_FORMAT_ARGB8888, 14935fc537bfSLinus Walleij DRM_FORMAT_ABGR8888, 14945fc537bfSLinus Walleij DRM_FORMAT_XRGB8888, 14955fc537bfSLinus Walleij DRM_FORMAT_XBGR8888, 14965fc537bfSLinus Walleij DRM_FORMAT_RGB888, 14975fc537bfSLinus Walleij DRM_FORMAT_BGR888, 14985fc537bfSLinus Walleij DRM_FORMAT_ARGB4444, 14995fc537bfSLinus Walleij DRM_FORMAT_ABGR4444, 15005fc537bfSLinus Walleij DRM_FORMAT_XRGB4444, 15015fc537bfSLinus Walleij DRM_FORMAT_XBGR4444, 15025fc537bfSLinus Walleij /* These are actually IRGB1555 so intensity bit is lost */ 15035fc537bfSLinus Walleij DRM_FORMAT_XRGB1555, 15045fc537bfSLinus Walleij DRM_FORMAT_XBGR1555, 15055fc537bfSLinus Walleij DRM_FORMAT_RGB565, 15065fc537bfSLinus Walleij DRM_FORMAT_BGR565, 15075fc537bfSLinus Walleij DRM_FORMAT_YUV422, 15085fc537bfSLinus Walleij }; 15095fc537bfSLinus Walleij 1510d795fd32SLinus Walleij ret = mcde_init_clock_divider(mcde); 1511d795fd32SLinus Walleij if (ret) 1512d795fd32SLinus Walleij return ret; 1513d795fd32SLinus Walleij 15145fc537bfSLinus Walleij ret = drm_simple_display_pipe_init(drm, &mcde->pipe, 15155fc537bfSLinus Walleij &mcde_display_funcs, 15165fc537bfSLinus Walleij formats, ARRAY_SIZE(formats), 15175fc537bfSLinus Walleij NULL, 15185fc537bfSLinus Walleij mcde->connector); 15195fc537bfSLinus Walleij if (ret) 15205fc537bfSLinus Walleij return ret; 15215fc537bfSLinus Walleij 15225fc537bfSLinus Walleij return 0; 15235fc537bfSLinus Walleij } 15245fc537bfSLinus Walleij EXPORT_SYMBOL_GPL(mcde_display_init); 1525