Commit | Line | Data |
---|---|---|
1ccea77e | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
bbbe775e NA |
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 | * | |
bbbe775e NA |
8 | * Written by: |
9 | * Jasper St. Pierre <jstpierre@mecheye.net> | |
10 | */ | |
11 | ||
7db647aa | 12 | #include <linux/bitfield.h> |
66620f48 | 13 | |
bbbe775e NA |
14 | #include <drm/drm_atomic.h> |
15 | #include <drm/drm_atomic_helper.h> | |
66620f48 | 16 | #include <drm/drm_device.h> |
bbbe775e | 17 | #include <drm/drm_fb_cma_helper.h> |
66620f48 SR |
18 | #include <drm/drm_fourcc.h> |
19 | #include <drm/drm_gem_cma_helper.h> | |
42843dc2 | 20 | #include <drm/drm_gem_framebuffer_helper.h> |
66620f48 | 21 | #include <drm/drm_plane_helper.h> |
bbbe775e NA |
22 | |
23 | #include "meson_plane.h" | |
bbbe775e | 24 | #include "meson_registers.h" |
66620f48 | 25 | #include "meson_viu.h" |
68e2f64e | 26 | #include "meson_osd_afbcd.h" |
bbbe775e | 27 | |
7db647aa NA |
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 | ||
bbbe775e NA |
64 | struct meson_plane { |
65 | struct drm_plane base; | |
66 | struct meson_drm *priv; | |
3a936bc2 | 67 | bool enabled; |
bbbe775e NA |
68 | }; |
69 | #define to_meson_plane(x) container_of(x, struct meson_plane, base) | |
70 | ||
7db647aa NA |
71 | #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) |
72 | ||
bbbe775e NA |
73 | static int meson_plane_atomic_check(struct drm_plane *plane, |
74 | struct drm_plane_state *state) | |
75 | { | |
76 | struct drm_crtc_state *crtc_state; | |
bbbe775e | 77 | |
dcafc45d NA |
78 | if (!state->crtc) |
79 | return 0; | |
80 | ||
bbbe775e NA |
81 | crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); |
82 | if (IS_ERR(crtc_state)) | |
83 | return PTR_ERR(crtc_state); | |
84 | ||
7db647aa NA |
85 | /* |
86 | * Only allow : | |
87 | * - Upscaling up to 5x, vertical and horizontal | |
88 | * - Final coordinates must match crtc size | |
89 | */ | |
81af63a4 | 90 | return drm_atomic_helper_check_plane_state(state, crtc_state, |
7db647aa | 91 | FRAC_16_16(1, 5), |
a01cb8ba | 92 | DRM_PLANE_HELPER_NO_SCALING, |
7db647aa | 93 | false, true); |
bbbe775e NA |
94 | } |
95 | ||
68e2f64e NA |
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) | |
101 | ||
bbbe775e NA |
102 | /* Takes a fixed 16.16 number and converts it to integer. */ |
103 | static inline int64_t fixed16_to_int(int64_t value) | |
104 | { | |
105 | return value >> 16; | |
106 | } | |
107 | ||
68e2f64e NA |
108 | static u32 meson_g12a_afbcd_line_stride(struct meson_drm *priv) |
109 | { | |
110 | u32 line_stride = 0; | |
111 | ||
112 | switch (priv->afbcd.format) { | |
113 | case DRM_FORMAT_RGB565: | |
114 | line_stride = ((priv->viu.osd1_width << 4) + 127) >> 7; | |
115 | break; | |
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; | |
122 | break; | |
123 | } | |
124 | ||
125 | return ((line_stride + 1) >> 1) << 1; | |
126 | } | |
127 | ||
bbbe775e NA |
128 | static void meson_plane_atomic_update(struct drm_plane *plane, |
129 | struct drm_plane_state *old_state) | |
130 | { | |
131 | struct meson_plane *meson_plane = to_meson_plane(plane); | |
132 | struct drm_plane_state *state = plane->state; | |
7db647aa | 133 | struct drm_rect dest = drm_plane_state_dest(state); |
bbbe775e | 134 | struct meson_drm *priv = meson_plane->priv; |
7db647aa | 135 | struct drm_framebuffer *fb = state->fb; |
bbbe775e | 136 | struct drm_gem_cma_object *gem; |
bbbe775e | 137 | unsigned long flags; |
7db647aa NA |
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; | |
143 | int bot_ini_phase; | |
144 | int hf_bank_len; | |
145 | int vf_bank_len; | |
66cae477 | 146 | u8 canvas_id_osd1; |
bbbe775e NA |
147 | |
148 | /* | |
149 | * Update Coordinates | |
150 | * Update Formats | |
151 | * Update Buffer | |
152 | * Enable Plane | |
153 | */ | |
154 | spin_lock_irqsave(&priv->drm->event_lock, flags); | |
155 | ||
68e2f64e NA |
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; | |
161 | else | |
162 | priv->viu.osd1_afbcd = false; | |
163 | ||
bbbe775e NA |
164 | /* Enable OSD and BLK0, set max global alpha */ |
165 | priv->viu.osd1_ctrl_stat = OSD_ENABLE | | |
166 | (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | | |
167 | OSD_BLK0_ENABLE; | |
168 | ||
68e2f64e NA |
169 | priv->viu.osd1_ctrl_stat2 = readl(priv->io_base + |
170 | _REG(VIU_OSD1_CTRL_STAT2)); | |
171 | ||
2bf6b5b0 | 172 | canvas_id_osd1 = priv->canvas_id_osd1; |
66cae477 | 173 | |
bbbe775e | 174 | /* Set up BLK0 to point to the right canvas */ |
68e2f64e NA |
175 | priv->viu.osd1_blk0_cfg[0] = canvas_id_osd1 << OSD_CANVAS_SEL; |
176 | ||
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; | |
184 | } | |
185 | ||
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; | |
189 | } | |
190 | } else { | |
191 | priv->viu.osd1_blk0_cfg[0] |= OSD_ENDIANNESS_LE; | |
192 | ||
193 | if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) | |
194 | priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD; | |
195 | } | |
bbbe775e NA |
196 | |
197 | /* On GXBB, Use the old non-HDR RGB2YUV converter */ | |
528a25d0 | 198 | if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) |
bbbe775e NA |
199 | priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; |
200 | ||
68e2f64e NA |
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, | |
205 | fb->format->format); | |
206 | } else { | |
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; | |
212 | break; | |
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; | |
217 | break; | |
218 | case DRM_FORMAT_RGB888: | |
219 | priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | | |
220 | OSD_COLOR_MATRIX_24_RGB; | |
221 | break; | |
222 | case DRM_FORMAT_RGB565: | |
223 | priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_16 | | |
224 | OSD_COLOR_MATRIX_16_RGB565; | |
225 | break; | |
439c2787 | 226 | } |
68e2f64e NA |
227 | } |
228 | ||
438b74a5 | 229 | switch (fb->format->format) { |
bbbe775e | 230 | case DRM_FORMAT_XRGB8888: |
5ffff441 NA |
231 | case DRM_FORMAT_XBGR8888: |
232 | /* For XRGB, replace the pixel's alpha by 0xFF */ | |
68e2f64e | 233 | priv->viu.osd1_ctrl_stat2 |= OSD_REPLACE_EN; |
5ffff441 | 234 | break; |
bbbe775e | 235 | case DRM_FORMAT_ARGB8888: |
5ffff441 NA |
236 | case DRM_FORMAT_ABGR8888: |
237 | /* For ARGB, use the pixel's alpha */ | |
68e2f64e | 238 | priv->viu.osd1_ctrl_stat2 &= ~OSD_REPLACE_EN; |
bbbe775e | 239 | break; |
3eaf8912 | 240 | } |
bbbe775e | 241 | |
7db647aa NA |
242 | /* Default scaler parameters */ |
243 | vsc_bot_rcv_num = 0; | |
244 | vsc_bot_rpt_p0_num = 0; | |
245 | hf_bank_len = 4; | |
246 | vf_bank_len = 4; | |
247 | ||
248 | if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { | |
249 | vsc_bot_rcv_num = 6; | |
250 | vsc_bot_rpt_p0_num = 2; | |
251 | } | |
252 | ||
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; | |
257 | ||
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; | |
262 | ||
20d7fe03 NA |
263 | /* |
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 | |
266 | * at each vsync. | |
267 | * But the vertical scaler can provide such funtionnality if | |
268 | * is configured for 2:1 scaling with interlace options enabled. | |
269 | */ | |
bbbe775e | 270 | if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) { |
bbbe775e NA |
271 | dest.y1 /= 2; |
272 | dest.y2 /= 2; | |
7db647aa NA |
273 | dst_h /= 2; |
274 | } | |
275 | ||
276 | hf_phase_step = ((src_w << 18) / dst_w) << 6; | |
277 | vf_phase_step = (src_h << 20) / dst_h; | |
278 | ||
279 | if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) | |
280 | bot_ini_phase = ((vf_phase_step / 2) >> 4); | |
281 | else | |
282 | bot_ini_phase = 0; | |
20d7fe03 | 283 | |
7db647aa | 284 | vf_phase_step = (vf_phase_step << 4); |
20d7fe03 | 285 | |
7db647aa NA |
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; | |
296 | } else { | |
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; | |
301 | } | |
20d7fe03 | 302 | |
7db647aa NA |
303 | /* In interlaced mode, vertical scaler is always active */ |
304 | if (src_h != dst_h) { | |
20d7fe03 | 305 | priv->viu.osd_sc_v_ctrl0 = |
7db647aa NA |
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; | |
310 | ||
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) | | |
315 | VSC_PROG_INTERLACE; | |
316 | ||
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); | |
319 | } else { | |
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; | |
323 | } | |
324 | ||
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) | | |
331 | HSC_HORIZ_SCALER_EN; | |
332 | priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step); | |
20d7fe03 | 333 | priv->viu.osd_sc_h_ini_phase = 0; |
20d7fe03 | 334 | } else { |
20d7fe03 | 335 | priv->viu.osd_sc_h_ctrl0 = 0; |
7db647aa NA |
336 | priv->viu.osd_sc_h_phase_step = 0; |
337 | priv->viu.osd_sc_h_ini_phase = 0; | |
20d7fe03 | 338 | } |
bbbe775e NA |
339 | |
340 | /* | |
341 | * The format of these registers is (x2 << 16 | x1), | |
342 | * where x2 is exclusive. | |
343 | * e.g. +30x1920 would be (1919 << 16) | 30 | |
344 | */ | |
7db647aa NA |
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); | |
bbbe775e NA |
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; | |
353 | ||
528a25d0 | 354 | if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { |
490f50c1 NA |
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; | |
359 | } | |
360 | ||
bbbe775e NA |
361 | /* Update Canvas with buffer address */ |
362 | gem = drm_fb_cma_get_gem_obj(fb, 0); | |
363 | ||
e88230a3 NA |
364 | priv->viu.osd1_addr = gem->paddr; |
365 | priv->viu.osd1_stride = fb->pitches[0]; | |
366 | priv->viu.osd1_height = fb->height; | |
ce7cb472 | 367 | priv->viu.osd1_width = fb->width; |
bbbe775e | 368 | |
68e2f64e NA |
369 | if (priv->viu.osd1_afbcd) { |
370 | priv->afbcd.modifier = fb->modifier; | |
371 | priv->afbcd.format = fb->format->format; | |
372 | ||
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); | |
377 | } | |
378 | ||
3a936bc2 NA |
379 | if (!meson_plane->enabled) { |
380 | /* Reset OSD1 before enabling it on GXL+ SoCs */ | |
528a25d0 JM |
381 | if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) || |
382 | meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) | |
3a936bc2 NA |
383 | meson_viu_osd1_reset(priv); |
384 | ||
385 | meson_plane->enabled = true; | |
386 | } | |
387 | ||
c03ea50e NA |
388 | priv->viu.osd1_enabled = true; |
389 | ||
bbbe775e NA |
390 | spin_unlock_irqrestore(&priv->drm->event_lock, flags); |
391 | } | |
392 | ||
393 | static void meson_plane_atomic_disable(struct drm_plane *plane, | |
394 | struct drm_plane_state *old_state) | |
395 | { | |
396 | struct meson_plane *meson_plane = to_meson_plane(plane); | |
397 | struct meson_drm *priv = meson_plane->priv; | |
398 | ||
68e2f64e NA |
399 | if (priv->afbcd.ops) { |
400 | priv->afbcd.ops->reset(priv); | |
401 | priv->afbcd.ops->disable(priv); | |
402 | } | |
403 | ||
bbbe775e | 404 | /* Disable OSD1 */ |
528a25d0 | 405 | if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) |
147ae1cb | 406 | writel_bits_relaxed(VIU_OSD1_POSTBLD_SRC_OSD1, 0, |
0b84933d | 407 | priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); |
490f50c1 NA |
408 | else |
409 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, | |
410 | priv->io_base + _REG(VPP_MISC)); | |
bbbe775e | 411 | |
3a936bc2 | 412 | meson_plane->enabled = false; |
c03ea50e | 413 | priv->viu.osd1_enabled = false; |
bbbe775e NA |
414 | } |
415 | ||
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, | |
42843dc2 | 420 | .prepare_fb = drm_gem_fb_prepare_fb, |
bbbe775e NA |
421 | }; |
422 | ||
68e2f64e NA |
423 | static bool meson_plane_format_mod_supported(struct drm_plane *plane, |
424 | u32 format, u64 modifier) | |
425 | { | |
426 | struct meson_plane *meson_plane = to_meson_plane(plane); | |
427 | struct meson_drm *priv = meson_plane->priv; | |
428 | int i; | |
429 | ||
430 | if (modifier == DRM_FORMAT_MOD_INVALID) | |
431 | return false; | |
432 | ||
433 | if (modifier == DRM_FORMAT_MOD_LINEAR) | |
434 | return true; | |
435 | ||
436 | if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) && | |
437 | !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) | |
438 | return false; | |
439 | ||
440 | if (modifier & ~DRM_FORMAT_MOD_ARM_AFBC(MESON_MOD_AFBC_VALID_BITS)) | |
441 | return false; | |
442 | ||
443 | for (i = 0 ; i < plane->modifier_count ; ++i) | |
444 | if (plane->modifiers[i] == modifier) | |
445 | break; | |
446 | ||
447 | if (i == plane->modifier_count) { | |
448 | DRM_DEBUG_KMS("Unsupported modifier\n"); | |
449 | return false; | |
450 | } | |
451 | ||
452 | if (priv->afbcd.ops && priv->afbcd.ops->supported_fmt) | |
453 | return priv->afbcd.ops->supported_fmt(modifier, format); | |
454 | ||
455 | DRM_DEBUG_KMS("AFBC Unsupported\n"); | |
456 | return false; | |
457 | } | |
458 | ||
bbbe775e NA |
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, | |
68e2f64e | 466 | .format_mod_supported = meson_plane_format_mod_supported, |
bbbe775e NA |
467 | }; |
468 | ||
469 | static const uint32_t supported_drm_formats[] = { | |
470 | DRM_FORMAT_ARGB8888, | |
5ffff441 | 471 | DRM_FORMAT_ABGR8888, |
bbbe775e | 472 | DRM_FORMAT_XRGB8888, |
5ffff441 | 473 | DRM_FORMAT_XBGR8888, |
bbbe775e NA |
474 | DRM_FORMAT_RGB888, |
475 | DRM_FORMAT_RGB565, | |
476 | }; | |
477 | ||
68e2f64e NA |
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, | |
489 | }; | |
490 | ||
491 | static const uint64_t format_modifiers_afbc_g12a[] = { | |
492 | /* | |
493 | * - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED) | |
494 | * - SPLIT is mandatory for performances reasons when in 16x16 | |
495 | * block size | |
496 | * - 32x8 block size + SPLIT is mandatory with 4K frame size | |
497 | * for performances reasons | |
498 | */ | |
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, | |
520 | }; | |
521 | ||
522 | static const uint64_t format_modifiers_default[] = { | |
523 | DRM_FORMAT_MOD_LINEAR, | |
524 | DRM_FORMAT_MOD_INVALID, | |
525 | }; | |
526 | ||
bbbe775e NA |
527 | int meson_plane_create(struct meson_drm *priv) |
528 | { | |
529 | struct meson_plane *meson_plane; | |
530 | struct drm_plane *plane; | |
68e2f64e | 531 | const uint64_t *format_modifiers = format_modifiers_default; |
bbbe775e NA |
532 | |
533 | meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane), | |
534 | GFP_KERNEL); | |
535 | if (!meson_plane) | |
536 | return -ENOMEM; | |
537 | ||
538 | meson_plane->priv = priv; | |
539 | plane = &meson_plane->base; | |
540 | ||
68e2f64e NA |
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; | |
545 | ||
bbbe775e NA |
546 | drm_universal_plane_init(priv->drm, plane, 0xFF, |
547 | &meson_plane_funcs, | |
548 | supported_drm_formats, | |
549 | ARRAY_SIZE(supported_drm_formats), | |
68e2f64e | 550 | format_modifiers, |
bbbe775e NA |
551 | DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); |
552 | ||
553 | drm_plane_helper_add(plane, &meson_plane_helper_funcs); | |
554 | ||
fd311d88 NA |
555 | /* For now, OSD Primary plane is always on the front */ |
556 | drm_plane_create_zpos_immutable_property(plane, 1); | |
557 | ||
bbbe775e NA |
558 | priv->primary_plane = plane; |
559 | ||
560 | return 0; | |
561 | } |