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 | |
9 | #include <linux/export.h> |
10 | #include <linux/bitfield.h> |
11 | |
12 | #include <drm/drm_fourcc.h> |
13 | |
14 | #include "meson_drv.h" |
15 | #include "meson_viu.h" |
16 | #include "meson_registers.h" |
17 | |
18 | /** |
19 | * DOC: Video Input Unit |
20 | * |
21 | * VIU Handles the Pixel scanout and the basic Colorspace conversions |
22 | * We handle the following features : |
23 | * |
24 | * - OSD1 RGB565/RGB888/xRGB8888 scanout |
25 | * - RGB conversion to x/cb/cr |
26 | * - Progressive or Interlace buffer scanout |
27 | * - OSD1 Commit on Vsync |
28 | * - HDR OSD matrix for GXL/GXM |
29 | * |
30 | * What is missing : |
31 | * |
32 | * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes |
33 | * - YUV4:2:2 Y0CbY1Cr scanout |
34 | * - Conversion to YUV 4:4:4 from 4:2:2 input |
35 | * - Colorkey Alpha matching |
36 | * - Big endian scanout |
37 | * - X/Y reverse scanout |
38 | * - Global alpha setup |
39 | * - OSD2 support, would need interlace switching on vsync |
40 | * - OSD1 full scaling to support TV overscan |
41 | */ |
42 | |
43 | /* OSD csc defines */ |
44 | |
45 | enum viu_matrix_sel_e { |
46 | VIU_MATRIX_OSD_EOTF = 0, |
47 | VIU_MATRIX_OSD, |
48 | }; |
49 | |
50 | enum viu_lut_sel_e { |
51 | VIU_LUT_OSD_EOTF = 0, |
52 | VIU_LUT_OSD_OETF, |
53 | }; |
54 | |
55 | #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2)) |
56 | #define MATRIX_5X3_COEF_SIZE 24 |
57 | |
58 | #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2)) |
59 | #define EOTF_COEFF_SIZE 10 |
60 | #define EOTF_COEFF_RIGHTSHIFT 1 |
61 | |
62 | static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = { |
63 | 0, 0, 0, /* pre offset */ |
64 | COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765), |
65 | COEFF_NORM(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500), |
66 | COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-0.040116), |
67 | 0, 0, 0, /* 10'/11'/12' */ |
68 | 0, 0, 0, /* 20'/21'/22' */ |
69 | 64, 512, 512, /* offset */ |
70 | 0, 0, 0 /* mode, right_shift, clip_en */ |
71 | }; |
72 | |
73 | /* eotf matrix: bypass */ |
74 | static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { |
75 | EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0), |
76 | EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0), |
77 | EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0), |
78 | EOTF_COEFF_RIGHTSHIFT /* right shift */ |
79 | }; |
80 | |
81 | static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, |
82 | int *m, bool csc_on) |
83 | { |
84 | /* VPP WRAP OSD1 matrix */ |
85 | writel(val: ((m[0] & 0xfff) << 16) | (m[1] & 0xfff), |
86 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); |
87 | writel(val: m[2] & 0xfff, |
88 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); |
89 | writel(val: ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), |
90 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); |
91 | writel(val: ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), |
92 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); |
93 | writel(val: ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), |
94 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); |
95 | writel(val: ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), |
96 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); |
97 | writel(val: (m[11] & 0x1fff), |
98 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); |
99 | |
100 | writel(val: ((m[18] & 0xfff) << 16) | (m[19] & 0xfff), |
101 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); |
102 | writel(val: m[20] & 0xfff, |
103 | addr: priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); |
104 | |
105 | writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, |
106 | priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); |
107 | } |
108 | |
109 | static void meson_viu_set_osd_matrix(struct meson_drm *priv, |
110 | enum viu_matrix_sel_e m_select, |
111 | int *m, bool csc_on) |
112 | { |
113 | if (m_select == VIU_MATRIX_OSD) { |
114 | /* osd matrix, VIU_MATRIX_0 */ |
115 | writel(val: ((m[0] & 0xfff) << 16) | (m[1] & 0xfff), |
116 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1)); |
117 | writel(val: m[2] & 0xfff, |
118 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2)); |
119 | writel(val: ((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), |
120 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01)); |
121 | writel(val: ((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), |
122 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10)); |
123 | writel(val: ((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), |
124 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12)); |
125 | writel(val: ((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), |
126 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21)); |
127 | |
128 | if (m[21]) { |
129 | writel(val: ((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff), |
130 | addr: priv->io_base + |
131 | _REG(VIU_OSD1_MATRIX_COEF22_30)); |
132 | writel(val: ((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff), |
133 | addr: priv->io_base + |
134 | _REG(VIU_OSD1_MATRIX_COEF31_32)); |
135 | writel(val: ((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff), |
136 | addr: priv->io_base + |
137 | _REG(VIU_OSD1_MATRIX_COEF40_41)); |
138 | writel(val: m[17] & 0x1fff, addr: priv->io_base + |
139 | _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); |
140 | } else |
141 | writel(val: (m[11] & 0x1fff) << 16, addr: priv->io_base + |
142 | _REG(VIU_OSD1_MATRIX_COEF22_30)); |
143 | |
144 | writel(val: ((m[18] & 0xfff) << 16) | (m[19] & 0xfff), |
145 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1)); |
146 | writel(val: m[20] & 0xfff, |
147 | addr: priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2)); |
148 | |
149 | writel_bits_relaxed(3 << 30, m[21] << 30, |
150 | priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); |
151 | writel_bits_relaxed(7 << 16, m[22] << 16, |
152 | priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42)); |
153 | |
154 | /* 23 reserved for clipping control */ |
155 | writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, |
156 | priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL)); |
157 | writel_bits_relaxed(BIT(1), 0, |
158 | priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL)); |
159 | } else if (m_select == VIU_MATRIX_OSD_EOTF) { |
160 | int i; |
161 | |
162 | /* osd eotf matrix, VIU_MATRIX_OSD_EOTF */ |
163 | for (i = 0; i < 5; i++) |
164 | writel(val: ((m[i * 2] & 0x1fff) << 16) | |
165 | (m[i * 2 + 1] & 0x1fff), addr: priv->io_base + |
166 | _REG(VIU_OSD1_EOTF_CTL + i + 1)); |
167 | |
168 | writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0, |
169 | priv->io_base + _REG(VIU_OSD1_EOTF_CTL)); |
170 | writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0, |
171 | priv->io_base + _REG(VIU_OSD1_EOTF_CTL)); |
172 | } |
173 | } |
174 | |
175 | #define OSD_EOTF_LUT_SIZE 33 |
176 | #define OSD_OETF_LUT_SIZE 41 |
177 | |
178 | static void |
179 | meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, |
180 | unsigned int *r_map, unsigned int *g_map, |
181 | unsigned int *b_map, bool csc_on) |
182 | { |
183 | unsigned int addr_port; |
184 | unsigned int data_port; |
185 | unsigned int ctrl_port; |
186 | int i; |
187 | |
188 | if (lut_sel == VIU_LUT_OSD_EOTF) { |
189 | addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT; |
190 | data_port = VIU_OSD1_EOTF_LUT_DATA_PORT; |
191 | ctrl_port = VIU_OSD1_EOTF_CTL; |
192 | } else if (lut_sel == VIU_LUT_OSD_OETF) { |
193 | addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT; |
194 | data_port = VIU_OSD1_OETF_LUT_DATA_PORT; |
195 | ctrl_port = VIU_OSD1_OETF_CTL; |
196 | } else |
197 | return; |
198 | |
199 | if (lut_sel == VIU_LUT_OSD_OETF) { |
200 | writel(val: 0, addr: priv->io_base + _REG(addr_port)); |
201 | |
202 | for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) |
203 | writel(val: r_map[i * 2] | (r_map[i * 2 + 1] << 16), |
204 | addr: priv->io_base + _REG(data_port)); |
205 | |
206 | writel(val: r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16), |
207 | addr: priv->io_base + _REG(data_port)); |
208 | |
209 | for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) |
210 | writel(val: g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16), |
211 | addr: priv->io_base + _REG(data_port)); |
212 | |
213 | for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++) |
214 | writel(val: b_map[i * 2] | (b_map[i * 2 + 1] << 16), |
215 | addr: priv->io_base + _REG(data_port)); |
216 | |
217 | writel(val: b_map[OSD_OETF_LUT_SIZE - 1], |
218 | addr: priv->io_base + _REG(data_port)); |
219 | |
220 | if (csc_on) |
221 | writel_bits_relaxed(0x7 << 29, 7 << 29, |
222 | priv->io_base + _REG(ctrl_port)); |
223 | else |
224 | writel_bits_relaxed(0x7 << 29, 0, |
225 | priv->io_base + _REG(ctrl_port)); |
226 | } else if (lut_sel == VIU_LUT_OSD_EOTF) { |
227 | writel(val: 0, addr: priv->io_base + _REG(addr_port)); |
228 | |
229 | for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) |
230 | writel(val: r_map[i * 2] | (r_map[i * 2 + 1] << 16), |
231 | addr: priv->io_base + _REG(data_port)); |
232 | |
233 | writel(val: r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16), |
234 | addr: priv->io_base + _REG(data_port)); |
235 | |
236 | for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) |
237 | writel(val: g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16), |
238 | addr: priv->io_base + _REG(data_port)); |
239 | |
240 | for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++) |
241 | writel(val: b_map[i * 2] | (b_map[i * 2 + 1] << 16), |
242 | addr: priv->io_base + _REG(data_port)); |
243 | |
244 | writel(val: b_map[OSD_EOTF_LUT_SIZE - 1], |
245 | addr: priv->io_base + _REG(data_port)); |
246 | |
247 | if (csc_on) |
248 | writel_bits_relaxed(7 << 27, 7 << 27, |
249 | priv->io_base + _REG(ctrl_port)); |
250 | else |
251 | writel_bits_relaxed(7 << 27, 0, |
252 | priv->io_base + _REG(ctrl_port)); |
253 | |
254 | writel_bits_relaxed(BIT(31), BIT(31), |
255 | priv->io_base + _REG(ctrl_port)); |
256 | } |
257 | } |
258 | |
259 | /* eotf lut: linear */ |
260 | static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = { |
261 | 0x0000, 0x0200, 0x0400, 0x0600, |
262 | 0x0800, 0x0a00, 0x0c00, 0x0e00, |
263 | 0x1000, 0x1200, 0x1400, 0x1600, |
264 | 0x1800, 0x1a00, 0x1c00, 0x1e00, |
265 | 0x2000, 0x2200, 0x2400, 0x2600, |
266 | 0x2800, 0x2a00, 0x2c00, 0x2e00, |
267 | 0x3000, 0x3200, 0x3400, 0x3600, |
268 | 0x3800, 0x3a00, 0x3c00, 0x3e00, |
269 | 0x4000 |
270 | }; |
271 | |
272 | /* osd oetf lut: linear */ |
273 | static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = { |
274 | 0, 0, 0, 0, |
275 | 0, 32, 64, 96, |
276 | 128, 160, 196, 224, |
277 | 256, 288, 320, 352, |
278 | 384, 416, 448, 480, |
279 | 512, 544, 576, 608, |
280 | 640, 672, 704, 736, |
281 | 768, 800, 832, 864, |
282 | 896, 928, 960, 992, |
283 | 1023, 1023, 1023, 1023, |
284 | 1023 |
285 | }; |
286 | |
287 | static void meson_viu_load_matrix(struct meson_drm *priv) |
288 | { |
289 | /* eotf lut bypass */ |
290 | meson_viu_set_osd_lut(priv, lut_sel: VIU_LUT_OSD_EOTF, |
291 | r_map: eotf_33_linear_mapping, /* R */ |
292 | g_map: eotf_33_linear_mapping, /* G */ |
293 | b_map: eotf_33_linear_mapping, /* B */ |
294 | csc_on: false); |
295 | |
296 | /* eotf matrix bypass */ |
297 | meson_viu_set_osd_matrix(priv, m_select: VIU_MATRIX_OSD_EOTF, |
298 | m: eotf_bypass_coeff, |
299 | csc_on: false); |
300 | |
301 | /* oetf lut bypass */ |
302 | meson_viu_set_osd_lut(priv, lut_sel: VIU_LUT_OSD_OETF, |
303 | r_map: oetf_41_linear_mapping, /* R */ |
304 | g_map: oetf_41_linear_mapping, /* G */ |
305 | b_map: oetf_41_linear_mapping, /* B */ |
306 | csc_on: false); |
307 | |
308 | /* osd matrix RGB709 to YUV709 limit */ |
309 | meson_viu_set_osd_matrix(priv, m_select: VIU_MATRIX_OSD, |
310 | m: RGB709_to_YUV709l_coeff, |
311 | csc_on: true); |
312 | } |
313 | |
314 | /* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */ |
315 | void meson_viu_osd1_reset(struct meson_drm *priv) |
316 | { |
317 | uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2; |
318 | |
319 | /* Save these 2 registers state */ |
320 | osd1_fifo_ctrl_stat = readl_relaxed( |
321 | priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); |
322 | osd1_ctrl_stat2 = readl_relaxed( |
323 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); |
324 | |
325 | /* Reset OSD1 */ |
326 | writel_bits_relaxed(VIU_SW_RESET_OSD1, VIU_SW_RESET_OSD1, |
327 | priv->io_base + _REG(VIU_SW_RESET)); |
328 | writel_bits_relaxed(VIU_SW_RESET_OSD1, 0, |
329 | priv->io_base + _REG(VIU_SW_RESET)); |
330 | |
331 | /* Rewrite these registers state lost in the reset */ |
332 | writel_relaxed(osd1_fifo_ctrl_stat, |
333 | priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); |
334 | writel_relaxed(osd1_ctrl_stat2, |
335 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); |
336 | |
337 | /* Reload the conversion matrix */ |
338 | meson_viu_load_matrix(priv); |
339 | } |
340 | |
341 | #define OSD1_MALI_ORDER_ABGR \ |
342 | (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ |
343 | VIU_OSD1_MALI_REORDER_A) | \ |
344 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ |
345 | VIU_OSD1_MALI_REORDER_B) | \ |
346 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ |
347 | VIU_OSD1_MALI_REORDER_G) | \ |
348 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ |
349 | VIU_OSD1_MALI_REORDER_R)) |
350 | |
351 | #define OSD1_MALI_ORDER_ARGB \ |
352 | (FIELD_PREP(VIU_OSD1_MALI_AFBCD_A_REORDER, \ |
353 | VIU_OSD1_MALI_REORDER_A) | \ |
354 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_B_REORDER, \ |
355 | VIU_OSD1_MALI_REORDER_R) | \ |
356 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_G_REORDER, \ |
357 | VIU_OSD1_MALI_REORDER_G) | \ |
358 | FIELD_PREP(VIU_OSD1_MALI_AFBCD_R_REORDER, \ |
359 | VIU_OSD1_MALI_REORDER_B)) |
360 | |
361 | void meson_viu_g12a_enable_osd1_afbc(struct meson_drm *priv) |
362 | { |
363 | u32 afbc_order = OSD1_MALI_ORDER_ARGB; |
364 | |
365 | /* Enable Mali AFBC Unpack */ |
366 | writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, |
367 | VIU_OSD1_MALI_UNPACK_EN, |
368 | priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
369 | |
370 | switch (priv->afbcd.format) { |
371 | case DRM_FORMAT_XBGR8888: |
372 | case DRM_FORMAT_ABGR8888: |
373 | afbc_order = OSD1_MALI_ORDER_ABGR; |
374 | break; |
375 | } |
376 | |
377 | /* Setup RGBA Reordering */ |
378 | writel_bits_relaxed(VIU_OSD1_MALI_AFBCD_A_REORDER | |
379 | VIU_OSD1_MALI_AFBCD_B_REORDER | |
380 | VIU_OSD1_MALI_AFBCD_G_REORDER | |
381 | VIU_OSD1_MALI_AFBCD_R_REORDER, |
382 | afbc_order, |
383 | priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
384 | |
385 | /* Select AFBCD path for OSD1 */ |
386 | writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, |
387 | OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, |
388 | priv->io_base + _REG(OSD_PATH_MISC_CTRL)); |
389 | } |
390 | |
391 | void meson_viu_g12a_disable_osd1_afbc(struct meson_drm *priv) |
392 | { |
393 | /* Disable AFBCD path for OSD1 */ |
394 | writel_bits_relaxed(OSD_PATH_OSD_AXI_SEL_OSD1_AFBCD, 0, |
395 | priv->io_base + _REG(OSD_PATH_MISC_CTRL)); |
396 | |
397 | /* Disable AFBCD unpack */ |
398 | writel_bits_relaxed(VIU_OSD1_MALI_UNPACK_EN, 0, |
399 | priv->io_base + _REG(VIU_OSD1_MALI_UNPACK_CTRL)); |
400 | } |
401 | |
402 | void meson_viu_gxm_enable_osd1_afbc(struct meson_drm *priv) |
403 | { |
404 | writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x90), |
405 | priv->io_base + _REG(VIU_MISC_CTRL1)); |
406 | } |
407 | |
408 | void meson_viu_gxm_disable_osd1_afbc(struct meson_drm *priv) |
409 | { |
410 | writel_bits_relaxed(MALI_AFBC_MISC, FIELD_PREP(MALI_AFBC_MISC, 0x00), |
411 | priv->io_base + _REG(VIU_MISC_CTRL1)); |
412 | } |
413 | |
414 | void meson_viu_init(struct meson_drm *priv) |
415 | { |
416 | uint32_t reg; |
417 | |
418 | /* Disable OSDs */ |
419 | writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, |
420 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
421 | writel_bits_relaxed(VIU_OSD1_OSD_BLK_ENABLE | VIU_OSD1_OSD_ENABLE, 0, |
422 | priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); |
423 | |
424 | /* On GXL/GXM, Use the 10bit HDR conversion matrix */ |
425 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM) || |
426 | meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXL)) |
427 | meson_viu_load_matrix(priv); |
428 | else if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
429 | meson_viu_set_g12a_osd1_matrix(priv, m: RGB709_to_YUV709l_coeff, |
430 | csc_on: true); |
431 | /* fix green/pink color distortion from vendor u-boot */ |
432 | writel_bits_relaxed(OSD1_HDR2_CTRL_REG_ONLY_MAT | |
433 | OSD1_HDR2_CTRL_VDIN0_HDR2_TOP_EN, 0, |
434 | priv->io_base + _REG(OSD1_HDR2_CTRL)); |
435 | } |
436 | |
437 | /* Initialize OSD1 fifo control register */ |
438 | reg = VIU_OSD_DDR_PRIORITY_URGENT | |
439 | VIU_OSD_FIFO_DEPTH_VAL(32) | /* fifo_depth_val: 32*8=256 */ |
440 | VIU_OSD_WORDS_PER_BURST(4) | /* 4 words in 1 burst */ |
441 | VIU_OSD_FIFO_LIMITS(2); /* fifo_lim: 2*16=32 */ |
442 | |
443 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) |
444 | reg |= (VIU_OSD_BURST_LENGTH_32 | VIU_OSD_HOLD_FIFO_LINES(31)); |
445 | else |
446 | reg |= (VIU_OSD_BURST_LENGTH_64 | VIU_OSD_HOLD_FIFO_LINES(4)); |
447 | |
448 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); |
449 | writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); |
450 | |
451 | /* Set OSD alpha replace value */ |
452 | writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT, |
453 | 0xff << OSD_REPLACE_SHIFT, |
454 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); |
455 | writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT, |
456 | 0xff << OSD_REPLACE_SHIFT, |
457 | priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); |
458 | |
459 | /* Disable VD1 AFBC */ |
460 | /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/ |
461 | writel_bits_relaxed(VIU_CTRL0_VD1_AFBC_MASK, 0, |
462 | priv->io_base + _REG(VIU_MISC_CTRL0)); |
463 | writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); |
464 | |
465 | writel_relaxed(0x00FF00C0, |
466 | priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE)); |
467 | writel_relaxed(0x00FF00C0, |
468 | priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); |
469 | |
470 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
471 | u32 val = (u32)VIU_OSD_BLEND_REORDER(0, 1) | |
472 | (u32)VIU_OSD_BLEND_REORDER(1, 0) | |
473 | (u32)VIU_OSD_BLEND_REORDER(2, 0) | |
474 | (u32)VIU_OSD_BLEND_REORDER(3, 0) | |
475 | (u32)VIU_OSD_BLEND_DIN_EN(1) | |
476 | (u32)VIU_OSD_BLEND1_DIN3_BYPASS_TO_DOUT1 | |
477 | (u32)VIU_OSD_BLEND1_DOUT_BYPASS_TO_BLEND2 | |
478 | (u32)VIU_OSD_BLEND_DIN0_BYPASS_TO_DOUT0 | |
479 | (u32)VIU_OSD_BLEND_BLEN2_PREMULT_EN(1) | |
480 | (u32)VIU_OSD_BLEND_HOLD_LINES(4); |
481 | writel_relaxed(val, priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); |
482 | |
483 | writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, |
484 | priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); |
485 | writel_relaxed(OSD_BLEND_PATH_SEL_ENABLE, |
486 | priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); |
487 | writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); |
488 | writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); |
489 | writel_relaxed(0, |
490 | priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); |
491 | writel_relaxed(0, |
492 | priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); |
493 | |
494 | writel_bits_relaxed(DOLBY_BYPASS_EN(0xc), DOLBY_BYPASS_EN(0xc), |
495 | priv->io_base + _REG(DOLBY_PATH_CTRL)); |
496 | |
497 | meson_viu_g12a_disable_osd1_afbc(priv); |
498 | } |
499 | |
500 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM)) |
501 | meson_viu_gxm_disable_osd1_afbc(priv); |
502 | |
503 | priv->viu.osd1_enabled = false; |
504 | priv->viu.osd1_commit = false; |
505 | priv->viu.osd1_interlace = false; |
506 | } |
507 | |