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>
890bb087fSVille Syrjälä #include <drm/drm_blend.h>
96bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
10720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
11820c1707SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
124a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
139021c317SLaurentiu Palcu
149021c317SLaurentiu Palcu #include "dcss-dev.h"
159021c317SLaurentiu Palcu #include "dcss-kms.h"
169021c317SLaurentiu Palcu
179021c317SLaurentiu Palcu static const u32 dcss_common_formats[] = {
189021c317SLaurentiu Palcu /* RGB */
199021c317SLaurentiu Palcu DRM_FORMAT_ARGB8888,
209021c317SLaurentiu Palcu DRM_FORMAT_XRGB8888,
219021c317SLaurentiu Palcu DRM_FORMAT_ABGR8888,
229021c317SLaurentiu Palcu DRM_FORMAT_XBGR8888,
239021c317SLaurentiu Palcu DRM_FORMAT_RGBA8888,
249021c317SLaurentiu Palcu DRM_FORMAT_RGBX8888,
259021c317SLaurentiu Palcu DRM_FORMAT_BGRA8888,
269021c317SLaurentiu Palcu DRM_FORMAT_BGRX8888,
279021c317SLaurentiu Palcu DRM_FORMAT_XRGB2101010,
289021c317SLaurentiu Palcu DRM_FORMAT_XBGR2101010,
299021c317SLaurentiu Palcu DRM_FORMAT_RGBX1010102,
309021c317SLaurentiu Palcu DRM_FORMAT_BGRX1010102,
319021c317SLaurentiu Palcu DRM_FORMAT_ARGB2101010,
329021c317SLaurentiu Palcu DRM_FORMAT_ABGR2101010,
339021c317SLaurentiu Palcu DRM_FORMAT_RGBA1010102,
349021c317SLaurentiu Palcu DRM_FORMAT_BGRA1010102,
359021c317SLaurentiu Palcu };
369021c317SLaurentiu Palcu
379021c317SLaurentiu Palcu static const u64 dcss_video_format_modifiers[] = {
389021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR,
399021c317SLaurentiu Palcu DRM_FORMAT_MOD_INVALID,
409021c317SLaurentiu Palcu };
419021c317SLaurentiu Palcu
429021c317SLaurentiu Palcu static const u64 dcss_graphics_format_modifiers[] = {
439021c317SLaurentiu Palcu DRM_FORMAT_MOD_VIVANTE_TILED,
449021c317SLaurentiu Palcu DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
459021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR,
469021c317SLaurentiu Palcu DRM_FORMAT_MOD_INVALID,
479021c317SLaurentiu Palcu };
489021c317SLaurentiu Palcu
to_dcss_plane(struct drm_plane * p)499021c317SLaurentiu Palcu static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
509021c317SLaurentiu Palcu {
519021c317SLaurentiu Palcu return container_of(p, struct dcss_plane, base);
529021c317SLaurentiu Palcu }
539021c317SLaurentiu Palcu
dcss_plane_fb_is_linear(const struct drm_framebuffer * fb)549021c317SLaurentiu Palcu static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
559021c317SLaurentiu Palcu {
569021c317SLaurentiu Palcu return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
579021c317SLaurentiu Palcu ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
589021c317SLaurentiu Palcu fb->modifier == DRM_FORMAT_MOD_LINEAR);
599021c317SLaurentiu Palcu }
609021c317SLaurentiu Palcu
dcss_plane_destroy(struct drm_plane * plane)619021c317SLaurentiu Palcu static void dcss_plane_destroy(struct drm_plane *plane)
629021c317SLaurentiu Palcu {
639021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
649021c317SLaurentiu Palcu base);
659021c317SLaurentiu Palcu
669021c317SLaurentiu Palcu drm_plane_cleanup(plane);
679021c317SLaurentiu Palcu kfree(dcss_plane);
689021c317SLaurentiu Palcu }
699021c317SLaurentiu Palcu
dcss_plane_format_mod_supported(struct drm_plane * plane,u32 format,u64 modifier)709021c317SLaurentiu Palcu static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
719021c317SLaurentiu Palcu u32 format,
729021c317SLaurentiu Palcu u64 modifier)
739021c317SLaurentiu Palcu {
749021c317SLaurentiu Palcu switch (plane->type) {
759021c317SLaurentiu Palcu case DRM_PLANE_TYPE_PRIMARY:
769021c317SLaurentiu Palcu switch (format) {
779021c317SLaurentiu Palcu case DRM_FORMAT_ARGB8888:
789021c317SLaurentiu Palcu case DRM_FORMAT_XRGB8888:
799021c317SLaurentiu Palcu case DRM_FORMAT_ARGB2101010:
809021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR ||
819021c317SLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
829021c317SLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
839021c317SLaurentiu Palcu default:
849021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR;
859021c317SLaurentiu Palcu }
869021c317SLaurentiu Palcu break;
879021c317SLaurentiu Palcu case DRM_PLANE_TYPE_OVERLAY:
889021c317SLaurentiu Palcu return modifier == DRM_FORMAT_MOD_LINEAR;
899021c317SLaurentiu Palcu default:
909021c317SLaurentiu Palcu return false;
919021c317SLaurentiu Palcu }
929021c317SLaurentiu Palcu }
939021c317SLaurentiu Palcu
949021c317SLaurentiu Palcu static const struct drm_plane_funcs dcss_plane_funcs = {
959021c317SLaurentiu Palcu .update_plane = drm_atomic_helper_update_plane,
969021c317SLaurentiu Palcu .disable_plane = drm_atomic_helper_disable_plane,
979021c317SLaurentiu Palcu .destroy = dcss_plane_destroy,
989021c317SLaurentiu Palcu .reset = drm_atomic_helper_plane_reset,
999021c317SLaurentiu Palcu .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
1009021c317SLaurentiu Palcu .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
1019021c317SLaurentiu Palcu .format_mod_supported = dcss_plane_format_mod_supported,
1029021c317SLaurentiu Palcu };
1039021c317SLaurentiu Palcu
dcss_plane_can_rotate(const struct drm_format_info * format,bool mod_present,u64 modifier,unsigned int rotation)1049021c317SLaurentiu Palcu static bool dcss_plane_can_rotate(const struct drm_format_info *format,
1059021c317SLaurentiu Palcu bool mod_present, u64 modifier,
1069021c317SLaurentiu Palcu unsigned int rotation)
1079021c317SLaurentiu Palcu {
108594486b5SLaurentiu Palcu bool linear_format = !mod_present || modifier == DRM_FORMAT_MOD_LINEAR;
1099021c317SLaurentiu Palcu u32 supported_rotation = DRM_MODE_ROTATE_0;
1109021c317SLaurentiu Palcu
1119021c317SLaurentiu Palcu if (!format->is_yuv && linear_format)
1129021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1139021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK;
1149021c317SLaurentiu Palcu else if (!format->is_yuv &&
11559cb403fSLaurentiu Palcu (modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
11659cb403fSLaurentiu Palcu modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))
1179021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_MASK |
1189021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK;
1199021c317SLaurentiu Palcu else if (format->is_yuv && linear_format &&
1209021c317SLaurentiu Palcu (format->format == DRM_FORMAT_NV12 ||
1219021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21))
1229021c317SLaurentiu Palcu supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1239021c317SLaurentiu Palcu DRM_MODE_REFLECT_MASK;
1249021c317SLaurentiu Palcu
1259021c317SLaurentiu Palcu return !!(rotation & supported_rotation);
1269021c317SLaurentiu Palcu }
1279021c317SLaurentiu Palcu
dcss_plane_is_source_size_allowed(u16 src_w,u16 src_h,u32 pix_fmt)1289021c317SLaurentiu Palcu static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
1299021c317SLaurentiu Palcu {
1309021c317SLaurentiu Palcu if (src_w < 64 &&
1319021c317SLaurentiu Palcu (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
1329021c317SLaurentiu Palcu return false;
1339021c317SLaurentiu Palcu else if (src_w < 32 &&
1349021c317SLaurentiu Palcu (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
1359021c317SLaurentiu Palcu pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
1369021c317SLaurentiu Palcu return false;
1379021c317SLaurentiu Palcu
1389021c317SLaurentiu Palcu return src_w >= 16 && src_h >= 8;
1399021c317SLaurentiu Palcu }
1409021c317SLaurentiu Palcu
dcss_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)1419021c317SLaurentiu Palcu static int dcss_plane_atomic_check(struct drm_plane *plane,
1427c11b99aSMaxime Ripard struct drm_atomic_state *state)
1439021c317SLaurentiu Palcu {
1447c11b99aSMaxime Ripard struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1457c11b99aSMaxime Ripard plane);
1469021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane);
1479021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private;
148ba5c1649SMaxime Ripard struct drm_framebuffer *fb = new_plane_state->fb;
1499021c317SLaurentiu Palcu bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
1504a83c26aSDanilo Krummrich struct drm_gem_dma_object *dma_obj;
1519021c317SLaurentiu Palcu struct drm_crtc_state *crtc_state;
1529021c317SLaurentiu Palcu int hdisplay, vdisplay;
1539021c317SLaurentiu Palcu int min, max;
1549021c317SLaurentiu Palcu int ret;
1559021c317SLaurentiu Palcu
156ba5c1649SMaxime Ripard if (!fb || !new_plane_state->crtc)
1579021c317SLaurentiu Palcu return 0;
1589021c317SLaurentiu Palcu
1594a83c26aSDanilo Krummrich dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
1604a83c26aSDanilo Krummrich WARN_ON(!dma_obj);
1619021c317SLaurentiu Palcu
162dec92020SMaxime Ripard crtc_state = drm_atomic_get_existing_crtc_state(state,
163ba5c1649SMaxime Ripard new_plane_state->crtc);
1649021c317SLaurentiu Palcu
1659021c317SLaurentiu Palcu hdisplay = crtc_state->adjusted_mode.hdisplay;
1669021c317SLaurentiu Palcu vdisplay = crtc_state->adjusted_mode.vdisplay;
1679021c317SLaurentiu Palcu
168ba5c1649SMaxime Ripard if (!dcss_plane_is_source_size_allowed(new_plane_state->src_w >> 16,
169ba5c1649SMaxime Ripard new_plane_state->src_h >> 16,
1709021c317SLaurentiu Palcu fb->format->format)) {
1719021c317SLaurentiu Palcu DRM_DEBUG_KMS("Source plane size is not allowed!\n");
1729021c317SLaurentiu Palcu return -EINVAL;
1739021c317SLaurentiu Palcu }
1749021c317SLaurentiu Palcu
1759021c317SLaurentiu Palcu dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
1769021c317SLaurentiu Palcu &min, &max);
1779021c317SLaurentiu Palcu
178ba5c1649SMaxime Ripard ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
1799021c317SLaurentiu Palcu min, max, !is_primary_plane,
1809021c317SLaurentiu Palcu false);
1819021c317SLaurentiu Palcu if (ret)
1829021c317SLaurentiu Palcu return ret;
1839021c317SLaurentiu Palcu
184ba5c1649SMaxime Ripard if (!new_plane_state->visible)
1859021c317SLaurentiu Palcu return 0;
1869021c317SLaurentiu Palcu
1879021c317SLaurentiu Palcu if (!dcss_plane_can_rotate(fb->format,
1889021c317SLaurentiu Palcu !!(fb->flags & DRM_MODE_FB_MODIFIERS),
1899021c317SLaurentiu Palcu fb->modifier,
190ba5c1649SMaxime Ripard new_plane_state->rotation)) {
1919021c317SLaurentiu Palcu DRM_DEBUG_KMS("requested rotation is not allowed!\n");
1929021c317SLaurentiu Palcu return -EINVAL;
1939021c317SLaurentiu Palcu }
1949021c317SLaurentiu Palcu
195ba5c1649SMaxime Ripard if ((new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 ||
196ba5c1649SMaxime Ripard new_plane_state->crtc_x + new_plane_state->crtc_w > hdisplay ||
197ba5c1649SMaxime Ripard new_plane_state->crtc_y + new_plane_state->crtc_h > vdisplay) &&
1989021c317SLaurentiu Palcu !dcss_plane_fb_is_linear(fb)) {
1999021c317SLaurentiu Palcu DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
2009021c317SLaurentiu Palcu return -EINVAL;
2019021c317SLaurentiu Palcu }
2029021c317SLaurentiu Palcu
2039021c317SLaurentiu Palcu if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
2049021c317SLaurentiu Palcu !plane->funcs->format_mod_supported(plane,
2059021c317SLaurentiu Palcu fb->format->format,
2069021c317SLaurentiu Palcu fb->modifier)) {
2079021c317SLaurentiu Palcu DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
2089021c317SLaurentiu Palcu return -EINVAL;
2099021c317SLaurentiu Palcu }
2109021c317SLaurentiu Palcu
2119021c317SLaurentiu Palcu return 0;
2129021c317SLaurentiu Palcu }
2139021c317SLaurentiu Palcu
dcss_plane_atomic_set_base(struct dcss_plane * dcss_plane)2149021c317SLaurentiu Palcu static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
2159021c317SLaurentiu Palcu {
2169021c317SLaurentiu Palcu struct drm_plane *plane = &dcss_plane->base;
2179021c317SLaurentiu Palcu struct drm_plane_state *state = plane->state;
2189021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private;
2199021c317SLaurentiu Palcu struct drm_framebuffer *fb = state->fb;
2209021c317SLaurentiu Palcu const struct drm_format_info *format = fb->format;
2214a83c26aSDanilo Krummrich struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
2229021c317SLaurentiu Palcu unsigned long p1_ba = 0, p2_ba = 0;
2239021c317SLaurentiu Palcu
2249021c317SLaurentiu Palcu if (!format->is_yuv ||
2259021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV12 ||
2269021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21)
227*8c30eeccSDanilo Krummrich p1_ba = dma_obj->dma_addr + fb->offsets[0] +
2289021c317SLaurentiu Palcu fb->pitches[0] * (state->src.y1 >> 16) +
2299021c317SLaurentiu Palcu format->char_per_block[0] * (state->src.x1 >> 16);
2309021c317SLaurentiu Palcu else if (format->format == DRM_FORMAT_UYVY ||
2319021c317SLaurentiu Palcu format->format == DRM_FORMAT_VYUY ||
2329021c317SLaurentiu Palcu format->format == DRM_FORMAT_YUYV ||
2339021c317SLaurentiu Palcu format->format == DRM_FORMAT_YVYU)
234*8c30eeccSDanilo Krummrich p1_ba = dma_obj->dma_addr + fb->offsets[0] +
2359021c317SLaurentiu Palcu fb->pitches[0] * (state->src.y1 >> 16) +
2369021c317SLaurentiu Palcu 2 * format->char_per_block[0] * (state->src.x1 >> 17);
2379021c317SLaurentiu Palcu
2389021c317SLaurentiu Palcu if (format->format == DRM_FORMAT_NV12 ||
2399021c317SLaurentiu Palcu format->format == DRM_FORMAT_NV21)
240*8c30eeccSDanilo Krummrich p2_ba = dma_obj->dma_addr + fb->offsets[1] +
2419021c317SLaurentiu Palcu (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
2429021c317SLaurentiu Palcu (state->src.x1 >> 17)) << 1);
2439021c317SLaurentiu Palcu
2449021c317SLaurentiu Palcu dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
2459021c317SLaurentiu Palcu fb->pitches[0]);
2469021c317SLaurentiu Palcu }
2479021c317SLaurentiu Palcu
dcss_plane_needs_setup(struct drm_plane_state * state,struct drm_plane_state * old_state)2489021c317SLaurentiu Palcu static bool dcss_plane_needs_setup(struct drm_plane_state *state,
2499021c317SLaurentiu Palcu struct drm_plane_state *old_state)
2509021c317SLaurentiu Palcu {
2519021c317SLaurentiu Palcu struct drm_framebuffer *fb = state->fb;
2529021c317SLaurentiu Palcu struct drm_framebuffer *old_fb = old_state->fb;
2539021c317SLaurentiu Palcu
2549021c317SLaurentiu Palcu return state->crtc_x != old_state->crtc_x ||
2559021c317SLaurentiu Palcu state->crtc_y != old_state->crtc_y ||
2569021c317SLaurentiu Palcu state->crtc_w != old_state->crtc_w ||
2579021c317SLaurentiu Palcu state->crtc_h != old_state->crtc_h ||
2589021c317SLaurentiu Palcu state->src_x != old_state->src_x ||
2599021c317SLaurentiu Palcu state->src_y != old_state->src_y ||
2609021c317SLaurentiu Palcu state->src_w != old_state->src_w ||
2619021c317SLaurentiu Palcu state->src_h != old_state->src_h ||
2629021c317SLaurentiu Palcu fb->format->format != old_fb->format->format ||
2639021c317SLaurentiu Palcu fb->modifier != old_fb->modifier ||
26405faf155SLaurentiu Palcu state->rotation != old_state->rotation ||
26505faf155SLaurentiu Palcu state->scaling_filter != old_state->scaling_filter;
2669021c317SLaurentiu Palcu }
2679021c317SLaurentiu Palcu
dcss_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)2689021c317SLaurentiu Palcu static void dcss_plane_atomic_update(struct drm_plane *plane,
269977697e2SMaxime Ripard struct drm_atomic_state *state)
2709021c317SLaurentiu Palcu {
271977697e2SMaxime Ripard struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
272977697e2SMaxime Ripard plane);
27337418bf1SMaxime Ripard struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
27437418bf1SMaxime Ripard plane);
2759021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane);
2769021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private;
27741016fe1SMaxime Ripard struct drm_framebuffer *fb = new_state->fb;
2789021c317SLaurentiu Palcu struct drm_crtc_state *crtc_state;
2799021c317SLaurentiu Palcu bool modifiers_present;
2809021c317SLaurentiu Palcu u32 src_w, src_h, dst_w, dst_h;
2819021c317SLaurentiu Palcu struct drm_rect src, dst;
2829021c317SLaurentiu Palcu bool enable = true;
28359cb403fSLaurentiu Palcu bool is_rotation_90_or_270;
2849021c317SLaurentiu Palcu
28541016fe1SMaxime Ripard if (!fb || !new_state->crtc || !new_state->visible)
2869021c317SLaurentiu Palcu return;
2879021c317SLaurentiu Palcu
28841016fe1SMaxime Ripard crtc_state = new_state->crtc->state;
2899021c317SLaurentiu Palcu modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
2909021c317SLaurentiu Palcu
2919021c317SLaurentiu Palcu if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
29241016fe1SMaxime Ripard !dcss_plane_needs_setup(new_state, old_state)) {
2939021c317SLaurentiu Palcu dcss_plane_atomic_set_base(dcss_plane);
2949021c317SLaurentiu Palcu return;
2959021c317SLaurentiu Palcu }
2969021c317SLaurentiu Palcu
2979021c317SLaurentiu Palcu src = plane->state->src;
2989021c317SLaurentiu Palcu dst = plane->state->dst;
2999021c317SLaurentiu Palcu
3009021c317SLaurentiu Palcu /*
3019021c317SLaurentiu Palcu * The width and height after clipping.
3029021c317SLaurentiu Palcu */
3039021c317SLaurentiu Palcu src_w = drm_rect_width(&src) >> 16;
3049021c317SLaurentiu Palcu src_h = drm_rect_height(&src) >> 16;
3059021c317SLaurentiu Palcu dst_w = drm_rect_width(&dst);
3069021c317SLaurentiu Palcu dst_h = drm_rect_height(&dst);
3079021c317SLaurentiu Palcu
3089021c317SLaurentiu Palcu if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
3099021c317SLaurentiu Palcu modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
3109021c317SLaurentiu Palcu modifiers_present = false;
3119021c317SLaurentiu Palcu
31241016fe1SMaxime Ripard dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num,
31341016fe1SMaxime Ripard new_state->fb->format,
3149021c317SLaurentiu Palcu modifiers_present ? fb->modifier :
3159021c317SLaurentiu Palcu DRM_FORMAT_MOD_LINEAR);
3169021c317SLaurentiu Palcu dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
3179021c317SLaurentiu Palcu dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
31841016fe1SMaxime Ripard new_state->rotation);
3199021c317SLaurentiu Palcu
3209021c317SLaurentiu Palcu dcss_plane_atomic_set_base(dcss_plane);
3219021c317SLaurentiu Palcu
32241016fe1SMaxime Ripard is_rotation_90_or_270 = new_state->rotation & (DRM_MODE_ROTATE_90 |
32359cb403fSLaurentiu Palcu DRM_MODE_ROTATE_270);
32459cb403fSLaurentiu Palcu
32505faf155SLaurentiu Palcu dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num,
32641016fe1SMaxime Ripard new_state->scaling_filter);
32705faf155SLaurentiu Palcu
3289021c317SLaurentiu Palcu dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
32941016fe1SMaxime Ripard new_state->fb->format,
33059cb403fSLaurentiu Palcu is_rotation_90_or_270 ? src_h : src_w,
33159cb403fSLaurentiu Palcu is_rotation_90_or_270 ? src_w : src_h,
3329021c317SLaurentiu Palcu dst_w, dst_h,
3339021c317SLaurentiu Palcu drm_mode_vrefresh(&crtc_state->mode));
3349021c317SLaurentiu Palcu
3359021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3369021c317SLaurentiu Palcu dst.x1, dst.y1, dst_w, dst_h);
3379021c317SLaurentiu Palcu dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
33841016fe1SMaxime Ripard fb->format, new_state->alpha >> 8);
3399021c317SLaurentiu Palcu
34041016fe1SMaxime Ripard if (!dcss_plane->ch_num && (new_state->alpha >> 8) == 0)
3419021c317SLaurentiu Palcu enable = false;
3429021c317SLaurentiu Palcu
3439021c317SLaurentiu Palcu dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
3449021c317SLaurentiu Palcu dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
3459021c317SLaurentiu Palcu
3469021c317SLaurentiu Palcu if (!enable)
3479021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
3489021c317SLaurentiu Palcu 0, 0, 0, 0);
3499021c317SLaurentiu Palcu
3509021c317SLaurentiu Palcu dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
3519021c317SLaurentiu Palcu }
3529021c317SLaurentiu Palcu
dcss_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)3539021c317SLaurentiu Palcu static void dcss_plane_atomic_disable(struct drm_plane *plane,
354977697e2SMaxime Ripard struct drm_atomic_state *state)
3559021c317SLaurentiu Palcu {
3569021c317SLaurentiu Palcu struct dcss_plane *dcss_plane = to_dcss_plane(plane);
3579021c317SLaurentiu Palcu struct dcss_dev *dcss = plane->dev->dev_private;
3589021c317SLaurentiu Palcu
3599021c317SLaurentiu Palcu dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
3609021c317SLaurentiu Palcu dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
3619021c317SLaurentiu Palcu dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
3629021c317SLaurentiu Palcu dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
3639021c317SLaurentiu Palcu }
3649021c317SLaurentiu Palcu
3659021c317SLaurentiu Palcu static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
3669021c317SLaurentiu Palcu .atomic_check = dcss_plane_atomic_check,
3679021c317SLaurentiu Palcu .atomic_update = dcss_plane_atomic_update,
3689021c317SLaurentiu Palcu .atomic_disable = dcss_plane_atomic_disable,
3699021c317SLaurentiu Palcu };
3709021c317SLaurentiu Palcu
dcss_plane_init(struct drm_device * drm,unsigned int possible_crtcs,enum drm_plane_type type,unsigned int zpos)3719021c317SLaurentiu Palcu struct dcss_plane *dcss_plane_init(struct drm_device *drm,
3729021c317SLaurentiu Palcu unsigned int possible_crtcs,
3739021c317SLaurentiu Palcu enum drm_plane_type type,
3749021c317SLaurentiu Palcu unsigned int zpos)
3759021c317SLaurentiu Palcu {
3769021c317SLaurentiu Palcu struct dcss_plane *dcss_plane;
3779021c317SLaurentiu Palcu const u64 *format_modifiers = dcss_video_format_modifiers;
3789021c317SLaurentiu Palcu int ret;
3799021c317SLaurentiu Palcu
3809021c317SLaurentiu Palcu if (zpos > 2)
3819021c317SLaurentiu Palcu return ERR_PTR(-EINVAL);
3829021c317SLaurentiu Palcu
3839021c317SLaurentiu Palcu dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
3849021c317SLaurentiu Palcu if (!dcss_plane) {
3859021c317SLaurentiu Palcu DRM_ERROR("failed to allocate plane\n");
3869021c317SLaurentiu Palcu return ERR_PTR(-ENOMEM);
3879021c317SLaurentiu Palcu }
3889021c317SLaurentiu Palcu
3899021c317SLaurentiu Palcu if (type == DRM_PLANE_TYPE_PRIMARY)
3909021c317SLaurentiu Palcu format_modifiers = dcss_graphics_format_modifiers;
3919021c317SLaurentiu Palcu
3929021c317SLaurentiu Palcu ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
3939021c317SLaurentiu Palcu &dcss_plane_funcs, dcss_common_formats,
3949021c317SLaurentiu Palcu ARRAY_SIZE(dcss_common_formats),
3959021c317SLaurentiu Palcu format_modifiers, type, NULL);
3969021c317SLaurentiu Palcu if (ret) {
3979021c317SLaurentiu Palcu DRM_ERROR("failed to initialize plane\n");
3989021c317SLaurentiu Palcu kfree(dcss_plane);
3999021c317SLaurentiu Palcu return ERR_PTR(ret);
4009021c317SLaurentiu Palcu }
4019021c317SLaurentiu Palcu
4029021c317SLaurentiu Palcu drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
4039021c317SLaurentiu Palcu
4049021c317SLaurentiu Palcu ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
4059021c317SLaurentiu Palcu if (ret)
4069021c317SLaurentiu Palcu return ERR_PTR(ret);
4079021c317SLaurentiu Palcu
40805faf155SLaurentiu Palcu drm_plane_create_scaling_filter_property(&dcss_plane->base,
40905faf155SLaurentiu Palcu BIT(DRM_SCALING_FILTER_DEFAULT) |
41005faf155SLaurentiu Palcu BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
41105faf155SLaurentiu Palcu
4129021c317SLaurentiu Palcu drm_plane_create_rotation_property(&dcss_plane->base,
4139021c317SLaurentiu Palcu DRM_MODE_ROTATE_0,
4149021c317SLaurentiu Palcu DRM_MODE_ROTATE_0 |
4159021c317SLaurentiu Palcu DRM_MODE_ROTATE_90 |
4169021c317SLaurentiu Palcu DRM_MODE_ROTATE_180 |
4179021c317SLaurentiu Palcu DRM_MODE_ROTATE_270 |
4189021c317SLaurentiu Palcu DRM_MODE_REFLECT_X |
4199021c317SLaurentiu Palcu DRM_MODE_REFLECT_Y);
4209021c317SLaurentiu Palcu
4219021c317SLaurentiu Palcu dcss_plane->ch_num = zpos;
4229021c317SLaurentiu Palcu
4239021c317SLaurentiu Palcu return dcss_plane;
4249021c317SLaurentiu Palcu }
425