9f8a450d50d5d0f896a99c0119b0e79160aa885c
[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(BIT(0), BIT(0),
324                             priv->io_base + _REG(VIU_SW_RESET));
325         writel_bits_relaxed(BIT(0), 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 void meson_viu_init(struct meson_drm *priv)
339 {
340         uint32_t reg;
341
342         /* Disable OSDs */
343         writel_bits_relaxed(BIT(0) | BIT(21), 0,
344                         priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
345         writel_bits_relaxed(BIT(0) | BIT(21), 0,
346                         priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
347
348         /* On GXL/GXM, Use the 10bit HDR conversion matrix */
349         if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
350             meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
351                 meson_viu_load_matrix(priv);
352         else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
353                 meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff,
354                                                true);
355
356         /* Initialize OSD1 fifo control register */
357         reg = BIT(0) |  /* Urgent DDR request priority */
358               (4 << 5); /* hold_fifo_lines */
359         if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu"))
360                 reg |= (1 << 10) | /* burst length 32 */
361                        (32 << 12) | /* fifo_depth_val: 32*8=256 */
362                        (2 << 22) | /* 4 words in 1 burst */
363                        (2 << 24) |
364                        (1 << 31);
365         else
366                 reg |= (3 << 10) | /* burst length 64 */
367                        (32 << 12) | /* fifo_depth_val: 32*8=256 */
368                        (2 << 22) | /* 4 words in 1 burst */
369                        (2 << 24);
370         writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
371         writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
372
373         /* Set OSD alpha replace value */
374         writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
375                             0xff << OSD_REPLACE_SHIFT,
376                             priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
377         writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
378                             0xff << OSD_REPLACE_SHIFT,
379                             priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
380
381         /* Disable VD1 AFBC */
382         /* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 */
383         writel_bits_relaxed(0x7 << 16, 0,
384                         priv->io_base + _REG(VIU_MISC_CTRL0));
385         /* afbc vd1 set=0 */
386         writel_bits_relaxed(BIT(20), 0,
387                         priv->io_base + _REG(VIU_MISC_CTRL0));
388         writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE));
389
390         writel_relaxed(0x00FF00C0,
391                         priv->io_base + _REG(VD1_IF0_LUMA_FIFO_SIZE));
392         writel_relaxed(0x00FF00C0,
393                         priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE));
394
395         if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) {
396                 writel_relaxed(4 << 29 |
397                                 1 << 27 |
398                                 1 << 26 | /* blend_din0 input to blend0 */
399                                 1 << 25 | /* blend1_dout to blend2 */
400                                 1 << 24 | /* blend1_din3 input to blend1 */
401                                 1 << 20 |
402                                 0 << 16 |
403                                 1,
404                                 priv->io_base + _REG(VIU_OSD_BLEND_CTRL));
405                 writel_relaxed(1 << 20,
406                                 priv->io_base + _REG(OSD1_BLEND_SRC_CTRL));
407                 writel_relaxed(1 << 20,
408                                 priv->io_base + _REG(OSD2_BLEND_SRC_CTRL));
409                 writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL));
410                 writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL));
411                 writel_relaxed(0,
412                                 priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0));
413                 writel_relaxed(0,
414                                 priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA));
415                 writel_bits_relaxed(0x3 << 2, 0x3 << 2,
416                                 priv->io_base + _REG(DOLBY_PATH_CTRL));
417         }
418
419         priv->viu.osd1_enabled = false;
420         priv->viu.osd1_commit = false;
421         priv->viu.osd1_interlace = false;
422 }