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