1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
6 * Copyright (C) 2014 Endless Mobile
9 * Jasper St. Pierre <jstpierre@mecheye.net>
12 #include <linux/bitfield.h>
14 #include <drm/drm_atomic.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_device.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_fourcc.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_gem_framebuffer_helper.h>
21 #include <drm/drm_plane_helper.h>
23 #include "meson_plane.h"
24 #include "meson_registers.h"
25 #include "meson_viu.h"
26 #include "meson_osd_afbcd.h"
29 #define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w)
30 #define SCI_WH_M1_H(h) FIELD_PREP(GENMASK(12, 0), h)
32 /* OSD_SCO_H_START_END */
33 /* OSD_SCO_V_START_END */
34 #define SCO_HV_START(start) FIELD_PREP(GENMASK(27, 16), start)
35 #define SCO_HV_END(end) FIELD_PREP(GENMASK(11, 0), end)
38 #define SC_CTRL0_PATH_EN BIT(3)
39 #define SC_CTRL0_SEL_OSD1 BIT(2)
42 #define VSC_BANK_LEN(value) FIELD_PREP(GENMASK(2, 0), value)
43 #define VSC_TOP_INI_RCV_NUM(value) FIELD_PREP(GENMASK(6, 3), value)
44 #define VSC_TOP_RPT_L0_NUM(value) FIELD_PREP(GENMASK(9, 8), value)
45 #define VSC_BOT_INI_RCV_NUM(value) FIELD_PREP(GENMASK(14, 11), value)
46 #define VSC_BOT_RPT_L0_NUM(value) FIELD_PREP(GENMASK(17, 16), value)
47 #define VSC_PROG_INTERLACE BIT(23)
48 #define VSC_VERTICAL_SCALER_EN BIT(24)
50 /* OSD_VSC_INI_PHASE */
51 #define VSC_INI_PHASE_BOT(bottom) FIELD_PREP(GENMASK(31, 16), bottom)
52 #define VSC_INI_PHASE_TOP(top) FIELD_PREP(GENMASK(15, 0), top)
55 #define HSC_BANK_LENGTH(value) FIELD_PREP(GENMASK(2, 0), value)
56 #define HSC_INI_RCV_NUM0(value) FIELD_PREP(GENMASK(6, 3), value)
57 #define HSC_RPT_P0_NUM0(value) FIELD_PREP(GENMASK(9, 8), value)
58 #define HSC_HORIZ_SCALER_EN BIT(22)
60 /* VPP_OSD_VSC_PHASE_STEP */
61 /* VPP_OSD_HSC_PHASE_STEP */
62 #define SC_PHASE_STEP(value) FIELD_PREP(GENMASK(27, 0), value)
65 struct drm_plane base
;
66 struct meson_drm
*priv
;
69 #define to_meson_plane(x) container_of(x, struct meson_plane, base)
71 #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
73 static int meson_plane_atomic_check(struct drm_plane
*plane
,
74 struct drm_plane_state
*state
)
76 struct drm_crtc_state
*crtc_state
;
81 crtc_state
= drm_atomic_get_crtc_state(state
->state
, state
->crtc
);
82 if (IS_ERR(crtc_state
))
83 return PTR_ERR(crtc_state
);
87 * - Upscaling up to 5x, vertical and horizontal
88 * - Final coordinates must match crtc size
90 return drm_atomic_helper_check_plane_state(state
, crtc_state
,
92 DRM_PLANE_HELPER_NO_SCALING
,
96 #define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | \
97 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | \
98 AFBC_FORMAT_MOD_YTR | \
99 AFBC_FORMAT_MOD_SPARSE | \
100 AFBC_FORMAT_MOD_SPLIT)
102 /* Takes a fixed 16.16 number and converts it to integer. */
103 static inline int64_t fixed16_to_int(int64_t value
)
108 static u32
meson_g12a_afbcd_line_stride(struct meson_drm
*priv
)
112 switch (priv
->afbcd
.format
) {
113 case DRM_FORMAT_RGB565
:
114 line_stride
= ((priv
->viu
.osd1_width
<< 4) + 127) >> 7;
116 case DRM_FORMAT_RGB888
:
117 case DRM_FORMAT_XRGB8888
:
118 case DRM_FORMAT_ARGB8888
:
119 case DRM_FORMAT_XBGR8888
:
120 case DRM_FORMAT_ABGR8888
:
121 line_stride
= ((priv
->viu
.osd1_width
<< 5) + 127) >> 7;
125 return ((line_stride
+ 1) >> 1) << 1;
128 static void meson_plane_atomic_update(struct drm_plane
*plane
,
129 struct drm_plane_state
*old_state
)
131 struct meson_plane
*meson_plane
= to_meson_plane(plane
);
132 struct drm_plane_state
*state
= plane
->state
;
133 struct drm_rect dest
= drm_plane_state_dest(state
);
134 struct meson_drm
*priv
= meson_plane
->priv
;
135 struct drm_framebuffer
*fb
= state
->fb
;
136 struct drm_gem_cma_object
*gem
;
138 int vsc_ini_rcv_num
, vsc_ini_rpt_p0_num
;
139 int vsc_bot_rcv_num
, vsc_bot_rpt_p0_num
;
140 int hsc_ini_rcv_num
, hsc_ini_rpt_p0_num
;
141 int hf_phase_step
, vf_phase_step
;
142 int src_w
, src_h
, dst_w
, dst_h
;
154 spin_lock_irqsave(&priv
->drm
->event_lock
, flags
);
156 /* Check if AFBC decoder is required for this buffer */
157 if ((meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
) ||
158 meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
)) &&
159 fb
->modifier
& DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS
))
160 priv
->viu
.osd1_afbcd
= true;
162 priv
->viu
.osd1_afbcd
= false;
164 /* Enable OSD and BLK0, set max global alpha */
165 priv
->viu
.osd1_ctrl_stat
= OSD_ENABLE
|
166 (0xFF << OSD_GLOBAL_ALPHA_SHIFT
) |
169 priv
->viu
.osd1_ctrl_stat2
= readl(priv
->io_base
+
170 _REG(VIU_OSD1_CTRL_STAT2
));
172 canvas_id_osd1
= priv
->canvas_id_osd1
;
174 /* Set up BLK0 to point to the right canvas */
175 priv
->viu
.osd1_blk0_cfg
[0] = canvas_id_osd1
<< OSD_CANVAS_SEL
;
177 if (priv
->viu
.osd1_afbcd
) {
178 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
)) {
179 /* This is the internal decoding memory address */
180 priv
->viu
.osd1_blk1_cfg4
= MESON_G12A_AFBCD_OUT_ADDR
;
181 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_ENDIANNESS_BE
;
182 priv
->viu
.osd1_ctrl_stat2
|= OSD_PENDING_STAT_CLEAN
;
183 priv
->viu
.osd1_ctrl_stat
|= VIU_OSD1_CFG_SYN_EN
;
186 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
)) {
187 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_ENDIANNESS_LE
;
188 priv
->viu
.osd1_ctrl_stat2
|= OSD_DPATH_MALI_AFBCD
;
191 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_ENDIANNESS_LE
;
193 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
))
194 priv
->viu
.osd1_ctrl_stat2
&= ~OSD_DPATH_MALI_AFBCD
;
197 /* On GXBB, Use the old non-HDR RGB2YUV converter */
198 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXBB
))
199 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_OUTPUT_COLOR_RGB
;
201 if (priv
->viu
.osd1_afbcd
&&
202 meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
)) {
203 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_MALI_SRC_EN
|
204 priv
->afbcd
.ops
->fmt_to_blk_mode(fb
->modifier
,
207 switch (fb
->format
->format
) {
208 case DRM_FORMAT_XRGB8888
:
209 case DRM_FORMAT_ARGB8888
:
210 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_BLK_MODE_32
|
211 OSD_COLOR_MATRIX_32_ARGB
;
213 case DRM_FORMAT_XBGR8888
:
214 case DRM_FORMAT_ABGR8888
:
215 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_BLK_MODE_32
|
216 OSD_COLOR_MATRIX_32_ABGR
;
218 case DRM_FORMAT_RGB888
:
219 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_BLK_MODE_24
|
220 OSD_COLOR_MATRIX_24_RGB
;
222 case DRM_FORMAT_RGB565
:
223 priv
->viu
.osd1_blk0_cfg
[0] |= OSD_BLK_MODE_16
|
224 OSD_COLOR_MATRIX_16_RGB565
;
229 switch (fb
->format
->format
) {
230 case DRM_FORMAT_XRGB8888
:
231 case DRM_FORMAT_XBGR8888
:
232 /* For XRGB, replace the pixel's alpha by 0xFF */
233 priv
->viu
.osd1_ctrl_stat2
|= OSD_REPLACE_EN
;
235 case DRM_FORMAT_ARGB8888
:
236 case DRM_FORMAT_ABGR8888
:
237 /* For ARGB, use the pixel's alpha */
238 priv
->viu
.osd1_ctrl_stat2
&= ~OSD_REPLACE_EN
;
242 /* Default scaler parameters */
244 vsc_bot_rpt_p0_num
= 0;
248 if (state
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
) {
250 vsc_bot_rpt_p0_num
= 2;
253 hsc_ini_rcv_num
= hf_bank_len
;
254 vsc_ini_rcv_num
= vf_bank_len
;
255 hsc_ini_rpt_p0_num
= (hf_bank_len
/ 2) - 1;
256 vsc_ini_rpt_p0_num
= (vf_bank_len
/ 2) - 1;
258 src_w
= fixed16_to_int(state
->src_w
);
259 src_h
= fixed16_to_int(state
->src_h
);
260 dst_w
= state
->crtc_w
;
261 dst_h
= state
->crtc_h
;
264 * When the output is interlaced, the OSD must switch between
265 * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
267 * But the vertical scaler can provide such funtionnality if
268 * is configured for 2:1 scaling with interlace options enabled.
270 if (state
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
) {
276 hf_phase_step
= ((src_w
<< 18) / dst_w
) << 6;
277 vf_phase_step
= (src_h
<< 20) / dst_h
;
279 if (state
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
)
280 bot_ini_phase
= ((vf_phase_step
/ 2) >> 4);
284 vf_phase_step
= (vf_phase_step
<< 4);
286 /* In interlaced mode, scaler is always active */
287 if (src_h
!= dst_h
|| src_w
!= dst_w
) {
288 priv
->viu
.osd_sc_i_wh_m1
= SCI_WH_M1_W(src_w
- 1) |
289 SCI_WH_M1_H(src_h
- 1);
290 priv
->viu
.osd_sc_o_h_start_end
= SCO_HV_START(dest
.x1
) |
291 SCO_HV_END(dest
.x2
- 1);
292 priv
->viu
.osd_sc_o_v_start_end
= SCO_HV_START(dest
.y1
) |
293 SCO_HV_END(dest
.y2
- 1);
294 /* Enable OSD Scaler */
295 priv
->viu
.osd_sc_ctrl0
= SC_CTRL0_PATH_EN
| SC_CTRL0_SEL_OSD1
;
297 priv
->viu
.osd_sc_i_wh_m1
= 0;
298 priv
->viu
.osd_sc_o_h_start_end
= 0;
299 priv
->viu
.osd_sc_o_v_start_end
= 0;
300 priv
->viu
.osd_sc_ctrl0
= 0;
303 /* In interlaced mode, vertical scaler is always active */
304 if (src_h
!= dst_h
) {
305 priv
->viu
.osd_sc_v_ctrl0
=
306 VSC_BANK_LEN(vf_bank_len
) |
307 VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num
) |
308 VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num
) |
309 VSC_VERTICAL_SCALER_EN
;
311 if (state
->crtc
->mode
.flags
& DRM_MODE_FLAG_INTERLACE
)
312 priv
->viu
.osd_sc_v_ctrl0
|=
313 VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num
) |
314 VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num
) |
317 priv
->viu
.osd_sc_v_phase_step
= SC_PHASE_STEP(vf_phase_step
);
318 priv
->viu
.osd_sc_v_ini_phase
= VSC_INI_PHASE_BOT(bot_ini_phase
);
320 priv
->viu
.osd_sc_v_ctrl0
= 0;
321 priv
->viu
.osd_sc_v_phase_step
= 0;
322 priv
->viu
.osd_sc_v_ini_phase
= 0;
325 /* Horizontal scaler is only used if width does not match */
326 if (src_w
!= dst_w
) {
327 priv
->viu
.osd_sc_h_ctrl0
=
328 HSC_BANK_LENGTH(hf_bank_len
) |
329 HSC_INI_RCV_NUM0(hsc_ini_rcv_num
) |
330 HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num
) |
332 priv
->viu
.osd_sc_h_phase_step
= SC_PHASE_STEP(hf_phase_step
);
333 priv
->viu
.osd_sc_h_ini_phase
= 0;
335 priv
->viu
.osd_sc_h_ctrl0
= 0;
336 priv
->viu
.osd_sc_h_phase_step
= 0;
337 priv
->viu
.osd_sc_h_ini_phase
= 0;
341 * The format of these registers is (x2 << 16 | x1),
342 * where x2 is exclusive.
343 * e.g. +30x1920 would be (1919 << 16) | 30
345 priv
->viu
.osd1_blk0_cfg
[1] =
346 ((fixed16_to_int(state
->src
.x2
) - 1) << 16) |
347 fixed16_to_int(state
->src
.x1
);
348 priv
->viu
.osd1_blk0_cfg
[2] =
349 ((fixed16_to_int(state
->src
.y2
) - 1) << 16) |
350 fixed16_to_int(state
->src
.y1
);
351 priv
->viu
.osd1_blk0_cfg
[3] = ((dest
.x2
- 1) << 16) | dest
.x1
;
352 priv
->viu
.osd1_blk0_cfg
[4] = ((dest
.y2
- 1) << 16) | dest
.y1
;
354 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
)) {
355 priv
->viu
.osd_blend_din0_scope_h
= ((dest
.x2
- 1) << 16) | dest
.x1
;
356 priv
->viu
.osd_blend_din0_scope_v
= ((dest
.y2
- 1) << 16) | dest
.y1
;
357 priv
->viu
.osb_blend0_size
= dst_h
<< 16 | dst_w
;
358 priv
->viu
.osb_blend1_size
= dst_h
<< 16 | dst_w
;
361 /* Update Canvas with buffer address */
362 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
364 priv
->viu
.osd1_addr
= gem
->paddr
;
365 priv
->viu
.osd1_stride
= fb
->pitches
[0];
366 priv
->viu
.osd1_height
= fb
->height
;
367 priv
->viu
.osd1_width
= fb
->width
;
369 if (priv
->viu
.osd1_afbcd
) {
370 priv
->afbcd
.modifier
= fb
->modifier
;
371 priv
->afbcd
.format
= fb
->format
->format
;
373 /* Calculate decoder write stride */
374 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
))
375 priv
->viu
.osd1_blk2_cfg4
=
376 meson_g12a_afbcd_line_stride(priv
);
379 if (!meson_plane
->enabled
) {
380 /* Reset OSD1 before enabling it on GXL+ SoCs */
381 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
) ||
382 meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXL
))
383 meson_viu_osd1_reset(priv
);
385 meson_plane
->enabled
= true;
388 priv
->viu
.osd1_enabled
= true;
390 spin_unlock_irqrestore(&priv
->drm
->event_lock
, flags
);
393 static void meson_plane_atomic_disable(struct drm_plane
*plane
,
394 struct drm_plane_state
*old_state
)
396 struct meson_plane
*meson_plane
= to_meson_plane(plane
);
397 struct meson_drm
*priv
= meson_plane
->priv
;
399 if (priv
->afbcd
.ops
) {
400 priv
->afbcd
.ops
->reset(priv
);
401 priv
->afbcd
.ops
->disable(priv
);
405 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
))
406 writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1
, 0,
407 priv
->io_base
+ _REG(OSD1_BLEND_SRC_CTRL
));
409 writel_bits_relaxed(VPP_OSD1_POSTBLEND
, 0,
410 priv
->io_base
+ _REG(VPP_MISC
));
412 meson_plane
->enabled
= false;
413 priv
->viu
.osd1_enabled
= false;
416 static const struct drm_plane_helper_funcs meson_plane_helper_funcs
= {
417 .atomic_check
= meson_plane_atomic_check
,
418 .atomic_disable
= meson_plane_atomic_disable
,
419 .atomic_update
= meson_plane_atomic_update
,
420 .prepare_fb
= drm_gem_fb_prepare_fb
,
423 static bool meson_plane_format_mod_supported(struct drm_plane
*plane
,
424 u32 format
, u64 modifier
)
426 struct meson_plane
*meson_plane
= to_meson_plane(plane
);
427 struct meson_drm
*priv
= meson_plane
->priv
;
430 if (modifier
== DRM_FORMAT_MOD_INVALID
)
433 if (modifier
== DRM_FORMAT_MOD_LINEAR
)
436 if (!meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
) &&
437 !meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
))
440 if (modifier
& ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS
))
443 for (i
= 0 ; i
< plane
->modifier_count
; ++i
)
444 if (plane
->modifiers
[i
] == modifier
)
447 if (i
== plane
->modifier_count
) {
448 DRM_DEBUG_KMS("Unsupported modifier\n");
452 if (priv
->afbcd
.ops
&& priv
->afbcd
.ops
->supported_fmt
)
453 return priv
->afbcd
.ops
->supported_fmt(modifier
, format
);
455 DRM_DEBUG_KMS("AFBC Unsupported\n");
459 static const struct drm_plane_funcs meson_plane_funcs
= {
460 .update_plane
= drm_atomic_helper_update_plane
,
461 .disable_plane
= drm_atomic_helper_disable_plane
,
462 .destroy
= drm_plane_cleanup
,
463 .reset
= drm_atomic_helper_plane_reset
,
464 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
465 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
466 .format_mod_supported
= meson_plane_format_mod_supported
,
469 static const uint32_t supported_drm_formats
[] = {
478 static const uint64_t format_modifiers_afbc_gxm
[] = {
479 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
480 AFBC_FORMAT_MOD_SPARSE
|
481 AFBC_FORMAT_MOD_YTR
),
482 /* SPLIT mandates SPARSE, RGB modes mandates YTR */
483 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
484 AFBC_FORMAT_MOD_YTR
|
485 AFBC_FORMAT_MOD_SPARSE
|
486 AFBC_FORMAT_MOD_SPLIT
),
487 DRM_FORMAT_MOD_LINEAR
,
488 DRM_FORMAT_MOD_INVALID
,
491 static const uint64_t format_modifiers_afbc_g12a
[] = {
493 * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED)
494 * - SPLIT is mandatory for performances reasons when in 16x16
496 * - 32x8 block size + SPLIT is mandatory with 4K frame size
497 * for performances reasons
499 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
500 AFBC_FORMAT_MOD_SPARSE
|
501 AFBC_FORMAT_MOD_SPLIT
),
502 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
503 AFBC_FORMAT_MOD_YTR
|
504 AFBC_FORMAT_MOD_SPARSE
|
505 AFBC_FORMAT_MOD_SPLIT
),
506 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
|
507 AFBC_FORMAT_MOD_SPARSE
),
508 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
|
509 AFBC_FORMAT_MOD_YTR
|
510 AFBC_FORMAT_MOD_SPARSE
),
511 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
|
512 AFBC_FORMAT_MOD_SPARSE
|
513 AFBC_FORMAT_MOD_SPLIT
),
514 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8
|
515 AFBC_FORMAT_MOD_YTR
|
516 AFBC_FORMAT_MOD_SPARSE
|
517 AFBC_FORMAT_MOD_SPLIT
),
518 DRM_FORMAT_MOD_LINEAR
,
519 DRM_FORMAT_MOD_INVALID
,
522 static const uint64_t format_modifiers_default
[] = {
523 DRM_FORMAT_MOD_LINEAR
,
524 DRM_FORMAT_MOD_INVALID
,
527 int meson_plane_create(struct meson_drm
*priv
)
529 struct meson_plane
*meson_plane
;
530 struct drm_plane
*plane
;
531 const uint64_t *format_modifiers
= format_modifiers_default
;
533 meson_plane
= devm_kzalloc(priv
->drm
->dev
, sizeof(*meson_plane
),
538 meson_plane
->priv
= priv
;
539 plane
= &meson_plane
->base
;
541 if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_GXM
))
542 format_modifiers
= format_modifiers_afbc_gxm
;
543 else if (meson_vpu_is_compatible(priv
, VPU_COMPATIBLE_G12A
))
544 format_modifiers
= format_modifiers_afbc_g12a
;
546 drm_universal_plane_init(priv
->drm
, plane
, 0xFF,
548 supported_drm_formats
,
549 ARRAY_SIZE(supported_drm_formats
),
551 DRM_PLANE_TYPE_PRIMARY
, "meson_primary_plane");
553 drm_plane_helper_add(plane
, &meson_plane_helper_funcs
);
555 /* For now, OSD Primary plane is always on the front */
556 drm_plane_create_zpos_immutable_property(plane
, 1);
558 priv
->primary_plane
= plane
;