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