Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/imx/dcss/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 12 kB image not shown  

Quelle  dcss-plane.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2019 NXP.
 */


#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_blend.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>

#include "dcss-dev.h"
#include "dcss-kms.h"

static const u32 dcss_common_formats[] = {
 /* RGB */
 DRM_FORMAT_ARGB8888,
 DRM_FORMAT_XRGB8888,
 DRM_FORMAT_ABGR8888,
 DRM_FORMAT_XBGR8888,
 DRM_FORMAT_RGBA8888,
 DRM_FORMAT_RGBX8888,
 DRM_FORMAT_BGRA8888,
 DRM_FORMAT_BGRX8888,
 DRM_FORMAT_XRGB2101010,
 DRM_FORMAT_XBGR2101010,
 DRM_FORMAT_RGBX1010102,
 DRM_FORMAT_BGRX1010102,
 DRM_FORMAT_ARGB2101010,
 DRM_FORMAT_ABGR2101010,
 DRM_FORMAT_RGBA1010102,
 DRM_FORMAT_BGRA1010102,
};

static const u64 dcss_video_format_modifiers[] = {
 DRM_FORMAT_MOD_LINEAR,
 DRM_FORMAT_MOD_INVALID,
};

static const u64 dcss_graphics_format_modifiers[] = {
 DRM_FORMAT_MOD_VIVANTE_TILED,
 DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
 DRM_FORMAT_MOD_LINEAR,
 DRM_FORMAT_MOD_INVALID,
};

static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
{
 return container_of(p, struct dcss_plane, base);
}

static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
{
 return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
        ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
  fb->modifier == DRM_FORMAT_MOD_LINEAR);
}

static void dcss_plane_destroy(struct drm_plane *plane)
{
 struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
           base);

 drm_plane_cleanup(plane);
 kfree(dcss_plane);
}

static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
         u32 format,
         u64 modifier)
{
 switch (plane->type) {
 case DRM_PLANE_TYPE_PRIMARY:
  switch (format) {
  case DRM_FORMAT_ARGB8888:
  case DRM_FORMAT_XRGB8888:
  case DRM_FORMAT_ARGB2101010:
   return modifier == DRM_FORMAT_MOD_LINEAR ||
          modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
          modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
  default:
   return modifier == DRM_FORMAT_MOD_LINEAR;
  }
  break;
 case DRM_PLANE_TYPE_OVERLAY:
  return modifier == DRM_FORMAT_MOD_LINEAR;
 default:
  return false;
 }
}

static const struct drm_plane_funcs dcss_plane_funcs = {
 .update_plane  = drm_atomic_helper_update_plane,
 .disable_plane  = drm_atomic_helper_disable_plane,
 .destroy  = dcss_plane_destroy,
 .reset   = drm_atomic_helper_plane_reset,
 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 .format_mod_supported = dcss_plane_format_mod_supported,
};

static bool dcss_plane_can_rotate(const struct drm_format_info *format,
      bool mod_present, u64 modifier,
      unsigned int rotation)
{
 bool linear_format = !mod_present || modifier == DRM_FORMAT_MOD_LINEAR;
 u32 supported_rotation = DRM_MODE_ROTATE_0;

 if (!format->is_yuv && linear_format)
  supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
         DRM_MODE_REFLECT_MASK;
 else if (!format->is_yuv &&
   (modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
    modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))
  supported_rotation = DRM_MODE_ROTATE_MASK |
         DRM_MODE_REFLECT_MASK;
 else if (format->is_yuv && linear_format &&
   (format->format == DRM_FORMAT_NV12 ||
    format->format == DRM_FORMAT_NV21))
  supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
         DRM_MODE_REFLECT_MASK;

 return !!(rotation & supported_rotation);
}

static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
{
 if (src_w < 64 &&
     (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
  return false;
 else if (src_w < 32 &&
   (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
    pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
  return false;

 return src_w >= 16 && src_h >= 8;
}

static int dcss_plane_atomic_check(struct drm_plane *plane,
       struct drm_atomic_state *state)
{
 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
           plane);
 struct dcss_plane *dcss_plane = to_dcss_plane(plane);
 struct dcss_dev *dcss = plane->dev->dev_private;
 struct drm_framebuffer *fb = new_plane_state->fb;
 bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
 struct drm_gem_dma_object *dma_obj;
 struct drm_crtc_state *crtc_state;
 int hdisplay, vdisplay;
 int min, max;
 int ret;

 if (!fb || !new_plane_state->crtc)
  return 0;

 dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
 WARN_ON(!dma_obj);

 crtc_state = drm_atomic_get_existing_crtc_state(state,
       new_plane_state->crtc);

 hdisplay = crtc_state->adjusted_mode.hdisplay;
 vdisplay = crtc_state->adjusted_mode.vdisplay;

 if (!dcss_plane_is_source_size_allowed(new_plane_state->src_w >> 16,
            new_plane_state->src_h >> 16,
            fb->format->format)) {
  DRM_DEBUG_KMS("Source plane size is not allowed!\n");
  return -EINVAL;
 }

 dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
           &min, &max);

 ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
        min, max, !is_primary_plane,
        false);
 if (ret)
  return ret;

 if (!new_plane_state->visible)
  return 0;

 if (!dcss_plane_can_rotate(fb->format,
       !!(fb->flags & DRM_MODE_FB_MODIFIERS),
       fb->modifier,
       new_plane_state->rotation)) {
  DRM_DEBUG_KMS("requested rotation is not allowed!\n");
  return -EINVAL;
 }

 if ((new_plane_state->crtc_x < 0 || new_plane_state->crtc_y < 0 ||
      new_plane_state->crtc_x + new_plane_state->crtc_w > hdisplay ||
      new_plane_state->crtc_y + new_plane_state->crtc_h > vdisplay) &&
     !dcss_plane_fb_is_linear(fb)) {
  DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
  return -EINVAL;
 }

 if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
     !plane->funcs->format_mod_supported(plane,
    fb->format->format,
    fb->modifier)) {
  DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
  return -EINVAL;
 }

 return 0;
}

static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
{
 struct drm_plane *plane = &dcss_plane->base;
 struct drm_plane_state *state = plane->state;
 struct dcss_dev *dcss = plane->dev->dev_private;
 struct drm_framebuffer *fb = state->fb;
 const struct drm_format_info *format = fb->format;
 struct drm_gem_dma_object *dma_obj = drm_fb_dma_get_gem_obj(fb, 0);
 unsigned long p1_ba = 0, p2_ba = 0;

 if (!format->is_yuv ||
     format->format == DRM_FORMAT_NV12 ||
     format->format == DRM_FORMAT_NV21)
  p1_ba = dma_obj->dma_addr + fb->offsets[0] +
   fb->pitches[0] * (state->src.y1 >> 16) +
   format->char_per_block[0] * (state->src.x1 >> 16);
 else if (format->format == DRM_FORMAT_UYVY ||
   format->format == DRM_FORMAT_VYUY ||
   format->format == DRM_FORMAT_YUYV ||
   format->format == DRM_FORMAT_YVYU)
  p1_ba = dma_obj->dma_addr + fb->offsets[0] +
   fb->pitches[0] * (state->src.y1 >> 16) +
   2 * format->char_per_block[0] * (state->src.x1 >> 17);

 if (format->format == DRM_FORMAT_NV12 ||
     format->format == DRM_FORMAT_NV21)
  p2_ba = dma_obj->dma_addr + fb->offsets[1] +
   (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
   (state->src.x1 >> 17)) << 1);

 dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
     fb->pitches[0]);
}

static bool dcss_plane_needs_setup(struct drm_plane_state *state,
       struct drm_plane_state *old_state)
{
 struct drm_framebuffer *fb = state->fb;
 struct drm_framebuffer *old_fb = old_state->fb;

 return state->crtc_x != old_state->crtc_x ||
        state->crtc_y != old_state->crtc_y ||
        state->crtc_w != old_state->crtc_w ||
        state->crtc_h != old_state->crtc_h ||
        state->src_x  != old_state->src_x  ||
        state->src_y  != old_state->src_y  ||
        state->src_w  != old_state->src_w  ||
        state->src_h  != old_state->src_h  ||
        fb->format->format != old_fb->format->format ||
        fb->modifier  != old_fb->modifier ||
        state->rotation != old_state->rotation ||
        state->scaling_filter != old_state->scaling_filter;
}

static void dcss_plane_atomic_update(struct drm_plane *plane,
         struct drm_atomic_state *state)
{
 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
            plane);
 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
            plane);
 struct dcss_plane *dcss_plane = to_dcss_plane(plane);
 struct dcss_dev *dcss = plane->dev->dev_private;
 struct drm_framebuffer *fb = new_state->fb;
 struct drm_crtc_state *crtc_state;
 bool modifiers_present;
 u32 src_w, src_h, dst_w, dst_h;
 struct drm_rect src, dst;
 bool enable = true;
 bool is_rotation_90_or_270;

 if (!fb || !new_state->crtc || !new_state->visible)
  return;

 crtc_state = new_state->crtc->state;
 modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);

 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
     !dcss_plane_needs_setup(new_state, old_state)) {
  dcss_plane_atomic_set_base(dcss_plane);
  return;
 }

 src = plane->state->src;
 dst = plane->state->dst;

 /*
 * The width and height after clipping.
 */

 src_w = drm_rect_width(&src) >> 16;
 src_h = drm_rect_height(&src) >> 16;
 dst_w = drm_rect_width(&dst);
 dst_h = drm_rect_height(&dst);

 if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
     modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
  modifiers_present = false;

 dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num,
       new_state->fb->format,
       modifiers_present ? fb->modifier :
      DRM_FORMAT_MOD_LINEAR);
 dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
 dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
         new_state->rotation);

 dcss_plane_atomic_set_base(dcss_plane);

 is_rotation_90_or_270 = new_state->rotation & (DRM_MODE_ROTATE_90 |
         DRM_MODE_ROTATE_270);

 dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num,
          new_state->scaling_filter);

 dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
     new_state->fb->format,
     is_rotation_90_or_270 ? src_h : src_w,
     is_rotation_90_or_270 ? src_w : src_h,
     dst_w, dst_h,
     drm_mode_vrefresh(&crtc_state->mode));

 dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
          dst.x1, dst.y1, dst_w, dst_h);
 dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
     fb->format, new_state->alpha >> 8);

 if (!dcss_plane->ch_num && (new_state->alpha >> 8) == 0)
  enable = false;

 dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
 dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);

 if (!enable)
  dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
           0, 0, 0, 0);

 dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
}

static void dcss_plane_atomic_disable(struct drm_plane *plane,
          struct drm_atomic_state *state)
{
 struct dcss_plane *dcss_plane = to_dcss_plane(plane);
 struct dcss_dev *dcss = plane->dev->dev_private;

 dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
 dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
 dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
 dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
}

static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
 .atomic_check = dcss_plane_atomic_check,
 .atomic_update = dcss_plane_atomic_update,
 .atomic_disable = dcss_plane_atomic_disable,
};

struct dcss_plane *dcss_plane_init(struct drm_device *drm,
       unsigned int possible_crtcs,
       enum drm_plane_type type,
       unsigned int zpos)
{
 struct dcss_plane *dcss_plane;
 const u64 *format_modifiers = dcss_video_format_modifiers;
 int ret;

 if (zpos > 2)
  return ERR_PTR(-EINVAL);

 dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
 if (!dcss_plane) {
  DRM_ERROR("failed to allocate plane\n");
  return ERR_PTR(-ENOMEM);
 }

 if (type == DRM_PLANE_TYPE_PRIMARY)
  format_modifiers = dcss_graphics_format_modifiers;

 ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
           &dcss_plane_funcs, dcss_common_formats,
           ARRAY_SIZE(dcss_common_formats),
           format_modifiers, type, NULL);
 if (ret) {
  DRM_ERROR("failed to initialize plane\n");
  kfree(dcss_plane);
  return ERR_PTR(ret);
 }

 drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);

 ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
 if (ret)
  return ERR_PTR(ret);

 drm_plane_create_scaling_filter_property(&dcss_plane->base,
     BIT(DRM_SCALING_FILTER_DEFAULT) |
     BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));

 drm_plane_create_rotation_property(&dcss_plane->base,
        DRM_MODE_ROTATE_0,
        DRM_MODE_ROTATE_0   |
        DRM_MODE_ROTATE_90  |
        DRM_MODE_ROTATE_180 |
        DRM_MODE_ROTATE_270 |
        DRM_MODE_REFLECT_X  |
        DRM_MODE_REFLECT_Y);

 dcss_plane->ch_num = zpos;

 return dcss_plane;
}

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.