Loading...
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
45enum viu_matrix_sel_e {
46 VIU_MATRIX_OSD_EOTF = 0,
47 VIU_MATRIX_OSD,
48};
49
50enum 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
62static 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 */
74static 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
81static 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(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
86 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1));
87 writel(m[2] & 0xfff,
88 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2));
89 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
90 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01));
91 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
92 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10));
93 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
94 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12));
95 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
96 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21));
97 writel((m[11] & 0x1fff),
98 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22));
99
100 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
101 priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1));
102 writel(m[20] & 0xfff,
103 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
109static 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(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
116 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
117 writel(m[2] & 0xfff,
118 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
119 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
120 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
121 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
122 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
123 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
124 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
125 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
126 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
127
128 if (m[21]) {
129 writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
130 priv->io_base +
131 _REG(VIU_OSD1_MATRIX_COEF22_30));
132 writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
133 priv->io_base +
134 _REG(VIU_OSD1_MATRIX_COEF31_32));
135 writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
136 priv->io_base +
137 _REG(VIU_OSD1_MATRIX_COEF40_41));
138 writel(m[17] & 0x1fff, priv->io_base +
139 _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
140 } else
141 writel((m[11] & 0x1fff) << 16, priv->io_base +
142 _REG(VIU_OSD1_MATRIX_COEF22_30));
143
144 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
145 priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
146 writel(m[20] & 0xfff,
147 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(((m[i * 2] & 0x1fff) << 16) |
165 (m[i * 2 + 1] & 0x1fff), 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
178static void
179meson_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(0, priv->io_base + _REG(addr_port));
201
202 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
203 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
204 priv->io_base + _REG(data_port));
205
206 writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
207 priv->io_base + _REG(data_port));
208
209 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
210 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
211 priv->io_base + _REG(data_port));
212
213 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
214 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
215 priv->io_base + _REG(data_port));
216
217 writel(b_map[OSD_OETF_LUT_SIZE - 1],
218 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(0, priv->io_base + _REG(addr_port));
228
229 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
230 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
231 priv->io_base + _REG(data_port));
232
233 writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
234 priv->io_base + _REG(data_port));
235
236 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
237 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
238 priv->io_base + _REG(data_port));
239
240 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
241 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
242 priv->io_base + _REG(data_port));
243
244 writel(b_map[OSD_EOTF_LUT_SIZE - 1],
245 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 */
260static 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 */
273static 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
287static void meson_viu_load_matrix(struct meson_drm *priv)
288{
289 /* eotf lut bypass */
290 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
291 eotf_33_linear_mapping, /* R */
292 eotf_33_linear_mapping, /* G */
293 eotf_33_linear_mapping, /* B */
294 false);
295
296 /* eotf matrix bypass */
297 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
298 eotf_bypass_coeff,
299 false);
300
301 /* oetf lut bypass */
302 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
303 oetf_41_linear_mapping, /* R */
304 oetf_41_linear_mapping, /* G */
305 oetf_41_linear_mapping, /* B */
306 false);
307
308 /* osd matrix RGB709 to YUV709 limit */
309 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
310 RGB709_to_YUV709l_coeff,
311 true);
312}
313
314/* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
315void 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
361void 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
391void 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
402void 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
408void 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
414void 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, VPU_COMPATIBLE_GXM) ||
426 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
427 meson_viu_load_matrix(priv);
428 else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
429 meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
430 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, 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, 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, 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}
1/*
2 * Copyright (C) 2016 BayLibre, SAS
3 * Author: Neil Armstrong <narmstrong@baylibre.com>
4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5 * Copyright (C) 2014 Endless Mobile
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <drm/drmP.h>
24#include "meson_drv.h"
25#include "meson_viu.h"
26#include "meson_vpp.h"
27#include "meson_venc.h"
28#include "meson_canvas.h"
29#include "meson_registers.h"
30
31/*
32 * VIU Handles the Pixel scanout and the basic Colorspace conversions
33 * We handle the following features :
34 * - OSD1 RGB565/RGB888/xRGB8888 scanout
35 * - RGB conversion to x/cb/cr
36 * - Progressive or Interlace buffer scanout
37 * - OSD1 Commit on Vsync
38 * - HDR OSD matrix for GXL/GXM
39 *
40 * What is missing :
41 * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
42 * - YUV4:2:2 Y0CbY1Cr scanout
43 * - Conversion to YUV 4:4:4 from 4:2:2 input
44 * - Colorkey Alpha matching
45 * - Big endian scanout
46 * - X/Y reverse scanout
47 * - Global alpha setup
48 * - OSD2 support, would need interlace switching on vsync
49 * - OSD1 full scaling to support TV overscan
50 */
51
52/* OSD csc defines */
53
54enum viu_matrix_sel_e {
55 VIU_MATRIX_OSD_EOTF = 0,
56 VIU_MATRIX_OSD,
57};
58
59enum viu_lut_sel_e {
60 VIU_LUT_OSD_EOTF = 0,
61 VIU_LUT_OSD_OETF,
62};
63
64#define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
65#define MATRIX_5X3_COEF_SIZE 24
66
67#define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
68#define EOTF_COEFF_SIZE 10
69#define EOTF_COEFF_RIGHTSHIFT 1
70
71static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
72 0, 0, 0, /* pre offset */
73 COEFF_NORM(0.181873), COEFF_NORM(0.611831), COEFF_NORM(0.061765),
74 COEFF_NORM(-0.100251), COEFF_NORM(-0.337249), COEFF_NORM(0.437500),
75 COEFF_NORM(0.437500), COEFF_NORM(-0.397384), COEFF_NORM(-0.040116),
76 0, 0, 0, /* 10'/11'/12' */
77 0, 0, 0, /* 20'/21'/22' */
78 64, 512, 512, /* offset */
79 0, 0, 0 /* mode, right_shift, clip_en */
80};
81
82/* eotf matrix: bypass */
83static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
84 EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0),
85 EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0), EOTF_COEFF_NORM(0.0),
86 EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(0.0), EOTF_COEFF_NORM(1.0),
87 EOTF_COEFF_RIGHTSHIFT /* right shift */
88};
89
90void meson_viu_set_osd_matrix(struct meson_drm *priv,
91 enum viu_matrix_sel_e m_select,
92 int *m, bool csc_on)
93{
94 if (m_select == VIU_MATRIX_OSD) {
95 /* osd matrix, VIU_MATRIX_0 */
96 writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
97 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
98 writel(m[2] & 0xfff,
99 priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
100 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
101 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
102 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
103 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
104 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
105 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
106 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
107 priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
108
109 if (m[21]) {
110 writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
111 priv->io_base +
112 _REG(VIU_OSD1_MATRIX_COEF22_30));
113 writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
114 priv->io_base +
115 _REG(VIU_OSD1_MATRIX_COEF31_32));
116 writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
117 priv->io_base +
118 _REG(VIU_OSD1_MATRIX_COEF40_41));
119 writel(m[17] & 0x1fff, priv->io_base +
120 _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
121 } else
122 writel((m[11] & 0x1fff) << 16, priv->io_base +
123 _REG(VIU_OSD1_MATRIX_COEF22_30));
124
125 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
126 priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
127 writel(m[20] & 0xfff,
128 priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
129
130 writel_bits_relaxed(3 << 30, m[21] << 30,
131 priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
132 writel_bits_relaxed(7 << 16, m[22] << 16,
133 priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
134
135 /* 23 reserved for clipping control */
136 writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
137 priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
138 writel_bits_relaxed(BIT(1), 0,
139 priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
140 } else if (m_select == VIU_MATRIX_OSD_EOTF) {
141 int i;
142
143 /* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
144 for (i = 0; i < 5; i++)
145 writel(((m[i * 2] & 0x1fff) << 16) |
146 (m[i * 2 + 1] & 0x1fff), priv->io_base +
147 _REG(VIU_OSD1_EOTF_CTL + i + 1));
148
149 writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
150 priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
151 writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
152 priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
153 }
154}
155
156#define OSD_EOTF_LUT_SIZE 33
157#define OSD_OETF_LUT_SIZE 41
158
159void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
160 unsigned int *r_map, unsigned int *g_map,
161 unsigned int *b_map,
162 bool csc_on)
163{
164 unsigned int addr_port;
165 unsigned int data_port;
166 unsigned int ctrl_port;
167 int i;
168
169 if (lut_sel == VIU_LUT_OSD_EOTF) {
170 addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
171 data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
172 ctrl_port = VIU_OSD1_EOTF_CTL;
173 } else if (lut_sel == VIU_LUT_OSD_OETF) {
174 addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
175 data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
176 ctrl_port = VIU_OSD1_OETF_CTL;
177 } else
178 return;
179
180 if (lut_sel == VIU_LUT_OSD_OETF) {
181 writel(0, priv->io_base + _REG(addr_port));
182
183 for (i = 0; i < 20; i++)
184 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
185 priv->io_base + _REG(data_port));
186
187 writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
188 priv->io_base + _REG(data_port));
189
190 for (i = 0; i < 20; i++)
191 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
192 priv->io_base + _REG(data_port));
193
194 for (i = 0; i < 20; i++)
195 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
196 priv->io_base + _REG(data_port));
197
198 writel(b_map[OSD_OETF_LUT_SIZE - 1],
199 priv->io_base + _REG(data_port));
200
201 if (csc_on)
202 writel_bits_relaxed(0x7 << 29, 7 << 29,
203 priv->io_base + _REG(ctrl_port));
204 else
205 writel_bits_relaxed(0x7 << 29, 0,
206 priv->io_base + _REG(ctrl_port));
207 } else if (lut_sel == VIU_LUT_OSD_EOTF) {
208 writel(0, priv->io_base + _REG(addr_port));
209
210 for (i = 0; i < 20; i++)
211 writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
212 priv->io_base + _REG(data_port));
213
214 writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
215 priv->io_base + _REG(data_port));
216
217 for (i = 0; i < 20; i++)
218 writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
219 priv->io_base + _REG(data_port));
220
221 for (i = 0; i < 20; i++)
222 writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
223 priv->io_base + _REG(data_port));
224
225 writel(b_map[OSD_EOTF_LUT_SIZE - 1],
226 priv->io_base + _REG(data_port));
227
228 if (csc_on)
229 writel_bits_relaxed(7 << 27, 7 << 27,
230 priv->io_base + _REG(ctrl_port));
231 else
232 writel_bits_relaxed(7 << 27, 0,
233 priv->io_base + _REG(ctrl_port));
234
235 writel_bits_relaxed(BIT(31), BIT(31),
236 priv->io_base + _REG(ctrl_port));
237 }
238}
239
240/* eotf lut: linear */
241static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
242 0x0000, 0x0200, 0x0400, 0x0600,
243 0x0800, 0x0a00, 0x0c00, 0x0e00,
244 0x1000, 0x1200, 0x1400, 0x1600,
245 0x1800, 0x1a00, 0x1c00, 0x1e00,
246 0x2000, 0x2200, 0x2400, 0x2600,
247 0x2800, 0x2a00, 0x2c00, 0x2e00,
248 0x3000, 0x3200, 0x3400, 0x3600,
249 0x3800, 0x3a00, 0x3c00, 0x3e00,
250 0x4000
251};
252
253/* osd oetf lut: linear */
254static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
255 0, 0, 0, 0,
256 0, 32, 64, 96,
257 128, 160, 196, 224,
258 256, 288, 320, 352,
259 384, 416, 448, 480,
260 512, 544, 576, 608,
261 640, 672, 704, 736,
262 768, 800, 832, 864,
263 896, 928, 960, 992,
264 1023, 1023, 1023, 1023,
265 1023
266};
267
268static void meson_viu_load_matrix(struct meson_drm *priv)
269{
270 /* eotf lut bypass */
271 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
272 eotf_33_linear_mapping, /* R */
273 eotf_33_linear_mapping, /* G */
274 eotf_33_linear_mapping, /* B */
275 false);
276
277 /* eotf matrix bypass */
278 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
279 eotf_bypass_coeff,
280 false);
281
282 /* oetf lut bypass */
283 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
284 oetf_41_linear_mapping, /* R */
285 oetf_41_linear_mapping, /* G */
286 oetf_41_linear_mapping, /* B */
287 false);
288
289 /* osd matrix RGB709 to YUV709 limit */
290 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
291 RGB709_to_YUV709l_coeff,
292 true);
293}
294
295void meson_viu_init(struct meson_drm *priv)
296{
297 uint32_t reg;
298
299 /* Disable OSDs */
300 writel_bits_relaxed(BIT(0) | BIT(21), 0,
301 priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
302 writel_bits_relaxed(BIT(0) | BIT(21), 0,
303 priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
304
305 /* On GXL/GXM, Use the 10bit HDR conversion matrix */
306 if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
307 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
308 meson_viu_load_matrix(priv);
309
310 /* Initialize OSD1 fifo control register */
311 reg = BIT(0) | /* Urgent DDR request priority */
312 (4 << 5) | /* hold_fifo_lines */
313 (3 << 10) | /* burst length 64 */
314 (32 << 12) | /* fifo_depth_val: 32*8=256 */
315 (2 << 22) | /* 4 words in 1 burst */
316 (2 << 24);
317 writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
318 writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
319
320 /* Set OSD alpha replace value */
321 writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
322 0xff << OSD_REPLACE_SHIFT,
323 priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
324 writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
325 0xff << OSD_REPLACE_SHIFT,
326 priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
327
328 priv->viu.osd1_enabled = false;
329 priv->viu.osd1_commit = false;
330 priv->viu.osd1_interlace = false;
331}