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_blend.h>
11 #include <drm/drm_fourcc.h>
12 #include <drm/drm_framebuffer.h>
13 #include <drm/drm_gem_atomic_helper.h>
14 #include <drm/drm_print.h>
15 #include <linux/align.h>
16
17 #include "mtk_crtc.h"
18 #include "mtk_ddp_comp.h"
19 #include "mtk_drm_drv.h"
20 #include "mtk_gem.h"
21 #include "mtk_plane.h"
22
23 static const u64 modifiers[] = {
24 DRM_FORMAT_MOD_LINEAR,
25 DRM_FORMAT_MOD_INVALID,
26 };
27
mtk_plane_reset(struct drm_plane * plane)28 static void mtk_plane_reset(struct drm_plane *plane)
29 {
30 struct mtk_plane_state *state;
31
32 if (plane->state) {
33 __drm_atomic_helper_plane_destroy_state(plane->state);
34
35 state = to_mtk_plane_state(plane->state);
36 memset(state, 0, sizeof(*state));
37 } else {
38 state = kzalloc(sizeof(*state), GFP_KERNEL);
39 if (!state)
40 return;
41 }
42
43 __drm_atomic_helper_plane_reset(plane, &state->base);
44
45 state->base.plane = plane;
46 state->pending.format = DRM_FORMAT_RGB565;
47 state->pending.modifier = DRM_FORMAT_MOD_LINEAR;
48 }
49
mtk_plane_duplicate_state(struct drm_plane * plane)50 static struct drm_plane_state *mtk_plane_duplicate_state(struct drm_plane *plane)
51 {
52 struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
53 struct mtk_plane_state *state;
54
55 state = kmalloc(sizeof(*state), GFP_KERNEL);
56 if (!state)
57 return NULL;
58
59 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
60
61 WARN_ON(state->base.plane != plane);
62
63 state->pending = old_state->pending;
64
65 return &state->base;
66 }
67
mtk_plane_format_mod_supported(struct drm_plane * plane,uint32_t format,uint64_t modifier)68 static bool mtk_plane_format_mod_supported(struct drm_plane *plane,
69 uint32_t format,
70 uint64_t modifier)
71 {
72 return modifier == DRM_FORMAT_MOD_LINEAR;
73 }
74
mtk_plane_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)75 static void mtk_plane_destroy_state(struct drm_plane *plane,
76 struct drm_plane_state *state)
77 {
78 __drm_atomic_helper_plane_destroy_state(state);
79 kfree(to_mtk_plane_state(state));
80 }
81
mtk_plane_atomic_async_check(struct drm_plane * plane,struct drm_atomic_state * state,bool flip)82 static int mtk_plane_atomic_async_check(struct drm_plane *plane,
83 struct drm_atomic_state *state, bool flip)
84 {
85 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
86 plane);
87 struct drm_crtc_state *crtc_state;
88 int ret;
89
90 if (plane != new_plane_state->crtc->cursor)
91 return -EINVAL;
92
93 if (!plane->state)
94 return -EINVAL;
95
96 if (!plane->state->fb)
97 return -EINVAL;
98
99 ret = mtk_crtc_plane_check(new_plane_state->crtc, plane,
100 to_mtk_plane_state(new_plane_state));
101 if (ret)
102 return ret;
103
104 crtc_state = drm_atomic_get_new_crtc_state(state,
105 new_plane_state->crtc);
106
107 return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
108 DRM_PLANE_NO_SCALING,
109 DRM_PLANE_NO_SCALING,
110 true, true);
111 }
112
mtk_plane_update_new_state(struct drm_plane_state * new_state,struct mtk_plane_state * mtk_plane_state)113 static void mtk_plane_update_new_state(struct drm_plane_state *new_state,
114 struct mtk_plane_state *mtk_plane_state)
115 {
116 struct drm_framebuffer *fb = new_state->fb;
117 struct drm_gem_object *gem;
118 struct mtk_gem_obj *mtk_gem;
119 unsigned int pitch, format;
120 u64 modifier;
121 dma_addr_t addr;
122 dma_addr_t hdr_addr = 0;
123 unsigned int hdr_pitch = 0;
124 int offset;
125
126 gem = fb->obj[0];
127 mtk_gem = to_mtk_gem_obj(gem);
128 addr = mtk_gem->dma_addr;
129 pitch = fb->pitches[0];
130 format = fb->format->format;
131 modifier = fb->modifier;
132
133 if (modifier == DRM_FORMAT_MOD_LINEAR) {
134 /*
135 * Using dma_addr_t variable to calculate with multiplier of different types,
136 * for example: addr += (new_state->src.x1 >> 16) * fb->format->cpp[0];
137 * may cause coverity issue with unintentional overflow.
138 */
139 offset = (new_state->src.x1 >> 16) * fb->format->cpp[0];
140 addr += offset;
141 offset = (new_state->src.y1 >> 16) * pitch;
142 addr += offset;
143 } else {
144 int width_in_blocks = ALIGN(fb->width, AFBC_DATA_BLOCK_WIDTH)
145 / AFBC_DATA_BLOCK_WIDTH;
146 int height_in_blocks = ALIGN(fb->height, AFBC_DATA_BLOCK_HEIGHT)
147 / AFBC_DATA_BLOCK_HEIGHT;
148 int x_offset_in_blocks = (new_state->src.x1 >> 16) / AFBC_DATA_BLOCK_WIDTH;
149 int y_offset_in_blocks = (new_state->src.y1 >> 16) / AFBC_DATA_BLOCK_HEIGHT;
150 int hdr_size, hdr_offset;
151
152 hdr_pitch = width_in_blocks * AFBC_HEADER_BLOCK_SIZE;
153 pitch = width_in_blocks * AFBC_DATA_BLOCK_WIDTH *
154 AFBC_DATA_BLOCK_HEIGHT * fb->format->cpp[0];
155
156 hdr_size = ALIGN(hdr_pitch * height_in_blocks, AFBC_HEADER_ALIGNMENT);
157 hdr_offset = hdr_pitch * y_offset_in_blocks +
158 AFBC_HEADER_BLOCK_SIZE * x_offset_in_blocks;
159
160 /*
161 * Using dma_addr_t variable to calculate with multiplier of different types,
162 * for example: addr += hdr_pitch * y_offset_in_blocks;
163 * may cause coverity issue with unintentional overflow.
164 */
165 hdr_addr = addr + hdr_offset;
166
167 /* The data plane is offset by 1 additional block. */
168 offset = pitch * y_offset_in_blocks +
169 AFBC_DATA_BLOCK_WIDTH * AFBC_DATA_BLOCK_HEIGHT *
170 fb->format->cpp[0] * (x_offset_in_blocks + 1);
171
172 /*
173 * Using dma_addr_t variable to calculate with multiplier of different types,
174 * for example: addr += pitch * y_offset_in_blocks;
175 * may cause coverity issue with unintentional overflow.
176 */
177 addr = addr + hdr_size + offset;
178 }
179
180 mtk_plane_state->pending.enable = true;
181 mtk_plane_state->pending.pitch = pitch;
182 mtk_plane_state->pending.hdr_pitch = hdr_pitch;
183 mtk_plane_state->pending.format = format;
184 mtk_plane_state->pending.modifier = modifier;
185 mtk_plane_state->pending.addr = addr;
186 mtk_plane_state->pending.hdr_addr = hdr_addr;
187 mtk_plane_state->pending.x = new_state->dst.x1;
188 mtk_plane_state->pending.y = new_state->dst.y1;
189 mtk_plane_state->pending.width = drm_rect_width(&new_state->dst);
190 mtk_plane_state->pending.height = drm_rect_height(&new_state->dst);
191 mtk_plane_state->pending.rotation = new_state->rotation;
192 mtk_plane_state->pending.color_encoding = new_state->color_encoding;
193 }
194
mtk_plane_atomic_async_update(struct drm_plane * plane,struct drm_atomic_state * state)195 static void mtk_plane_atomic_async_update(struct drm_plane *plane,
196 struct drm_atomic_state *state)
197 {
198 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
199 plane);
200 struct mtk_plane_state *new_plane_state = to_mtk_plane_state(plane->state);
201
202 plane->state->crtc_x = new_state->crtc_x;
203 plane->state->crtc_y = new_state->crtc_y;
204 plane->state->crtc_h = new_state->crtc_h;
205 plane->state->crtc_w = new_state->crtc_w;
206 plane->state->src_x = new_state->src_x;
207 plane->state->src_y = new_state->src_y;
208 plane->state->src_h = new_state->src_h;
209 plane->state->src_w = new_state->src_w;
210 plane->state->dst.x1 = new_state->dst.x1;
211 plane->state->dst.y1 = new_state->dst.y1;
212
213 mtk_plane_update_new_state(new_state, new_plane_state);
214 swap(plane->state->fb, new_state->fb);
215 wmb(); /* Make sure the above parameters are set before update */
216 new_plane_state->pending.async_dirty = true;
217 mtk_crtc_async_update(new_state->crtc, plane, state);
218 }
219
220 static const struct drm_plane_funcs mtk_plane_funcs = {
221 .update_plane = drm_atomic_helper_update_plane,
222 .disable_plane = drm_atomic_helper_disable_plane,
223 .destroy = drm_plane_cleanup,
224 .reset = mtk_plane_reset,
225 .atomic_duplicate_state = mtk_plane_duplicate_state,
226 .atomic_destroy_state = mtk_plane_destroy_state,
227 .format_mod_supported = mtk_plane_format_mod_supported,
228 };
229
mtk_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)230 static int mtk_plane_atomic_check(struct drm_plane *plane,
231 struct drm_atomic_state *state)
232 {
233 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
234 plane);
235 struct drm_framebuffer *fb = new_plane_state->fb;
236 struct drm_crtc_state *crtc_state;
237 int ret;
238
239 if (!fb)
240 return 0;
241
242 if (WARN_ON(!new_plane_state->crtc))
243 return 0;
244
245 ret = mtk_crtc_plane_check(new_plane_state->crtc, plane,
246 to_mtk_plane_state(new_plane_state));
247 if (ret)
248 return ret;
249
250 crtc_state = drm_atomic_get_crtc_state(state,
251 new_plane_state->crtc);
252 if (IS_ERR(crtc_state))
253 return PTR_ERR(crtc_state);
254
255 return drm_atomic_helper_check_plane_state(new_plane_state,
256 crtc_state,
257 DRM_PLANE_NO_SCALING,
258 DRM_PLANE_NO_SCALING,
259 true, true);
260 }
261
mtk_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)262 static void mtk_plane_atomic_disable(struct drm_plane *plane,
263 struct drm_atomic_state *state)
264 {
265 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
266 plane);
267 struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
268 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
269 plane);
270
271 mtk_plane_state->pending.enable = false;
272 wmb(); /* Make sure the above parameter is set before update */
273 mtk_plane_state->pending.dirty = true;
274
275 if (old_state && old_state->crtc)
276 mtk_crtc_plane_disable(old_state->crtc, plane);
277 }
278
mtk_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)279 static void mtk_plane_atomic_update(struct drm_plane *plane,
280 struct drm_atomic_state *state)
281 {
282 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
283 plane);
284 struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
285
286 if (!new_state->crtc || WARN_ON(!new_state->fb))
287 return;
288
289 if (!new_state->visible) {
290 mtk_plane_atomic_disable(plane, state);
291 return;
292 }
293
294 mtk_plane_update_new_state(new_state, mtk_plane_state);
295 wmb(); /* Make sure the above parameters are set before update */
296 mtk_plane_state->pending.dirty = true;
297 }
298
299 static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
300 .atomic_check = mtk_plane_atomic_check,
301 .atomic_update = mtk_plane_atomic_update,
302 .atomic_disable = mtk_plane_atomic_disable,
303 .atomic_async_update = mtk_plane_atomic_async_update,
304 .atomic_async_check = mtk_plane_atomic_async_check,
305 };
306
mtk_plane_init(struct drm_device * dev,struct drm_plane * plane,unsigned long possible_crtcs,enum drm_plane_type type,unsigned int supported_rotations,const u32 blend_modes,const u32 * formats,size_t num_formats,bool supports_afbc,unsigned int plane_idx)307 int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
308 unsigned long possible_crtcs, enum drm_plane_type type,
309 unsigned int supported_rotations, const u32 blend_modes,
310 const u32 *formats, size_t num_formats,
311 bool supports_afbc, unsigned int plane_idx)
312 {
313 int err;
314
315 if (!formats || !num_formats) {
316 DRM_ERROR("no formats for plane\n");
317 return -EINVAL;
318 }
319
320 err = drm_universal_plane_init(dev, plane, possible_crtcs,
321 &mtk_plane_funcs, formats,
322 num_formats,
323 supports_afbc ? modifiers : NULL,
324 type, NULL);
325 if (err) {
326 DRM_ERROR("failed to initialize plane\n");
327 return err;
328 }
329
330 /*
331 * The hardware does not support repositioning planes by muxing: their
332 * Z-position is infact fixed and the only way to change the actual
333 * order is to swap the contents of the entire register set of one
334 * overlay with another, which may be more expensive than desired.
335 *
336 * With no repositioning, the caller of this function guarantees that
337 * the plane_idx is correct. This means that, for example, the PRIMARY
338 * plane fed to this function will always have plane_idx zero.
339 */
340 err = drm_plane_create_zpos_immutable_property(plane, plane_idx);
341 if (err) {
342 DRM_ERROR("Failed to create zpos property for plane %u\n", plane_idx);
343 return err;
344 }
345
346 if (supported_rotations) {
347 err = drm_plane_create_rotation_property(plane,
348 DRM_MODE_ROTATE_0,
349 supported_rotations);
350 if (err)
351 DRM_INFO("Create rotation property failed\n");
352 }
353
354 err = drm_plane_create_alpha_property(plane);
355 if (err)
356 DRM_ERROR("failed to create property: alpha\n");
357
358 if (blend_modes) {
359 err = drm_plane_create_blend_mode_property(plane, blend_modes);
360 if (err)
361 DRM_ERROR("failed to create property: blend_mode\n");
362 }
363
364 drm_plane_helper_add(plane, &mtk_plane_helper_funcs);
365
366 return 0;
367 }
368