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, ©->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 ©->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