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