1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2015 MediaTek Inc. 4 * Author: CK Hu <ck.hu@mediatek.com> 5 */ 6 7 #include <drm/drm_atomic.h> 8 #include <drm/drm_atomic_helper.h> 9 #include <drm/drm_atomic_uapi.h> 10 #include <drm/drm_fourcc.h> 11 #include <drm/drm_gem_atomic_helper.h> 12 #include <drm/drm_plane_helper.h> 13 14 #include "mtk_drm_crtc.h" 15 #include "mtk_drm_ddp_comp.h" 16 #include "mtk_drm_drv.h" 17 #include "mtk_drm_gem.h" 18 #include "mtk_drm_plane.h" 19 20 static const u32 formats[] = { 21 DRM_FORMAT_XRGB8888, 22 DRM_FORMAT_ARGB8888, 23 DRM_FORMAT_BGRX8888, 24 DRM_FORMAT_BGRA8888, 25 DRM_FORMAT_ABGR8888, 26 DRM_FORMAT_XBGR8888, 27 DRM_FORMAT_RGB888, 28 DRM_FORMAT_BGR888, 29 DRM_FORMAT_RGB565, 30 DRM_FORMAT_UYVY, 31 DRM_FORMAT_YUYV, 32 }; 33 34 static void mtk_plane_reset(struct drm_plane *plane) 35 { 36 struct mtk_plane_state *state; 37 38 if (plane->state) { 39 __drm_atomic_helper_plane_destroy_state(plane->state); 40 41 state = to_mtk_plane_state(plane->state); 42 memset(state, 0, sizeof(*state)); 43 } else { 44 state = kzalloc(sizeof(*state), GFP_KERNEL); 45 if (!state) 46 return; 47 plane->state = &state->base; 48 } 49 50 state->base.plane = plane; 51 state->pending.format = DRM_FORMAT_RGB565; 52 } 53 54 static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane) 55 { 56 struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state); 57 struct mtk_plane_state *state; 58 59 state = kzalloc(sizeof(*state), GFP_KERNEL); 60 if (!state) 61 return NULL; 62 63 __drm_atomic_helper_plane_duplicate_state(plane, &state->base); 64 65 WARN_ON(state->base.plane != plane); 66 67 state->pending = old_state->pending; 68 69 return &state->base; 70 } 71 72 static void mtk_drm_plane_destroy_state(struct drm_plane *plane, 73 struct drm_plane_state *state) 74 { 75 __drm_atomic_helper_plane_destroy_state(state); 76 kfree(to_mtk_plane_state(state)); 77 } 78 79 static int mtk_plane_atomic_async_check(struct drm_plane *plane, 80 struct drm_atomic_state *state) 81 { 82 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 83 plane); 84 struct drm_crtc_state *crtc_state; 85 int ret; 86 87 if (plane != new_plane_state->crtc->cursor) 88 return -EINVAL; 89 90 if (!plane->state) 91 return -EINVAL; 92 93 if (!plane->state->fb) 94 return -EINVAL; 95 96 ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, 97 to_mtk_plane_state(new_plane_state)); 98 if (ret) 99 return ret; 100 101 if (state) 102 crtc_state = drm_atomic_get_existing_crtc_state(state, 103 new_plane_state->crtc); 104 else /* Special case for asynchronous cursor updates. */ 105 crtc_state = new_plane_state->crtc->state; 106 107 return drm_atomic_helper_check_plane_state(plane->state, crtc_state, 108 DRM_PLANE_HELPER_NO_SCALING, 109 DRM_PLANE_HELPER_NO_SCALING, 110 true, true); 111 } 112 113 static void mtk_plane_atomic_async_update(struct drm_plane *plane, 114 struct drm_atomic_state *state) 115 { 116 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 117 plane); 118 struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state); 119 120 plane->state->crtc_x = new_state->crtc_x; 121 plane->state->crtc_y = new_state->crtc_y; 122 plane->state->crtc_h = new_state->crtc_h; 123 plane->state->crtc_w = new_state->crtc_w; 124 plane->state->src_x = new_state->src_x; 125 plane->state->src_y = new_state->src_y; 126 plane->state->src_h = new_state->src_h; 127 plane->state->src_w = new_state->src_w; 128 swap(plane->state->fb, new_state->fb); 129 new_plane_state->pending.async_dirty = true; 130 131 mtk_drm_crtc_async_update(new_state->crtc, plane, state); 132 } 133 134 static const struct drm_plane_funcs mtk_plane_funcs = { 135 .update_plane = drm_atomic_helper_update_plane, 136 .disable_plane = drm_atomic_helper_disable_plane, 137 .destroy = drm_plane_cleanup, 138 .reset = mtk_plane_reset, 139 .atomic_duplicate_state = mtk_plane_duplicate_state, 140 .atomic_destroy_state = mtk_drm_plane_destroy_state, 141 }; 142 143 static int mtk_plane_atomic_check(struct drm_plane *plane, 144 struct drm_atomic_state *state) 145 { 146 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 147 plane); 148 struct drm_framebuffer *fb = new_plane_state->fb; 149 struct drm_crtc_state *crtc_state; 150 int ret; 151 152 if (!fb) 153 return 0; 154 155 if (WARN_ON(!new_plane_state->crtc)) 156 return 0; 157 158 ret = mtk_drm_crtc_plane_check(new_plane_state->crtc, plane, 159 to_mtk_plane_state(new_plane_state)); 160 if (ret) 161 return ret; 162 163 crtc_state = drm_atomic_get_crtc_state(state, 164 new_plane_state->crtc); 165 if (IS_ERR(crtc_state)) 166 return PTR_ERR(crtc_state); 167 168 return drm_atomic_helper_check_plane_state(new_plane_state, 169 crtc_state, 170 DRM_PLANE_HELPER_NO_SCALING, 171 DRM_PLANE_HELPER_NO_SCALING, 172 true, true); 173 } 174 175 static void mtk_plane_atomic_disable(struct drm_plane *plane, 176 struct drm_atomic_state *state) 177 { 178 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 179 plane); 180 struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); 181 mtk_plane_state->pending.enable = false; 182 wmb(); /* Make sure the above parameter is set before update */ 183 mtk_plane_state->pending.dirty = true; 184 } 185 186 static void mtk_plane_atomic_update(struct drm_plane *plane, 187 struct drm_atomic_state *state) 188 { 189 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, 190 plane); 191 struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state); 192 struct drm_crtc *crtc = new_state->crtc; 193 struct drm_framebuffer *fb = new_state->fb; 194 struct drm_gem_object *gem; 195 struct mtk_drm_gem_obj *mtk_gem; 196 unsigned int pitch, format; 197 dma_addr_t addr; 198 199 if (!crtc || WARN_ON(!fb)) 200 return; 201 202 if (!new_state->visible) { 203 mtk_plane_atomic_disable(plane, state); 204 return; 205 } 206 207 gem = fb->obj[0]; 208 mtk_gem = to_mtk_gem_obj(gem); 209 addr = mtk_gem->dma_addr; 210 pitch = fb->pitches[0]; 211 format = fb->format->format; 212 213 addr += (new_state->src.x1 >> 16) * fb->format->cpp[0]; 214 addr += (new_state->src.y1 >> 16) * pitch; 215 216 mtk_plane_state->pending.enable = true; 217 mtk_plane_state->pending.pitch = pitch; 218 mtk_plane_state->pending.format = format; 219 mtk_plane_state->pending.addr = addr; 220 mtk_plane_state->pending.x = new_state->dst.x1; 221 mtk_plane_state->pending.y = new_state->dst.y1; 222 mtk_plane_state->pending.width = drm_rect_width(&new_state->dst); 223 mtk_plane_state->pending.height = drm_rect_height(&new_state->dst); 224 mtk_plane_state->pending.rotation = new_state->rotation; 225 wmb(); /* Make sure the above parameters are set before update */ 226 mtk_plane_state->pending.dirty = true; 227 } 228 229 static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = { 230 .prepare_fb = drm_gem_plane_helper_prepare_fb, 231 .atomic_check = mtk_plane_atomic_check, 232 .atomic_update = mtk_plane_atomic_update, 233 .atomic_disable = mtk_plane_atomic_disable, 234 .atomic_async_update = mtk_plane_atomic_async_update, 235 .atomic_async_check = mtk_plane_atomic_async_check, 236 }; 237 238 int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane, 239 unsigned long possible_crtcs, enum drm_plane_type type, 240 unsigned int supported_rotations) 241 { 242 int err; 243 244 err = drm_universal_plane_init(dev, plane, possible_crtcs, 245 &mtk_plane_funcs, formats, 246 ARRAY_SIZE(formats), NULL, type, NULL); 247 if (err) { 248 DRM_ERROR("failed to initialize plane\n"); 249 return err; 250 } 251 252 if (supported_rotations & ~DRM_MODE_ROTATE_0) { 253 err = drm_plane_create_rotation_property(plane, 254 DRM_MODE_ROTATE_0, 255 supported_rotations); 256 if (err) 257 DRM_INFO("Create rotation property failed\n"); 258 } 259 260 drm_plane_helper_add(plane, &mtk_plane_helper_funcs); 261 262 return 0; 263 } 264