blob: 92228b5ceb7f0d5ab216a592fae48f0519f18bb3 [file] [log] [blame]
Neil Armstrong3bed4222018-07-24 17:45:28 +02001// 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
22void 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
27static 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
39static 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
52static 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
64static 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
79enum viu_matrix_sel_e {
80 VIU_MATRIX_OSD_EOTF = 0,
81 VIU_MATRIX_OSD,
82};
83
84enum 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
96static 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 */
108static 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
115static 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
187static 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 */
271static 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 */
284static 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
298static 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
325void 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}