Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 BayLibre, SAS
0004  * Author: Neil Armstrong <narmstrong@baylibre.com>
0005  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
0006  * Copyright (C) 2014 Endless Mobile
0007  *
0008  * Written by:
0009  *     Jasper St. Pierre <jstpierre@mecheye.net>
0010  */
0011 
0012 #include <linux/bitfield.h>
0013 
0014 #include <drm/drm_atomic.h>
0015 #include <drm/drm_atomic_helper.h>
0016 #include <drm/drm_blend.h>
0017 #include <drm/drm_device.h>
0018 #include <drm/drm_fb_cma_helper.h>
0019 #include <drm/drm_fourcc.h>
0020 #include <drm/drm_framebuffer.h>
0021 #include <drm/drm_gem_atomic_helper.h>
0022 #include <drm/drm_gem_cma_helper.h>
0023 #include <drm/drm_plane_helper.h>
0024 
0025 #include "meson_plane.h"
0026 #include "meson_registers.h"
0027 #include "meson_viu.h"
0028 #include "meson_osd_afbcd.h"
0029 
0030 /* OSD_SCI_WH_M1 */
0031 #define SCI_WH_M1_W(w)          FIELD_PREP(GENMASK(28, 16), w)
0032 #define SCI_WH_M1_H(h)          FIELD_PREP(GENMASK(12, 0), h)
0033 
0034 /* OSD_SCO_H_START_END */
0035 /* OSD_SCO_V_START_END */
0036 #define SCO_HV_START(start)     FIELD_PREP(GENMASK(27, 16), start)
0037 #define SCO_HV_END(end)         FIELD_PREP(GENMASK(11, 0), end)
0038 
0039 /* OSD_SC_CTRL0 */
0040 #define SC_CTRL0_PATH_EN        BIT(3)
0041 #define SC_CTRL0_SEL_OSD1       BIT(2)
0042 
0043 /* OSD_VSC_CTRL0 */
0044 #define VSC_BANK_LEN(value)     FIELD_PREP(GENMASK(2, 0), value)
0045 #define VSC_TOP_INI_RCV_NUM(value)  FIELD_PREP(GENMASK(6, 3), value)
0046 #define VSC_TOP_RPT_L0_NUM(value)   FIELD_PREP(GENMASK(9, 8), value)
0047 #define VSC_BOT_INI_RCV_NUM(value)  FIELD_PREP(GENMASK(14, 11), value)
0048 #define VSC_BOT_RPT_L0_NUM(value)   FIELD_PREP(GENMASK(17, 16), value)
0049 #define VSC_PROG_INTERLACE      BIT(23)
0050 #define VSC_VERTICAL_SCALER_EN      BIT(24)
0051 
0052 /* OSD_VSC_INI_PHASE */
0053 #define VSC_INI_PHASE_BOT(bottom)   FIELD_PREP(GENMASK(31, 16), bottom)
0054 #define VSC_INI_PHASE_TOP(top)      FIELD_PREP(GENMASK(15, 0), top)
0055 
0056 /* OSD_HSC_CTRL0 */
0057 #define HSC_BANK_LENGTH(value)      FIELD_PREP(GENMASK(2, 0), value)
0058 #define HSC_INI_RCV_NUM0(value)     FIELD_PREP(GENMASK(6, 3), value)
0059 #define HSC_RPT_P0_NUM0(value)      FIELD_PREP(GENMASK(9, 8), value)
0060 #define HSC_HORIZ_SCALER_EN     BIT(22)
0061 
0062 /* VPP_OSD_VSC_PHASE_STEP */
0063 /* VPP_OSD_HSC_PHASE_STEP */
0064 #define SC_PHASE_STEP(value)        FIELD_PREP(GENMASK(27, 0), value)
0065 
0066 struct meson_plane {
0067     struct drm_plane base;
0068     struct meson_drm *priv;
0069     bool enabled;
0070 };
0071 #define to_meson_plane(x) container_of(x, struct meson_plane, base)
0072 
0073 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
0074 
0075 static int meson_plane_atomic_check(struct drm_plane *plane,
0076                     struct drm_atomic_state *state)
0077 {
0078     struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0079                                          plane);
0080     struct drm_crtc_state *crtc_state;
0081 
0082     if (!new_plane_state->crtc)
0083         return 0;
0084 
0085     crtc_state = drm_atomic_get_crtc_state(state,
0086                            new_plane_state->crtc);
0087     if (IS_ERR(crtc_state))
0088         return PTR_ERR(crtc_state);
0089 
0090     /*
0091      * Only allow :
0092      * - Upscaling up to 5x, vertical and horizontal
0093      * - Final coordinates must match crtc size
0094      */
0095     return drm_atomic_helper_check_plane_state(new_plane_state,
0096                            crtc_state,
0097                            FRAC_16_16(1, 5),
0098                            DRM_PLANE_HELPER_NO_SCALING,
0099                            false, true);
0100 }
0101 
0102 #define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |   \
0103                    AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |    \
0104                    AFBC_FORMAT_MOD_YTR |        \
0105                    AFBC_FORMAT_MOD_SPARSE |     \
0106                    AFBC_FORMAT_MOD_SPLIT)
0107 
0108 /* Takes a fixed 16.16 number and converts it to integer. */
0109 static inline int64_t fixed16_to_int(int64_t value)
0110 {
0111     return value >> 16;
0112 }
0113 
0114 static u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv)
0115 {
0116     u32 line_stride = 0;
0117 
0118     switch (priv->afbcd.format) {
0119     case DRM_FORMAT_RGB565:
0120         line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7;
0121         break;
0122     case DRM_FORMAT_RGB888:
0123     case DRM_FORMAT_XRGB8888:
0124     case DRM_FORMAT_ARGB8888:
0125     case DRM_FORMAT_XBGR8888:
0126     case DRM_FORMAT_ABGR8888:
0127         line_stride = ((priv->viu.osd1_width << 5) + 127) >> 7;
0128         break;
0129     }
0130 
0131     return ((line_stride + 1) >> 1) << 1;
0132 }
0133 
0134 static void meson_plane_atomic_update(struct drm_plane *plane,
0135                       struct drm_atomic_state *state)
0136 {
0137     struct meson_plane *meson_plane = to_meson_plane(plane);
0138     struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0139                                        plane);
0140     struct drm_rect dest = drm_plane_state_dest(new_state);
0141     struct meson_drm *priv = meson_plane->priv;
0142     struct drm_framebuffer *fb = new_state->fb;
0143     struct drm_gem_cma_object *gem;
0144     unsigned long flags;
0145     int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
0146     int vsc_bot_rcv_num, vsc_bot_rpt_p0_num;
0147     int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
0148     int hf_phase_step, vf_phase_step;
0149     int src_w, src_h, dst_w, dst_h;
0150     int bot_ini_phase;
0151     int hf_bank_len;
0152     int vf_bank_len;
0153     u8 canvas_id_osd1;
0154 
0155     /*
0156      * Update Coordinates
0157      * Update Formats
0158      * Update Buffer
0159      * Enable Plane
0160      */
0161     spin_lock_irqsave(&priv->drm->event_lock, flags);
0162 
0163     /* Check if AFBC decoder is required for this buffer */
0164     if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
0165          meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) &&
0166         fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS))
0167         priv->viu.osd1_afbcd = true;
0168     else
0169         priv->viu.osd1_afbcd = false;
0170 
0171     /* Enable OSD and BLK0, set max global alpha */
0172     priv->viu.osd1_ctrl_stat = OSD_ENABLE |
0173                    (0x100 << OSD_GLOBAL_ALPHA_SHIFT) |
0174                    OSD_BLK0_ENABLE;
0175 
0176     priv->viu.osd1_ctrl_stat2 = readl(priv->io_base +
0177                       _REG(VIU_OSD1_CTRL_STAT2));
0178 
0179     canvas_id_osd1 = priv->canvas_id_osd1;
0180 
0181     /* Set up BLK0 to point to the right canvas */
0182     priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL;
0183 
0184     if (priv->viu.osd1_afbcd) {
0185         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0186             /* This is the internal decoding memory address */
0187             priv->viu.osd1_blk1_cfg4 = MESON_G12A_AFBCD_OUT_ADDR;
0188             priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_BE;
0189             priv->viu.osd1_ctrl_stat2 |= OSD_PENDING_STAT_CLEAN;
0190             priv->viu.osd1_ctrl_stat |= VIU_OSD1_CFG_SYN_EN;
0191         }
0192 
0193         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
0194             priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE;
0195             priv->viu.osd1_ctrl_stat2 |= OSD_DPATH_MALI_AFBCD;
0196         }
0197     } else {
0198         priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE;
0199 
0200         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
0201             priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD;
0202     }
0203 
0204     /* On GXBB, Use the old non-HDR RGB2YUV converter */
0205     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
0206         priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
0207 
0208     if (priv->viu.osd1_afbcd &&
0209         meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0210         priv->viu.osd1_blk0_cfg[0] |= OSD_MALI_SRC_EN |
0211             priv->afbcd.ops->fmt_to_blk_mode(fb->modifier,
0212                               fb->format->format);
0213     } else {
0214         switch (fb->format->format) {
0215         case DRM_FORMAT_XRGB8888:
0216         case DRM_FORMAT_ARGB8888:
0217             priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
0218                         OSD_COLOR_MATRIX_32_ARGB;
0219             break;
0220         case DRM_FORMAT_XBGR8888:
0221         case DRM_FORMAT_ABGR8888:
0222             priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
0223                         OSD_COLOR_MATRIX_32_ABGR;
0224             break;
0225         case DRM_FORMAT_RGB888:
0226             priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 |
0227                         OSD_COLOR_MATRIX_24_RGB;
0228             break;
0229         case DRM_FORMAT_RGB565:
0230             priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 |
0231                         OSD_COLOR_MATRIX_16_RGB565;
0232             break;
0233         }
0234     }
0235 
0236     switch (fb->format->format) {
0237     case DRM_FORMAT_XRGB8888:
0238     case DRM_FORMAT_XBGR8888:
0239         /* For XRGB, replace the pixel's alpha by 0xFF */
0240         priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN;
0241         break;
0242     case DRM_FORMAT_ARGB8888:
0243     case DRM_FORMAT_ABGR8888:
0244         /* For ARGB, use the pixel's alpha */
0245         priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN;
0246         break;
0247     }
0248 
0249     /* Default scaler parameters */
0250     vsc_bot_rcv_num = 0;
0251     vsc_bot_rpt_p0_num = 0;
0252     hf_bank_len = 4;
0253     vf_bank_len = 4;
0254 
0255     if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
0256         vsc_bot_rcv_num = 6;
0257         vsc_bot_rpt_p0_num = 2;
0258     }
0259 
0260     hsc_ini_rcv_num = hf_bank_len;
0261     vsc_ini_rcv_num = vf_bank_len;
0262     hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1;
0263     vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1;
0264 
0265     src_w = fixed16_to_int(new_state->src_w);
0266     src_h = fixed16_to_int(new_state->src_h);
0267     dst_w = new_state->crtc_w;
0268     dst_h = new_state->crtc_h;
0269 
0270     /*
0271      * When the output is interlaced, the OSD must switch between
0272      * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
0273      * at each vsync.
0274      * But the vertical scaler can provide such funtionnality if
0275      * is configured for 2:1 scaling with interlace options enabled.
0276      */
0277     if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
0278         dest.y1 /= 2;
0279         dest.y2 /= 2;
0280         dst_h /= 2;
0281     }
0282 
0283     hf_phase_step = ((src_w << 18) / dst_w) << 6;
0284     vf_phase_step = (src_h << 20) / dst_h;
0285 
0286     if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
0287         bot_ini_phase = ((vf_phase_step / 2) >> 4);
0288     else
0289         bot_ini_phase = 0;
0290 
0291     vf_phase_step = (vf_phase_step << 4);
0292 
0293     /* In interlaced mode, scaler is always active */
0294     if (src_h != dst_h || src_w != dst_w) {
0295         priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) |
0296                        SCI_WH_M1_H(src_h - 1);
0297         priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) |
0298                          SCO_HV_END(dest.x2 - 1);
0299         priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) |
0300                          SCO_HV_END(dest.y2 - 1);
0301         /* Enable OSD Scaler */
0302         priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1;
0303     } else {
0304         priv->viu.osd_sc_i_wh_m1 = 0;
0305         priv->viu.osd_sc_o_h_start_end = 0;
0306         priv->viu.osd_sc_o_v_start_end = 0;
0307         priv->viu.osd_sc_ctrl0 = 0;
0308     }
0309 
0310     /* In interlaced mode, vertical scaler is always active */
0311     if (src_h != dst_h) {
0312         priv->viu.osd_sc_v_ctrl0 =
0313                     VSC_BANK_LEN(vf_bank_len) |
0314                     VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) |
0315                     VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) |
0316                     VSC_VERTICAL_SCALER_EN;
0317 
0318         if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
0319             priv->viu.osd_sc_v_ctrl0 |=
0320                     VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) |
0321                     VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) |
0322                     VSC_PROG_INTERLACE;
0323 
0324         priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step);
0325         priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase);
0326     } else {
0327         priv->viu.osd_sc_v_ctrl0 = 0;
0328         priv->viu.osd_sc_v_phase_step = 0;
0329         priv->viu.osd_sc_v_ini_phase = 0;
0330     }
0331 
0332     /* Horizontal scaler is only used if width does not match */
0333     if (src_w != dst_w) {
0334         priv->viu.osd_sc_h_ctrl0 =
0335                     HSC_BANK_LENGTH(hf_bank_len) |
0336                     HSC_INI_RCV_NUM0(hsc_ini_rcv_num) |
0337                     HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) |
0338                     HSC_HORIZ_SCALER_EN;
0339         priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step);
0340         priv->viu.osd_sc_h_ini_phase = 0;
0341     } else {
0342         priv->viu.osd_sc_h_ctrl0 = 0;
0343         priv->viu.osd_sc_h_phase_step = 0;
0344         priv->viu.osd_sc_h_ini_phase = 0;
0345     }
0346 
0347     /*
0348      * The format of these registers is (x2 << 16 | x1),
0349      * where x2 is exclusive.
0350      * e.g. +30x1920 would be (1919 << 16) | 30
0351      */
0352     priv->viu.osd1_blk0_cfg[1] =
0353                 ((fixed16_to_int(new_state->src.x2) - 1) << 16) |
0354                 fixed16_to_int(new_state->src.x1);
0355     priv->viu.osd1_blk0_cfg[2] =
0356                 ((fixed16_to_int(new_state->src.y2) - 1) << 16) |
0357                 fixed16_to_int(new_state->src.y1);
0358     priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
0359     priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
0360 
0361     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
0362         priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
0363         priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
0364         priv->viu.osb_blend0_size = dst_h << 16 | dst_w;
0365         priv->viu.osb_blend1_size = dst_h << 16 | dst_w;
0366     }
0367 
0368     /* Update Canvas with buffer address */
0369     gem = drm_fb_cma_get_gem_obj(fb, 0);
0370 
0371     priv->viu.osd1_addr = gem->paddr;
0372     priv->viu.osd1_stride = fb->pitches[0];
0373     priv->viu.osd1_height = fb->height;
0374     priv->viu.osd1_width = fb->width;
0375 
0376     if (priv->viu.osd1_afbcd) {
0377         priv->afbcd.modifier = fb->modifier;
0378         priv->afbcd.format = fb->format->format;
0379 
0380         /* Calculate decoder write stride */
0381         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
0382             priv->viu.osd1_blk2_cfg4 =
0383                 meson_g12a_afbcd_line_stride(priv);
0384     }
0385 
0386     if (!meson_plane->enabled) {
0387         /* Reset OSD1 before enabling it on GXL+ SoCs */
0388         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
0389             meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
0390             meson_viu_osd1_reset(priv);
0391 
0392         meson_plane->enabled = true;
0393     }
0394 
0395     priv->viu.osd1_enabled = true;
0396 
0397     spin_unlock_irqrestore(&priv->drm->event_lock, flags);
0398 }
0399 
0400 static void meson_plane_atomic_disable(struct drm_plane *plane,
0401                        struct drm_atomic_state *state)
0402 {
0403     struct meson_plane *meson_plane = to_meson_plane(plane);
0404     struct meson_drm *priv = meson_plane->priv;
0405 
0406     if (priv->afbcd.ops) {
0407         priv->afbcd.ops->reset(priv);
0408         priv->afbcd.ops->disable(priv);
0409     }
0410 
0411     /* Disable OSD1 */
0412     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
0413         writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0,
0414                     priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
0415     else
0416         writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
0417                     priv->io_base + _REG(VPP_MISC));
0418 
0419     meson_plane->enabled = false;
0420     priv->viu.osd1_enabled = false;
0421 }
0422 
0423 static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
0424     .atomic_check   = meson_plane_atomic_check,
0425     .atomic_disable = meson_plane_atomic_disable,
0426     .atomic_update  = meson_plane_atomic_update,
0427 };
0428 
0429 static bool meson_plane_format_mod_supported(struct drm_plane *plane,
0430                          u32 format, u64 modifier)
0431 {
0432     struct meson_plane *meson_plane = to_meson_plane(plane);
0433     struct meson_drm *priv = meson_plane->priv;
0434     int i;
0435 
0436     if (modifier == DRM_FORMAT_MOD_INVALID)
0437         return false;
0438 
0439     if (modifier == DRM_FORMAT_MOD_LINEAR)
0440         return true;
0441 
0442     if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) &&
0443         !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
0444         return false;
0445 
0446     if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS))
0447         return false;
0448 
0449     for (i = 0 ; i < plane->modifier_count ; ++i)
0450         if (plane->modifiers[i] == modifier)
0451             break;
0452 
0453     if (i == plane->modifier_count) {
0454         DRM_DEBUG_KMS("Unsupported modifier\n");
0455         return false;
0456     }
0457 
0458     if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt)
0459         return priv->afbcd.ops->supported_fmt(modifier, format);
0460 
0461     DRM_DEBUG_KMS("AFBC Unsupported\n");
0462     return false;
0463 }
0464 
0465 static const struct drm_plane_funcs meson_plane_funcs = {
0466     .update_plane       = drm_atomic_helper_update_plane,
0467     .disable_plane      = drm_atomic_helper_disable_plane,
0468     .destroy        = drm_plane_cleanup,
0469     .reset          = drm_atomic_helper_plane_reset,
0470     .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0471     .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
0472     .format_mod_supported   = meson_plane_format_mod_supported,
0473 };
0474 
0475 static const uint32_t supported_drm_formats[] = {
0476     DRM_FORMAT_ARGB8888,
0477     DRM_FORMAT_ABGR8888,
0478     DRM_FORMAT_XRGB8888,
0479     DRM_FORMAT_XBGR8888,
0480     DRM_FORMAT_RGB888,
0481     DRM_FORMAT_RGB565,
0482 };
0483 
0484 static const uint64_t format_modifiers_afbc_gxm[] = {
0485     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
0486                 AFBC_FORMAT_MOD_SPARSE |
0487                 AFBC_FORMAT_MOD_YTR),
0488     /* SPLIT mandates SPARSE, RGB modes mandates YTR */
0489     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
0490                 AFBC_FORMAT_MOD_YTR |
0491                 AFBC_FORMAT_MOD_SPARSE |
0492                 AFBC_FORMAT_MOD_SPLIT),
0493     DRM_FORMAT_MOD_LINEAR,
0494     DRM_FORMAT_MOD_INVALID,
0495 };
0496 
0497 static const uint64_t format_modifiers_afbc_g12a[] = {
0498     /*
0499      * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED)
0500      * - SPLIT is mandatory for performances reasons when in 16x16
0501      *   block size
0502      * - 32x8 block size + SPLIT is mandatory with 4K frame size
0503      *   for performances reasons
0504      */
0505     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
0506                 AFBC_FORMAT_MOD_SPARSE |
0507                 AFBC_FORMAT_MOD_SPLIT),
0508     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
0509                 AFBC_FORMAT_MOD_YTR |
0510                 AFBC_FORMAT_MOD_SPARSE |
0511                 AFBC_FORMAT_MOD_SPLIT),
0512     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
0513                 AFBC_FORMAT_MOD_SPARSE),
0514     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
0515                 AFBC_FORMAT_MOD_YTR |
0516                 AFBC_FORMAT_MOD_SPARSE),
0517     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
0518                 AFBC_FORMAT_MOD_SPARSE |
0519                 AFBC_FORMAT_MOD_SPLIT),
0520     DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
0521                 AFBC_FORMAT_MOD_YTR |
0522                 AFBC_FORMAT_MOD_SPARSE |
0523                 AFBC_FORMAT_MOD_SPLIT),
0524     DRM_FORMAT_MOD_LINEAR,
0525     DRM_FORMAT_MOD_INVALID,
0526 };
0527 
0528 static const uint64_t format_modifiers_default[] = {
0529     DRM_FORMAT_MOD_LINEAR,
0530     DRM_FORMAT_MOD_INVALID,
0531 };
0532 
0533 int meson_plane_create(struct meson_drm *priv)
0534 {
0535     struct meson_plane *meson_plane;
0536     struct drm_plane *plane;
0537     const uint64_t *format_modifiers = format_modifiers_default;
0538 
0539     meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
0540                    GFP_KERNEL);
0541     if (!meson_plane)
0542         return -ENOMEM;
0543 
0544     meson_plane->priv = priv;
0545     plane = &meson_plane->base;
0546 
0547     if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
0548         format_modifiers = format_modifiers_afbc_gxm;
0549     else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
0550         format_modifiers = format_modifiers_afbc_g12a;
0551 
0552     drm_universal_plane_init(priv->drm, plane, 0xFF,
0553                  &meson_plane_funcs,
0554                  supported_drm_formats,
0555                  ARRAY_SIZE(supported_drm_formats),
0556                  format_modifiers,
0557                  DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
0558 
0559     drm_plane_helper_add(plane, &meson_plane_helper_funcs);
0560 
0561     /* For now, OSD Primary plane is always on the front */
0562     drm_plane_create_zpos_immutable_property(plane, 1);
0563 
0564     priv->primary_plane = plane;
0565 
0566     return 0;
0567 }