video: Add Meson Video Processing Unit Driver
[oweals/u-boot.git] / drivers / video / meson / meson_vpu_init.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Amlogic Meson Video Processing Unit driver
4  *
5  * Copyright (c) 2018 BayLibre, SAS.
6  * Author: Neil Armstrong <narmstrong@baylibre.com>
7  */
8
9 #define DEBUG
10
11 #include "meson_vpu.h"
12
13 /* HHI Registers */
14 #define HHI_VDAC_CNTL0          0x2F4 /* 0xbd offset in data sheet */
15 #define HHI_VDAC_CNTL1          0x2F8 /* 0xbe offset in data sheet */
16 #define HHI_HDMI_PHY_CNTL0      0x3a0 /* 0xe8 offset in data sheet */
17
18 /* OSDx_CTRL_STAT2 */
19 #define OSD_REPLACE_EN          BIT(14)
20 #define OSD_REPLACE_SHIFT       6
21
22 void meson_vpp_setup_mux(struct meson_vpu_priv *priv, unsigned int mux)
23 {
24         writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
25 }
26
27 static unsigned int vpp_filter_coefs_4point_bspline[] = {
28         0x15561500, 0x14561600, 0x13561700, 0x12561800,
29         0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
30         0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
31         0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
32         0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
33         0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
34         0x05473301, 0x05463401, 0x04453601, 0x04433702,
35         0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
36         0x033d3d03
37 };
38
39 static void meson_vpp_write_scaling_filter_coefs(struct meson_vpu_priv *priv,
40                                                  const unsigned int *coefs,
41                                                  bool is_horizontal)
42 {
43         int i;
44
45         writel(is_horizontal ? BIT(8) : 0,
46                priv->io_base + _REG(VPP_OSD_SCALE_COEF_IDX));
47         for (i = 0; i < 33; i++)
48                 writel(coefs[i],
49                        priv->io_base + _REG(VPP_OSD_SCALE_COEF));
50 }
51
52 static const u32 vpp_filter_coefs_bicubic[] = {
53         0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
54         0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
55         0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
56         0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
57         0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
58         0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
59         0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
60         0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
61         0xf84848f8
62 };
63
64 static void meson_vpp_write_vd_scaling_filter_coefs(struct meson_vpu_priv *priv,
65                                                     const unsigned int *coefs,
66                                                     bool is_horizontal)
67 {
68         int i;
69
70         writel(is_horizontal ? BIT(8) : 0,
71                priv->io_base + _REG(VPP_SCALE_COEF_IDX));
72         for (i = 0; i < 33; i++)
73                 writel(coefs[i],
74                        priv->io_base + _REG(VPP_SCALE_COEF));
75 }
76
77 /* OSD csc defines */
78
79 enum viu_matrix_sel_e {
80         VIU_MATRIX_OSD_EOTF = 0,
81         VIU_MATRIX_OSD,
82 };
83
84 enum viu_lut_sel_e {
85         VIU_LUT_OSD_EOTF = 0,
86         VIU_LUT_OSD_OETF,
87 };
88
89 #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
90 #define MATRIX_5X3_COEF_SIZE 24
91
92 #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
93 #define EOTF_COEFF_SIZE 10
94 #define EOTF_COEFF_RIGHTSHIFT 1
95
96 static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
97         0, 0, 0, /* pre offset */
98         COEFF_NORM(0.181873),   COEFF_NORM(0.611831),   COEFF_NORM(0.061765),
99         COEFF_NORM(-0.100251),  COEFF_NORM(-0.337249),  COEFF_NORM(0.437500),
100         COEFF_NORM(0.437500),   COEFF_NORM(-0.397384),  COEFF_NORM(-0.040116),
101         0, 0, 0, /* 10'/11'/12' */
102         0, 0, 0, /* 20'/21'/22' */
103         64, 512, 512, /* offset */
104         0, 0, 0 /* mode, right_shift, clip_en */
105 };
106
107 /*  eotf matrix: bypass */
108 static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
109         EOTF_COEFF_NORM(1.0),   EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(0.0),
110         EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(1.0),   EOTF_COEFF_NORM(0.0),
111         EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(1.0),
112         EOTF_COEFF_RIGHTSHIFT /* right shift */
113 };
114
115 static void meson_viu_set_osd_matrix(struct meson_vpu_priv *priv,
116                                      enum viu_matrix_sel_e m_select,
117                                      int *m, bool csc_on)
118 {
119         if (m_select == VIU_MATRIX_OSD) {
120                 /* osd matrix, VIU_MATRIX_0 */
121                 writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
122                        priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
123                 writel(m[2] & 0xfff,
124                        priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
125                 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
126                        priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
127                 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
128                        priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
129                 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
130                        priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
131                 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
132                        priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
133
134                 if (m[21]) {
135                         writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
136                                priv->io_base +
137                                         _REG(VIU_OSD1_MATRIX_COEF22_30));
138                         writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
139                                priv->io_base +
140                                         _REG(VIU_OSD1_MATRIX_COEF31_32));
141                         writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
142                                priv->io_base +
143                                         _REG(VIU_OSD1_MATRIX_COEF40_41));
144                         writel(m[17] & 0x1fff, priv->io_base +
145                                _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
146                 } else {
147                         writel((m[11] & 0x1fff) << 16, priv->io_base +
148                                _REG(VIU_OSD1_MATRIX_COEF22_30));
149                 }
150
151                 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
152                        priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
153                 writel(m[20] & 0xfff,
154                        priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
155
156                 writel_bits(3 << 30, m[21] << 30,
157                             priv->io_base +
158                             _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
159                 writel_bits(7 << 16, m[22] << 16,
160                             priv->io_base +
161                             _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
162
163                 /* 23 reserved for clipping control */
164                 writel_bits(BIT(0), csc_on ? BIT(0) : 0,
165                             priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
166                 writel_bits(BIT(1), 0,
167                             priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
168         } else if (m_select == VIU_MATRIX_OSD_EOTF) {
169                 int i;
170
171                 /* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
172                 for (i = 0; i < 5; i++)
173                         writel(((m[i * 2] & 0x1fff) << 16) |
174                                 (m[i * 2 + 1] & 0x1fff), priv->io_base +
175                                 _REG(VIU_OSD1_EOTF_CTL + i + 1));
176
177                 writel_bits(BIT(30), csc_on ? BIT(30) : 0,
178                             priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
179                 writel_bits(BIT(31), csc_on ? BIT(31) : 0,
180                             priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
181         }
182 }
183
184 #define OSD_EOTF_LUT_SIZE 33
185 #define OSD_OETF_LUT_SIZE 41
186
187 static void meson_viu_set_osd_lut(struct meson_vpu_priv *priv,
188                                   enum viu_lut_sel_e lut_sel,
189                                   unsigned int *r_map, unsigned int *g_map,
190                                   unsigned int *b_map,
191                                   bool csc_on)
192 {
193         unsigned int addr_port;
194         unsigned int data_port;
195         unsigned int ctrl_port;
196         int i;
197
198         if (lut_sel == VIU_LUT_OSD_EOTF) {
199                 addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
200                 data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
201                 ctrl_port = VIU_OSD1_EOTF_CTL;
202         } else if (lut_sel == VIU_LUT_OSD_OETF) {
203                 addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
204                 data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
205                 ctrl_port = VIU_OSD1_OETF_CTL;
206         } else {
207                 return;
208         }
209
210         if (lut_sel == VIU_LUT_OSD_OETF) {
211                 writel(0, priv->io_base + _REG(addr_port));
212
213                 for (i = 0; i < 20; i++)
214                         writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
215                                priv->io_base + _REG(data_port));
216
217                 writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
218                        priv->io_base + _REG(data_port));
219
220                 for (i = 0; i < 20; i++)
221                         writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
222                                priv->io_base + _REG(data_port));
223
224                 for (i = 0; i < 20; i++)
225                         writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
226                                priv->io_base + _REG(data_port));
227
228                 writel(b_map[OSD_OETF_LUT_SIZE - 1],
229                        priv->io_base + _REG(data_port));
230
231                 if (csc_on)
232                         writel_bits(0x7 << 29, 7 << 29,
233                                     priv->io_base + _REG(ctrl_port));
234                 else
235                         writel_bits(0x7 << 29, 0,
236                                     priv->io_base + _REG(ctrl_port));
237         } else if (lut_sel == VIU_LUT_OSD_EOTF) {
238                 writel(0, priv->io_base + _REG(addr_port));
239
240                 for (i = 0; i < 20; i++)
241                         writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
242                                priv->io_base + _REG(data_port));
243
244                 writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
245                        priv->io_base + _REG(data_port));
246
247                 for (i = 0; i < 20; i++)
248                         writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
249                                priv->io_base + _REG(data_port));
250
251                 for (i = 0; i < 20; i++)
252                         writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
253                                priv->io_base + _REG(data_port));
254
255                 writel(b_map[OSD_EOTF_LUT_SIZE - 1],
256                        priv->io_base + _REG(data_port));
257
258                 if (csc_on)
259                         writel_bits(7 << 27, 7 << 27,
260                                     priv->io_base + _REG(ctrl_port));
261                 else
262                         writel_bits(7 << 27, 0,
263                                     priv->io_base + _REG(ctrl_port));
264
265                 writel_bits(BIT(31), BIT(31),
266                             priv->io_base + _REG(ctrl_port));
267         }
268 }
269
270 /* eotf lut: linear */
271 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
272         0x0000, 0x0200, 0x0400, 0x0600,
273         0x0800, 0x0a00, 0x0c00, 0x0e00,
274         0x1000, 0x1200, 0x1400, 0x1600,
275         0x1800, 0x1a00, 0x1c00, 0x1e00,
276         0x2000, 0x2200, 0x2400, 0x2600,
277         0x2800, 0x2a00, 0x2c00, 0x2e00,
278         0x3000, 0x3200, 0x3400, 0x3600,
279         0x3800, 0x3a00, 0x3c00, 0x3e00,
280         0x4000
281 };
282
283 /* osd oetf lut: linear */
284 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
285         0, 0, 0, 0,
286         0, 32, 64, 96,
287         128, 160, 196, 224,
288         256, 288, 320, 352,
289         384, 416, 448, 480,
290         512, 544, 576, 608,
291         640, 672, 704, 736,
292         768, 800, 832, 864,
293         896, 928, 960, 992,
294         1023, 1023, 1023, 1023,
295         1023
296 };
297
298 static void meson_viu_load_matrix(struct meson_vpu_priv *priv)
299 {
300         /* eotf lut bypass */
301         meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
302                               eotf_33_linear_mapping, /* R */
303                               eotf_33_linear_mapping, /* G */
304                               eotf_33_linear_mapping, /* B */
305                               false);
306
307         /* eotf matrix bypass */
308         meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
309                                  eotf_bypass_coeff,
310                                  false);
311
312         /* oetf lut bypass */
313         meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
314                               oetf_41_linear_mapping, /* R */
315                               oetf_41_linear_mapping, /* G */
316                               oetf_41_linear_mapping, /* B */
317                               false);
318
319         /* osd matrix RGB709 to YUV709 limit */
320         meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
321                                  RGB709_to_YUV709l_coeff,
322                                  true);
323 }
324
325 void meson_vpu_init(struct udevice *dev)
326 {
327         struct meson_vpu_priv *priv = dev_get_priv(dev);
328         u32 reg;
329
330         /* vpu initialization */
331         writel(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
332         writel(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
333         writel(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
334         writel(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
335
336         /* Disable CVBS VDAC */
337         hhi_write(HHI_VDAC_CNTL0, 0);
338         hhi_write(HHI_VDAC_CNTL1, 8);
339
340         /* Power Down Dacs */
341         writel(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
342
343         /* Disable HDMI PHY */
344         hhi_write(HHI_HDMI_PHY_CNTL0, 0);
345
346         /* Disable HDMI */
347         writel_bits(0x3, 0, priv->io_base + _REG(VPU_HDMI_SETTING));
348
349         /* Disable all encoders */
350         writel(0, priv->io_base + _REG(ENCI_VIDEO_EN));
351         writel(0, priv->io_base + _REG(ENCP_VIDEO_EN));
352         writel(0, priv->io_base + _REG(ENCL_VIDEO_EN));
353
354         /* Disable VSync IRQ */
355         writel(0, priv->io_base + _REG(VENC_INTCTRL));
356
357         /* set dummy data default YUV black */
358         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
359                 writel(0x108080, priv->io_base + _REG(VPP_DUMMY_DATA1));
360         } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) {
361                 writel_bits(0xff << 16, 0xff << 16,
362                             priv->io_base + _REG(VIU_MISC_CTRL1));
363                 writel(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL));
364                 writel(0x1020080,
365                        priv->io_base + _REG(VPP_DUMMY_DATA1));
366         }
367
368         /* Initialize vpu fifo control registers */
369         writel(readl(priv->io_base + _REG(VPP_OFIFO_SIZE)) |
370                         0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE));
371         writel(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES));
372
373         /* Turn off preblend */
374         writel_bits(VPP_PREBLEND_ENABLE, 0,
375                     priv->io_base + _REG(VPP_MISC));
376
377         /* Turn off POSTBLEND */
378         writel_bits(VPP_POSTBLEND_ENABLE, 0,
379                     priv->io_base + _REG(VPP_MISC));
380
381         /* Force all planes off */
382         writel_bits(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND |
383                     VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND |
384                     VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0,
385                     priv->io_base + _REG(VPP_MISC));
386
387         /* Setup default VD settings */
388         writel(4096,
389                priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END));
390         writel(4096,
391                priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
392
393         /* Disable Scalers */
394         writel(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
395         writel(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
396         writel(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
397         writel(4 | (4 << 8) | BIT(15),
398                priv->io_base + _REG(VPP_SC_MISC));
399
400         /* Write in the proper filter coefficients. */
401         meson_vpp_write_scaling_filter_coefs(priv,
402                                 vpp_filter_coefs_4point_bspline, false);
403         meson_vpp_write_scaling_filter_coefs(priv,
404                                 vpp_filter_coefs_4point_bspline, true);
405
406         /* Write the VD proper filter coefficients. */
407         meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
408                                                 false);
409         meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
410                                                 true);
411
412         /* Disable OSDs */
413         writel_bits(BIT(0) | BIT(21), 0,
414                     priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
415         writel_bits(BIT(0) | BIT(21), 0,
416                     priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
417
418         /* On GXL/GXM, Use the 10bit HDR conversion matrix */
419         if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
420             meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL))
421                 meson_viu_load_matrix(priv);
422
423         /* Initialize OSD1 fifo control register */
424         reg = BIT(0) |  /* Urgent DDR request priority */
425               (4 << 5) | /* hold_fifo_lines */
426               (3 << 10) | /* burst length 64 */
427               (32 << 12) | /* fifo_depth_val: 32*8=256 */
428               (2 << 22) | /* 4 words in 1 burst */
429               (2 << 24);
430         writel(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
431         writel(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
432
433         /* Set OSD alpha replace value */
434         writel_bits(0xff << OSD_REPLACE_SHIFT,
435                     0xff << OSD_REPLACE_SHIFT,
436                     priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
437         writel_bits(0xff << OSD_REPLACE_SHIFT,
438                     0xff << OSD_REPLACE_SHIFT,
439                     priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
440 }