18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/iommu.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 98c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 108c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 118c2ecf20Sopenharmony_ci#include <drm/drm_gem_framebuffer_helper.h> 128c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "dc.h" 158c2ecf20Sopenharmony_ci#include "plane.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic void tegra_plane_destroy(struct drm_plane *plane) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct tegra_plane *p = to_tegra_plane(plane); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci drm_plane_cleanup(plane); 228c2ecf20Sopenharmony_ci kfree(p); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic void tegra_plane_reset(struct drm_plane *plane) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct tegra_plane *p = to_tegra_plane(plane); 288c2ecf20Sopenharmony_ci struct tegra_plane_state *state; 298c2ecf20Sopenharmony_ci unsigned int i; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (plane->state) 328c2ecf20Sopenharmony_ci __drm_atomic_helper_plane_destroy_state(plane->state); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci kfree(plane->state); 358c2ecf20Sopenharmony_ci plane->state = NULL; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 388c2ecf20Sopenharmony_ci if (state) { 398c2ecf20Sopenharmony_ci plane->state = &state->base; 408c2ecf20Sopenharmony_ci plane->state->plane = plane; 418c2ecf20Sopenharmony_ci plane->state->zpos = p->index; 428c2ecf20Sopenharmony_ci plane->state->normalized_zpos = p->index; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 458c2ecf20Sopenharmony_ci state->iova[i] = DMA_MAPPING_ERROR; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic struct drm_plane_state * 508c2ecf20Sopenharmony_citegra_plane_atomic_duplicate_state(struct drm_plane *plane) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct tegra_plane_state *state = to_tegra_plane_state(plane->state); 538c2ecf20Sopenharmony_ci struct tegra_plane_state *copy; 548c2ecf20Sopenharmony_ci unsigned int i; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci copy = kmalloc(sizeof(*copy), GFP_KERNEL); 578c2ecf20Sopenharmony_ci if (!copy) 588c2ecf20Sopenharmony_ci return NULL; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci __drm_atomic_helper_plane_duplicate_state(plane, ©->base); 618c2ecf20Sopenharmony_ci copy->tiling = state->tiling; 628c2ecf20Sopenharmony_ci copy->format = state->format; 638c2ecf20Sopenharmony_ci copy->swap = state->swap; 648c2ecf20Sopenharmony_ci copy->reflect_x = state->reflect_x; 658c2ecf20Sopenharmony_ci copy->reflect_y = state->reflect_y; 668c2ecf20Sopenharmony_ci copy->opaque = state->opaque; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 698c2ecf20Sopenharmony_ci copy->blending[i] = state->blending[i]; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 728c2ecf20Sopenharmony_ci copy->iova[i] = DMA_MAPPING_ERROR; 738c2ecf20Sopenharmony_ci copy->sgt[i] = NULL; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return ©->base; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic void tegra_plane_atomic_destroy_state(struct drm_plane *plane, 808c2ecf20Sopenharmony_ci struct drm_plane_state *state) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci __drm_atomic_helper_plane_destroy_state(state); 838c2ecf20Sopenharmony_ci kfree(state); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic bool tegra_plane_format_mod_supported(struct drm_plane *plane, 878c2ecf20Sopenharmony_ci uint32_t format, 888c2ecf20Sopenharmony_ci uint64_t modifier) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci const struct drm_format_info *info = drm_format_info(format); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (modifier == DRM_FORMAT_MOD_LINEAR) 938c2ecf20Sopenharmony_ci return true; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (info->num_planes == 1) 968c2ecf20Sopenharmony_ci return true; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return false; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciconst struct drm_plane_funcs tegra_plane_funcs = { 1028c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 1038c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 1048c2ecf20Sopenharmony_ci .destroy = tegra_plane_destroy, 1058c2ecf20Sopenharmony_ci .reset = tegra_plane_reset, 1068c2ecf20Sopenharmony_ci .atomic_duplicate_state = tegra_plane_atomic_duplicate_state, 1078c2ecf20Sopenharmony_ci .atomic_destroy_state = tegra_plane_atomic_destroy_state, 1088c2ecf20Sopenharmony_ci .format_mod_supported = tegra_plane_format_mod_supported, 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct iommu_domain *domain = iommu_get_domain_for_dev(dc->dev); 1148c2ecf20Sopenharmony_ci unsigned int i; 1158c2ecf20Sopenharmony_ci int err; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci for (i = 0; i < state->base.fb->format->num_planes; i++) { 1188c2ecf20Sopenharmony_ci struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 1198c2ecf20Sopenharmony_ci dma_addr_t phys_addr, *phys; 1208c2ecf20Sopenharmony_ci struct sg_table *sgt; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (!domain || dc->client.group) 1238c2ecf20Sopenharmony_ci phys = &phys_addr; 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci phys = NULL; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci sgt = host1x_bo_pin(dc->dev, &bo->base, phys); 1288c2ecf20Sopenharmony_ci if (IS_ERR(sgt)) { 1298c2ecf20Sopenharmony_ci err = PTR_ERR(sgt); 1308c2ecf20Sopenharmony_ci goto unpin; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (sgt) { 1348c2ecf20Sopenharmony_ci err = dma_map_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 1358c2ecf20Sopenharmony_ci if (err) 1368c2ecf20Sopenharmony_ci goto unpin; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * The display controller needs contiguous memory, so 1408c2ecf20Sopenharmony_ci * fail if the buffer is discontiguous and we fail to 1418c2ecf20Sopenharmony_ci * map its SG table to a single contiguous chunk of 1428c2ecf20Sopenharmony_ci * I/O virtual memory. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci if (sgt->nents > 1) { 1458c2ecf20Sopenharmony_ci err = -EINVAL; 1468c2ecf20Sopenharmony_ci goto unpin; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci state->iova[i] = sg_dma_address(sgt->sgl); 1508c2ecf20Sopenharmony_ci state->sgt[i] = sgt; 1518c2ecf20Sopenharmony_ci } else { 1528c2ecf20Sopenharmony_ci state->iova[i] = phys_addr; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return 0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciunpin: 1598c2ecf20Sopenharmony_ci dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci while (i--) { 1628c2ecf20Sopenharmony_ci struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 1638c2ecf20Sopenharmony_ci struct sg_table *sgt = state->sgt[i]; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (sgt) 1668c2ecf20Sopenharmony_ci dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci host1x_bo_unpin(dc->dev, &bo->base, sgt); 1698c2ecf20Sopenharmony_ci state->iova[i] = DMA_MAPPING_ERROR; 1708c2ecf20Sopenharmony_ci state->sgt[i] = NULL; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return err; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci unsigned int i; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci for (i = 0; i < state->base.fb->format->num_planes; i++) { 1818c2ecf20Sopenharmony_ci struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 1828c2ecf20Sopenharmony_ci struct sg_table *sgt = state->sgt[i]; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (sgt) 1858c2ecf20Sopenharmony_ci dma_unmap_sgtable(dc->dev, sgt, DMA_TO_DEVICE, 0); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci host1x_bo_unpin(dc->dev, &bo->base, sgt); 1888c2ecf20Sopenharmony_ci state->iova[i] = DMA_MAPPING_ERROR; 1898c2ecf20Sopenharmony_ci state->sgt[i] = NULL; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciint tegra_plane_prepare_fb(struct drm_plane *plane, 1948c2ecf20Sopenharmony_ci struct drm_plane_state *state) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct tegra_dc *dc = to_tegra_dc(state->crtc); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (!state->fb) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci drm_gem_fb_prepare_fb(plane, state); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return tegra_dc_pin(dc, to_tegra_plane_state(state)); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_civoid tegra_plane_cleanup_fb(struct drm_plane *plane, 2078c2ecf20Sopenharmony_ci struct drm_plane_state *state) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct tegra_dc *dc = to_tegra_dc(state->crtc); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (dc) 2128c2ecf20Sopenharmony_ci tegra_dc_unpin(dc, to_tegra_plane_state(state)); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint tegra_plane_state_add(struct tegra_plane *plane, 2168c2ecf20Sopenharmony_ci struct drm_plane_state *state) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct drm_crtc_state *crtc_state; 2198c2ecf20Sopenharmony_ci struct tegra_dc_state *tegra; 2208c2ecf20Sopenharmony_ci int err; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Propagate errors from allocation or locking failures. */ 2238c2ecf20Sopenharmony_ci crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 2248c2ecf20Sopenharmony_ci if (IS_ERR(crtc_state)) 2258c2ecf20Sopenharmony_ci return PTR_ERR(crtc_state); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Check plane state for visibility and calculate clipping bounds */ 2288c2ecf20Sopenharmony_ci err = drm_atomic_helper_check_plane_state(state, crtc_state, 2298c2ecf20Sopenharmony_ci 0, INT_MAX, true, true); 2308c2ecf20Sopenharmony_ci if (err < 0) 2318c2ecf20Sopenharmony_ci return err; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci tegra = to_dc_state(crtc_state); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci tegra->planes |= WIN_A_ACT_REQ << plane->index; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciint tegra_plane_format(u32 fourcc, u32 *format, u32 *swap) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci /* assume no swapping of fetched data */ 2438c2ecf20Sopenharmony_ci if (swap) 2448c2ecf20Sopenharmony_ci *swap = BYTE_SWAP_NOSWAP; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci switch (fourcc) { 2478c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB4444: 2488c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B4G4R4A4; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 2528c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B5G5R5A1; 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci case DRM_FORMAT_RGB565: 2568c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B5G6R5; 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBA5551: 2608c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_A1B5G5R5; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 2648c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B8G8R8A8; 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR8888: 2688c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R8G8B8A8; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR4444: 2728c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R4G4B4A4; 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR1555: 2768c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R5G5B5A; 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRA5551: 2808c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_AR5G5B5; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB1555: 2848c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B5G5R5X1; 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBX5551: 2888c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_X1B5G5R5; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR1555: 2928c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R5G5B5X1; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRX5551: 2968c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_X1R5G5B5; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci case DRM_FORMAT_BGR565: 3008c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R5G6B5; 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci case DRM_FORMAT_BGRA8888: 3048c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_A8R8G8B8; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBA8888: 3088c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_A8B8G8R8; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci case DRM_FORMAT_XRGB8888: 3128c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_B8G8R8X8; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci case DRM_FORMAT_XBGR8888: 3168c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_R8G8B8X8; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci case DRM_FORMAT_UYVY: 3208c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_YCbCr422; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci case DRM_FORMAT_YUYV: 3248c2ecf20Sopenharmony_ci if (!swap) 3258c2ecf20Sopenharmony_ci return -EINVAL; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_YCbCr422; 3288c2ecf20Sopenharmony_ci *swap = BYTE_SWAP_SWAP2; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV420: 3328c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_YCbCr420P; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci case DRM_FORMAT_YUV422: 3368c2ecf20Sopenharmony_ci *format = WIN_COLOR_DEPTH_YCbCr422P; 3378c2ecf20Sopenharmony_ci break; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci default: 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cibool tegra_plane_format_is_yuv(unsigned int format, bool *planar) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci switch (format) { 3498c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YCbCr422: 3508c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YUV422: 3518c2ecf20Sopenharmony_ci if (planar) 3528c2ecf20Sopenharmony_ci *planar = false; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return true; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YCbCr420P: 3578c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YUV420P: 3588c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YCbCr422P: 3598c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YUV422P: 3608c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YCbCr422R: 3618c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YUV422R: 3628c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YCbCr422RA: 3638c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_YUV422RA: 3648c2ecf20Sopenharmony_ci if (planar) 3658c2ecf20Sopenharmony_ci *planar = true; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return true; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (planar) 3718c2ecf20Sopenharmony_ci *planar = false; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return false; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic bool __drm_format_has_alpha(u32 format) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci switch (format) { 3798c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB1555: 3808c2ecf20Sopenharmony_ci case DRM_FORMAT_RGBA5551: 3818c2ecf20Sopenharmony_ci case DRM_FORMAT_ABGR8888: 3828c2ecf20Sopenharmony_ci case DRM_FORMAT_ARGB8888: 3838c2ecf20Sopenharmony_ci return true; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return false; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int tegra_plane_format_get_alpha(unsigned int opaque, 3908c2ecf20Sopenharmony_ci unsigned int *alpha) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci if (tegra_plane_format_is_yuv(opaque, NULL)) { 3938c2ecf20Sopenharmony_ci *alpha = opaque; 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci switch (opaque) { 3988c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_B5G5R5X1: 3998c2ecf20Sopenharmony_ci *alpha = WIN_COLOR_DEPTH_B5G5R5A1; 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_X1B5G5R5: 4038c2ecf20Sopenharmony_ci *alpha = WIN_COLOR_DEPTH_A1B5G5R5; 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_R8G8B8X8: 4078c2ecf20Sopenharmony_ci *alpha = WIN_COLOR_DEPTH_R8G8B8A8; 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_B8G8R8X8: 4118c2ecf20Sopenharmony_ci *alpha = WIN_COLOR_DEPTH_B8G8R8A8; 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_B5G6R5: 4158c2ecf20Sopenharmony_ci *alpha = opaque; 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* 4238c2ecf20Sopenharmony_ci * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 4248c2ecf20Sopenharmony_ci * be emulated using the alpha formats and alpha blending disabled. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_cistatic int tegra_plane_setup_opacity(struct tegra_plane *tegra, 4278c2ecf20Sopenharmony_ci struct tegra_plane_state *state) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci unsigned int format; 4308c2ecf20Sopenharmony_ci int err; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci switch (state->format) { 4338c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_B5G5R5A1: 4348c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_A1B5G5R5: 4358c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_R8G8B8A8: 4368c2ecf20Sopenharmony_ci case WIN_COLOR_DEPTH_B8G8R8A8: 4378c2ecf20Sopenharmony_ci state->opaque = false; 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci default: 4418c2ecf20Sopenharmony_ci err = tegra_plane_format_get_alpha(state->format, &format); 4428c2ecf20Sopenharmony_ci if (err < 0) 4438c2ecf20Sopenharmony_ci return err; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci state->format = format; 4468c2ecf20Sopenharmony_ci state->opaque = true; 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int tegra_plane_check_transparency(struct tegra_plane *tegra, 4548c2ecf20Sopenharmony_ci struct tegra_plane_state *state) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct drm_plane_state *old, *plane_state; 4578c2ecf20Sopenharmony_ci struct drm_plane *plane; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* check if zpos / transparency changed */ 4628c2ecf20Sopenharmony_ci if (old->normalized_zpos == state->base.normalized_zpos && 4638c2ecf20Sopenharmony_ci to_tegra_plane_state(old)->opaque == state->opaque) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* include all sibling planes into this commit */ 4678c2ecf20Sopenharmony_ci drm_for_each_plane(plane, tegra->base.dev) { 4688c2ecf20Sopenharmony_ci struct tegra_plane *p = to_tegra_plane(plane); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* skip this plane and planes on different CRTCs */ 4718c2ecf20Sopenharmony_ci if (p == tegra || p->dc != tegra->dc) 4728c2ecf20Sopenharmony_ci continue; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci plane_state = drm_atomic_get_plane_state(state->base.state, 4758c2ecf20Sopenharmony_ci plane); 4768c2ecf20Sopenharmony_ci if (IS_ERR(plane_state)) 4778c2ecf20Sopenharmony_ci return PTR_ERR(plane_state); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return 1; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 4848c2ecf20Sopenharmony_ci struct tegra_plane *other) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci unsigned int index = 0, i; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci WARN_ON(plane == other); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 4918c2ecf20Sopenharmony_ci if (i == plane->index) 4928c2ecf20Sopenharmony_ci continue; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (i == other->index) 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci index++; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return index; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic void tegra_plane_update_transparency(struct tegra_plane *tegra, 5048c2ecf20Sopenharmony_ci struct tegra_plane_state *state) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct drm_plane_state *new; 5078c2ecf20Sopenharmony_ci struct drm_plane *plane; 5088c2ecf20Sopenharmony_ci unsigned int i; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci for_each_new_plane_in_state(state->base.state, plane, new, i) { 5118c2ecf20Sopenharmony_ci struct tegra_plane *p = to_tegra_plane(plane); 5128c2ecf20Sopenharmony_ci unsigned index; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* skip this plane and planes on different CRTCs */ 5158c2ecf20Sopenharmony_ci if (p == tegra || p->dc != tegra->dc) 5168c2ecf20Sopenharmony_ci continue; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci index = tegra_plane_get_overlap_index(tegra, p); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (new->fb && __drm_format_has_alpha(new->fb->format->format)) 5218c2ecf20Sopenharmony_ci state->blending[index].alpha = true; 5228c2ecf20Sopenharmony_ci else 5238c2ecf20Sopenharmony_ci state->blending[index].alpha = false; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (new->normalized_zpos > state->base.normalized_zpos) 5268c2ecf20Sopenharmony_ci state->blending[index].top = true; 5278c2ecf20Sopenharmony_ci else 5288c2ecf20Sopenharmony_ci state->blending[index].top = false; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* 5318c2ecf20Sopenharmony_ci * Missing framebuffer means that plane is disabled, in this 5328c2ecf20Sopenharmony_ci * case mark B / C window as top to be able to differentiate 5338c2ecf20Sopenharmony_ci * windows indices order in regards to zPos for the middle 5348c2ecf20Sopenharmony_ci * window X / Y registers programming. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci if (!new->fb) 5378c2ecf20Sopenharmony_ci state->blending[index].top = (index == 1); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int tegra_plane_setup_transparency(struct tegra_plane *tegra, 5428c2ecf20Sopenharmony_ci struct tegra_plane_state *state) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct tegra_plane_state *tegra_state; 5458c2ecf20Sopenharmony_ci struct drm_plane_state *new; 5468c2ecf20Sopenharmony_ci struct drm_plane *plane; 5478c2ecf20Sopenharmony_ci int err; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * If planes zpos / transparency changed, sibling planes blending 5518c2ecf20Sopenharmony_ci * state may require adjustment and in this case they will be included 5528c2ecf20Sopenharmony_ci * into this atom commit, otherwise blending state is unchanged. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci err = tegra_plane_check_transparency(tegra, state); 5558c2ecf20Sopenharmony_ci if (err <= 0) 5568c2ecf20Sopenharmony_ci return err; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* 5598c2ecf20Sopenharmony_ci * All planes are now in the atomic state, walk them up and update 5608c2ecf20Sopenharmony_ci * transparency state for each plane. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci drm_for_each_plane(plane, tegra->base.dev) { 5638c2ecf20Sopenharmony_ci struct tegra_plane *p = to_tegra_plane(plane); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* skip planes on different CRTCs */ 5668c2ecf20Sopenharmony_ci if (p->dc != tegra->dc) 5678c2ecf20Sopenharmony_ci continue; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci new = drm_atomic_get_new_plane_state(state->base.state, plane); 5708c2ecf20Sopenharmony_ci tegra_state = to_tegra_plane_state(new); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* 5738c2ecf20Sopenharmony_ci * There is no need to update blending state for the disabled 5748c2ecf20Sopenharmony_ci * plane. 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_ci if (new->fb) 5778c2ecf20Sopenharmony_ci tegra_plane_update_transparency(p, tegra_state); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ciint tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 5848c2ecf20Sopenharmony_ci struct tegra_plane_state *state) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci int err; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci err = tegra_plane_setup_opacity(tegra, state); 5898c2ecf20Sopenharmony_ci if (err < 0) 5908c2ecf20Sopenharmony_ci return err; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci err = tegra_plane_setup_transparency(tegra, state); 5938c2ecf20Sopenharmony_ci if (err < 0) 5948c2ecf20Sopenharmony_ci return err; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 598