xref: /linux/drivers/gpu/drm/tegra/plane.c (revision 48519232bea9230d1c5dbbb680d9257d4861bb4c)
15acd3514SThierry Reding /*
25acd3514SThierry Reding  * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
35acd3514SThierry Reding  *
45acd3514SThierry Reding  * This program is free software; you can redistribute it and/or modify
55acd3514SThierry Reding  * it under the terms of the GNU General Public License version 2 as
65acd3514SThierry Reding  * published by the Free Software Foundation.
75acd3514SThierry Reding  */
85acd3514SThierry Reding 
95acd3514SThierry Reding #include <drm/drm_atomic.h>
105acd3514SThierry Reding #include <drm/drm_atomic_helper.h>
115acd3514SThierry Reding #include <drm/drm_plane_helper.h>
125acd3514SThierry Reding 
135acd3514SThierry Reding #include "dc.h"
145acd3514SThierry Reding #include "plane.h"
155acd3514SThierry Reding 
165acd3514SThierry Reding static void tegra_plane_destroy(struct drm_plane *plane)
175acd3514SThierry Reding {
185acd3514SThierry Reding 	struct tegra_plane *p = to_tegra_plane(plane);
195acd3514SThierry Reding 
205acd3514SThierry Reding 	drm_plane_cleanup(plane);
215acd3514SThierry Reding 	kfree(p);
225acd3514SThierry Reding }
235acd3514SThierry Reding 
245acd3514SThierry Reding static void tegra_plane_reset(struct drm_plane *plane)
255acd3514SThierry Reding {
265acd3514SThierry Reding 	struct tegra_plane_state *state;
275acd3514SThierry Reding 
285acd3514SThierry Reding 	if (plane->state)
295acd3514SThierry Reding 		__drm_atomic_helper_plane_destroy_state(plane->state);
305acd3514SThierry Reding 
315acd3514SThierry Reding 	kfree(plane->state);
325acd3514SThierry Reding 	plane->state = NULL;
335acd3514SThierry Reding 
345acd3514SThierry Reding 	state = kzalloc(sizeof(*state), GFP_KERNEL);
355acd3514SThierry Reding 	if (state) {
365acd3514SThierry Reding 		plane->state = &state->base;
375acd3514SThierry Reding 		plane->state->plane = plane;
385acd3514SThierry Reding 	}
395acd3514SThierry Reding }
405acd3514SThierry Reding 
415acd3514SThierry Reding static struct drm_plane_state *
425acd3514SThierry Reding tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
435acd3514SThierry Reding {
445acd3514SThierry Reding 	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
455acd3514SThierry Reding 	struct tegra_plane_state *copy;
46ebae8d07SThierry Reding 	unsigned int i;
475acd3514SThierry Reding 
485acd3514SThierry Reding 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
495acd3514SThierry Reding 	if (!copy)
505acd3514SThierry Reding 		return NULL;
515acd3514SThierry Reding 
525acd3514SThierry Reding 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
535acd3514SThierry Reding 	copy->tiling = state->tiling;
545acd3514SThierry Reding 	copy->format = state->format;
555acd3514SThierry Reding 	copy->swap = state->swap;
56ebae8d07SThierry Reding 	copy->opaque = state->opaque;
57ebae8d07SThierry Reding 
58ebae8d07SThierry Reding 	for (i = 0; i < 3; i++)
59ebae8d07SThierry Reding 		copy->dependent[i] = state->dependent[i];
605acd3514SThierry Reding 
615acd3514SThierry Reding 	return &copy->base;
625acd3514SThierry Reding }
635acd3514SThierry Reding 
645acd3514SThierry Reding static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
655acd3514SThierry Reding 					     struct drm_plane_state *state)
665acd3514SThierry Reding {
675acd3514SThierry Reding 	__drm_atomic_helper_plane_destroy_state(state);
685acd3514SThierry Reding 	kfree(state);
695acd3514SThierry Reding }
705acd3514SThierry Reding 
715acd3514SThierry Reding const struct drm_plane_funcs tegra_plane_funcs = {
725acd3514SThierry Reding 	.update_plane = drm_atomic_helper_update_plane,
735acd3514SThierry Reding 	.disable_plane = drm_atomic_helper_disable_plane,
745acd3514SThierry Reding 	.destroy = tegra_plane_destroy,
755acd3514SThierry Reding 	.reset = tegra_plane_reset,
765acd3514SThierry Reding 	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
775acd3514SThierry Reding 	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
785acd3514SThierry Reding };
795acd3514SThierry Reding 
805acd3514SThierry Reding int tegra_plane_state_add(struct tegra_plane *plane,
815acd3514SThierry Reding 			  struct drm_plane_state *state)
825acd3514SThierry Reding {
835acd3514SThierry Reding 	struct drm_crtc_state *crtc_state;
845acd3514SThierry Reding 	struct tegra_dc_state *tegra;
855acd3514SThierry Reding 	struct drm_rect clip;
865acd3514SThierry Reding 	int err;
875acd3514SThierry Reding 
885acd3514SThierry Reding 	/* Propagate errors from allocation or locking failures. */
895acd3514SThierry Reding 	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
905acd3514SThierry Reding 	if (IS_ERR(crtc_state))
915acd3514SThierry Reding 		return PTR_ERR(crtc_state);
925acd3514SThierry Reding 
935acd3514SThierry Reding 	clip.x1 = 0;
945acd3514SThierry Reding 	clip.y1 = 0;
955acd3514SThierry Reding 	clip.x2 = crtc_state->mode.hdisplay;
965acd3514SThierry Reding 	clip.y2 = crtc_state->mode.vdisplay;
975acd3514SThierry Reding 
985acd3514SThierry Reding 	/* Check plane state for visibility and calculate clipping bounds */
995acd3514SThierry Reding 	err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip,
1005acd3514SThierry Reding 						  0, INT_MAX, true, true);
1015acd3514SThierry Reding 	if (err < 0)
1025acd3514SThierry Reding 		return err;
1035acd3514SThierry Reding 
1045acd3514SThierry Reding 	tegra = to_dc_state(crtc_state);
1055acd3514SThierry Reding 
1065acd3514SThierry Reding 	tegra->planes |= WIN_A_ACT_REQ << plane->index;
1075acd3514SThierry Reding 
1085acd3514SThierry Reding 	return 0;
1095acd3514SThierry Reding }
1105acd3514SThierry Reding 
1115acd3514SThierry Reding int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
1125acd3514SThierry Reding {
1135acd3514SThierry Reding 	/* assume no swapping of fetched data */
1145acd3514SThierry Reding 	if (swap)
1155acd3514SThierry Reding 		*swap = BYTE_SWAP_NOSWAP;
1165acd3514SThierry Reding 
1175acd3514SThierry Reding 	switch (fourcc) {
118511c7023SThierry Reding 	case DRM_FORMAT_ARGB4444:
119511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B4G4R4A4;
1207772fdaeSThierry Reding 		break;
1217772fdaeSThierry Reding 
122511c7023SThierry Reding 	case DRM_FORMAT_ARGB1555:
123511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G5R5A1;
1245acd3514SThierry Reding 		break;
1255acd3514SThierry Reding 
126511c7023SThierry Reding 	case DRM_FORMAT_RGB565:
127511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G6R5;
128511c7023SThierry Reding 		break;
129511c7023SThierry Reding 
130511c7023SThierry Reding 	case DRM_FORMAT_RGBA5551:
131511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A1B5G5R5;
1327772fdaeSThierry Reding 		break;
1337772fdaeSThierry Reding 
1347772fdaeSThierry Reding 	case DRM_FORMAT_ARGB8888:
1355acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_B8G8R8A8;
1365acd3514SThierry Reding 		break;
1375acd3514SThierry Reding 
138511c7023SThierry Reding 	case DRM_FORMAT_ABGR8888:
139511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R8G8B8A8;
140511c7023SThierry Reding 		break;
141511c7023SThierry Reding 
142511c7023SThierry Reding 	case DRM_FORMAT_ABGR4444:
143511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R4G4B4A4;
144511c7023SThierry Reding 		break;
145511c7023SThierry Reding 
146511c7023SThierry Reding 	case DRM_FORMAT_ABGR1555:
147511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G5B5A;
148511c7023SThierry Reding 		break;
149511c7023SThierry Reding 
150511c7023SThierry Reding 	case DRM_FORMAT_BGRA5551:
151511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_AR5G5B5;
152511c7023SThierry Reding 		break;
153511c7023SThierry Reding 
154511c7023SThierry Reding 	case DRM_FORMAT_XRGB1555:
155511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G5R5X1;
156511c7023SThierry Reding 		break;
157511c7023SThierry Reding 
158511c7023SThierry Reding 	case DRM_FORMAT_RGBX5551:
159511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_X1B5G5R5;
160511c7023SThierry Reding 		break;
161511c7023SThierry Reding 
162511c7023SThierry Reding 	case DRM_FORMAT_XBGR1555:
163511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G5B5X1;
164511c7023SThierry Reding 		break;
165511c7023SThierry Reding 
166511c7023SThierry Reding 	case DRM_FORMAT_BGRX5551:
167511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_X1R5G5B5;
168511c7023SThierry Reding 		break;
169511c7023SThierry Reding 
170511c7023SThierry Reding 	case DRM_FORMAT_BGR565:
171511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G6B5;
172511c7023SThierry Reding 		break;
173511c7023SThierry Reding 
174511c7023SThierry Reding 	case DRM_FORMAT_BGRA8888:
175511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A8R8G8B8;
176511c7023SThierry Reding 		break;
177511c7023SThierry Reding 
178511c7023SThierry Reding 	case DRM_FORMAT_RGBA8888:
179511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A8B8G8R8;
180511c7023SThierry Reding 		break;
181511c7023SThierry Reding 
182511c7023SThierry Reding 	case DRM_FORMAT_XRGB8888:
183511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B8G8R8X8;
184511c7023SThierry Reding 		break;
185511c7023SThierry Reding 
186511c7023SThierry Reding 	case DRM_FORMAT_XBGR8888:
187511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R8G8B8X8;
1885acd3514SThierry Reding 		break;
1895acd3514SThierry Reding 
1905acd3514SThierry Reding 	case DRM_FORMAT_UYVY:
1915acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422;
1925acd3514SThierry Reding 		break;
1935acd3514SThierry Reding 
1945acd3514SThierry Reding 	case DRM_FORMAT_YUYV:
1955acd3514SThierry Reding 		if (!swap)
1965acd3514SThierry Reding 			return -EINVAL;
1975acd3514SThierry Reding 
1985acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422;
1995acd3514SThierry Reding 		*swap = BYTE_SWAP_SWAP2;
2005acd3514SThierry Reding 		break;
2015acd3514SThierry Reding 
2025acd3514SThierry Reding 	case DRM_FORMAT_YUV420:
2035acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr420P;
2045acd3514SThierry Reding 		break;
2055acd3514SThierry Reding 
2065acd3514SThierry Reding 	case DRM_FORMAT_YUV422:
2075acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422P;
2085acd3514SThierry Reding 		break;
2095acd3514SThierry Reding 
2105acd3514SThierry Reding 	default:
2115acd3514SThierry Reding 		return -EINVAL;
2125acd3514SThierry Reding 	}
2135acd3514SThierry Reding 
2145acd3514SThierry Reding 	return 0;
2155acd3514SThierry Reding }
2165acd3514SThierry Reding 
2175acd3514SThierry Reding bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
2185acd3514SThierry Reding {
2195acd3514SThierry Reding 	switch (format) {
2205acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422:
2215acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422:
2225acd3514SThierry Reding 		if (planar)
2235acd3514SThierry Reding 			*planar = false;
2245acd3514SThierry Reding 
2255acd3514SThierry Reding 		return true;
2265acd3514SThierry Reding 
2275acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr420P:
2285acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV420P:
2295acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422P:
2305acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422P:
2315acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422R:
2325acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422R:
2335acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422RA:
2345acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422RA:
2355acd3514SThierry Reding 		if (planar)
2365acd3514SThierry Reding 			*planar = true;
2375acd3514SThierry Reding 
2385acd3514SThierry Reding 		return true;
2395acd3514SThierry Reding 	}
2405acd3514SThierry Reding 
2415acd3514SThierry Reding 	if (planar)
2425acd3514SThierry Reding 		*planar = false;
2435acd3514SThierry Reding 
2445acd3514SThierry Reding 	return false;
2455acd3514SThierry Reding }
246ebae8d07SThierry Reding 
247ebae8d07SThierry Reding static bool __drm_format_has_alpha(u32 format)
248ebae8d07SThierry Reding {
249ebae8d07SThierry Reding 	switch (format) {
250ebae8d07SThierry Reding 	case DRM_FORMAT_ARGB1555:
251ebae8d07SThierry Reding 	case DRM_FORMAT_RGBA5551:
252ebae8d07SThierry Reding 	case DRM_FORMAT_ABGR8888:
253ebae8d07SThierry Reding 	case DRM_FORMAT_ARGB8888:
254ebae8d07SThierry Reding 		return true;
255ebae8d07SThierry Reding 	}
256ebae8d07SThierry Reding 
257ebae8d07SThierry Reding 	return false;
258ebae8d07SThierry Reding }
259ebae8d07SThierry Reding 
260ebae8d07SThierry Reding /*
261ebae8d07SThierry Reding  * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
262ebae8d07SThierry Reding  * be emulated using the alpha formats and alpha blending disabled.
263ebae8d07SThierry Reding  */
264ebae8d07SThierry Reding bool tegra_plane_format_has_alpha(unsigned int format)
265ebae8d07SThierry Reding {
266ebae8d07SThierry Reding 	switch (format) {
267ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B5G5R5A1:
268ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_A1B5G5R5:
269ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_R8G8B8A8:
270ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B8G8R8A8:
271ebae8d07SThierry Reding 		return true;
272ebae8d07SThierry Reding 	}
273ebae8d07SThierry Reding 
274ebae8d07SThierry Reding 	return false;
275ebae8d07SThierry Reding }
276ebae8d07SThierry Reding 
277ebae8d07SThierry Reding int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
278ebae8d07SThierry Reding {
2795467a8b8SThierry Reding 	if (tegra_plane_format_is_yuv(opaque, NULL)) {
2805467a8b8SThierry Reding 		*alpha = opaque;
2815467a8b8SThierry Reding 		return 0;
2825467a8b8SThierry Reding 	}
2835467a8b8SThierry Reding 
284ebae8d07SThierry Reding 	switch (opaque) {
285ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B5G5R5X1:
286ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
287ebae8d07SThierry Reding 		return 0;
288ebae8d07SThierry Reding 
289ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_X1B5G5R5:
290ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
291ebae8d07SThierry Reding 		return 0;
292ebae8d07SThierry Reding 
293ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_R8G8B8X8:
294ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
295ebae8d07SThierry Reding 		return 0;
296ebae8d07SThierry Reding 
297ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B8G8R8X8:
298ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
299ebae8d07SThierry Reding 		return 0;
3008a927d64SThierry Reding 
3018a927d64SThierry Reding 	case WIN_COLOR_DEPTH_B5G6R5:
3028a927d64SThierry Reding 		*alpha = opaque;
3038a927d64SThierry Reding 		return 0;
304ebae8d07SThierry Reding 	}
305ebae8d07SThierry Reding 
306ebae8d07SThierry Reding 	return -EINVAL;
307ebae8d07SThierry Reding }
308ebae8d07SThierry Reding 
309ebae8d07SThierry Reding unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
310ebae8d07SThierry Reding 					   struct tegra_plane *other)
311ebae8d07SThierry Reding {
312ebae8d07SThierry Reding 	unsigned int index = 0, i;
313ebae8d07SThierry Reding 
314ebae8d07SThierry Reding 	WARN_ON(plane == other);
315ebae8d07SThierry Reding 
316ebae8d07SThierry Reding 	for (i = 0; i < 3; i++) {
317ebae8d07SThierry Reding 		if (i == plane->index)
318ebae8d07SThierry Reding 			continue;
319ebae8d07SThierry Reding 
320ebae8d07SThierry Reding 		if (i == other->index)
321ebae8d07SThierry Reding 			break;
322ebae8d07SThierry Reding 
323ebae8d07SThierry Reding 		index++;
324ebae8d07SThierry Reding 	}
325ebae8d07SThierry Reding 
326ebae8d07SThierry Reding 	return index;
327ebae8d07SThierry Reding }
328ebae8d07SThierry Reding 
329ebae8d07SThierry Reding void tegra_plane_check_dependent(struct tegra_plane *tegra,
330ebae8d07SThierry Reding 				 struct tegra_plane_state *state)
331ebae8d07SThierry Reding {
332ebae8d07SThierry Reding 	struct drm_plane_state *old, *new;
333ebae8d07SThierry Reding 	struct drm_plane *plane;
334ebae8d07SThierry Reding 	unsigned int zpos[2];
335ebae8d07SThierry Reding 	unsigned int i;
336ebae8d07SThierry Reding 
337ebae8d07SThierry Reding 	for (i = 0; i < 2; i++)
338ebae8d07SThierry Reding 		zpos[i] = 0;
339ebae8d07SThierry Reding 
340ebae8d07SThierry Reding 	for_each_oldnew_plane_in_state(state->base.state, plane, old, new, i) {
341ebae8d07SThierry Reding 		struct tegra_plane *p = to_tegra_plane(plane);
342ebae8d07SThierry Reding 		unsigned index;
343ebae8d07SThierry Reding 
344ebae8d07SThierry Reding 		/* skip this plane and planes on different CRTCs */
345ebae8d07SThierry Reding 		if (p == tegra || new->crtc != state->base.crtc)
346ebae8d07SThierry Reding 			continue;
347ebae8d07SThierry Reding 
348ebae8d07SThierry Reding 		index = tegra_plane_get_overlap_index(tegra, p);
349ebae8d07SThierry Reding 
350*48519232SDmitry Osipenko 		state->dependent[index] = false;
351*48519232SDmitry Osipenko 
352ebae8d07SThierry Reding 		/*
353ebae8d07SThierry Reding 		 * If any of the other planes is on top of this plane and uses
354ebae8d07SThierry Reding 		 * a format with an alpha component, mark this plane as being
355ebae8d07SThierry Reding 		 * dependent, meaning it's alpha value will be 1 minus the sum
356ebae8d07SThierry Reding 		 * of alpha components of the overlapping planes.
357ebae8d07SThierry Reding 		 */
358ebae8d07SThierry Reding 		if (p->index > tegra->index) {
359ebae8d07SThierry Reding 			if (__drm_format_has_alpha(new->fb->format->format))
360ebae8d07SThierry Reding 				state->dependent[index] = true;
361ebae8d07SThierry Reding 
362ebae8d07SThierry Reding 			/* keep track of the Z position */
363ebae8d07SThierry Reding 			zpos[index] = p->index;
364ebae8d07SThierry Reding 		}
365ebae8d07SThierry Reding 	}
366ebae8d07SThierry Reding 
367ebae8d07SThierry Reding 	/*
368ebae8d07SThierry Reding 	 * The region where three windows overlap is the intersection of the
369ebae8d07SThierry Reding 	 * two regions where two windows overlap. It contributes to the area
370ebae8d07SThierry Reding 	 * if any of the windows on top of it have an alpha component.
371ebae8d07SThierry Reding 	 */
372ebae8d07SThierry Reding 	for (i = 0; i < 2; i++)
373ebae8d07SThierry Reding 		state->dependent[2] = state->dependent[2] ||
374ebae8d07SThierry Reding 				      state->dependent[i];
375ebae8d07SThierry Reding 
376ebae8d07SThierry Reding 	/*
377ebae8d07SThierry Reding 	 * However, if any of the windows on top of this window is opaque, it
378ebae8d07SThierry Reding 	 * will completely conceal this window within that area, so avoid the
379ebae8d07SThierry Reding 	 * window from contributing to the area.
380ebae8d07SThierry Reding 	 */
381ebae8d07SThierry Reding 	for (i = 0; i < 2; i++) {
382ebae8d07SThierry Reding 		if (zpos[i] > tegra->index)
383ebae8d07SThierry Reding 			state->dependent[2] = state->dependent[2] &&
384ebae8d07SThierry Reding 					      state->dependent[i];
385ebae8d07SThierry Reding 	}
386ebae8d07SThierry Reding }
387