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