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