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 867b6f8467SThierry Reding static bool tegra_plane_supports_sector_layout(struct drm_plane *plane) 877b6f8467SThierry Reding { 887b6f8467SThierry Reding struct drm_crtc *crtc; 897b6f8467SThierry Reding 907b6f8467SThierry Reding drm_for_each_crtc(crtc, plane->dev) { 917b6f8467SThierry Reding if (plane->possible_crtcs & drm_crtc_mask(crtc)) { 927b6f8467SThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 937b6f8467SThierry Reding 947b6f8467SThierry Reding if (!dc->soc->supports_sector_layout) 957b6f8467SThierry Reding return false; 967b6f8467SThierry Reding } 977b6f8467SThierry Reding } 987b6f8467SThierry Reding 997b6f8467SThierry Reding return true; 1007b6f8467SThierry Reding } 1017b6f8467SThierry 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 1117b6f8467SThierry Reding /* check for the sector layout bit */ 1127b6f8467SThierry Reding if ((modifier >> 56) == DRM_FORMAT_MOD_VENDOR_NVIDIA) { 1137b6f8467SThierry Reding if (modifier & DRM_FORMAT_MOD_NVIDIA_SECTOR_LAYOUT) { 1147b6f8467SThierry Reding if (!tegra_plane_supports_sector_layout(plane)) 1157b6f8467SThierry Reding return false; 1167b6f8467SThierry Reding } 1177b6f8467SThierry Reding } 1187b6f8467SThierry 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 378*e16efff4SThierry Reding bool tegra_plane_format_is_indexed(unsigned int format) 379*e16efff4SThierry Reding { 380*e16efff4SThierry Reding switch (format) { 381*e16efff4SThierry Reding case WIN_COLOR_DEPTH_P1: 382*e16efff4SThierry Reding case WIN_COLOR_DEPTH_P2: 383*e16efff4SThierry Reding case WIN_COLOR_DEPTH_P4: 384*e16efff4SThierry Reding case WIN_COLOR_DEPTH_P8: 385*e16efff4SThierry Reding return true; 386*e16efff4SThierry Reding } 387*e16efff4SThierry Reding 388*e16efff4SThierry Reding return false; 389*e16efff4SThierry Reding } 390*e16efff4SThierry Reding 391*e16efff4SThierry Reding bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc) 3925acd3514SThierry Reding { 3935acd3514SThierry Reding switch (format) { 3945acd3514SThierry Reding case WIN_COLOR_DEPTH_YCbCr422: 3955acd3514SThierry Reding case WIN_COLOR_DEPTH_YUV422: 3965acd3514SThierry Reding if (planar) 3975acd3514SThierry Reding *planar = false; 3985acd3514SThierry Reding 399*e16efff4SThierry Reding if (bpc) 400*e16efff4SThierry Reding *bpc = 8; 401*e16efff4SThierry Reding 4025acd3514SThierry Reding return true; 4035acd3514SThierry Reding 4045acd3514SThierry Reding case WIN_COLOR_DEPTH_YCbCr420P: 4055acd3514SThierry Reding case WIN_COLOR_DEPTH_YUV420P: 4065acd3514SThierry Reding case WIN_COLOR_DEPTH_YCbCr422P: 4075acd3514SThierry Reding case WIN_COLOR_DEPTH_YUV422P: 4085acd3514SThierry Reding case WIN_COLOR_DEPTH_YCbCr422R: 4095acd3514SThierry Reding case WIN_COLOR_DEPTH_YUV422R: 4105acd3514SThierry Reding case WIN_COLOR_DEPTH_YCbCr422RA: 4115acd3514SThierry Reding case WIN_COLOR_DEPTH_YUV422RA: 4125acd3514SThierry Reding if (planar) 4135acd3514SThierry Reding *planar = true; 4145acd3514SThierry Reding 415*e16efff4SThierry Reding if (bpc) 416*e16efff4SThierry Reding *bpc = 8; 417*e16efff4SThierry Reding 4185acd3514SThierry Reding return true; 4195acd3514SThierry Reding } 4205acd3514SThierry Reding 4215acd3514SThierry Reding if (planar) 4225acd3514SThierry Reding *planar = false; 4235acd3514SThierry Reding 4245acd3514SThierry Reding return false; 4255acd3514SThierry Reding } 426ebae8d07SThierry Reding 427ebae8d07SThierry Reding static bool __drm_format_has_alpha(u32 format) 428ebae8d07SThierry Reding { 429ebae8d07SThierry Reding switch (format) { 430ebae8d07SThierry Reding case DRM_FORMAT_ARGB1555: 431ebae8d07SThierry Reding case DRM_FORMAT_RGBA5551: 432ebae8d07SThierry Reding case DRM_FORMAT_ABGR8888: 433ebae8d07SThierry Reding case DRM_FORMAT_ARGB8888: 434ebae8d07SThierry Reding return true; 435ebae8d07SThierry Reding } 436ebae8d07SThierry Reding 437ebae8d07SThierry Reding return false; 438ebae8d07SThierry Reding } 439ebae8d07SThierry Reding 4403dae08bcSDmitry Osipenko static int tegra_plane_format_get_alpha(unsigned int opaque, 4413dae08bcSDmitry Osipenko unsigned int *alpha) 442ebae8d07SThierry Reding { 443*e16efff4SThierry Reding if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) { 4445467a8b8SThierry Reding *alpha = opaque; 4455467a8b8SThierry Reding return 0; 4465467a8b8SThierry Reding } 4475467a8b8SThierry Reding 448ebae8d07SThierry Reding switch (opaque) { 449ebae8d07SThierry Reding case WIN_COLOR_DEPTH_B5G5R5X1: 450ebae8d07SThierry Reding *alpha = WIN_COLOR_DEPTH_B5G5R5A1; 451ebae8d07SThierry Reding return 0; 452ebae8d07SThierry Reding 453ebae8d07SThierry Reding case WIN_COLOR_DEPTH_X1B5G5R5: 454ebae8d07SThierry Reding *alpha = WIN_COLOR_DEPTH_A1B5G5R5; 455ebae8d07SThierry Reding return 0; 456ebae8d07SThierry Reding 457ebae8d07SThierry Reding case WIN_COLOR_DEPTH_R8G8B8X8: 458ebae8d07SThierry Reding *alpha = WIN_COLOR_DEPTH_R8G8B8A8; 459ebae8d07SThierry Reding return 0; 460ebae8d07SThierry Reding 461ebae8d07SThierry Reding case WIN_COLOR_DEPTH_B8G8R8X8: 462ebae8d07SThierry Reding *alpha = WIN_COLOR_DEPTH_B8G8R8A8; 463ebae8d07SThierry Reding return 0; 4648a927d64SThierry Reding 4658a927d64SThierry Reding case WIN_COLOR_DEPTH_B5G6R5: 4668a927d64SThierry Reding *alpha = opaque; 4678a927d64SThierry Reding return 0; 468ebae8d07SThierry Reding } 469ebae8d07SThierry Reding 470ebae8d07SThierry Reding return -EINVAL; 471ebae8d07SThierry Reding } 472ebae8d07SThierry Reding 4733dae08bcSDmitry Osipenko /* 4743dae08bcSDmitry Osipenko * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 4753dae08bcSDmitry Osipenko * be emulated using the alpha formats and alpha blending disabled. 4763dae08bcSDmitry Osipenko */ 4773dae08bcSDmitry Osipenko static int tegra_plane_setup_opacity(struct tegra_plane *tegra, 4783dae08bcSDmitry Osipenko struct tegra_plane_state *state) 4793dae08bcSDmitry Osipenko { 4803dae08bcSDmitry Osipenko unsigned int format; 4813dae08bcSDmitry Osipenko int err; 4823dae08bcSDmitry Osipenko 4833dae08bcSDmitry Osipenko switch (state->format) { 4843dae08bcSDmitry Osipenko case WIN_COLOR_DEPTH_B5G5R5A1: 4853dae08bcSDmitry Osipenko case WIN_COLOR_DEPTH_A1B5G5R5: 4863dae08bcSDmitry Osipenko case WIN_COLOR_DEPTH_R8G8B8A8: 4873dae08bcSDmitry Osipenko case WIN_COLOR_DEPTH_B8G8R8A8: 4883dae08bcSDmitry Osipenko state->opaque = false; 4893dae08bcSDmitry Osipenko break; 4903dae08bcSDmitry Osipenko 4913dae08bcSDmitry Osipenko default: 4923dae08bcSDmitry Osipenko err = tegra_plane_format_get_alpha(state->format, &format); 4933dae08bcSDmitry Osipenko if (err < 0) 4943dae08bcSDmitry Osipenko return err; 4953dae08bcSDmitry Osipenko 4963dae08bcSDmitry Osipenko state->format = format; 4973dae08bcSDmitry Osipenko state->opaque = true; 4983dae08bcSDmitry Osipenko break; 4993dae08bcSDmitry Osipenko } 5003dae08bcSDmitry Osipenko 5013dae08bcSDmitry Osipenko return 0; 5023dae08bcSDmitry Osipenko } 5033dae08bcSDmitry Osipenko 5043dae08bcSDmitry Osipenko static int tegra_plane_check_transparency(struct tegra_plane *tegra, 5053dae08bcSDmitry Osipenko struct tegra_plane_state *state) 5063dae08bcSDmitry Osipenko { 5073dae08bcSDmitry Osipenko struct drm_plane_state *old, *plane_state; 5083dae08bcSDmitry Osipenko struct drm_plane *plane; 5093dae08bcSDmitry Osipenko 5103dae08bcSDmitry Osipenko old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base); 5113dae08bcSDmitry Osipenko 5123dae08bcSDmitry Osipenko /* check if zpos / transparency changed */ 5133dae08bcSDmitry Osipenko if (old->normalized_zpos == state->base.normalized_zpos && 5143dae08bcSDmitry Osipenko to_tegra_plane_state(old)->opaque == state->opaque) 5153dae08bcSDmitry Osipenko return 0; 5163dae08bcSDmitry Osipenko 5173dae08bcSDmitry Osipenko /* include all sibling planes into this commit */ 5183dae08bcSDmitry Osipenko drm_for_each_plane(plane, tegra->base.dev) { 5193dae08bcSDmitry Osipenko struct tegra_plane *p = to_tegra_plane(plane); 5203dae08bcSDmitry Osipenko 5213dae08bcSDmitry Osipenko /* skip this plane and planes on different CRTCs */ 5223dae08bcSDmitry Osipenko if (p == tegra || p->dc != tegra->dc) 5233dae08bcSDmitry Osipenko continue; 5243dae08bcSDmitry Osipenko 5253dae08bcSDmitry Osipenko plane_state = drm_atomic_get_plane_state(state->base.state, 5263dae08bcSDmitry Osipenko plane); 5273dae08bcSDmitry Osipenko if (IS_ERR(plane_state)) 5283dae08bcSDmitry Osipenko return PTR_ERR(plane_state); 5293dae08bcSDmitry Osipenko } 5303dae08bcSDmitry Osipenko 5313dae08bcSDmitry Osipenko return 1; 5323dae08bcSDmitry Osipenko } 5333dae08bcSDmitry Osipenko 5345e2e86f1SDmitry Osipenko static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 535ebae8d07SThierry Reding struct tegra_plane *other) 536ebae8d07SThierry Reding { 537ebae8d07SThierry Reding unsigned int index = 0, i; 538ebae8d07SThierry Reding 539ebae8d07SThierry Reding WARN_ON(plane == other); 540ebae8d07SThierry Reding 541ebae8d07SThierry Reding for (i = 0; i < 3; i++) { 542ebae8d07SThierry Reding if (i == plane->index) 543ebae8d07SThierry Reding continue; 544ebae8d07SThierry Reding 545ebae8d07SThierry Reding if (i == other->index) 546ebae8d07SThierry Reding break; 547ebae8d07SThierry Reding 548ebae8d07SThierry Reding index++; 549ebae8d07SThierry Reding } 550ebae8d07SThierry Reding 551ebae8d07SThierry Reding return index; 552ebae8d07SThierry Reding } 553ebae8d07SThierry Reding 5543dae08bcSDmitry Osipenko static void tegra_plane_update_transparency(struct tegra_plane *tegra, 555ebae8d07SThierry Reding struct tegra_plane_state *state) 556ebae8d07SThierry Reding { 5573dae08bcSDmitry Osipenko struct drm_plane_state *new; 558ebae8d07SThierry Reding struct drm_plane *plane; 559ebae8d07SThierry Reding unsigned int i; 560ebae8d07SThierry Reding 5613dae08bcSDmitry Osipenko for_each_new_plane_in_state(state->base.state, plane, new, i) { 562ebae8d07SThierry Reding struct tegra_plane *p = to_tegra_plane(plane); 563ebae8d07SThierry Reding unsigned index; 564ebae8d07SThierry Reding 565ebae8d07SThierry Reding /* skip this plane and planes on different CRTCs */ 5663dae08bcSDmitry Osipenko if (p == tegra || p->dc != tegra->dc) 567ebae8d07SThierry Reding continue; 568ebae8d07SThierry Reding 569ebae8d07SThierry Reding index = tegra_plane_get_overlap_index(tegra, p); 570ebae8d07SThierry Reding 5713dae08bcSDmitry Osipenko if (new->fb && __drm_format_has_alpha(new->fb->format->format)) 5723dae08bcSDmitry Osipenko state->blending[index].alpha = true; 5733dae08bcSDmitry Osipenko else 5743dae08bcSDmitry Osipenko state->blending[index].alpha = false; 5753dae08bcSDmitry Osipenko 5763dae08bcSDmitry Osipenko if (new->normalized_zpos > state->base.normalized_zpos) 5773dae08bcSDmitry Osipenko state->blending[index].top = true; 5783dae08bcSDmitry Osipenko else 5793dae08bcSDmitry Osipenko state->blending[index].top = false; 58048519232SDmitry Osipenko 581ebae8d07SThierry Reding /* 5823dae08bcSDmitry Osipenko * Missing framebuffer means that plane is disabled, in this 5833dae08bcSDmitry Osipenko * case mark B / C window as top to be able to differentiate 5843dae08bcSDmitry Osipenko * windows indices order in regards to zPos for the middle 5853dae08bcSDmitry Osipenko * window X / Y registers programming. 586ebae8d07SThierry Reding */ 5873dae08bcSDmitry Osipenko if (!new->fb) 5883dae08bcSDmitry Osipenko state->blending[index].top = (index == 1); 589ebae8d07SThierry Reding } 590ebae8d07SThierry Reding } 591ebae8d07SThierry Reding 5923dae08bcSDmitry Osipenko static int tegra_plane_setup_transparency(struct tegra_plane *tegra, 5933dae08bcSDmitry Osipenko struct tegra_plane_state *state) 5943dae08bcSDmitry Osipenko { 5953dae08bcSDmitry Osipenko struct tegra_plane_state *tegra_state; 5963dae08bcSDmitry Osipenko struct drm_plane_state *new; 5973dae08bcSDmitry Osipenko struct drm_plane *plane; 5983dae08bcSDmitry Osipenko int err; 599ebae8d07SThierry Reding 600ebae8d07SThierry Reding /* 6013dae08bcSDmitry Osipenko * If planes zpos / transparency changed, sibling planes blending 6023dae08bcSDmitry Osipenko * state may require adjustment and in this case they will be included 6033dae08bcSDmitry Osipenko * into this atom commit, otherwise blending state is unchanged. 604ebae8d07SThierry Reding */ 6053dae08bcSDmitry Osipenko err = tegra_plane_check_transparency(tegra, state); 6063dae08bcSDmitry Osipenko if (err <= 0) 6073dae08bcSDmitry Osipenko return err; 6083dae08bcSDmitry Osipenko 6093dae08bcSDmitry Osipenko /* 6103dae08bcSDmitry Osipenko * All planes are now in the atomic state, walk them up and update 6113dae08bcSDmitry Osipenko * transparency state for each plane. 6123dae08bcSDmitry Osipenko */ 6133dae08bcSDmitry Osipenko drm_for_each_plane(plane, tegra->base.dev) { 6143dae08bcSDmitry Osipenko struct tegra_plane *p = to_tegra_plane(plane); 6153dae08bcSDmitry Osipenko 6163dae08bcSDmitry Osipenko /* skip planes on different CRTCs */ 6173dae08bcSDmitry Osipenko if (p->dc != tegra->dc) 6183dae08bcSDmitry Osipenko continue; 6193dae08bcSDmitry Osipenko 6203dae08bcSDmitry Osipenko new = drm_atomic_get_new_plane_state(state->base.state, plane); 6213dae08bcSDmitry Osipenko tegra_state = to_tegra_plane_state(new); 6223dae08bcSDmitry Osipenko 6233dae08bcSDmitry Osipenko /* 6243dae08bcSDmitry Osipenko * There is no need to update blending state for the disabled 6253dae08bcSDmitry Osipenko * plane. 6263dae08bcSDmitry Osipenko */ 6273dae08bcSDmitry Osipenko if (new->fb) 6283dae08bcSDmitry Osipenko tegra_plane_update_transparency(p, tegra_state); 629ebae8d07SThierry Reding } 6303dae08bcSDmitry Osipenko 6313dae08bcSDmitry Osipenko return 0; 6323dae08bcSDmitry Osipenko } 6333dae08bcSDmitry Osipenko 6343dae08bcSDmitry Osipenko int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 6353dae08bcSDmitry Osipenko struct tegra_plane_state *state) 6363dae08bcSDmitry Osipenko { 6373dae08bcSDmitry Osipenko int err; 6383dae08bcSDmitry Osipenko 6393dae08bcSDmitry Osipenko err = tegra_plane_setup_opacity(tegra, state); 6403dae08bcSDmitry Osipenko if (err < 0) 6413dae08bcSDmitry Osipenko return err; 6423dae08bcSDmitry Osipenko 6433dae08bcSDmitry Osipenko err = tegra_plane_setup_transparency(tegra, state); 6443dae08bcSDmitry Osipenko if (err < 0) 6453dae08bcSDmitry Osipenko return err; 6463dae08bcSDmitry Osipenko 6473dae08bcSDmitry Osipenko return 0; 648ebae8d07SThierry Reding } 649