19021c317SLaurentiu Palcu // SPDX-License-Identifier: GPL-2.0 29021c317SLaurentiu Palcu /* 39021c317SLaurentiu Palcu * Copyright 2019 NXP. 49021c317SLaurentiu Palcu */ 59021c317SLaurentiu Palcu 69021c317SLaurentiu Palcu #include <drm/drm_atomic.h> 79021c317SLaurentiu Palcu #include <drm/drm_atomic_helper.h> 89021c317SLaurentiu Palcu #include <drm/drm_fb_cma_helper.h> 9820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h> 109021c317SLaurentiu Palcu #include <drm/drm_gem_cma_helper.h> 119021c317SLaurentiu Palcu 129021c317SLaurentiu Palcu #include "dcss-dev.h" 139021c317SLaurentiu Palcu #include "dcss-kms.h" 149021c317SLaurentiu Palcu 159021c317SLaurentiu Palcu static const u32 dcss_common_formats[] = { 169021c317SLaurentiu Palcu /* RGB */ 179021c317SLaurentiu Palcu DRM_FORMAT_ARGB8888, 189021c317SLaurentiu Palcu DRM_FORMAT_XRGB8888, 199021c317SLaurentiu Palcu DRM_FORMAT_ABGR8888, 209021c317SLaurentiu Palcu DRM_FORMAT_XBGR8888, 219021c317SLaurentiu Palcu DRM_FORMAT_RGBA8888, 229021c317SLaurentiu Palcu DRM_FORMAT_RGBX8888, 239021c317SLaurentiu Palcu DRM_FORMAT_BGRA8888, 249021c317SLaurentiu Palcu DRM_FORMAT_BGRX8888, 259021c317SLaurentiu Palcu DRM_FORMAT_XRGB2101010, 269021c317SLaurentiu Palcu DRM_FORMAT_XBGR2101010, 279021c317SLaurentiu Palcu DRM_FORMAT_RGBX1010102, 289021c317SLaurentiu Palcu DRM_FORMAT_BGRX1010102, 299021c317SLaurentiu Palcu DRM_FORMAT_ARGB2101010, 309021c317SLaurentiu Palcu DRM_FORMAT_ABGR2101010, 319021c317SLaurentiu Palcu DRM_FORMAT_RGBA1010102, 329021c317SLaurentiu Palcu DRM_FORMAT_BGRA1010102, 339021c317SLaurentiu Palcu }; 349021c317SLaurentiu Palcu 359021c317SLaurentiu Palcu static const u64 dcss_video_format_modifiers[] = { 369021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR, 379021c317SLaurentiu Palcu DRM_FORMAT_MOD_INVALID, 389021c317SLaurentiu Palcu }; 399021c317SLaurentiu Palcu 409021c317SLaurentiu Palcu static const u64 dcss_graphics_format_modifiers[] = { 419021c317SLaurentiu Palcu DRM_FORMAT_MOD_VIVANTE_TILED, 429021c317SLaurentiu Palcu DRM_FORMAT_MOD_VIVANTE_SUPER_TILED, 439021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR, 449021c317SLaurentiu Palcu DRM_FORMAT_MOD_INVALID, 459021c317SLaurentiu Palcu }; 469021c317SLaurentiu Palcu 479021c317SLaurentiu Palcu static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p) 489021c317SLaurentiu Palcu { 499021c317SLaurentiu Palcu return container_of(p, struct dcss_plane, base); 509021c317SLaurentiu Palcu } 519021c317SLaurentiu Palcu 529021c317SLaurentiu Palcu static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb) 539021c317SLaurentiu Palcu { 549021c317SLaurentiu Palcu return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) || 559021c317SLaurentiu Palcu ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 && 569021c317SLaurentiu Palcu fb->modifier == DRM_FORMAT_MOD_LINEAR); 579021c317SLaurentiu Palcu } 589021c317SLaurentiu Palcu 599021c317SLaurentiu Palcu static void dcss_plane_destroy(struct drm_plane *plane) 609021c317SLaurentiu Palcu { 619021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane, 629021c317SLaurentiu Palcu base); 639021c317SLaurentiu Palcu 649021c317SLaurentiu Palcu drm_plane_cleanup(plane); 659021c317SLaurentiu Palcu kfree(dcss_plane); 669021c317SLaurentiu Palcu } 679021c317SLaurentiu Palcu 689021c317SLaurentiu Palcu static bool dcss_plane_format_mod_supported(struct drm_plane *plane, 699021c317SLaurentiu Palcu u32 format, 709021c317SLaurentiu Palcu u64 modifier) 719021c317SLaurentiu Palcu { 729021c317SLaurentiu Palcu switch (plane->type) { 739021c317SLaurentiu Palcu case DRM_PLANE_TYPE_PRIMARY: 749021c317SLaurentiu Palcu switch (format) { 759021c317SLaurentiu Palcu case DRM_FORMAT_ARGB8888: 769021c317SLaurentiu Palcu case DRM_FORMAT_XRGB8888: 779021c317SLaurentiu Palcu case DRM_FORMAT_ARGB2101010: 789021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR || 799021c317SLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_TILED || 809021c317SLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED; 819021c317SLaurentiu Palcu default: 829021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR; 839021c317SLaurentiu Palcu } 849021c317SLaurentiu Palcu break; 859021c317SLaurentiu Palcu case DRM_PLANE_TYPE_OVERLAY: 869021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR; 879021c317SLaurentiu Palcu default: 889021c317SLaurentiu Palcu return false; 899021c317SLaurentiu Palcu } 909021c317SLaurentiu Palcu } 919021c317SLaurentiu Palcu 929021c317SLaurentiu Palcu static const struct drm_plane_funcs dcss_plane_funcs = { 939021c317SLaurentiu Palcu .update_plane = drm_atomic_helper_update_plane, 949021c317SLaurentiu Palcu .disable_plane = drm_atomic_helper_disable_plane, 959021c317SLaurentiu Palcu .destroy = dcss_plane_destroy, 969021c317SLaurentiu Palcu .reset = drm_atomic_helper_plane_reset, 979021c317SLaurentiu Palcu .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 989021c317SLaurentiu Palcu .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 999021c317SLaurentiu Palcu .format_mod_supported = dcss_plane_format_mod_supported, 1009021c317SLaurentiu Palcu }; 1019021c317SLaurentiu Palcu 1029021c317SLaurentiu Palcu static bool dcss_plane_can_rotate(const struct drm_format_info *format, 1039021c317SLaurentiu Palcu bool mod_present, u64 modifier, 1049021c317SLaurentiu Palcu unsigned int rotation) 1059021c317SLaurentiu Palcu { 106594486b5SLaurentiu Palcu bool linear_format = !mod_present || modifier == DRM_FORMAT_MOD_LINEAR; 1079021c317SLaurentiu Palcu u32 supported_rotation = DRM_MODE_ROTATE_0; 1089021c317SLaurentiu Palcu 1099021c317SLaurentiu Palcu if (!format->is_yuv && linear_format) 1109021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | 1119021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK; 1129021c317SLaurentiu Palcu else if (!format->is_yuv && 11359cb403fSLaurentiu Palcu (modifier == DRM_FORMAT_MOD_VIVANTE_TILED || 11459cb403fSLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)) 1159021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_MASK | 1169021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK; 1179021c317SLaurentiu Palcu else if (format->is_yuv && linear_format && 1189021c317SLaurentiu Palcu (format->format == DRM_FORMAT_NV12 || 1199021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21)) 1209021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 | 1219021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK; 1229021c317SLaurentiu Palcu 1239021c317SLaurentiu Palcu return !!(rotation & supported_rotation); 1249021c317SLaurentiu Palcu } 1259021c317SLaurentiu Palcu 1269021c317SLaurentiu Palcu static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt) 1279021c317SLaurentiu Palcu { 1289021c317SLaurentiu Palcu if (src_w < 64 && 1299021c317SLaurentiu Palcu (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21)) 1309021c317SLaurentiu Palcu return false; 1319021c317SLaurentiu Palcu else if (src_w < 32 && 1329021c317SLaurentiu Palcu (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY || 1339021c317SLaurentiu Palcu pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU)) 1349021c317SLaurentiu Palcu return false; 1359021c317SLaurentiu Palcu 1369021c317SLaurentiu Palcu return src_w >= 16 && src_h >= 8; 1379021c317SLaurentiu Palcu } 1389021c317SLaurentiu Palcu 1399021c317SLaurentiu Palcu static int dcss_plane_atomic_check(struct drm_plane *plane, 1407c11b99aSMaxime Ripard struct drm_atomic_state *state) 1419021c317SLaurentiu Palcu { 1427c11b99aSMaxime Ripard struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 1437c11b99aSMaxime Ripard plane); 1449021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane); 1459021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private; 146ba5c1649SMaxime Ripard struct drm_framebuffer *fb = new_plane_state->fb; 1479021c317SLaurentiu Palcu bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY; 1489021c317SLaurentiu Palcu struct drm_gem_cma_object *cma_obj; 1499021c317SLaurentiu Palcu struct drm_crtc_state *crtc_state; 1509021c317SLaurentiu Palcu int hdisplay, vdisplay; 1519021c317SLaurentiu Palcu int min, max; 1529021c317SLaurentiu Palcu int ret; 1539021c317SLaurentiu Palcu 154ba5c1649SMaxime Ripard if (!fb || !new_plane_state->crtc) 1559021c317SLaurentiu Palcu return 0; 1569021c317SLaurentiu Palcu 1579021c317SLaurentiu Palcu cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 1589021c317SLaurentiu Palcu WARN_ON(!cma_obj); 1599021c317SLaurentiu Palcu 160dec92020SMaxime Ripard crtc_state = drm_atomic_get_existing_crtc_state(state, 161ba5c1649SMaxime Ripard new_plane_state->crtc); 1629021c317SLaurentiu Palcu 1639021c317SLaurentiu Palcu hdisplay = crtc_state->adjusted_mode.hdisplay; 1649021c317SLaurentiu Palcu vdisplay = crtc_state->adjusted_mode.vdisplay; 1659021c317SLaurentiu Palcu 166ba5c1649SMaxime Ripard if (!dcss_plane_is_source_size_allowed(new_plane_state->src_w >> 16, 167ba5c1649SMaxime Ripard new_plane_state->src_h >> 16, 1689021c317SLaurentiu Palcu fb->format->format)) { 1699021c317SLaurentiu Palcu DRM_DEBUG_KMS("Source plane size is not allowed!\n"); 1709021c317SLaurentiu Palcu return -EINVAL; 1719021c317SLaurentiu Palcu } 1729021c317SLaurentiu Palcu 1739021c317SLaurentiu Palcu dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num, 1749021c317SLaurentiu Palcu &min, &max); 1759021c317SLaurentiu Palcu 176ba5c1649SMaxime Ripard ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, 1779021c317SLaurentiu Palcu min, max, !is_primary_plane, 1789021c317SLaurentiu Palcu false); 1799021c317SLaurentiu Palcu if (ret) 1809021c317SLaurentiu Palcu return ret; 1819021c317SLaurentiu Palcu 182ba5c1649SMaxime Ripard if (!new_plane_state->visible) 1839021c317SLaurentiu Palcu return 0; 1849021c317SLaurentiu Palcu 1859021c317SLaurentiu Palcu if (!dcss_plane_can_rotate(fb->format, 1869021c317SLaurentiu Palcu !!(fb->flags & DRM_MODE_FB_MODIFIERS), 1879021c317SLaurentiu Palcu fb->modifier, 188ba5c1649SMaxime Ripard new_plane_state->rotation)) { 1899021c317SLaurentiu Palcu DRM_DEBUG_KMS("requested rotation is not allowed!\n"); 1909021c317SLaurentiu Palcu return -EINVAL; 1919021c317SLaurentiu Palcu } 1929021c317SLaurentiu Palcu 193ba5c1649SMaxime Ripard if ((new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 || 194ba5c1649SMaxime Ripard new_plane_state->crtc_x + new_plane_state->crtc_w > hdisplay || 195ba5c1649SMaxime Ripard new_plane_state->crtc_y + new_plane_state->crtc_h > vdisplay) && 1969021c317SLaurentiu Palcu !dcss_plane_fb_is_linear(fb)) { 1979021c317SLaurentiu Palcu DRM_DEBUG_KMS("requested cropping operation is not allowed!\n"); 1989021c317SLaurentiu Palcu return -EINVAL; 1999021c317SLaurentiu Palcu } 2009021c317SLaurentiu Palcu 2019021c317SLaurentiu Palcu if ((fb->flags & DRM_MODE_FB_MODIFIERS) && 2029021c317SLaurentiu Palcu !plane->funcs->format_mod_supported(plane, 2039021c317SLaurentiu Palcu fb->format->format, 2049021c317SLaurentiu Palcu fb->modifier)) { 2059021c317SLaurentiu Palcu DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier); 2069021c317SLaurentiu Palcu return -EINVAL; 2079021c317SLaurentiu Palcu } 2089021c317SLaurentiu Palcu 2099021c317SLaurentiu Palcu return 0; 2109021c317SLaurentiu Palcu } 2119021c317SLaurentiu Palcu 2129021c317SLaurentiu Palcu static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane) 2139021c317SLaurentiu Palcu { 2149021c317SLaurentiu Palcu struct drm_plane *plane = &dcss_plane->base; 2159021c317SLaurentiu Palcu struct drm_plane_state *state = plane->state; 2169021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private; 2179021c317SLaurentiu Palcu struct drm_framebuffer *fb = state->fb; 2189021c317SLaurentiu Palcu const struct drm_format_info *format = fb->format; 2199021c317SLaurentiu Palcu struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0); 2209021c317SLaurentiu Palcu unsigned long p1_ba = 0, p2_ba = 0; 2219021c317SLaurentiu Palcu 2229021c317SLaurentiu Palcu if (!format->is_yuv || 2239021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV12 || 2249021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21) 2259021c317SLaurentiu Palcu p1_ba = cma_obj->paddr + fb->offsets[0] + 2269021c317SLaurentiu Palcu fb->pitches[0] * (state->src.y1 >> 16) + 2279021c317SLaurentiu Palcu format->char_per_block[0] * (state->src.x1 >> 16); 2289021c317SLaurentiu Palcu else if (format->format == DRM_FORMAT_UYVY || 2299021c317SLaurentiu Palcu format->format == DRM_FORMAT_VYUY || 2309021c317SLaurentiu Palcu format->format == DRM_FORMAT_YUYV || 2319021c317SLaurentiu Palcu format->format == DRM_FORMAT_YVYU) 2329021c317SLaurentiu Palcu p1_ba = cma_obj->paddr + fb->offsets[0] + 2339021c317SLaurentiu Palcu fb->pitches[0] * (state->src.y1 >> 16) + 2349021c317SLaurentiu Palcu 2 * format->char_per_block[0] * (state->src.x1 >> 17); 2359021c317SLaurentiu Palcu 2369021c317SLaurentiu Palcu if (format->format == DRM_FORMAT_NV12 || 2379021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21) 2389021c317SLaurentiu Palcu p2_ba = cma_obj->paddr + fb->offsets[1] + 2399021c317SLaurentiu Palcu (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) + 2409021c317SLaurentiu Palcu (state->src.x1 >> 17)) << 1); 2419021c317SLaurentiu Palcu 2429021c317SLaurentiu Palcu dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba, 2439021c317SLaurentiu Palcu fb->pitches[0]); 2449021c317SLaurentiu Palcu } 2459021c317SLaurentiu Palcu 2469021c317SLaurentiu Palcu static bool dcss_plane_needs_setup(struct drm_plane_state *state, 2479021c317SLaurentiu Palcu struct drm_plane_state *old_state) 2489021c317SLaurentiu Palcu { 2499021c317SLaurentiu Palcu struct drm_framebuffer *fb = state->fb; 2509021c317SLaurentiu Palcu struct drm_framebuffer *old_fb = old_state->fb; 2519021c317SLaurentiu Palcu 2529021c317SLaurentiu Palcu return state->crtc_x != old_state->crtc_x || 2539021c317SLaurentiu Palcu state->crtc_y != old_state->crtc_y || 2549021c317SLaurentiu Palcu state->crtc_w != old_state->crtc_w || 2559021c317SLaurentiu Palcu state->crtc_h != old_state->crtc_h || 2569021c317SLaurentiu Palcu state->src_x != old_state->src_x || 2579021c317SLaurentiu Palcu state->src_y != old_state->src_y || 2589021c317SLaurentiu Palcu state->src_w != old_state->src_w || 2599021c317SLaurentiu Palcu state->src_h != old_state->src_h || 2609021c317SLaurentiu Palcu fb->format->format != old_fb->format->format || 2619021c317SLaurentiu Palcu fb->modifier != old_fb->modifier || 26205faf155SLaurentiu Palcu state->rotation != old_state->rotation || 26305faf155SLaurentiu Palcu state->scaling_filter != old_state->scaling_filter; 2649021c317SLaurentiu Palcu } 2659021c317SLaurentiu Palcu 2669021c317SLaurentiu Palcu static void dcss_plane_atomic_update(struct drm_plane *plane, 2679021c317SLaurentiu Palcu struct drm_plane_state *old_state) 2689021c317SLaurentiu Palcu { 269*41016fe1SMaxime Ripard struct drm_plane_state *new_state = plane->state; 2709021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane); 2719021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private; 272*41016fe1SMaxime Ripard struct drm_framebuffer *fb = new_state->fb; 2739021c317SLaurentiu Palcu struct drm_crtc_state *crtc_state; 2749021c317SLaurentiu Palcu bool modifiers_present; 2759021c317SLaurentiu Palcu u32 src_w, src_h, dst_w, dst_h; 2769021c317SLaurentiu Palcu struct drm_rect src, dst; 2779021c317SLaurentiu Palcu bool enable = true; 27859cb403fSLaurentiu Palcu bool is_rotation_90_or_270; 2799021c317SLaurentiu Palcu 280*41016fe1SMaxime Ripard if (!fb || !new_state->crtc || !new_state->visible) 2819021c317SLaurentiu Palcu return; 2829021c317SLaurentiu Palcu 283*41016fe1SMaxime Ripard crtc_state = new_state->crtc->state; 2849021c317SLaurentiu Palcu modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS); 2859021c317SLaurentiu Palcu 2869021c317SLaurentiu Palcu if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) && 287*41016fe1SMaxime Ripard !dcss_plane_needs_setup(new_state, old_state)) { 2889021c317SLaurentiu Palcu dcss_plane_atomic_set_base(dcss_plane); 2899021c317SLaurentiu Palcu return; 2909021c317SLaurentiu Palcu } 2919021c317SLaurentiu Palcu 2929021c317SLaurentiu Palcu src = plane->state->src; 2939021c317SLaurentiu Palcu dst = plane->state->dst; 2949021c317SLaurentiu Palcu 2959021c317SLaurentiu Palcu /* 2969021c317SLaurentiu Palcu * The width and height after clipping. 2979021c317SLaurentiu Palcu */ 2989021c317SLaurentiu Palcu src_w = drm_rect_width(&src) >> 16; 2999021c317SLaurentiu Palcu src_h = drm_rect_height(&src) >> 16; 3009021c317SLaurentiu Palcu dst_w = drm_rect_width(&dst); 3019021c317SLaurentiu Palcu dst_h = drm_rect_height(&dst); 3029021c317SLaurentiu Palcu 3039021c317SLaurentiu Palcu if (plane->type == DRM_PLANE_TYPE_OVERLAY && 3049021c317SLaurentiu Palcu modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR) 3059021c317SLaurentiu Palcu modifiers_present = false; 3069021c317SLaurentiu Palcu 307*41016fe1SMaxime Ripard dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, 308*41016fe1SMaxime Ripard new_state->fb->format, 3099021c317SLaurentiu Palcu modifiers_present ? fb->modifier : 3109021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR); 3119021c317SLaurentiu Palcu dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h); 3129021c317SLaurentiu Palcu dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num, 313*41016fe1SMaxime Ripard new_state->rotation); 3149021c317SLaurentiu Palcu 3159021c317SLaurentiu Palcu dcss_plane_atomic_set_base(dcss_plane); 3169021c317SLaurentiu Palcu 317*41016fe1SMaxime Ripard is_rotation_90_or_270 = new_state->rotation & (DRM_MODE_ROTATE_90 | 31859cb403fSLaurentiu Palcu DRM_MODE_ROTATE_270); 31959cb403fSLaurentiu Palcu 32005faf155SLaurentiu Palcu dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num, 321*41016fe1SMaxime Ripard new_state->scaling_filter); 32205faf155SLaurentiu Palcu 3239021c317SLaurentiu Palcu dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num, 324*41016fe1SMaxime Ripard new_state->fb->format, 32559cb403fSLaurentiu Palcu is_rotation_90_or_270 ? src_h : src_w, 32659cb403fSLaurentiu Palcu is_rotation_90_or_270 ? src_w : src_h, 3279021c317SLaurentiu Palcu dst_w, dst_h, 3289021c317SLaurentiu Palcu drm_mode_vrefresh(&crtc_state->mode)); 3299021c317SLaurentiu Palcu 3309021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 3319021c317SLaurentiu Palcu dst.x1, dst.y1, dst_w, dst_h); 3329021c317SLaurentiu Palcu dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num, 333*41016fe1SMaxime Ripard fb->format, new_state->alpha >> 8); 3349021c317SLaurentiu Palcu 335*41016fe1SMaxime Ripard if (!dcss_plane->ch_num && (new_state->alpha >> 8) == 0) 3369021c317SLaurentiu Palcu enable = false; 3379021c317SLaurentiu Palcu 3389021c317SLaurentiu Palcu dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable); 3399021c317SLaurentiu Palcu dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable); 3409021c317SLaurentiu Palcu 3419021c317SLaurentiu Palcu if (!enable) 3429021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 3439021c317SLaurentiu Palcu 0, 0, 0, 0); 3449021c317SLaurentiu Palcu 3459021c317SLaurentiu Palcu dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable); 3469021c317SLaurentiu Palcu } 3479021c317SLaurentiu Palcu 3489021c317SLaurentiu Palcu static void dcss_plane_atomic_disable(struct drm_plane *plane, 3499021c317SLaurentiu Palcu struct drm_plane_state *old_state) 3509021c317SLaurentiu Palcu { 3519021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane); 3529021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private; 3539021c317SLaurentiu Palcu 3549021c317SLaurentiu Palcu dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false); 3559021c317SLaurentiu Palcu dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false); 3569021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0); 3579021c317SLaurentiu Palcu dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false); 3589021c317SLaurentiu Palcu } 3599021c317SLaurentiu Palcu 3609021c317SLaurentiu Palcu static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = { 361820c1707SThomas Zimmermann .prepare_fb = drm_gem_plane_helper_prepare_fb, 3629021c317SLaurentiu Palcu .atomic_check = dcss_plane_atomic_check, 3639021c317SLaurentiu Palcu .atomic_update = dcss_plane_atomic_update, 3649021c317SLaurentiu Palcu .atomic_disable = dcss_plane_atomic_disable, 3659021c317SLaurentiu Palcu }; 3669021c317SLaurentiu Palcu 3679021c317SLaurentiu Palcu struct dcss_plane *dcss_plane_init(struct drm_device *drm, 3689021c317SLaurentiu Palcu unsigned int possible_crtcs, 3699021c317SLaurentiu Palcu enum drm_plane_type type, 3709021c317SLaurentiu Palcu unsigned int zpos) 3719021c317SLaurentiu Palcu { 3729021c317SLaurentiu Palcu struct dcss_plane *dcss_plane; 3739021c317SLaurentiu Palcu const u64 *format_modifiers = dcss_video_format_modifiers; 3749021c317SLaurentiu Palcu int ret; 3759021c317SLaurentiu Palcu 3769021c317SLaurentiu Palcu if (zpos > 2) 3779021c317SLaurentiu Palcu return ERR_PTR(-EINVAL); 3789021c317SLaurentiu Palcu 3799021c317SLaurentiu Palcu dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL); 3809021c317SLaurentiu Palcu if (!dcss_plane) { 3819021c317SLaurentiu Palcu DRM_ERROR("failed to allocate plane\n"); 3829021c317SLaurentiu Palcu return ERR_PTR(-ENOMEM); 3839021c317SLaurentiu Palcu } 3849021c317SLaurentiu Palcu 3859021c317SLaurentiu Palcu if (type == DRM_PLANE_TYPE_PRIMARY) 3869021c317SLaurentiu Palcu format_modifiers = dcss_graphics_format_modifiers; 3879021c317SLaurentiu Palcu 3889021c317SLaurentiu Palcu ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs, 3899021c317SLaurentiu Palcu &dcss_plane_funcs, dcss_common_formats, 3909021c317SLaurentiu Palcu ARRAY_SIZE(dcss_common_formats), 3919021c317SLaurentiu Palcu format_modifiers, type, NULL); 3929021c317SLaurentiu Palcu if (ret) { 3939021c317SLaurentiu Palcu DRM_ERROR("failed to initialize plane\n"); 3949021c317SLaurentiu Palcu kfree(dcss_plane); 3959021c317SLaurentiu Palcu return ERR_PTR(ret); 3969021c317SLaurentiu Palcu } 3979021c317SLaurentiu Palcu 3989021c317SLaurentiu Palcu drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs); 3999021c317SLaurentiu Palcu 4009021c317SLaurentiu Palcu ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos); 4019021c317SLaurentiu Palcu if (ret) 4029021c317SLaurentiu Palcu return ERR_PTR(ret); 4039021c317SLaurentiu Palcu 40405faf155SLaurentiu Palcu drm_plane_create_scaling_filter_property(&dcss_plane->base, 40505faf155SLaurentiu Palcu BIT(DRM_SCALING_FILTER_DEFAULT) | 40605faf155SLaurentiu Palcu BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); 40705faf155SLaurentiu Palcu 4089021c317SLaurentiu Palcu drm_plane_create_rotation_property(&dcss_plane->base, 4099021c317SLaurentiu Palcu DRM_MODE_ROTATE_0, 4109021c317SLaurentiu Palcu DRM_MODE_ROTATE_0 | 4119021c317SLaurentiu Palcu DRM_MODE_ROTATE_90 | 4129021c317SLaurentiu Palcu DRM_MODE_ROTATE_180 | 4139021c317SLaurentiu Palcu DRM_MODE_ROTATE_270 | 4149021c317SLaurentiu Palcu DRM_MODE_REFLECT_X | 4159021c317SLaurentiu Palcu DRM_MODE_REFLECT_Y); 4169021c317SLaurentiu Palcu 4179021c317SLaurentiu Palcu dcss_plane->ch_num = zpos; 4189021c317SLaurentiu Palcu 4199021c317SLaurentiu Palcu return dcss_plane; 4209021c317SLaurentiu Palcu } 421