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