xref: /linux/drivers/gpu/drm/tegra/plane.c (revision 7b6f846785f41d57917e36851c120cfbe87f0809)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25acd3514SThierry Reding /*
35acd3514SThierry Reding  * Copyright (C) 2017 NVIDIA CORPORATION.  All rights reserved.
45acd3514SThierry Reding  */
55acd3514SThierry Reding 
6273da5a0SThierry Reding #include <linux/iommu.h>
7273da5a0SThierry Reding 
85acd3514SThierry Reding #include <drm/drm_atomic.h>
95acd3514SThierry Reding #include <drm/drm_atomic_helper.h>
10eb1df694SSam Ravnborg #include <drm/drm_fourcc.h>
11820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
125acd3514SThierry Reding #include <drm/drm_plane_helper.h>
135acd3514SThierry Reding 
145acd3514SThierry Reding #include "dc.h"
155acd3514SThierry Reding #include "plane.h"
165acd3514SThierry Reding 
175acd3514SThierry Reding static void tegra_plane_destroy(struct drm_plane *plane)
185acd3514SThierry Reding {
195acd3514SThierry Reding 	struct tegra_plane *p = to_tegra_plane(plane);
205acd3514SThierry Reding 
215acd3514SThierry Reding 	drm_plane_cleanup(plane);
225acd3514SThierry Reding 	kfree(p);
235acd3514SThierry Reding }
245acd3514SThierry Reding 
255acd3514SThierry Reding static void tegra_plane_reset(struct drm_plane *plane)
265acd3514SThierry Reding {
273dae08bcSDmitry Osipenko 	struct tegra_plane *p = to_tegra_plane(plane);
285acd3514SThierry Reding 	struct tegra_plane_state *state;
292e8d8749SThierry Reding 	unsigned int i;
305acd3514SThierry Reding 
315acd3514SThierry Reding 	if (plane->state)
325acd3514SThierry Reding 		__drm_atomic_helper_plane_destroy_state(plane->state);
335acd3514SThierry Reding 
345acd3514SThierry Reding 	kfree(plane->state);
355acd3514SThierry Reding 	plane->state = NULL;
365acd3514SThierry Reding 
375acd3514SThierry Reding 	state = kzalloc(sizeof(*state), GFP_KERNEL);
385acd3514SThierry Reding 	if (state) {
395acd3514SThierry Reding 		plane->state = &state->base;
405acd3514SThierry Reding 		plane->state->plane = plane;
413dae08bcSDmitry Osipenko 		plane->state->zpos = p->index;
423dae08bcSDmitry Osipenko 		plane->state->normalized_zpos = p->index;
432e8d8749SThierry Reding 
442e8d8749SThierry Reding 		for (i = 0; i < 3; i++)
452e8d8749SThierry Reding 			state->iova[i] = DMA_MAPPING_ERROR;
465acd3514SThierry Reding 	}
475acd3514SThierry Reding }
485acd3514SThierry Reding 
495acd3514SThierry Reding static struct drm_plane_state *
505acd3514SThierry Reding tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
515acd3514SThierry Reding {
525acd3514SThierry Reding 	struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
535acd3514SThierry Reding 	struct tegra_plane_state *copy;
54ebae8d07SThierry Reding 	unsigned int i;
555acd3514SThierry Reding 
565acd3514SThierry Reding 	copy = kmalloc(sizeof(*copy), GFP_KERNEL);
575acd3514SThierry Reding 	if (!copy)
585acd3514SThierry Reding 		return NULL;
595acd3514SThierry Reding 
605acd3514SThierry Reding 	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
615acd3514SThierry Reding 	copy->tiling = state->tiling;
625acd3514SThierry Reding 	copy->format = state->format;
635acd3514SThierry Reding 	copy->swap = state->swap;
64cd740777SDmitry Osipenko 	copy->reflect_x = state->reflect_x;
65e9e476f7SDmitry Osipenko 	copy->reflect_y = state->reflect_y;
66ebae8d07SThierry Reding 	copy->opaque = state->opaque;
67ebae8d07SThierry Reding 
683dae08bcSDmitry Osipenko 	for (i = 0; i < 2; i++)
693dae08bcSDmitry Osipenko 		copy->blending[i] = state->blending[i];
705acd3514SThierry Reding 
712e8d8749SThierry Reding 	for (i = 0; i < 3; i++) {
722e8d8749SThierry Reding 		copy->iova[i] = DMA_MAPPING_ERROR;
732e8d8749SThierry Reding 		copy->sgt[i] = NULL;
742e8d8749SThierry Reding 	}
752e8d8749SThierry Reding 
765acd3514SThierry Reding 	return &copy->base;
775acd3514SThierry Reding }
785acd3514SThierry Reding 
795acd3514SThierry Reding static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
805acd3514SThierry Reding 					     struct drm_plane_state *state)
815acd3514SThierry Reding {
825acd3514SThierry Reding 	__drm_atomic_helper_plane_destroy_state(state);
835acd3514SThierry Reding 	kfree(state);
845acd3514SThierry Reding }
855acd3514SThierry Reding 
86*7b6f8467SThierry Reding static bool tegra_plane_supports_sector_layout(struct drm_plane *plane)
87*7b6f8467SThierry Reding {
88*7b6f8467SThierry Reding 	struct drm_crtc *crtc;
89*7b6f8467SThierry Reding 
90*7b6f8467SThierry Reding 	drm_for_each_crtc(crtc, plane->dev) {
91*7b6f8467SThierry Reding 		if (plane->possible_crtcs & drm_crtc_mask(crtc)) {
92*7b6f8467SThierry Reding 			struct tegra_dc *dc = to_tegra_dc(crtc);
93*7b6f8467SThierry Reding 
94*7b6f8467SThierry Reding 			if (!dc->soc->supports_sector_layout)
95*7b6f8467SThierry Reding 				return false;
96*7b6f8467SThierry Reding 		}
97*7b6f8467SThierry Reding 	}
98*7b6f8467SThierry Reding 
99*7b6f8467SThierry Reding 	return true;
100*7b6f8467SThierry Reding }
101*7b6f8467SThierry Reding 
102e90124cbSThierry Reding static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
103e90124cbSThierry Reding 					     uint32_t format,
104e90124cbSThierry Reding 					     uint64_t modifier)
105e90124cbSThierry Reding {
106e90124cbSThierry Reding 	const struct drm_format_info *info = drm_format_info(format);
107e90124cbSThierry Reding 
108e90124cbSThierry Reding 	if (modifier == DRM_FORMAT_MOD_LINEAR)
109e90124cbSThierry Reding 		return true;
110e90124cbSThierry Reding 
111*7b6f8467SThierry Reding 	/* check for the sector layout bit */
112*7b6f8467SThierry Reding 	if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) {
113*7b6f8467SThierry Reding 		if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) {
114*7b6f8467SThierry Reding 			if (!tegra_plane_supports_sector_layout(plane))
115*7b6f8467SThierry Reding 				return false;
116*7b6f8467SThierry Reding 		}
117*7b6f8467SThierry Reding 	}
118*7b6f8467SThierry Reding 
119e90124cbSThierry Reding 	if (info->num_planes == 1)
120e90124cbSThierry Reding 		return true;
121e90124cbSThierry Reding 
122e90124cbSThierry Reding 	return false;
123e90124cbSThierry Reding }
124e90124cbSThierry Reding 
1255acd3514SThierry Reding const struct drm_plane_funcs tegra_plane_funcs = {
1265acd3514SThierry Reding 	.update_plane = drm_atomic_helper_update_plane,
1275acd3514SThierry Reding 	.disable_plane = drm_atomic_helper_disable_plane,
1285acd3514SThierry Reding 	.destroy = tegra_plane_destroy,
1295acd3514SThierry Reding 	.reset = tegra_plane_reset,
1305acd3514SThierry Reding 	.atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
1315acd3514SThierry Reding 	.atomic_destroy_state = tegra_plane_atomic_destroy_state,
132e90124cbSThierry Reding 	.format_mod_supported = tegra_plane_format_mod_supported,
1335acd3514SThierry Reding };
1345acd3514SThierry Reding 
1352e8d8749SThierry Reding static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state)
1362e8d8749SThierry Reding {
137273da5a0SThierry Reding 	struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev);
1382e8d8749SThierry Reding 	unsigned int i;
1392e8d8749SThierry Reding 	int err;
1402e8d8749SThierry Reding 
1412e8d8749SThierry Reding 	for (i = 0; i < state->base.fb->format->num_planes; i++) {
1422e8d8749SThierry Reding 		struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
143273da5a0SThierry Reding 		dma_addr_t phys_addr, *phys;
1442e8d8749SThierry Reding 		struct sg_table *sgt;
1452e8d8749SThierry Reding 
146476e9320SThierry Reding 		/*
147476e9320SThierry Reding 		 * If we're not attached to a domain, we already stored the
148476e9320SThierry Reding 		 * physical address when the buffer was allocated. If we're
149476e9320SThierry Reding 		 * part of a group that's shared between all display
150476e9320SThierry Reding 		 * controllers, we've also already mapped the framebuffer
151476e9320SThierry Reding 		 * through the SMMU. In both cases we can short-circuit the
152476e9320SThierry Reding 		 * code below and retrieve the stored IOV address.
153476e9320SThierry Reding 		 */
154273da5a0SThierry Reding 		if (!domain || dc->client.group)
155273da5a0SThierry Reding 			phys = &phys_addr;
156273da5a0SThierry Reding 		else
157273da5a0SThierry Reding 			phys = NULL;
158273da5a0SThierry Reding 
159273da5a0SThierry Reding 		sgt = host1x_bo_pin(dc->dev, &bo->base, phys);
1602e8d8749SThierry Reding 		if (IS_ERR(sgt)) {
1612e8d8749SThierry Reding 			err = PTR_ERR(sgt);
1622e8d8749SThierry Reding 			goto unpin;
1632e8d8749SThierry Reding 		}
1642e8d8749SThierry Reding 
165273da5a0SThierry Reding 		if (sgt) {
166d4fea3e6SMarek Szyprowski 			err = dma_map_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0);
167d4fea3e6SMarek Szyprowski 			if (err)
1682e8d8749SThierry Reding 				goto unpin;
1692e8d8749SThierry Reding 
17049f82191SThierry Reding 			/*
17149f82191SThierry Reding 			 * The display controller needs contiguous memory, so
17249f82191SThierry Reding 			 * fail if the buffer is discontiguous and we fail to
17349f82191SThierry Reding 			 * map its SG table to a single contiguous chunk of
17449f82191SThierry Reding 			 * I/O virtual memory.
17549f82191SThierry Reding 			 */
176d4fea3e6SMarek Szyprowski 			if (sgt->nents > 1) {
17749f82191SThierry Reding 				err = -EINVAL;
17849f82191SThierry Reding 				goto unpin;
17949f82191SThierry Reding 			}
18049f82191SThierry Reding 
1812e8d8749SThierry Reding 			state->iova[i] = sg_dma_address(sgt->sgl);
1822e8d8749SThierry Reding 			state->sgt[i] = sgt;
1832e8d8749SThierry Reding 		} else {
184273da5a0SThierry Reding 			state->iova[i] = phys_addr;
1852e8d8749SThierry Reding 		}
1862e8d8749SThierry Reding 	}
1872e8d8749SThierry Reding 
1882e8d8749SThierry Reding 	return 0;
1892e8d8749SThierry Reding 
1902e8d8749SThierry Reding unpin:
1912e8d8749SThierry Reding 	dev_err(dc->dev, "failed to map plane %u: %d\n", i, err);
1922e8d8749SThierry Reding 
1932e8d8749SThierry Reding 	while (i--) {
1942e8d8749SThierry Reding 		struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
1952e8d8749SThierry Reding 		struct sg_table *sgt = state->sgt[i];
1962e8d8749SThierry Reding 
197273da5a0SThierry Reding 		if (sgt)
198d4fea3e6SMarek Szyprowski 			dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0);
1992e8d8749SThierry Reding 
200273da5a0SThierry Reding 		host1x_bo_unpin(dc->dev, &bo->base, sgt);
2012e8d8749SThierry Reding 		state->iova[i] = DMA_MAPPING_ERROR;
2022e8d8749SThierry Reding 		state->sgt[i] = NULL;
2032e8d8749SThierry Reding 	}
2042e8d8749SThierry Reding 
2052e8d8749SThierry Reding 	return err;
2062e8d8749SThierry Reding }
2072e8d8749SThierry Reding 
2082e8d8749SThierry Reding static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state)
2092e8d8749SThierry Reding {
2102e8d8749SThierry Reding 	unsigned int i;
2112e8d8749SThierry Reding 
2122e8d8749SThierry Reding 	for (i = 0; i < state->base.fb->format->num_planes; i++) {
2132e8d8749SThierry Reding 		struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i);
2142e8d8749SThierry Reding 		struct sg_table *sgt = state->sgt[i];
2152e8d8749SThierry Reding 
216273da5a0SThierry Reding 		if (sgt)
217d4fea3e6SMarek Szyprowski 			dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0);
2182e8d8749SThierry Reding 
219273da5a0SThierry Reding 		host1x_bo_unpin(dc->dev, &bo->base, sgt);
2202e8d8749SThierry Reding 		state->iova[i] = DMA_MAPPING_ERROR;
2212e8d8749SThierry Reding 		state->sgt[i] = NULL;
2222e8d8749SThierry Reding 	}
2232e8d8749SThierry Reding }
2242e8d8749SThierry Reding 
2252e8d8749SThierry Reding int tegra_plane_prepare_fb(struct drm_plane *plane,
2262e8d8749SThierry Reding 			   struct drm_plane_state *state)
2272e8d8749SThierry Reding {
2282e8d8749SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(state->crtc);
2292e8d8749SThierry Reding 
2302e8d8749SThierry Reding 	if (!state->fb)
2312e8d8749SThierry Reding 		return 0;
2322e8d8749SThierry Reding 
233820c1707SThomas Zimmermann 	drm_gem_plane_helper_prepare_fb(plane, state);
2342e8d8749SThierry Reding 
2352e8d8749SThierry Reding 	return tegra_dc_pin(dc, to_tegra_plane_state(state));
2362e8d8749SThierry Reding }
2372e8d8749SThierry Reding 
2382e8d8749SThierry Reding void tegra_plane_cleanup_fb(struct drm_plane *plane,
2392e8d8749SThierry Reding 			    struct drm_plane_state *state)
2402e8d8749SThierry Reding {
2412e8d8749SThierry Reding 	struct tegra_dc *dc = to_tegra_dc(state->crtc);
2422e8d8749SThierry Reding 
2432e8d8749SThierry Reding 	if (dc)
2442e8d8749SThierry Reding 		tegra_dc_unpin(dc, to_tegra_plane_state(state));
2452e8d8749SThierry Reding }
2462e8d8749SThierry Reding 
2475acd3514SThierry Reding int tegra_plane_state_add(struct tegra_plane *plane,
2485acd3514SThierry Reding 			  struct drm_plane_state *state)
2495acd3514SThierry Reding {
2505acd3514SThierry Reding 	struct drm_crtc_state *crtc_state;
2515acd3514SThierry Reding 	struct tegra_dc_state *tegra;
2525acd3514SThierry Reding 	int err;
2535acd3514SThierry Reding 
2545acd3514SThierry Reding 	/* Propagate errors from allocation or locking failures. */
2555acd3514SThierry Reding 	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
2565acd3514SThierry Reding 	if (IS_ERR(crtc_state))
2575acd3514SThierry Reding 		return PTR_ERR(crtc_state);
2585acd3514SThierry Reding 
2595acd3514SThierry Reding 	/* Check plane state for visibility and calculate clipping bounds */
26081af63a4SVille Syrjälä 	err = drm_atomic_helper_check_plane_state(state, crtc_state,
2615acd3514SThierry Reding 						  0, INT_MAX, true, true);
2625acd3514SThierry Reding 	if (err < 0)
2635acd3514SThierry Reding 		return err;
2645acd3514SThierry Reding 
2655acd3514SThierry Reding 	tegra = to_dc_state(crtc_state);
2665acd3514SThierry Reding 
2675acd3514SThierry Reding 	tegra->planes |= WIN_A_ACT_REQ << plane->index;
2685acd3514SThierry Reding 
2695acd3514SThierry Reding 	return 0;
2705acd3514SThierry Reding }
2715acd3514SThierry Reding 
2725acd3514SThierry Reding int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
2735acd3514SThierry Reding {
2745acd3514SThierry Reding 	/* assume no swapping of fetched data */
2755acd3514SThierry Reding 	if (swap)
2765acd3514SThierry Reding 		*swap = BYTE_SWAP_NOSWAP;
2775acd3514SThierry Reding 
2785acd3514SThierry Reding 	switch (fourcc) {
279511c7023SThierry Reding 	case DRM_FORMAT_ARGB4444:
280511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B4G4R4A4;
2817772fdaeSThierry Reding 		break;
2827772fdaeSThierry Reding 
283511c7023SThierry Reding 	case DRM_FORMAT_ARGB1555:
284511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G5R5A1;
2855acd3514SThierry Reding 		break;
2865acd3514SThierry Reding 
287511c7023SThierry Reding 	case DRM_FORMAT_RGB565:
288511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G6R5;
289511c7023SThierry Reding 		break;
290511c7023SThierry Reding 
291511c7023SThierry Reding 	case DRM_FORMAT_RGBA5551:
292511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A1B5G5R5;
2937772fdaeSThierry Reding 		break;
2947772fdaeSThierry Reding 
2957772fdaeSThierry Reding 	case DRM_FORMAT_ARGB8888:
2965acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_B8G8R8A8;
2975acd3514SThierry Reding 		break;
2985acd3514SThierry Reding 
299511c7023SThierry Reding 	case DRM_FORMAT_ABGR8888:
300511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R8G8B8A8;
301511c7023SThierry Reding 		break;
302511c7023SThierry Reding 
303511c7023SThierry Reding 	case DRM_FORMAT_ABGR4444:
304511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R4G4B4A4;
305511c7023SThierry Reding 		break;
306511c7023SThierry Reding 
307511c7023SThierry Reding 	case DRM_FORMAT_ABGR1555:
308511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G5B5A;
309511c7023SThierry Reding 		break;
310511c7023SThierry Reding 
311511c7023SThierry Reding 	case DRM_FORMAT_BGRA5551:
312511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_AR5G5B5;
313511c7023SThierry Reding 		break;
314511c7023SThierry Reding 
315511c7023SThierry Reding 	case DRM_FORMAT_XRGB1555:
316511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B5G5R5X1;
317511c7023SThierry Reding 		break;
318511c7023SThierry Reding 
319511c7023SThierry Reding 	case DRM_FORMAT_RGBX5551:
320511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_X1B5G5R5;
321511c7023SThierry Reding 		break;
322511c7023SThierry Reding 
323511c7023SThierry Reding 	case DRM_FORMAT_XBGR1555:
324511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G5B5X1;
325511c7023SThierry Reding 		break;
326511c7023SThierry Reding 
327511c7023SThierry Reding 	case DRM_FORMAT_BGRX5551:
328511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_X1R5G5B5;
329511c7023SThierry Reding 		break;
330511c7023SThierry Reding 
331511c7023SThierry Reding 	case DRM_FORMAT_BGR565:
332511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R5G6B5;
333511c7023SThierry Reding 		break;
334511c7023SThierry Reding 
335511c7023SThierry Reding 	case DRM_FORMAT_BGRA8888:
336511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A8R8G8B8;
337511c7023SThierry Reding 		break;
338511c7023SThierry Reding 
339511c7023SThierry Reding 	case DRM_FORMAT_RGBA8888:
340511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_A8B8G8R8;
341511c7023SThierry Reding 		break;
342511c7023SThierry Reding 
343511c7023SThierry Reding 	case DRM_FORMAT_XRGB8888:
344511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_B8G8R8X8;
345511c7023SThierry Reding 		break;
346511c7023SThierry Reding 
347511c7023SThierry Reding 	case DRM_FORMAT_XBGR8888:
348511c7023SThierry Reding 		*format = WIN_COLOR_DEPTH_R8G8B8X8;
3495acd3514SThierry Reding 		break;
3505acd3514SThierry Reding 
3515acd3514SThierry Reding 	case DRM_FORMAT_UYVY:
3525acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422;
3535acd3514SThierry Reding 		break;
3545acd3514SThierry Reding 
3555acd3514SThierry Reding 	case DRM_FORMAT_YUYV:
3565acd3514SThierry Reding 		if (!swap)
3575acd3514SThierry Reding 			return -EINVAL;
3585acd3514SThierry Reding 
3595acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422;
3605acd3514SThierry Reding 		*swap = BYTE_SWAP_SWAP2;
3615acd3514SThierry Reding 		break;
3625acd3514SThierry Reding 
3635acd3514SThierry Reding 	case DRM_FORMAT_YUV420:
3645acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr420P;
3655acd3514SThierry Reding 		break;
3665acd3514SThierry Reding 
3675acd3514SThierry Reding 	case DRM_FORMAT_YUV422:
3685acd3514SThierry Reding 		*format = WIN_COLOR_DEPTH_YCbCr422P;
3695acd3514SThierry Reding 		break;
3705acd3514SThierry Reding 
3715acd3514SThierry Reding 	default:
3725acd3514SThierry Reding 		return -EINVAL;
3735acd3514SThierry Reding 	}
3745acd3514SThierry Reding 
3755acd3514SThierry Reding 	return 0;
3765acd3514SThierry Reding }
3775acd3514SThierry Reding 
3785acd3514SThierry Reding bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
3795acd3514SThierry Reding {
3805acd3514SThierry Reding 	switch (format) {
3815acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422:
3825acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422:
3835acd3514SThierry Reding 		if (planar)
3845acd3514SThierry Reding 			*planar = false;
3855acd3514SThierry Reding 
3865acd3514SThierry Reding 		return true;
3875acd3514SThierry Reding 
3885acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr420P:
3895acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV420P:
3905acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422P:
3915acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422P:
3925acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422R:
3935acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422R:
3945acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YCbCr422RA:
3955acd3514SThierry Reding 	case WIN_COLOR_DEPTH_YUV422RA:
3965acd3514SThierry Reding 		if (planar)
3975acd3514SThierry Reding 			*planar = true;
3985acd3514SThierry Reding 
3995acd3514SThierry Reding 		return true;
4005acd3514SThierry Reding 	}
4015acd3514SThierry Reding 
4025acd3514SThierry Reding 	if (planar)
4035acd3514SThierry Reding 		*planar = false;
4045acd3514SThierry Reding 
4055acd3514SThierry Reding 	return false;
4065acd3514SThierry Reding }
407ebae8d07SThierry Reding 
408ebae8d07SThierry Reding static bool __drm_format_has_alpha(u32 format)
409ebae8d07SThierry Reding {
410ebae8d07SThierry Reding 	switch (format) {
411ebae8d07SThierry Reding 	case DRM_FORMAT_ARGB1555:
412ebae8d07SThierry Reding 	case DRM_FORMAT_RGBA5551:
413ebae8d07SThierry Reding 	case DRM_FORMAT_ABGR8888:
414ebae8d07SThierry Reding 	case DRM_FORMAT_ARGB8888:
415ebae8d07SThierry Reding 		return true;
416ebae8d07SThierry Reding 	}
417ebae8d07SThierry Reding 
418ebae8d07SThierry Reding 	return false;
419ebae8d07SThierry Reding }
420ebae8d07SThierry Reding 
4213dae08bcSDmitry Osipenko static int tegra_plane_format_get_alpha(unsigned int opaque,
4223dae08bcSDmitry Osipenko 					unsigned int *alpha)
423ebae8d07SThierry Reding {
4245467a8b8SThierry Reding 	if (tegra_plane_format_is_yuv(opaque, NULL)) {
4255467a8b8SThierry Reding 		*alpha = opaque;
4265467a8b8SThierry Reding 		return 0;
4275467a8b8SThierry Reding 	}
4285467a8b8SThierry Reding 
429ebae8d07SThierry Reding 	switch (opaque) {
430ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B5G5R5X1:
431ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_B5G5R5A1;
432ebae8d07SThierry Reding 		return 0;
433ebae8d07SThierry Reding 
434ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_X1B5G5R5:
435ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_A1B5G5R5;
436ebae8d07SThierry Reding 		return 0;
437ebae8d07SThierry Reding 
438ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_R8G8B8X8:
439ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_R8G8B8A8;
440ebae8d07SThierry Reding 		return 0;
441ebae8d07SThierry Reding 
442ebae8d07SThierry Reding 	case WIN_COLOR_DEPTH_B8G8R8X8:
443ebae8d07SThierry Reding 		*alpha = WIN_COLOR_DEPTH_B8G8R8A8;
444ebae8d07SThierry Reding 		return 0;
4458a927d64SThierry Reding 
4468a927d64SThierry Reding 	case WIN_COLOR_DEPTH_B5G6R5:
4478a927d64SThierry Reding 		*alpha = opaque;
4488a927d64SThierry Reding 		return 0;
449ebae8d07SThierry Reding 	}
450ebae8d07SThierry Reding 
451ebae8d07SThierry Reding 	return -EINVAL;
452ebae8d07SThierry Reding }
453ebae8d07SThierry Reding 
4543dae08bcSDmitry Osipenko /*
4553dae08bcSDmitry Osipenko  * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
4563dae08bcSDmitry Osipenko  * be emulated using the alpha formats and alpha blending disabled.
4573dae08bcSDmitry Osipenko  */
4583dae08bcSDmitry Osipenko static int tegra_plane_setup_opacity(struct tegra_plane *tegra,
4593dae08bcSDmitry Osipenko 				     struct tegra_plane_state *state)
4603dae08bcSDmitry Osipenko {
4613dae08bcSDmitry Osipenko 	unsigned int format;
4623dae08bcSDmitry Osipenko 	int err;
4633dae08bcSDmitry Osipenko 
4643dae08bcSDmitry Osipenko 	switch (state->format) {
4653dae08bcSDmitry Osipenko 	case WIN_COLOR_DEPTH_B5G5R5A1:
4663dae08bcSDmitry Osipenko 	case WIN_COLOR_DEPTH_A1B5G5R5:
4673dae08bcSDmitry Osipenko 	case WIN_COLOR_DEPTH_R8G8B8A8:
4683dae08bcSDmitry Osipenko 	case WIN_COLOR_DEPTH_B8G8R8A8:
4693dae08bcSDmitry Osipenko 		state->opaque = false;
4703dae08bcSDmitry Osipenko 		break;
4713dae08bcSDmitry Osipenko 
4723dae08bcSDmitry Osipenko 	default:
4733dae08bcSDmitry Osipenko 		err = tegra_plane_format_get_alpha(state->format, &format);
4743dae08bcSDmitry Osipenko 		if (err < 0)
4753dae08bcSDmitry Osipenko 			return err;
4763dae08bcSDmitry Osipenko 
4773dae08bcSDmitry Osipenko 		state->format = format;
4783dae08bcSDmitry Osipenko 		state->opaque = true;
4793dae08bcSDmitry Osipenko 		break;
4803dae08bcSDmitry Osipenko 	}
4813dae08bcSDmitry Osipenko 
4823dae08bcSDmitry Osipenko 	return 0;
4833dae08bcSDmitry Osipenko }
4843dae08bcSDmitry Osipenko 
4853dae08bcSDmitry Osipenko static int tegra_plane_check_transparency(struct tegra_plane *tegra,
4863dae08bcSDmitry Osipenko 					  struct tegra_plane_state *state)
4873dae08bcSDmitry Osipenko {
4883dae08bcSDmitry Osipenko 	struct drm_plane_state *old, *plane_state;
4893dae08bcSDmitry Osipenko 	struct drm_plane *plane;
4903dae08bcSDmitry Osipenko 
4913dae08bcSDmitry Osipenko 	old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
4923dae08bcSDmitry Osipenko 
4933dae08bcSDmitry Osipenko 	/* check if zpos / transparency changed */
4943dae08bcSDmitry Osipenko 	if (old->normalized_zpos == state->base.normalized_zpos &&
4953dae08bcSDmitry Osipenko 	    to_tegra_plane_state(old)->opaque == state->opaque)
4963dae08bcSDmitry Osipenko 		return 0;
4973dae08bcSDmitry Osipenko 
4983dae08bcSDmitry Osipenko 	/* include all sibling planes into this commit */
4993dae08bcSDmitry Osipenko 	drm_for_each_plane(plane, tegra->base.dev) {
5003dae08bcSDmitry Osipenko 		struct tegra_plane *p = to_tegra_plane(plane);
5013dae08bcSDmitry Osipenko 
5023dae08bcSDmitry Osipenko 		/* skip this plane and planes on different CRTCs */
5033dae08bcSDmitry Osipenko 		if (p == tegra || p->dc != tegra->dc)
5043dae08bcSDmitry Osipenko 			continue;
5053dae08bcSDmitry Osipenko 
5063dae08bcSDmitry Osipenko 		plane_state = drm_atomic_get_plane_state(state->base.state,
5073dae08bcSDmitry Osipenko 							 plane);
5083dae08bcSDmitry Osipenko 		if (IS_ERR(plane_state))
5093dae08bcSDmitry Osipenko 			return PTR_ERR(plane_state);
5103dae08bcSDmitry Osipenko 	}
5113dae08bcSDmitry Osipenko 
5123dae08bcSDmitry Osipenko 	return 1;
5133dae08bcSDmitry Osipenko }
5143dae08bcSDmitry Osipenko 
5155e2e86f1SDmitry Osipenko static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
516ebae8d07SThierry Reding 						  struct tegra_plane *other)
517ebae8d07SThierry Reding {
518ebae8d07SThierry Reding 	unsigned int index = 0, i;
519ebae8d07SThierry Reding 
520ebae8d07SThierry Reding 	WARN_ON(plane == other);
521ebae8d07SThierry Reding 
522ebae8d07SThierry Reding 	for (i = 0; i < 3; i++) {
523ebae8d07SThierry Reding 		if (i == plane->index)
524ebae8d07SThierry Reding 			continue;
525ebae8d07SThierry Reding 
526ebae8d07SThierry Reding 		if (i == other->index)
527ebae8d07SThierry Reding 			break;
528ebae8d07SThierry Reding 
529ebae8d07SThierry Reding 		index++;
530ebae8d07SThierry Reding 	}
531ebae8d07SThierry Reding 
532ebae8d07SThierry Reding 	return index;
533ebae8d07SThierry Reding }
534ebae8d07SThierry Reding 
5353dae08bcSDmitry Osipenko static void tegra_plane_update_transparency(struct tegra_plane *tegra,
536ebae8d07SThierry Reding 					    struct tegra_plane_state *state)
537ebae8d07SThierry Reding {
5383dae08bcSDmitry Osipenko 	struct drm_plane_state *new;
539ebae8d07SThierry Reding 	struct drm_plane *plane;
540ebae8d07SThierry Reding 	unsigned int i;
541ebae8d07SThierry Reding 
5423dae08bcSDmitry Osipenko 	for_each_new_plane_in_state(state->base.state, plane, new, i) {
543ebae8d07SThierry Reding 		struct tegra_plane *p = to_tegra_plane(plane);
544ebae8d07SThierry Reding 		unsigned index;
545ebae8d07SThierry Reding 
546ebae8d07SThierry Reding 		/* skip this plane and planes on different CRTCs */
5473dae08bcSDmitry Osipenko 		if (p == tegra || p->dc != tegra->dc)
548ebae8d07SThierry Reding 			continue;
549ebae8d07SThierry Reding 
550ebae8d07SThierry Reding 		index = tegra_plane_get_overlap_index(tegra, p);
551ebae8d07SThierry Reding 
5523dae08bcSDmitry Osipenko 		if (new->fb && __drm_format_has_alpha(new->fb->format->format))
5533dae08bcSDmitry Osipenko 			state->blending[index].alpha = true;
5543dae08bcSDmitry Osipenko 		else
5553dae08bcSDmitry Osipenko 			state->blending[index].alpha = false;
5563dae08bcSDmitry Osipenko 
5573dae08bcSDmitry Osipenko 		if (new->normalized_zpos > state->base.normalized_zpos)
5583dae08bcSDmitry Osipenko 			state->blending[index].top = true;
5593dae08bcSDmitry Osipenko 		else
5603dae08bcSDmitry Osipenko 			state->blending[index].top = false;
56148519232SDmitry Osipenko 
562ebae8d07SThierry Reding 		/*
5633dae08bcSDmitry Osipenko 		 * Missing framebuffer means that plane is disabled, in this
5643dae08bcSDmitry Osipenko 		 * case mark B / C window as top to be able to differentiate
5653dae08bcSDmitry Osipenko 		 * windows indices order in regards to zPos for the middle
5663dae08bcSDmitry Osipenko 		 * window X / Y registers programming.
567ebae8d07SThierry Reding 		 */
5683dae08bcSDmitry Osipenko 		if (!new->fb)
5693dae08bcSDmitry Osipenko 			state->blending[index].top = (index == 1);
570ebae8d07SThierry Reding 	}
571ebae8d07SThierry Reding }
572ebae8d07SThierry Reding 
5733dae08bcSDmitry Osipenko static int tegra_plane_setup_transparency(struct tegra_plane *tegra,
5743dae08bcSDmitry Osipenko 					  struct tegra_plane_state *state)
5753dae08bcSDmitry Osipenko {
5763dae08bcSDmitry Osipenko 	struct tegra_plane_state *tegra_state;
5773dae08bcSDmitry Osipenko 	struct drm_plane_state *new;
5783dae08bcSDmitry Osipenko 	struct drm_plane *plane;
5793dae08bcSDmitry Osipenko 	int err;
580ebae8d07SThierry Reding 
581ebae8d07SThierry Reding 	/*
5823dae08bcSDmitry Osipenko 	 * If planes zpos / transparency changed, sibling planes blending
5833dae08bcSDmitry Osipenko 	 * state may require adjustment and in this case they will be included
5843dae08bcSDmitry Osipenko 	 * into this atom commit, otherwise blending state is unchanged.
585ebae8d07SThierry Reding 	 */
5863dae08bcSDmitry Osipenko 	err = tegra_plane_check_transparency(tegra, state);
5873dae08bcSDmitry Osipenko 	if (err <= 0)
5883dae08bcSDmitry Osipenko 		return err;
5893dae08bcSDmitry Osipenko 
5903dae08bcSDmitry Osipenko 	/*
5913dae08bcSDmitry Osipenko 	 * All planes are now in the atomic state, walk them up and update
5923dae08bcSDmitry Osipenko 	 * transparency state for each plane.
5933dae08bcSDmitry Osipenko 	 */
5943dae08bcSDmitry Osipenko 	drm_for_each_plane(plane, tegra->base.dev) {
5953dae08bcSDmitry Osipenko 		struct tegra_plane *p = to_tegra_plane(plane);
5963dae08bcSDmitry Osipenko 
5973dae08bcSDmitry Osipenko 		/* skip planes on different CRTCs */
5983dae08bcSDmitry Osipenko 		if (p->dc != tegra->dc)
5993dae08bcSDmitry Osipenko 			continue;
6003dae08bcSDmitry Osipenko 
6013dae08bcSDmitry Osipenko 		new = drm_atomic_get_new_plane_state(state->base.state, plane);
6023dae08bcSDmitry Osipenko 		tegra_state = to_tegra_plane_state(new);
6033dae08bcSDmitry Osipenko 
6043dae08bcSDmitry Osipenko 		/*
6053dae08bcSDmitry Osipenko 		 * There is no need to update blending state for the disabled
6063dae08bcSDmitry Osipenko 		 * plane.
6073dae08bcSDmitry Osipenko 		 */
6083dae08bcSDmitry Osipenko 		if (new->fb)
6093dae08bcSDmitry Osipenko 			tegra_plane_update_transparency(p, tegra_state);
610ebae8d07SThierry Reding 	}
6113dae08bcSDmitry Osipenko 
6123dae08bcSDmitry Osipenko 	return 0;
6133dae08bcSDmitry Osipenko }
6143dae08bcSDmitry Osipenko 
6153dae08bcSDmitry Osipenko int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
6163dae08bcSDmitry Osipenko 				   struct tegra_plane_state *state)
6173dae08bcSDmitry Osipenko {
6183dae08bcSDmitry Osipenko 	int err;
6193dae08bcSDmitry Osipenko 
6203dae08bcSDmitry Osipenko 	err = tegra_plane_setup_opacity(tegra, state);
6213dae08bcSDmitry Osipenko 	if (err < 0)
6223dae08bcSDmitry Osipenko 		return err;
6233dae08bcSDmitry Osipenko 
6243dae08bcSDmitry Osipenko 	err = tegra_plane_setup_transparency(tegra, state);
6253dae08bcSDmitry Osipenko 	if (err < 0)
6263dae08bcSDmitry Osipenko 		return err;
6273dae08bcSDmitry Osipenko 
6283dae08bcSDmitry Osipenko 	return 0;
629ebae8d07SThierry Reding }
630