drm: Rename plane atomic_check state names
[sfrench/cifs-2.6.git] / drivers / gpu / drm / meson / meson_plane.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
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
7  *
8  * Written by:
9  *     Jasper St. Pierre <jstpierre@mecheye.net>
10  */
11
12 #include <linux/bitfield.h>
13
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_atomic_helper.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_plane_helper.h>
22
23 #include "meson_plane.h"
24 #include "meson_registers.h"
25 #include "meson_viu.h"
26 #include "meson_osd_afbcd.h"
27
28 /* OSD_SCI_WH_M1 */
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)
31
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)
36
37 /* OSD_SC_CTRL0 */
38 #define SC_CTRL0_PATH_EN                BIT(3)
39 #define SC_CTRL0_SEL_OSD1               BIT(2)
40
41 /* OSD_VSC_CTRL0 */
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)
49
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)
53
54 /* OSD_HSC_CTRL0 */
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)
59
60 /* VPP_OSD_VSC_PHASE_STEP */
61 /* VPP_OSD_HSC_PHASE_STEP */
62 #define SC_PHASE_STEP(value)            FIELD_PREP(GENMASK(27, 0), value)
63
64 struct meson_plane {
65         struct drm_plane base;
66         struct meson_drm *priv;
67         bool enabled;
68 };
69 #define to_meson_plane(x) container_of(x, struct meson_plane, base)
70
71 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
72
73 static int meson_plane_atomic_check(struct drm_plane *plane,
74                                     struct drm_plane_state *new_plane_state)
75 {
76         struct drm_crtc_state *crtc_state;
77
78         if (!new_plane_state->crtc)
79                 return 0;
80
81         crtc_state = drm_atomic_get_crtc_state(new_plane_state->state,
82                                                new_plane_state->crtc);
83         if (IS_ERR(crtc_state))
84                 return PTR_ERR(crtc_state);
85
86         /*
87          * Only allow :
88          * - Upscaling up to 5x, vertical and horizontal
89          * - Final coordinates must match crtc size
90          */
91         return drm_atomic_helper_check_plane_state(new_plane_state,
92                                                    crtc_state,
93                                                    FRAC_16_16(1, 5),
94                                                    DRM_PLANE_HELPER_NO_SCALING,
95                                                    false, true);
96 }
97
98 #define MESON_MOD_AFBC_VALID_BITS (AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |   \
99                                    AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |    \
100                                    AFBC_FORMAT_MOD_YTR |                \
101                                    AFBC_FORMAT_MOD_SPARSE |             \
102                                    AFBC_FORMAT_MOD_SPLIT)
103
104 /* Takes a fixed 16.16 number and converts it to integer. */
105 static inline int64_t fixed16_to_int(int64_t value)
106 {
107         return value >> 16;
108 }
109
110 static u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv)
111 {
112         u32 line_stride = 0;
113
114         switch (priv->afbcd.format) {
115         case DRM_FORMAT_RGB565:
116                 line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7;
117                 break;
118         case DRM_FORMAT_RGB888:
119         case DRM_FORMAT_XRGB8888:
120         case DRM_FORMAT_ARGB8888:
121         case DRM_FORMAT_XBGR8888:
122         case DRM_FORMAT_ABGR8888:
123                 line_stride = ((priv->viu.osd1_width << 5) + 127) >> 7;
124                 break;
125         }
126
127         return ((line_stride + 1) >> 1) << 1;
128 }
129
130 static void meson_plane_atomic_update(struct drm_plane *plane,
131                                       struct drm_plane_state *old_state)
132 {
133         struct meson_plane *meson_plane = to_meson_plane(plane);
134         struct drm_plane_state *state = plane->state;
135         struct drm_rect dest = drm_plane_state_dest(state);
136         struct meson_drm *priv = meson_plane->priv;
137         struct drm_framebuffer *fb = state->fb;
138         struct drm_gem_cma_object *gem;
139         unsigned long flags;
140         int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
141         int vsc_bot_rcv_num, vsc_bot_rpt_p0_num;
142         int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
143         int hf_phase_step, vf_phase_step;
144         int src_w, src_h, dst_w, dst_h;
145         int bot_ini_phase;
146         int hf_bank_len;
147         int vf_bank_len;
148         u8 canvas_id_osd1;
149
150         /*
151          * Update Coordinates
152          * Update Formats
153          * Update Buffer
154          * Enable Plane
155          */
156         spin_lock_irqsave(&priv->drm->event_lock, flags);
157
158         /* Check if AFBC decoder is required for this buffer */
159         if ((meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
160              meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) &&
161             fb->modifier & DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS))
162                 priv->viu.osd1_afbcd = true;
163         else
164                 priv->viu.osd1_afbcd = false;
165
166         /* Enable OSD and BLK0, set max global alpha */
167         priv->viu.osd1_ctrl_stat = OSD_ENABLE |
168                                    (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
169                                    OSD_BLK0_ENABLE;
170
171         priv->viu.osd1_ctrl_stat2 = readl(priv->io_base +
172                                           _REG(VIU_OSD1_CTRL_STAT2));
173
174         canvas_id_osd1 = priv->canvas_id_osd1;
175
176         /* Set up BLK0 to point to the right canvas */
177         priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL;
178
179         if (priv->viu.osd1_afbcd) {
180                 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
181                         /* This is the internal decoding memory address */
182                         priv->viu.osd1_blk1_cfg4 = MESON_G12A_AFBCD_OUT_ADDR;
183                         priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_BE;
184                         priv->viu.osd1_ctrl_stat2 |= OSD_PENDING_STAT_CLEAN;
185                         priv->viu.osd1_ctrl_stat |= VIU_OSD1_CFG_SYN_EN;
186                 }
187
188                 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
189                         priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE;
190                         priv->viu.osd1_ctrl_stat2 |= OSD_DPATH_MALI_AFBCD;
191                 }
192         } else {
193                 priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE;
194
195                 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
196                         priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD;
197         }
198
199         /* On GXBB, Use the old non-HDR RGB2YUV converter */
200         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
201                 priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
202
203         if (priv->viu.osd1_afbcd &&
204             meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
205                 priv->viu.osd1_blk0_cfg[0] |= OSD_MALI_SRC_EN |
206                         priv->afbcd.ops->fmt_to_blk_mode(fb->modifier,
207                                                           fb->format->format);
208         } else {
209                 switch (fb->format->format) {
210                 case DRM_FORMAT_XRGB8888:
211                 case DRM_FORMAT_ARGB8888:
212                         priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
213                                                 OSD_COLOR_MATRIX_32_ARGB;
214                         break;
215                 case DRM_FORMAT_XBGR8888:
216                 case DRM_FORMAT_ABGR8888:
217                         priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 |
218                                                 OSD_COLOR_MATRIX_32_ABGR;
219                         break;
220                 case DRM_FORMAT_RGB888:
221                         priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 |
222                                                 OSD_COLOR_MATRIX_24_RGB;
223                         break;
224                 case DRM_FORMAT_RGB565:
225                         priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 |
226                                                 OSD_COLOR_MATRIX_16_RGB565;
227                         break;
228                 }
229         }
230
231         switch (fb->format->format) {
232         case DRM_FORMAT_XRGB8888:
233         case DRM_FORMAT_XBGR8888:
234                 /* For XRGB, replace the pixel's alpha by 0xFF */
235                 priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN;
236                 break;
237         case DRM_FORMAT_ARGB8888:
238         case DRM_FORMAT_ABGR8888:
239                 /* For ARGB, use the pixel's alpha */
240                 priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN;
241                 break;
242         }
243
244         /* Default scaler parameters */
245         vsc_bot_rcv_num = 0;
246         vsc_bot_rpt_p0_num = 0;
247         hf_bank_len = 4;
248         vf_bank_len = 4;
249
250         if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
251                 vsc_bot_rcv_num = 6;
252                 vsc_bot_rpt_p0_num = 2;
253         }
254
255         hsc_ini_rcv_num = hf_bank_len;
256         vsc_ini_rcv_num = vf_bank_len;
257         hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1;
258         vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1;
259
260         src_w = fixed16_to_int(state->src_w);
261         src_h = fixed16_to_int(state->src_h);
262         dst_w = state->crtc_w;
263         dst_h = state->crtc_h;
264
265         /*
266          * When the output is interlaced, the OSD must switch between
267          * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
268          * at each vsync.
269          * But the vertical scaler can provide such funtionnality if
270          * is configured for 2:1 scaling with interlace options enabled.
271          */
272         if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
273                 dest.y1 /= 2;
274                 dest.y2 /= 2;
275                 dst_h /= 2;
276         }
277
278         hf_phase_step = ((src_w << 18) / dst_w) << 6;
279         vf_phase_step = (src_h << 20) / dst_h;
280
281         if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
282                 bot_ini_phase = ((vf_phase_step / 2) >> 4);
283         else
284                 bot_ini_phase = 0;
285
286         vf_phase_step = (vf_phase_step << 4);
287
288         /* In interlaced mode, scaler is always active */
289         if (src_h != dst_h || src_w != dst_w) {
290                 priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) |
291                                            SCI_WH_M1_H(src_h - 1);
292                 priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) |
293                                                  SCO_HV_END(dest.x2 - 1);
294                 priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) |
295                                                  SCO_HV_END(dest.y2 - 1);
296                 /* Enable OSD Scaler */
297                 priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1;
298         } else {
299                 priv->viu.osd_sc_i_wh_m1 = 0;
300                 priv->viu.osd_sc_o_h_start_end = 0;
301                 priv->viu.osd_sc_o_v_start_end = 0;
302                 priv->viu.osd_sc_ctrl0 = 0;
303         }
304
305         /* In interlaced mode, vertical scaler is always active */
306         if (src_h != dst_h) {
307                 priv->viu.osd_sc_v_ctrl0 =
308                                         VSC_BANK_LEN(vf_bank_len) |
309                                         VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) |
310                                         VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) |
311                                         VSC_VERTICAL_SCALER_EN;
312
313                 if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
314                         priv->viu.osd_sc_v_ctrl0 |=
315                                         VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) |
316                                         VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) |
317                                         VSC_PROG_INTERLACE;
318
319                 priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step);
320                 priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase);
321         } else {
322                 priv->viu.osd_sc_v_ctrl0 = 0;
323                 priv->viu.osd_sc_v_phase_step = 0;
324                 priv->viu.osd_sc_v_ini_phase = 0;
325         }
326
327         /* Horizontal scaler is only used if width does not match */
328         if (src_w != dst_w) {
329                 priv->viu.osd_sc_h_ctrl0 =
330                                         HSC_BANK_LENGTH(hf_bank_len) |
331                                         HSC_INI_RCV_NUM0(hsc_ini_rcv_num) |
332                                         HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) |
333                                         HSC_HORIZ_SCALER_EN;
334                 priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step);
335                 priv->viu.osd_sc_h_ini_phase = 0;
336         } else {
337                 priv->viu.osd_sc_h_ctrl0 = 0;
338                 priv->viu.osd_sc_h_phase_step = 0;
339                 priv->viu.osd_sc_h_ini_phase = 0;
340         }
341
342         /*
343          * The format of these registers is (x2 << 16 | x1),
344          * where x2 is exclusive.
345          * e.g. +30x1920 would be (1919 << 16) | 30
346          */
347         priv->viu.osd1_blk0_cfg[1] =
348                                 ((fixed16_to_int(state->src.x2) - 1) << 16) |
349                                 fixed16_to_int(state->src.x1);
350         priv->viu.osd1_blk0_cfg[2] =
351                                 ((fixed16_to_int(state->src.y2) - 1) << 16) |
352                                 fixed16_to_int(state->src.y1);
353         priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
354         priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
355
356         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
357                 priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1;
358                 priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1;
359                 priv->viu.osb_blend0_size = dst_h << 16 | dst_w;
360                 priv->viu.osb_blend1_size = dst_h << 16 | dst_w;
361         }
362
363         /* Update Canvas with buffer address */
364         gem = drm_fb_cma_get_gem_obj(fb, 0);
365
366         priv->viu.osd1_addr = gem->paddr;
367         priv->viu.osd1_stride = fb->pitches[0];
368         priv->viu.osd1_height = fb->height;
369         priv->viu.osd1_width = fb->width;
370
371         if (priv->viu.osd1_afbcd) {
372                 priv->afbcd.modifier = fb->modifier;
373                 priv->afbcd.format = fb->format->format;
374
375                 /* Calculate decoder write stride */
376                 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
377                         priv->viu.osd1_blk2_cfg4 =
378                                 meson_g12a_afbcd_line_stride(priv);
379         }
380
381         if (!meson_plane->enabled) {
382                 /* Reset OSD1 before enabling it on GXL+ SoCs */
383                 if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
384                     meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
385                         meson_viu_osd1_reset(priv);
386
387                 meson_plane->enabled = true;
388         }
389
390         priv->viu.osd1_enabled = true;
391
392         spin_unlock_irqrestore(&priv->drm->event_lock, flags);
393 }
394
395 static void meson_plane_atomic_disable(struct drm_plane *plane,
396                                        struct drm_plane_state *old_state)
397 {
398         struct meson_plane *meson_plane = to_meson_plane(plane);
399         struct meson_drm *priv = meson_plane->priv;
400
401         if (priv->afbcd.ops) {
402                 priv->afbcd.ops->reset(priv);
403                 priv->afbcd.ops->disable(priv);
404         }
405
406         /* Disable OSD1 */
407         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
408                 writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0,
409                                     priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
410         else
411                 writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
412                                     priv->io_base + _REG(VPP_MISC));
413
414         meson_plane->enabled = false;
415         priv->viu.osd1_enabled = false;
416 }
417
418 static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
419         .atomic_check   = meson_plane_atomic_check,
420         .atomic_disable = meson_plane_atomic_disable,
421         .atomic_update  = meson_plane_atomic_update,
422         .prepare_fb     = drm_gem_plane_helper_prepare_fb,
423 };
424
425 static bool meson_plane_format_mod_supported(struct drm_plane *plane,
426                                              u32 format, u64 modifier)
427 {
428         struct meson_plane *meson_plane = to_meson_plane(plane);
429         struct meson_drm *priv = meson_plane->priv;
430         int i;
431
432         if (modifier == DRM_FORMAT_MOD_INVALID)
433                 return false;
434
435         if (modifier == DRM_FORMAT_MOD_LINEAR)
436                 return true;
437
438         if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) &&
439             !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
440                 return false;
441
442         if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS))
443                 return false;
444
445         for (i = 0 ; i < plane->modifier_count ; ++i)
446                 if (plane->modifiers[i] == modifier)
447                         break;
448
449         if (i == plane->modifier_count) {
450                 DRM_DEBUG_KMS("Unsupported modifier\n");
451                 return false;
452         }
453
454         if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt)
455                 return priv->afbcd.ops->supported_fmt(modifier, format);
456
457         DRM_DEBUG_KMS("AFBC Unsupported\n");
458         return false;
459 }
460
461 static const struct drm_plane_funcs meson_plane_funcs = {
462         .update_plane           = drm_atomic_helper_update_plane,
463         .disable_plane          = drm_atomic_helper_disable_plane,
464         .destroy                = drm_plane_cleanup,
465         .reset                  = drm_atomic_helper_plane_reset,
466         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
467         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
468         .format_mod_supported   = meson_plane_format_mod_supported,
469 };
470
471 static const uint32_t supported_drm_formats[] = {
472         DRM_FORMAT_ARGB8888,
473         DRM_FORMAT_ABGR8888,
474         DRM_FORMAT_XRGB8888,
475         DRM_FORMAT_XBGR8888,
476         DRM_FORMAT_RGB888,
477         DRM_FORMAT_RGB565,
478 };
479
480 static const uint64_t format_modifiers_afbc_gxm[] = {
481         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
482                                 AFBC_FORMAT_MOD_SPARSE |
483                                 AFBC_FORMAT_MOD_YTR),
484         /* SPLIT mandates SPARSE, RGB modes mandates YTR */
485         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
486                                 AFBC_FORMAT_MOD_YTR |
487                                 AFBC_FORMAT_MOD_SPARSE |
488                                 AFBC_FORMAT_MOD_SPLIT),
489         DRM_FORMAT_MOD_LINEAR,
490         DRM_FORMAT_MOD_INVALID,
491 };
492
493 static const uint64_t format_modifiers_afbc_g12a[] = {
494         /*
495          * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED)
496          * - SPLIT is mandatory for performances reasons when in 16x16
497          *   block size
498          * - 32x8 block size + SPLIT is mandatory with 4K frame size
499          *   for performances reasons
500          */
501         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
502                                 AFBC_FORMAT_MOD_SPARSE |
503                                 AFBC_FORMAT_MOD_SPLIT),
504         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
505                                 AFBC_FORMAT_MOD_YTR |
506                                 AFBC_FORMAT_MOD_SPARSE |
507                                 AFBC_FORMAT_MOD_SPLIT),
508         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
509                                 AFBC_FORMAT_MOD_SPARSE),
510         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
511                                 AFBC_FORMAT_MOD_YTR |
512                                 AFBC_FORMAT_MOD_SPARSE),
513         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
514                                 AFBC_FORMAT_MOD_SPARSE |
515                                 AFBC_FORMAT_MOD_SPLIT),
516         DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
517                                 AFBC_FORMAT_MOD_YTR |
518                                 AFBC_FORMAT_MOD_SPARSE |
519                                 AFBC_FORMAT_MOD_SPLIT),
520         DRM_FORMAT_MOD_LINEAR,
521         DRM_FORMAT_MOD_INVALID,
522 };
523
524 static const uint64_t format_modifiers_default[] = {
525         DRM_FORMAT_MOD_LINEAR,
526         DRM_FORMAT_MOD_INVALID,
527 };
528
529 int meson_plane_create(struct meson_drm *priv)
530 {
531         struct meson_plane *meson_plane;
532         struct drm_plane *plane;
533         const uint64_t *format_modifiers = format_modifiers_default;
534
535         meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
536                                    GFP_KERNEL);
537         if (!meson_plane)
538                 return -ENOMEM;
539
540         meson_plane->priv = priv;
541         plane = &meson_plane->base;
542
543         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
544                 format_modifiers = format_modifiers_afbc_gxm;
545         else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
546                 format_modifiers = format_modifiers_afbc_g12a;
547
548         drm_universal_plane_init(priv->drm, plane, 0xFF,
549                                  &meson_plane_funcs,
550                                  supported_drm_formats,
551                                  ARRAY_SIZE(supported_drm_formats),
552                                  format_modifiers,
553                                  DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
554
555         drm_plane_helper_add(plane, &meson_plane_helper_funcs);
556
557         /* For now, OSD Primary plane is always on the front */
558         drm_plane_create_zpos_immutable_property(plane, 1);
559
560         priv->primary_plane = plane;
561
562         return 0;
563 }