1*b07bcf34SKevin Tang // SPDX-License-Identifier: GPL-2.0 2*b07bcf34SKevin Tang /* 3*b07bcf34SKevin Tang * Copyright (C) 2020 Unisoc Inc. 4*b07bcf34SKevin Tang */ 5*b07bcf34SKevin Tang 6*b07bcf34SKevin Tang #include <linux/component.h> 7*b07bcf34SKevin Tang #include <linux/delay.h> 8*b07bcf34SKevin Tang #include <linux/dma-buf.h> 9*b07bcf34SKevin Tang #include <linux/io.h> 10*b07bcf34SKevin Tang #include <linux/module.h> 11*b07bcf34SKevin Tang #include <linux/of.h> 12*b07bcf34SKevin Tang #include <linux/of_address.h> 13*b07bcf34SKevin Tang #include <linux/of_device.h> 14*b07bcf34SKevin Tang #include <linux/of_graph.h> 15*b07bcf34SKevin Tang #include <linux/of_irq.h> 16*b07bcf34SKevin Tang #include <linux/wait.h> 17*b07bcf34SKevin Tang #include <linux/workqueue.h> 18*b07bcf34SKevin Tang 19*b07bcf34SKevin Tang #include <drm/drm_atomic_helper.h> 20*b07bcf34SKevin Tang #include <drm/drm_crtc_helper.h> 21*b07bcf34SKevin Tang #include <drm/drm_fb_cma_helper.h> 22*b07bcf34SKevin Tang #include <drm/drm_gem_cma_helper.h> 23*b07bcf34SKevin Tang #include <drm/drm_gem_framebuffer_helper.h> 24*b07bcf34SKevin Tang #include <drm/drm_plane_helper.h> 25*b07bcf34SKevin Tang 26*b07bcf34SKevin Tang #include "sprd_drm.h" 27*b07bcf34SKevin Tang #include "sprd_dpu.h" 28*b07bcf34SKevin Tang 29*b07bcf34SKevin Tang /* Global control registers */ 30*b07bcf34SKevin Tang #define REG_DPU_CTRL 0x04 31*b07bcf34SKevin Tang #define REG_DPU_CFG0 0x08 32*b07bcf34SKevin Tang #define REG_PANEL_SIZE 0x20 33*b07bcf34SKevin Tang #define REG_BLEND_SIZE 0x24 34*b07bcf34SKevin Tang #define REG_BG_COLOR 0x2C 35*b07bcf34SKevin Tang 36*b07bcf34SKevin Tang /* Layer0 control registers */ 37*b07bcf34SKevin Tang #define REG_LAY_BASE_ADDR0 0x30 38*b07bcf34SKevin Tang #define REG_LAY_BASE_ADDR1 0x34 39*b07bcf34SKevin Tang #define REG_LAY_BASE_ADDR2 0x38 40*b07bcf34SKevin Tang #define REG_LAY_CTRL 0x40 41*b07bcf34SKevin Tang #define REG_LAY_SIZE 0x44 42*b07bcf34SKevin Tang #define REG_LAY_PITCH 0x48 43*b07bcf34SKevin Tang #define REG_LAY_POS 0x4C 44*b07bcf34SKevin Tang #define REG_LAY_ALPHA 0x50 45*b07bcf34SKevin Tang #define REG_LAY_CROP_START 0x5C 46*b07bcf34SKevin Tang 47*b07bcf34SKevin Tang /* Interrupt control registers */ 48*b07bcf34SKevin Tang #define REG_DPU_INT_EN 0x1E0 49*b07bcf34SKevin Tang #define REG_DPU_INT_CLR 0x1E4 50*b07bcf34SKevin Tang #define REG_DPU_INT_STS 0x1E8 51*b07bcf34SKevin Tang 52*b07bcf34SKevin Tang /* DPI control registers */ 53*b07bcf34SKevin Tang #define REG_DPI_CTRL 0x1F0 54*b07bcf34SKevin Tang #define REG_DPI_H_TIMING 0x1F4 55*b07bcf34SKevin Tang #define REG_DPI_V_TIMING 0x1F8 56*b07bcf34SKevin Tang 57*b07bcf34SKevin Tang /* MMU control registers */ 58*b07bcf34SKevin Tang #define REG_MMU_EN 0x800 59*b07bcf34SKevin Tang #define REG_MMU_VPN_RANGE 0x80C 60*b07bcf34SKevin Tang #define REG_MMU_PPN1 0x83C 61*b07bcf34SKevin Tang #define REG_MMU_RANGE1 0x840 62*b07bcf34SKevin Tang #define REG_MMU_PPN2 0x844 63*b07bcf34SKevin Tang #define REG_MMU_RANGE2 0x848 64*b07bcf34SKevin Tang 65*b07bcf34SKevin Tang /* Global control bits */ 66*b07bcf34SKevin Tang #define BIT_DPU_RUN BIT(0) 67*b07bcf34SKevin Tang #define BIT_DPU_STOP BIT(1) 68*b07bcf34SKevin Tang #define BIT_DPU_REG_UPDATE BIT(2) 69*b07bcf34SKevin Tang #define BIT_DPU_IF_EDPI BIT(0) 70*b07bcf34SKevin Tang 71*b07bcf34SKevin Tang /* Layer control bits */ 72*b07bcf34SKevin Tang #define BIT_DPU_LAY_EN BIT(0) 73*b07bcf34SKevin Tang #define BIT_DPU_LAY_LAYER_ALPHA (0x01 << 2) 74*b07bcf34SKevin Tang #define BIT_DPU_LAY_COMBO_ALPHA (0x02 << 2) 75*b07bcf34SKevin Tang #define BIT_DPU_LAY_FORMAT_YUV422_2PLANE (0x00 << 4) 76*b07bcf34SKevin Tang #define BIT_DPU_LAY_FORMAT_YUV420_2PLANE (0x01 << 4) 77*b07bcf34SKevin Tang #define BIT_DPU_LAY_FORMAT_YUV420_3PLANE (0x02 << 4) 78*b07bcf34SKevin Tang #define BIT_DPU_LAY_FORMAT_ARGB8888 (0x03 << 4) 79*b07bcf34SKevin Tang #define BIT_DPU_LAY_FORMAT_RGB565 (0x04 << 4) 80*b07bcf34SKevin Tang #define BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3 (0x00 << 8) 81*b07bcf34SKevin Tang #define BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0 (0x01 << 8) 82*b07bcf34SKevin Tang #define BIT_DPU_LAY_NO_SWITCH (0x00 << 10) 83*b07bcf34SKevin Tang #define BIT_DPU_LAY_RB_OR_UV_SWITCH (0x01 << 10) 84*b07bcf34SKevin Tang #define BIT_DPU_LAY_MODE_BLEND_NORMAL (0x00 << 16) 85*b07bcf34SKevin Tang #define BIT_DPU_LAY_MODE_BLEND_PREMULT (0x01 << 16) 86*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_0 (0x00 << 20) 87*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_90 (0x01 << 20) 88*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_180 (0x02 << 20) 89*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_270 (0x03 << 20) 90*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_0_M (0x04 << 20) 91*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_90_M (0x05 << 20) 92*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_180_M (0x06 << 20) 93*b07bcf34SKevin Tang #define BIT_DPU_LAY_ROTATION_270_M (0x07 << 20) 94*b07bcf34SKevin Tang 95*b07bcf34SKevin Tang /* Interrupt control & status bits */ 96*b07bcf34SKevin Tang #define BIT_DPU_INT_DONE BIT(0) 97*b07bcf34SKevin Tang #define BIT_DPU_INT_TE BIT(1) 98*b07bcf34SKevin Tang #define BIT_DPU_INT_ERR BIT(2) 99*b07bcf34SKevin Tang #define BIT_DPU_INT_UPDATE_DONE BIT(4) 100*b07bcf34SKevin Tang #define BIT_DPU_INT_VSYNC BIT(5) 101*b07bcf34SKevin Tang 102*b07bcf34SKevin Tang /* DPI control bits */ 103*b07bcf34SKevin Tang #define BIT_DPU_EDPI_TE_EN BIT(8) 104*b07bcf34SKevin Tang #define BIT_DPU_EDPI_FROM_EXTERNAL_PAD BIT(10) 105*b07bcf34SKevin Tang #define BIT_DPU_DPI_HALT_EN BIT(16) 106*b07bcf34SKevin Tang 107*b07bcf34SKevin Tang static const u32 layer_fmts[] = { 108*b07bcf34SKevin Tang DRM_FORMAT_XRGB8888, 109*b07bcf34SKevin Tang DRM_FORMAT_XBGR8888, 110*b07bcf34SKevin Tang DRM_FORMAT_ARGB8888, 111*b07bcf34SKevin Tang DRM_FORMAT_ABGR8888, 112*b07bcf34SKevin Tang DRM_FORMAT_RGBA8888, 113*b07bcf34SKevin Tang DRM_FORMAT_BGRA8888, 114*b07bcf34SKevin Tang DRM_FORMAT_RGBX8888, 115*b07bcf34SKevin Tang DRM_FORMAT_RGB565, 116*b07bcf34SKevin Tang DRM_FORMAT_BGR565, 117*b07bcf34SKevin Tang DRM_FORMAT_NV12, 118*b07bcf34SKevin Tang DRM_FORMAT_NV21, 119*b07bcf34SKevin Tang DRM_FORMAT_NV16, 120*b07bcf34SKevin Tang DRM_FORMAT_NV61, 121*b07bcf34SKevin Tang DRM_FORMAT_YUV420, 122*b07bcf34SKevin Tang DRM_FORMAT_YVU420, 123*b07bcf34SKevin Tang }; 124*b07bcf34SKevin Tang 125*b07bcf34SKevin Tang struct sprd_plane { 126*b07bcf34SKevin Tang struct drm_plane base; 127*b07bcf34SKevin Tang }; 128*b07bcf34SKevin Tang 129*b07bcf34SKevin Tang static int dpu_wait_stop_done(struct sprd_dpu *dpu) 130*b07bcf34SKevin Tang { 131*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 132*b07bcf34SKevin Tang int rc; 133*b07bcf34SKevin Tang 134*b07bcf34SKevin Tang if (ctx->stopped) 135*b07bcf34SKevin Tang return 0; 136*b07bcf34SKevin Tang 137*b07bcf34SKevin Tang rc = wait_event_interruptible_timeout(ctx->wait_queue, ctx->evt_stop, 138*b07bcf34SKevin Tang msecs_to_jiffies(500)); 139*b07bcf34SKevin Tang ctx->evt_stop = false; 140*b07bcf34SKevin Tang 141*b07bcf34SKevin Tang ctx->stopped = true; 142*b07bcf34SKevin Tang 143*b07bcf34SKevin Tang if (!rc) { 144*b07bcf34SKevin Tang drm_err(dpu->drm, "dpu wait for stop done time out!\n"); 145*b07bcf34SKevin Tang return -ETIMEDOUT; 146*b07bcf34SKevin Tang } 147*b07bcf34SKevin Tang 148*b07bcf34SKevin Tang return 0; 149*b07bcf34SKevin Tang } 150*b07bcf34SKevin Tang 151*b07bcf34SKevin Tang static int dpu_wait_update_done(struct sprd_dpu *dpu) 152*b07bcf34SKevin Tang { 153*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 154*b07bcf34SKevin Tang int rc; 155*b07bcf34SKevin Tang 156*b07bcf34SKevin Tang ctx->evt_update = false; 157*b07bcf34SKevin Tang 158*b07bcf34SKevin Tang rc = wait_event_interruptible_timeout(ctx->wait_queue, ctx->evt_update, 159*b07bcf34SKevin Tang msecs_to_jiffies(500)); 160*b07bcf34SKevin Tang 161*b07bcf34SKevin Tang if (!rc) { 162*b07bcf34SKevin Tang drm_err(dpu->drm, "dpu wait for reg update done time out!\n"); 163*b07bcf34SKevin Tang return -ETIMEDOUT; 164*b07bcf34SKevin Tang } 165*b07bcf34SKevin Tang 166*b07bcf34SKevin Tang return 0; 167*b07bcf34SKevin Tang } 168*b07bcf34SKevin Tang 169*b07bcf34SKevin Tang static u32 drm_format_to_dpu(struct drm_framebuffer *fb) 170*b07bcf34SKevin Tang { 171*b07bcf34SKevin Tang u32 format = 0; 172*b07bcf34SKevin Tang 173*b07bcf34SKevin Tang switch (fb->format->format) { 174*b07bcf34SKevin Tang case DRM_FORMAT_BGRA8888: 175*b07bcf34SKevin Tang /* BGRA8888 -> ARGB8888 */ 176*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0; 177*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_ARGB8888; 178*b07bcf34SKevin Tang break; 179*b07bcf34SKevin Tang case DRM_FORMAT_RGBX8888: 180*b07bcf34SKevin Tang case DRM_FORMAT_RGBA8888: 181*b07bcf34SKevin Tang /* RGBA8888 -> ABGR8888 */ 182*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0; 183*b07bcf34SKevin Tang fallthrough; 184*b07bcf34SKevin Tang case DRM_FORMAT_ABGR8888: 185*b07bcf34SKevin Tang /* RB switch */ 186*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 187*b07bcf34SKevin Tang fallthrough; 188*b07bcf34SKevin Tang case DRM_FORMAT_ARGB8888: 189*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_ARGB8888; 190*b07bcf34SKevin Tang break; 191*b07bcf34SKevin Tang case DRM_FORMAT_XBGR8888: 192*b07bcf34SKevin Tang /* RB switch */ 193*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 194*b07bcf34SKevin Tang fallthrough; 195*b07bcf34SKevin Tang case DRM_FORMAT_XRGB8888: 196*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_ARGB8888; 197*b07bcf34SKevin Tang break; 198*b07bcf34SKevin Tang case DRM_FORMAT_BGR565: 199*b07bcf34SKevin Tang /* RB switch */ 200*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 201*b07bcf34SKevin Tang fallthrough; 202*b07bcf34SKevin Tang case DRM_FORMAT_RGB565: 203*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_RGB565; 204*b07bcf34SKevin Tang break; 205*b07bcf34SKevin Tang case DRM_FORMAT_NV12: 206*b07bcf34SKevin Tang /* 2-Lane: Yuv420 */ 207*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV420_2PLANE; 208*b07bcf34SKevin Tang /* Y endian */ 209*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3; 210*b07bcf34SKevin Tang /* UV endian */ 211*b07bcf34SKevin Tang format |= BIT_DPU_LAY_NO_SWITCH; 212*b07bcf34SKevin Tang break; 213*b07bcf34SKevin Tang case DRM_FORMAT_NV21: 214*b07bcf34SKevin Tang /* 2-Lane: Yuv420 */ 215*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV420_2PLANE; 216*b07bcf34SKevin Tang /* Y endian */ 217*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3; 218*b07bcf34SKevin Tang /* UV endian */ 219*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 220*b07bcf34SKevin Tang break; 221*b07bcf34SKevin Tang case DRM_FORMAT_NV16: 222*b07bcf34SKevin Tang /* 2-Lane: Yuv422 */ 223*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV422_2PLANE; 224*b07bcf34SKevin Tang /* Y endian */ 225*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B3B2B1B0; 226*b07bcf34SKevin Tang /* UV endian */ 227*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 228*b07bcf34SKevin Tang break; 229*b07bcf34SKevin Tang case DRM_FORMAT_NV61: 230*b07bcf34SKevin Tang /* 2-Lane: Yuv422 */ 231*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV422_2PLANE; 232*b07bcf34SKevin Tang /* Y endian */ 233*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3; 234*b07bcf34SKevin Tang /* UV endian */ 235*b07bcf34SKevin Tang format |= BIT_DPU_LAY_NO_SWITCH; 236*b07bcf34SKevin Tang break; 237*b07bcf34SKevin Tang case DRM_FORMAT_YUV420: 238*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV420_3PLANE; 239*b07bcf34SKevin Tang /* Y endian */ 240*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3; 241*b07bcf34SKevin Tang /* UV endian */ 242*b07bcf34SKevin Tang format |= BIT_DPU_LAY_NO_SWITCH; 243*b07bcf34SKevin Tang break; 244*b07bcf34SKevin Tang case DRM_FORMAT_YVU420: 245*b07bcf34SKevin Tang format |= BIT_DPU_LAY_FORMAT_YUV420_3PLANE; 246*b07bcf34SKevin Tang /* Y endian */ 247*b07bcf34SKevin Tang format |= BIT_DPU_LAY_DATA_ENDIAN_B0B1B2B3; 248*b07bcf34SKevin Tang /* UV endian */ 249*b07bcf34SKevin Tang format |= BIT_DPU_LAY_RB_OR_UV_SWITCH; 250*b07bcf34SKevin Tang break; 251*b07bcf34SKevin Tang default: 252*b07bcf34SKevin Tang break; 253*b07bcf34SKevin Tang } 254*b07bcf34SKevin Tang 255*b07bcf34SKevin Tang return format; 256*b07bcf34SKevin Tang } 257*b07bcf34SKevin Tang 258*b07bcf34SKevin Tang static u32 drm_rotation_to_dpu(struct drm_plane_state *state) 259*b07bcf34SKevin Tang { 260*b07bcf34SKevin Tang u32 rotation = 0; 261*b07bcf34SKevin Tang 262*b07bcf34SKevin Tang switch (state->rotation) { 263*b07bcf34SKevin Tang default: 264*b07bcf34SKevin Tang case DRM_MODE_ROTATE_0: 265*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_0; 266*b07bcf34SKevin Tang break; 267*b07bcf34SKevin Tang case DRM_MODE_ROTATE_90: 268*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_90; 269*b07bcf34SKevin Tang break; 270*b07bcf34SKevin Tang case DRM_MODE_ROTATE_180: 271*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_180; 272*b07bcf34SKevin Tang break; 273*b07bcf34SKevin Tang case DRM_MODE_ROTATE_270: 274*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_270; 275*b07bcf34SKevin Tang break; 276*b07bcf34SKevin Tang case DRM_MODE_REFLECT_Y: 277*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_180_M; 278*b07bcf34SKevin Tang break; 279*b07bcf34SKevin Tang case (DRM_MODE_REFLECT_Y | DRM_MODE_ROTATE_90): 280*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_90_M; 281*b07bcf34SKevin Tang break; 282*b07bcf34SKevin Tang case DRM_MODE_REFLECT_X: 283*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_0_M; 284*b07bcf34SKevin Tang break; 285*b07bcf34SKevin Tang case (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90): 286*b07bcf34SKevin Tang rotation = BIT_DPU_LAY_ROTATION_270_M; 287*b07bcf34SKevin Tang break; 288*b07bcf34SKevin Tang } 289*b07bcf34SKevin Tang 290*b07bcf34SKevin Tang return rotation; 291*b07bcf34SKevin Tang } 292*b07bcf34SKevin Tang 293*b07bcf34SKevin Tang static u32 drm_blend_to_dpu(struct drm_plane_state *state) 294*b07bcf34SKevin Tang { 295*b07bcf34SKevin Tang u32 blend = 0; 296*b07bcf34SKevin Tang 297*b07bcf34SKevin Tang switch (state->pixel_blend_mode) { 298*b07bcf34SKevin Tang case DRM_MODE_BLEND_COVERAGE: 299*b07bcf34SKevin Tang /* alpha mode select - combo alpha */ 300*b07bcf34SKevin Tang blend |= BIT_DPU_LAY_COMBO_ALPHA; 301*b07bcf34SKevin Tang /* Normal mode */ 302*b07bcf34SKevin Tang blend |= BIT_DPU_LAY_MODE_BLEND_NORMAL; 303*b07bcf34SKevin Tang break; 304*b07bcf34SKevin Tang case DRM_MODE_BLEND_PREMULTI: 305*b07bcf34SKevin Tang /* alpha mode select - combo alpha */ 306*b07bcf34SKevin Tang blend |= BIT_DPU_LAY_COMBO_ALPHA; 307*b07bcf34SKevin Tang /* Pre-mult mode */ 308*b07bcf34SKevin Tang blend |= BIT_DPU_LAY_MODE_BLEND_PREMULT; 309*b07bcf34SKevin Tang break; 310*b07bcf34SKevin Tang case DRM_MODE_BLEND_PIXEL_NONE: 311*b07bcf34SKevin Tang default: 312*b07bcf34SKevin Tang /* don't do blending, maybe RGBX */ 313*b07bcf34SKevin Tang /* alpha mode select - layer alpha */ 314*b07bcf34SKevin Tang blend |= BIT_DPU_LAY_LAYER_ALPHA; 315*b07bcf34SKevin Tang break; 316*b07bcf34SKevin Tang } 317*b07bcf34SKevin Tang 318*b07bcf34SKevin Tang return blend; 319*b07bcf34SKevin Tang } 320*b07bcf34SKevin Tang 321*b07bcf34SKevin Tang static void sprd_dpu_layer(struct sprd_dpu *dpu, struct drm_plane_state *state) 322*b07bcf34SKevin Tang { 323*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 324*b07bcf34SKevin Tang struct drm_gem_cma_object *cma_obj; 325*b07bcf34SKevin Tang struct drm_framebuffer *fb = state->fb; 326*b07bcf34SKevin Tang u32 addr, size, offset, pitch, blend, format, rotation; 327*b07bcf34SKevin Tang u32 src_x = state->src_x >> 16; 328*b07bcf34SKevin Tang u32 src_y = state->src_y >> 16; 329*b07bcf34SKevin Tang u32 src_w = state->src_w >> 16; 330*b07bcf34SKevin Tang u32 src_h = state->src_h >> 16; 331*b07bcf34SKevin Tang u32 dst_x = state->crtc_x; 332*b07bcf34SKevin Tang u32 dst_y = state->crtc_y; 333*b07bcf34SKevin Tang u32 alpha = state->alpha; 334*b07bcf34SKevin Tang u32 index = state->zpos; 335*b07bcf34SKevin Tang int i; 336*b07bcf34SKevin Tang 337*b07bcf34SKevin Tang offset = (dst_x & 0xffff) | (dst_y << 16); 338*b07bcf34SKevin Tang size = (src_w & 0xffff) | (src_h << 16); 339*b07bcf34SKevin Tang 340*b07bcf34SKevin Tang for (i = 0; i < fb->format->num_planes; i++) { 341*b07bcf34SKevin Tang cma_obj = drm_fb_cma_get_gem_obj(fb, i); 342*b07bcf34SKevin Tang addr = cma_obj->paddr + fb->offsets[i]; 343*b07bcf34SKevin Tang 344*b07bcf34SKevin Tang if (i == 0) 345*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_BASE_ADDR0, addr, index); 346*b07bcf34SKevin Tang else if (i == 1) 347*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_BASE_ADDR1, addr, index); 348*b07bcf34SKevin Tang else 349*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_BASE_ADDR2, addr, index); 350*b07bcf34SKevin Tang } 351*b07bcf34SKevin Tang 352*b07bcf34SKevin Tang if (fb->format->num_planes == 3) { 353*b07bcf34SKevin Tang /* UV pitch is 1/2 of Y pitch */ 354*b07bcf34SKevin Tang pitch = (fb->pitches[0] / fb->format->cpp[0]) | 355*b07bcf34SKevin Tang (fb->pitches[0] / fb->format->cpp[0] << 15); 356*b07bcf34SKevin Tang } else { 357*b07bcf34SKevin Tang pitch = fb->pitches[0] / fb->format->cpp[0]; 358*b07bcf34SKevin Tang } 359*b07bcf34SKevin Tang 360*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_POS, offset, index); 361*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_SIZE, size, index); 362*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_CROP_START, 363*b07bcf34SKevin Tang src_y << 16 | src_x, index); 364*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_ALPHA, alpha, index); 365*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_PITCH, pitch, index); 366*b07bcf34SKevin Tang 367*b07bcf34SKevin Tang format = drm_format_to_dpu(fb); 368*b07bcf34SKevin Tang blend = drm_blend_to_dpu(state); 369*b07bcf34SKevin Tang rotation = drm_rotation_to_dpu(state); 370*b07bcf34SKevin Tang 371*b07bcf34SKevin Tang layer_reg_wr(ctx, REG_LAY_CTRL, BIT_DPU_LAY_EN | 372*b07bcf34SKevin Tang format | 373*b07bcf34SKevin Tang blend | 374*b07bcf34SKevin Tang rotation, 375*b07bcf34SKevin Tang index); 376*b07bcf34SKevin Tang } 377*b07bcf34SKevin Tang 378*b07bcf34SKevin Tang static void sprd_dpu_flip(struct sprd_dpu *dpu) 379*b07bcf34SKevin Tang { 380*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 381*b07bcf34SKevin Tang 382*b07bcf34SKevin Tang /* 383*b07bcf34SKevin Tang * Make sure the dpu is in stop status. DPU has no shadow 384*b07bcf34SKevin Tang * registers in EDPI mode. So the config registers can only be 385*b07bcf34SKevin Tang * updated in the rising edge of DPU_RUN bit. 386*b07bcf34SKevin Tang */ 387*b07bcf34SKevin Tang if (ctx->if_type == SPRD_DPU_IF_EDPI) 388*b07bcf34SKevin Tang dpu_wait_stop_done(dpu); 389*b07bcf34SKevin Tang 390*b07bcf34SKevin Tang /* update trigger and wait */ 391*b07bcf34SKevin Tang if (ctx->if_type == SPRD_DPU_IF_DPI) { 392*b07bcf34SKevin Tang if (!ctx->stopped) { 393*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_CTRL, BIT_DPU_REG_UPDATE); 394*b07bcf34SKevin Tang dpu_wait_update_done(dpu); 395*b07bcf34SKevin Tang } 396*b07bcf34SKevin Tang 397*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_INT_EN, BIT_DPU_INT_ERR); 398*b07bcf34SKevin Tang } else if (ctx->if_type == SPRD_DPU_IF_EDPI) { 399*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_CTRL, BIT_DPU_RUN); 400*b07bcf34SKevin Tang 401*b07bcf34SKevin Tang ctx->stopped = false; 402*b07bcf34SKevin Tang } 403*b07bcf34SKevin Tang } 404*b07bcf34SKevin Tang 405*b07bcf34SKevin Tang static void sprd_dpu_init(struct sprd_dpu *dpu) 406*b07bcf34SKevin Tang { 407*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 408*b07bcf34SKevin Tang u32 int_mask = 0; 409*b07bcf34SKevin Tang 410*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_BG_COLOR); 411*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_MMU_EN); 412*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_MMU_PPN1); 413*b07bcf34SKevin Tang writel(0xffff, ctx->base + REG_MMU_RANGE1); 414*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_MMU_PPN2); 415*b07bcf34SKevin Tang writel(0xffff, ctx->base + REG_MMU_RANGE2); 416*b07bcf34SKevin Tang writel(0x1ffff, ctx->base + REG_MMU_VPN_RANGE); 417*b07bcf34SKevin Tang 418*b07bcf34SKevin Tang if (ctx->if_type == SPRD_DPU_IF_DPI) { 419*b07bcf34SKevin Tang /* use dpi as interface */ 420*b07bcf34SKevin Tang dpu_reg_clr(ctx, REG_DPU_CFG0, BIT_DPU_IF_EDPI); 421*b07bcf34SKevin Tang /* disable Halt function for SPRD DSI */ 422*b07bcf34SKevin Tang dpu_reg_clr(ctx, REG_DPI_CTRL, BIT_DPU_DPI_HALT_EN); 423*b07bcf34SKevin Tang /* select te from external pad */ 424*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPI_CTRL, BIT_DPU_EDPI_FROM_EXTERNAL_PAD); 425*b07bcf34SKevin Tang 426*b07bcf34SKevin Tang /* enable dpu update done INT */ 427*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_UPDATE_DONE; 428*b07bcf34SKevin Tang /* enable dpu done INT */ 429*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_DONE; 430*b07bcf34SKevin Tang /* enable dpu dpi vsync */ 431*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_VSYNC; 432*b07bcf34SKevin Tang /* enable dpu TE INT */ 433*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_TE; 434*b07bcf34SKevin Tang /* enable underflow err INT */ 435*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_ERR; 436*b07bcf34SKevin Tang } else if (ctx->if_type == SPRD_DPU_IF_EDPI) { 437*b07bcf34SKevin Tang /* use edpi as interface */ 438*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_CFG0, BIT_DPU_IF_EDPI); 439*b07bcf34SKevin Tang /* use external te */ 440*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPI_CTRL, BIT_DPU_EDPI_FROM_EXTERNAL_PAD); 441*b07bcf34SKevin Tang /* enable te */ 442*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPI_CTRL, BIT_DPU_EDPI_TE_EN); 443*b07bcf34SKevin Tang 444*b07bcf34SKevin Tang /* enable stop done INT */ 445*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_DONE; 446*b07bcf34SKevin Tang /* enable TE INT */ 447*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_TE; 448*b07bcf34SKevin Tang } 449*b07bcf34SKevin Tang 450*b07bcf34SKevin Tang writel(int_mask, ctx->base + REG_DPU_INT_EN); 451*b07bcf34SKevin Tang } 452*b07bcf34SKevin Tang 453*b07bcf34SKevin Tang static void sprd_dpu_fini(struct sprd_dpu *dpu) 454*b07bcf34SKevin Tang { 455*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 456*b07bcf34SKevin Tang 457*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_DPU_INT_EN); 458*b07bcf34SKevin Tang writel(0xff, ctx->base + REG_DPU_INT_CLR); 459*b07bcf34SKevin Tang } 460*b07bcf34SKevin Tang 461*b07bcf34SKevin Tang static void sprd_dpi_init(struct sprd_dpu *dpu) 462*b07bcf34SKevin Tang { 463*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 464*b07bcf34SKevin Tang u32 reg_val; 465*b07bcf34SKevin Tang u32 size; 466*b07bcf34SKevin Tang 467*b07bcf34SKevin Tang size = (ctx->vm.vactive << 16) | ctx->vm.hactive; 468*b07bcf34SKevin Tang writel(size, ctx->base + REG_PANEL_SIZE); 469*b07bcf34SKevin Tang writel(size, ctx->base + REG_BLEND_SIZE); 470*b07bcf34SKevin Tang 471*b07bcf34SKevin Tang if (ctx->if_type == SPRD_DPU_IF_DPI) { 472*b07bcf34SKevin Tang /* set dpi timing */ 473*b07bcf34SKevin Tang reg_val = ctx->vm.hsync_len << 0 | 474*b07bcf34SKevin Tang ctx->vm.hback_porch << 8 | 475*b07bcf34SKevin Tang ctx->vm.hfront_porch << 20; 476*b07bcf34SKevin Tang writel(reg_val, ctx->base + REG_DPI_H_TIMING); 477*b07bcf34SKevin Tang 478*b07bcf34SKevin Tang reg_val = ctx->vm.vsync_len << 0 | 479*b07bcf34SKevin Tang ctx->vm.vback_porch << 8 | 480*b07bcf34SKevin Tang ctx->vm.vfront_porch << 20; 481*b07bcf34SKevin Tang writel(reg_val, ctx->base + REG_DPI_V_TIMING); 482*b07bcf34SKevin Tang } 483*b07bcf34SKevin Tang } 484*b07bcf34SKevin Tang 485*b07bcf34SKevin Tang void sprd_dpu_run(struct sprd_dpu *dpu) 486*b07bcf34SKevin Tang { 487*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 488*b07bcf34SKevin Tang 489*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_CTRL, BIT_DPU_RUN); 490*b07bcf34SKevin Tang 491*b07bcf34SKevin Tang ctx->stopped = false; 492*b07bcf34SKevin Tang } 493*b07bcf34SKevin Tang 494*b07bcf34SKevin Tang void sprd_dpu_stop(struct sprd_dpu *dpu) 495*b07bcf34SKevin Tang { 496*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 497*b07bcf34SKevin Tang 498*b07bcf34SKevin Tang if (ctx->if_type == SPRD_DPU_IF_DPI) 499*b07bcf34SKevin Tang dpu_reg_set(ctx, REG_DPU_CTRL, BIT_DPU_STOP); 500*b07bcf34SKevin Tang 501*b07bcf34SKevin Tang dpu_wait_stop_done(dpu); 502*b07bcf34SKevin Tang } 503*b07bcf34SKevin Tang 504*b07bcf34SKevin Tang static int sprd_plane_atomic_check(struct drm_plane *plane, 505*b07bcf34SKevin Tang struct drm_atomic_state *state) 506*b07bcf34SKevin Tang { 507*b07bcf34SKevin Tang struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, 508*b07bcf34SKevin Tang plane); 509*b07bcf34SKevin Tang struct drm_crtc_state *crtc_state; 510*b07bcf34SKevin Tang u32 fmt; 511*b07bcf34SKevin Tang 512*b07bcf34SKevin Tang if (!plane_state->fb || !plane_state->crtc) 513*b07bcf34SKevin Tang return 0; 514*b07bcf34SKevin Tang 515*b07bcf34SKevin Tang fmt = drm_format_to_dpu(plane_state->fb); 516*b07bcf34SKevin Tang if (!fmt) 517*b07bcf34SKevin Tang return -EINVAL; 518*b07bcf34SKevin Tang 519*b07bcf34SKevin Tang crtc_state = drm_atomic_get_crtc_state(plane_state->state, plane_state->crtc); 520*b07bcf34SKevin Tang if (IS_ERR(crtc_state)) 521*b07bcf34SKevin Tang return PTR_ERR(crtc_state); 522*b07bcf34SKevin Tang 523*b07bcf34SKevin Tang return drm_atomic_helper_check_plane_state(plane_state, crtc_state, 524*b07bcf34SKevin Tang DRM_PLANE_HELPER_NO_SCALING, 525*b07bcf34SKevin Tang DRM_PLANE_HELPER_NO_SCALING, 526*b07bcf34SKevin Tang true, true); 527*b07bcf34SKevin Tang } 528*b07bcf34SKevin Tang 529*b07bcf34SKevin Tang static void sprd_plane_atomic_update(struct drm_plane *drm_plane, 530*b07bcf34SKevin Tang struct drm_atomic_state *state) 531*b07bcf34SKevin Tang { 532*b07bcf34SKevin Tang struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 533*b07bcf34SKevin Tang drm_plane); 534*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(new_state->crtc); 535*b07bcf34SKevin Tang 536*b07bcf34SKevin Tang /* start configure dpu layers */ 537*b07bcf34SKevin Tang sprd_dpu_layer(dpu, new_state); 538*b07bcf34SKevin Tang } 539*b07bcf34SKevin Tang 540*b07bcf34SKevin Tang static void sprd_plane_atomic_disable(struct drm_plane *drm_plane, 541*b07bcf34SKevin Tang struct drm_atomic_state *state) 542*b07bcf34SKevin Tang { 543*b07bcf34SKevin Tang struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, 544*b07bcf34SKevin Tang drm_plane); 545*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(old_state->crtc); 546*b07bcf34SKevin Tang 547*b07bcf34SKevin Tang layer_reg_wr(&dpu->ctx, REG_LAY_CTRL, 0x00, old_state->zpos); 548*b07bcf34SKevin Tang } 549*b07bcf34SKevin Tang 550*b07bcf34SKevin Tang static void sprd_plane_create_properties(struct sprd_plane *plane, int index) 551*b07bcf34SKevin Tang { 552*b07bcf34SKevin Tang unsigned int supported_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) | 553*b07bcf34SKevin Tang BIT(DRM_MODE_BLEND_PREMULTI) | 554*b07bcf34SKevin Tang BIT(DRM_MODE_BLEND_COVERAGE); 555*b07bcf34SKevin Tang 556*b07bcf34SKevin Tang /* create rotation property */ 557*b07bcf34SKevin Tang drm_plane_create_rotation_property(&plane->base, 558*b07bcf34SKevin Tang DRM_MODE_ROTATE_0, 559*b07bcf34SKevin Tang DRM_MODE_ROTATE_MASK | 560*b07bcf34SKevin Tang DRM_MODE_REFLECT_MASK); 561*b07bcf34SKevin Tang 562*b07bcf34SKevin Tang /* create alpha property */ 563*b07bcf34SKevin Tang drm_plane_create_alpha_property(&plane->base); 564*b07bcf34SKevin Tang 565*b07bcf34SKevin Tang /* create blend mode property */ 566*b07bcf34SKevin Tang drm_plane_create_blend_mode_property(&plane->base, supported_modes); 567*b07bcf34SKevin Tang 568*b07bcf34SKevin Tang /* create zpos property */ 569*b07bcf34SKevin Tang drm_plane_create_zpos_immutable_property(&plane->base, index); 570*b07bcf34SKevin Tang } 571*b07bcf34SKevin Tang 572*b07bcf34SKevin Tang static const struct drm_plane_helper_funcs sprd_plane_helper_funcs = { 573*b07bcf34SKevin Tang .atomic_check = sprd_plane_atomic_check, 574*b07bcf34SKevin Tang .atomic_update = sprd_plane_atomic_update, 575*b07bcf34SKevin Tang .atomic_disable = sprd_plane_atomic_disable, 576*b07bcf34SKevin Tang }; 577*b07bcf34SKevin Tang 578*b07bcf34SKevin Tang static const struct drm_plane_funcs sprd_plane_funcs = { 579*b07bcf34SKevin Tang .update_plane = drm_atomic_helper_update_plane, 580*b07bcf34SKevin Tang .disable_plane = drm_atomic_helper_disable_plane, 581*b07bcf34SKevin Tang .destroy = drm_plane_cleanup, 582*b07bcf34SKevin Tang .reset = drm_atomic_helper_plane_reset, 583*b07bcf34SKevin Tang .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 584*b07bcf34SKevin Tang .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 585*b07bcf34SKevin Tang }; 586*b07bcf34SKevin Tang 587*b07bcf34SKevin Tang static struct sprd_plane *sprd_planes_init(struct drm_device *drm) 588*b07bcf34SKevin Tang { 589*b07bcf34SKevin Tang struct sprd_plane *plane, *primary; 590*b07bcf34SKevin Tang enum drm_plane_type plane_type; 591*b07bcf34SKevin Tang int i; 592*b07bcf34SKevin Tang 593*b07bcf34SKevin Tang for (i = 0; i < 6; i++) { 594*b07bcf34SKevin Tang plane_type = (i == 0) ? DRM_PLANE_TYPE_PRIMARY : 595*b07bcf34SKevin Tang DRM_PLANE_TYPE_OVERLAY; 596*b07bcf34SKevin Tang 597*b07bcf34SKevin Tang plane = drmm_universal_plane_alloc(drm, struct sprd_plane, base, 598*b07bcf34SKevin Tang 1, &sprd_plane_funcs, 599*b07bcf34SKevin Tang layer_fmts, ARRAY_SIZE(layer_fmts), 600*b07bcf34SKevin Tang NULL, plane_type, NULL); 601*b07bcf34SKevin Tang if (IS_ERR(plane)) { 602*b07bcf34SKevin Tang drm_err(drm, "failed to init drm plane: %d\n", i); 603*b07bcf34SKevin Tang return plane; 604*b07bcf34SKevin Tang } 605*b07bcf34SKevin Tang 606*b07bcf34SKevin Tang drm_plane_helper_add(&plane->base, &sprd_plane_helper_funcs); 607*b07bcf34SKevin Tang 608*b07bcf34SKevin Tang sprd_plane_create_properties(plane, i); 609*b07bcf34SKevin Tang 610*b07bcf34SKevin Tang if (i == 0) 611*b07bcf34SKevin Tang primary = plane; 612*b07bcf34SKevin Tang } 613*b07bcf34SKevin Tang 614*b07bcf34SKevin Tang return primary; 615*b07bcf34SKevin Tang } 616*b07bcf34SKevin Tang 617*b07bcf34SKevin Tang static void sprd_crtc_mode_set_nofb(struct drm_crtc *crtc) 618*b07bcf34SKevin Tang { 619*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 620*b07bcf34SKevin Tang struct drm_display_mode *mode = &crtc->state->adjusted_mode; 621*b07bcf34SKevin Tang 622*b07bcf34SKevin Tang drm_display_mode_to_videomode(mode, &dpu->ctx.vm); 623*b07bcf34SKevin Tang 624*b07bcf34SKevin Tang sprd_dpi_init(dpu); 625*b07bcf34SKevin Tang } 626*b07bcf34SKevin Tang 627*b07bcf34SKevin Tang static void sprd_crtc_atomic_enable(struct drm_crtc *crtc, 628*b07bcf34SKevin Tang struct drm_atomic_state *state) 629*b07bcf34SKevin Tang { 630*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 631*b07bcf34SKevin Tang 632*b07bcf34SKevin Tang sprd_dpu_init(dpu); 633*b07bcf34SKevin Tang 634*b07bcf34SKevin Tang drm_crtc_vblank_on(&dpu->base); 635*b07bcf34SKevin Tang } 636*b07bcf34SKevin Tang 637*b07bcf34SKevin Tang static void sprd_crtc_atomic_disable(struct drm_crtc *crtc, 638*b07bcf34SKevin Tang struct drm_atomic_state *state) 639*b07bcf34SKevin Tang { 640*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 641*b07bcf34SKevin Tang struct drm_device *drm = dpu->base.dev; 642*b07bcf34SKevin Tang 643*b07bcf34SKevin Tang drm_crtc_vblank_off(&dpu->base); 644*b07bcf34SKevin Tang 645*b07bcf34SKevin Tang sprd_dpu_fini(dpu); 646*b07bcf34SKevin Tang 647*b07bcf34SKevin Tang spin_lock_irq(&drm->event_lock); 648*b07bcf34SKevin Tang if (crtc->state->event) { 649*b07bcf34SKevin Tang drm_crtc_send_vblank_event(crtc, crtc->state->event); 650*b07bcf34SKevin Tang crtc->state->event = NULL; 651*b07bcf34SKevin Tang } 652*b07bcf34SKevin Tang spin_unlock_irq(&drm->event_lock); 653*b07bcf34SKevin Tang } 654*b07bcf34SKevin Tang 655*b07bcf34SKevin Tang static void sprd_crtc_atomic_flush(struct drm_crtc *crtc, 656*b07bcf34SKevin Tang struct drm_atomic_state *state) 657*b07bcf34SKevin Tang 658*b07bcf34SKevin Tang { 659*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 660*b07bcf34SKevin Tang struct drm_device *drm = dpu->base.dev; 661*b07bcf34SKevin Tang 662*b07bcf34SKevin Tang sprd_dpu_flip(dpu); 663*b07bcf34SKevin Tang 664*b07bcf34SKevin Tang spin_lock_irq(&drm->event_lock); 665*b07bcf34SKevin Tang if (crtc->state->event) { 666*b07bcf34SKevin Tang drm_crtc_send_vblank_event(crtc, crtc->state->event); 667*b07bcf34SKevin Tang crtc->state->event = NULL; 668*b07bcf34SKevin Tang } 669*b07bcf34SKevin Tang spin_unlock_irq(&drm->event_lock); 670*b07bcf34SKevin Tang } 671*b07bcf34SKevin Tang 672*b07bcf34SKevin Tang static int sprd_crtc_enable_vblank(struct drm_crtc *crtc) 673*b07bcf34SKevin Tang { 674*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 675*b07bcf34SKevin Tang 676*b07bcf34SKevin Tang dpu_reg_set(&dpu->ctx, REG_DPU_INT_EN, BIT_DPU_INT_VSYNC); 677*b07bcf34SKevin Tang 678*b07bcf34SKevin Tang return 0; 679*b07bcf34SKevin Tang } 680*b07bcf34SKevin Tang 681*b07bcf34SKevin Tang static void sprd_crtc_disable_vblank(struct drm_crtc *crtc) 682*b07bcf34SKevin Tang { 683*b07bcf34SKevin Tang struct sprd_dpu *dpu = to_sprd_crtc(crtc); 684*b07bcf34SKevin Tang 685*b07bcf34SKevin Tang dpu_reg_clr(&dpu->ctx, REG_DPU_INT_EN, BIT_DPU_INT_VSYNC); 686*b07bcf34SKevin Tang } 687*b07bcf34SKevin Tang 688*b07bcf34SKevin Tang static const struct drm_crtc_helper_funcs sprd_crtc_helper_funcs = { 689*b07bcf34SKevin Tang .mode_set_nofb = sprd_crtc_mode_set_nofb, 690*b07bcf34SKevin Tang .atomic_flush = sprd_crtc_atomic_flush, 691*b07bcf34SKevin Tang .atomic_enable = sprd_crtc_atomic_enable, 692*b07bcf34SKevin Tang .atomic_disable = sprd_crtc_atomic_disable, 693*b07bcf34SKevin Tang }; 694*b07bcf34SKevin Tang 695*b07bcf34SKevin Tang static const struct drm_crtc_funcs sprd_crtc_funcs = { 696*b07bcf34SKevin Tang .destroy = drm_crtc_cleanup, 697*b07bcf34SKevin Tang .set_config = drm_atomic_helper_set_config, 698*b07bcf34SKevin Tang .page_flip = drm_atomic_helper_page_flip, 699*b07bcf34SKevin Tang .reset = drm_atomic_helper_crtc_reset, 700*b07bcf34SKevin Tang .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 701*b07bcf34SKevin Tang .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 702*b07bcf34SKevin Tang .enable_vblank = sprd_crtc_enable_vblank, 703*b07bcf34SKevin Tang .disable_vblank = sprd_crtc_disable_vblank, 704*b07bcf34SKevin Tang }; 705*b07bcf34SKevin Tang 706*b07bcf34SKevin Tang static struct sprd_dpu *sprd_crtc_init(struct drm_device *drm, 707*b07bcf34SKevin Tang struct drm_plane *primary, struct device *dev) 708*b07bcf34SKevin Tang { 709*b07bcf34SKevin Tang struct device_node *port; 710*b07bcf34SKevin Tang struct sprd_dpu *dpu; 711*b07bcf34SKevin Tang 712*b07bcf34SKevin Tang dpu = drmm_crtc_alloc_with_planes(drm, struct sprd_dpu, base, 713*b07bcf34SKevin Tang primary, NULL, 714*b07bcf34SKevin Tang &sprd_crtc_funcs, NULL); 715*b07bcf34SKevin Tang if (IS_ERR(dpu)) { 716*b07bcf34SKevin Tang drm_err(drm, "failed to init crtc\n"); 717*b07bcf34SKevin Tang return dpu; 718*b07bcf34SKevin Tang } 719*b07bcf34SKevin Tang drm_crtc_helper_add(&dpu->base, &sprd_crtc_helper_funcs); 720*b07bcf34SKevin Tang 721*b07bcf34SKevin Tang /* 722*b07bcf34SKevin Tang * set crtc port so that drm_of_find_possible_crtcs call works 723*b07bcf34SKevin Tang */ 724*b07bcf34SKevin Tang port = of_graph_get_port_by_id(dev->of_node, 0); 725*b07bcf34SKevin Tang if (!port) { 726*b07bcf34SKevin Tang drm_err(drm, "failed to found crtc output port for %s\n", 727*b07bcf34SKevin Tang dev->of_node->full_name); 728*b07bcf34SKevin Tang return ERR_PTR(-EINVAL); 729*b07bcf34SKevin Tang } 730*b07bcf34SKevin Tang dpu->base.port = port; 731*b07bcf34SKevin Tang of_node_put(port); 732*b07bcf34SKevin Tang 733*b07bcf34SKevin Tang return dpu; 734*b07bcf34SKevin Tang } 735*b07bcf34SKevin Tang 736*b07bcf34SKevin Tang static irqreturn_t sprd_dpu_isr(int irq, void *data) 737*b07bcf34SKevin Tang { 738*b07bcf34SKevin Tang struct sprd_dpu *dpu = data; 739*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 740*b07bcf34SKevin Tang u32 reg_val, int_mask = 0; 741*b07bcf34SKevin Tang 742*b07bcf34SKevin Tang reg_val = readl(ctx->base + REG_DPU_INT_STS); 743*b07bcf34SKevin Tang 744*b07bcf34SKevin Tang /* disable err interrupt */ 745*b07bcf34SKevin Tang if (reg_val & BIT_DPU_INT_ERR) { 746*b07bcf34SKevin Tang int_mask |= BIT_DPU_INT_ERR; 747*b07bcf34SKevin Tang drm_warn(dpu->drm, "Warning: dpu underflow!\n"); 748*b07bcf34SKevin Tang } 749*b07bcf34SKevin Tang 750*b07bcf34SKevin Tang /* dpu update done isr */ 751*b07bcf34SKevin Tang if (reg_val & BIT_DPU_INT_UPDATE_DONE) { 752*b07bcf34SKevin Tang ctx->evt_update = true; 753*b07bcf34SKevin Tang wake_up_interruptible_all(&ctx->wait_queue); 754*b07bcf34SKevin Tang } 755*b07bcf34SKevin Tang 756*b07bcf34SKevin Tang /* dpu stop done isr */ 757*b07bcf34SKevin Tang if (reg_val & BIT_DPU_INT_DONE) { 758*b07bcf34SKevin Tang ctx->evt_stop = true; 759*b07bcf34SKevin Tang wake_up_interruptible_all(&ctx->wait_queue); 760*b07bcf34SKevin Tang } 761*b07bcf34SKevin Tang 762*b07bcf34SKevin Tang if (reg_val & BIT_DPU_INT_VSYNC) 763*b07bcf34SKevin Tang drm_crtc_handle_vblank(&dpu->base); 764*b07bcf34SKevin Tang 765*b07bcf34SKevin Tang writel(reg_val, ctx->base + REG_DPU_INT_CLR); 766*b07bcf34SKevin Tang dpu_reg_clr(ctx, REG_DPU_INT_EN, int_mask); 767*b07bcf34SKevin Tang 768*b07bcf34SKevin Tang return IRQ_HANDLED; 769*b07bcf34SKevin Tang } 770*b07bcf34SKevin Tang 771*b07bcf34SKevin Tang static int sprd_dpu_context_init(struct sprd_dpu *dpu, 772*b07bcf34SKevin Tang struct device *dev) 773*b07bcf34SKevin Tang { 774*b07bcf34SKevin Tang struct platform_device *pdev = to_platform_device(dev); 775*b07bcf34SKevin Tang struct dpu_context *ctx = &dpu->ctx; 776*b07bcf34SKevin Tang struct resource *res; 777*b07bcf34SKevin Tang int ret; 778*b07bcf34SKevin Tang 779*b07bcf34SKevin Tang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 780*b07bcf34SKevin Tang ctx->base = devm_ioremap(dev, res->start, resource_size(res)); 781*b07bcf34SKevin Tang if (!ctx->base) { 782*b07bcf34SKevin Tang dev_err(dev, "failed to map dpu registers\n"); 783*b07bcf34SKevin Tang return -EFAULT; 784*b07bcf34SKevin Tang } 785*b07bcf34SKevin Tang 786*b07bcf34SKevin Tang ctx->irq = platform_get_irq(pdev, 0); 787*b07bcf34SKevin Tang if (ctx->irq < 0) { 788*b07bcf34SKevin Tang dev_err(dev, "failed to get dpu irq\n"); 789*b07bcf34SKevin Tang return ctx->irq; 790*b07bcf34SKevin Tang } 791*b07bcf34SKevin Tang 792*b07bcf34SKevin Tang /* disable and clear interrupts before register dpu IRQ. */ 793*b07bcf34SKevin Tang writel(0x00, ctx->base + REG_DPU_INT_EN); 794*b07bcf34SKevin Tang writel(0xff, ctx->base + REG_DPU_INT_CLR); 795*b07bcf34SKevin Tang 796*b07bcf34SKevin Tang ret = devm_request_irq(dev, ctx->irq, sprd_dpu_isr, 797*b07bcf34SKevin Tang IRQF_TRIGGER_NONE, "DPU", dpu); 798*b07bcf34SKevin Tang if (ret) { 799*b07bcf34SKevin Tang dev_err(dev, "failed to register dpu irq handler\n"); 800*b07bcf34SKevin Tang return ret; 801*b07bcf34SKevin Tang } 802*b07bcf34SKevin Tang 803*b07bcf34SKevin Tang init_waitqueue_head(&ctx->wait_queue); 804*b07bcf34SKevin Tang 805*b07bcf34SKevin Tang return 0; 806*b07bcf34SKevin Tang } 807*b07bcf34SKevin Tang 808*b07bcf34SKevin Tang static int sprd_dpu_bind(struct device *dev, struct device *master, void *data) 809*b07bcf34SKevin Tang { 810*b07bcf34SKevin Tang struct drm_device *drm = data; 811*b07bcf34SKevin Tang struct sprd_dpu *dpu; 812*b07bcf34SKevin Tang struct sprd_plane *plane; 813*b07bcf34SKevin Tang int ret; 814*b07bcf34SKevin Tang 815*b07bcf34SKevin Tang plane = sprd_planes_init(drm); 816*b07bcf34SKevin Tang if (IS_ERR(plane)) 817*b07bcf34SKevin Tang return PTR_ERR(plane); 818*b07bcf34SKevin Tang 819*b07bcf34SKevin Tang dpu = sprd_crtc_init(drm, &plane->base, dev); 820*b07bcf34SKevin Tang if (IS_ERR(dpu)) 821*b07bcf34SKevin Tang return PTR_ERR(dpu); 822*b07bcf34SKevin Tang 823*b07bcf34SKevin Tang dpu->drm = drm; 824*b07bcf34SKevin Tang dev_set_drvdata(dev, dpu); 825*b07bcf34SKevin Tang 826*b07bcf34SKevin Tang ret = sprd_dpu_context_init(dpu, dev); 827*b07bcf34SKevin Tang if (ret) 828*b07bcf34SKevin Tang return ret; 829*b07bcf34SKevin Tang 830*b07bcf34SKevin Tang return 0; 831*b07bcf34SKevin Tang } 832*b07bcf34SKevin Tang 833*b07bcf34SKevin Tang static const struct component_ops dpu_component_ops = { 834*b07bcf34SKevin Tang .bind = sprd_dpu_bind, 835*b07bcf34SKevin Tang }; 836*b07bcf34SKevin Tang 837*b07bcf34SKevin Tang static const struct of_device_id dpu_match_table[] = { 838*b07bcf34SKevin Tang { .compatible = "sprd,sharkl3-dpu" }, 839*b07bcf34SKevin Tang { /* sentinel */ }, 840*b07bcf34SKevin Tang }; 841*b07bcf34SKevin Tang MODULE_DEVICE_TABLE(of, dpu_match_table); 842*b07bcf34SKevin Tang 843*b07bcf34SKevin Tang static int sprd_dpu_probe(struct platform_device *pdev) 844*b07bcf34SKevin Tang { 845*b07bcf34SKevin Tang return component_add(&pdev->dev, &dpu_component_ops); 846*b07bcf34SKevin Tang } 847*b07bcf34SKevin Tang 848*b07bcf34SKevin Tang static int sprd_dpu_remove(struct platform_device *pdev) 849*b07bcf34SKevin Tang { 850*b07bcf34SKevin Tang component_del(&pdev->dev, &dpu_component_ops); 851*b07bcf34SKevin Tang 852*b07bcf34SKevin Tang return 0; 853*b07bcf34SKevin Tang } 854*b07bcf34SKevin Tang 855*b07bcf34SKevin Tang struct platform_driver sprd_dpu_driver = { 856*b07bcf34SKevin Tang .probe = sprd_dpu_probe, 857*b07bcf34SKevin Tang .remove = sprd_dpu_remove, 858*b07bcf34SKevin Tang .driver = { 859*b07bcf34SKevin Tang .name = "sprd-dpu-drv", 860*b07bcf34SKevin Tang .of_match_table = dpu_match_table, 861*b07bcf34SKevin Tang }, 862*b07bcf34SKevin Tang }; 863*b07bcf34SKevin Tang 864*b07bcf34SKevin Tang MODULE_AUTHOR("Leon He <leon.he@unisoc.com>"); 865*b07bcf34SKevin Tang MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>"); 866*b07bcf34SKevin Tang MODULE_DESCRIPTION("Unisoc Display Controller Driver"); 867*b07bcf34SKevin Tang MODULE_LICENSE("GPL v2"); 868