GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / gpu / drm / meson / meson_viu.c
1 /*
2  * Copyright (C) 2016 BayLibre, SAS
3  * Author: Neil Armstrong <narmstrong@baylibre.com>
4  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5  * Copyright (C) 2014 Endless Mobile
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <drm/drmP.h>
24 #include "meson_drv.h"
25 #include "meson_viu.h"
26 #include "meson_vpp.h"
27 #include "meson_venc.h"
28 #include "meson_canvas.h"
29 #include "meson_registers.h"
30
31 /**
32  * DOC: Video Input Unit
33  *
34  * VIU Handles the Pixel scanout and the basic Colorspace conversions
35  * We handle the following features :
36  *
37  * - OSD1 RGB565/RGB888/xRGB8888 scanout
38  * - RGB conversion to x/cb/cr
39  * - Progressive or Interlace buffer scanout
40  * - OSD1 Commit on Vsync
41  * - HDR OSD matrix for GXL/GXM
42  *
43  * What is missing :
44  *
45  * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
46  * - YUV4:2:2 Y0CbY1Cr scanout
47  * - Conversion to YUV 4:4:4 from 4:2:2 input
48  * - Colorkey Alpha matching
49  * - Big endian scanout
50  * - X/Y reverse scanout
51  * - Global alpha setup
52  * - OSD2 support, would need interlace switching on vsync
53  * - OSD1 full scaling to support TV overscan
54  */
55
56 /* OSD csc defines */
57
58 enum viu_matrix_sel_e {
59         VIU_MATRIX_OSD_EOTF = 0,
60         VIU_MATRIX_OSD,
61 };
62
63 enum viu_lut_sel_e {
64         VIU_LUT_OSD_EOTF = 0,
65         VIU_LUT_OSD_OETF,
66 };
67
68 #define COEFF_NORM(a) ((int)((((a) * 2048.0) + 1) / 2))
69 #define MATRIX_5X3_COEF_SIZE 24
70
71 #define EOTF_COEFF_NORM(a) ((int)((((a) * 4096.0) + 1) / 2))
72 #define EOTF_COEFF_SIZE 10
73 #define EOTF_COEFF_RIGHTSHIFT 1
74
75 static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
76         0, 0, 0, /* pre offset */
77         COEFF_NORM(0.181873),   COEFF_NORM(0.611831),   COEFF_NORM(0.061765),
78         COEFF_NORM(-0.100251),  COEFF_NORM(-0.337249),  COEFF_NORM(0.437500),
79         COEFF_NORM(0.437500),   COEFF_NORM(-0.397384),  COEFF_NORM(-0.040116),
80         0, 0, 0, /* 10'/11'/12' */
81         0, 0, 0, /* 20'/21'/22' */
82         64, 512, 512, /* offset */
83         0, 0, 0 /* mode, right_shift, clip_en */
84 };
85
86 /*  eotf matrix: bypass */
87 static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = {
88         EOTF_COEFF_NORM(1.0),   EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(0.0),
89         EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(1.0),   EOTF_COEFF_NORM(0.0),
90         EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(0.0),   EOTF_COEFF_NORM(1.0),
91         EOTF_COEFF_RIGHTSHIFT /* right shift */
92 };
93
94 void meson_viu_set_osd_matrix(struct meson_drm *priv,
95                               enum viu_matrix_sel_e m_select,
96                               int *m, bool csc_on)
97 {
98         if (m_select == VIU_MATRIX_OSD) {
99                 /* osd matrix, VIU_MATRIX_0 */
100                 writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff),
101                         priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET0_1));
102                 writel(m[2] & 0xfff,
103                         priv->io_base + _REG(VIU_OSD1_MATRIX_PRE_OFFSET2));
104                 writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff),
105                         priv->io_base + _REG(VIU_OSD1_MATRIX_COEF00_01));
106                 writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff),
107                         priv->io_base + _REG(VIU_OSD1_MATRIX_COEF02_10));
108                 writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff),
109                         priv->io_base + _REG(VIU_OSD1_MATRIX_COEF11_12));
110                 writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff),
111                         priv->io_base + _REG(VIU_OSD1_MATRIX_COEF20_21));
112
113                 if (m[21]) {
114                         writel(((m[11] & 0x1fff) << 16) | (m[12] & 0x1fff),
115                                 priv->io_base +
116                                         _REG(VIU_OSD1_MATRIX_COEF22_30));
117                         writel(((m[13] & 0x1fff) << 16) | (m[14] & 0x1fff),
118                                 priv->io_base +
119                                         _REG(VIU_OSD1_MATRIX_COEF31_32));
120                         writel(((m[15] & 0x1fff) << 16) | (m[16] & 0x1fff),
121                                 priv->io_base +
122                                         _REG(VIU_OSD1_MATRIX_COEF40_41));
123                         writel(m[17] & 0x1fff, priv->io_base +
124                                 _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
125                 } else
126                         writel((m[11] & 0x1fff) << 16, priv->io_base +
127                                 _REG(VIU_OSD1_MATRIX_COEF22_30));
128
129                 writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff),
130                         priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET0_1));
131                 writel(m[20] & 0xfff,
132                         priv->io_base + _REG(VIU_OSD1_MATRIX_OFFSET2));
133
134                 writel_bits_relaxed(3 << 30, m[21] << 30,
135                         priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
136                 writel_bits_relaxed(7 << 16, m[22] << 16,
137                         priv->io_base + _REG(VIU_OSD1_MATRIX_COLMOD_COEF42));
138
139                 /* 23 reserved for clipping control */
140                 writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0,
141                         priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
142                 writel_bits_relaxed(BIT(1), 0,
143                         priv->io_base + _REG(VIU_OSD1_MATRIX_CTRL));
144         } else if (m_select == VIU_MATRIX_OSD_EOTF) {
145                 int i;
146
147                 /* osd eotf matrix, VIU_MATRIX_OSD_EOTF */
148                 for (i = 0; i < 5; i++)
149                         writel(((m[i * 2] & 0x1fff) << 16) |
150                                 (m[i * 2 + 1] & 0x1fff), priv->io_base +
151                                 _REG(VIU_OSD1_EOTF_CTL + i + 1));
152
153                 writel_bits_relaxed(BIT(30), csc_on ? BIT(30) : 0,
154                         priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
155                 writel_bits_relaxed(BIT(31), csc_on ? BIT(31) : 0,
156                         priv->io_base + _REG(VIU_OSD1_EOTF_CTL));
157         }
158 }
159
160 #define OSD_EOTF_LUT_SIZE 33
161 #define OSD_OETF_LUT_SIZE 41
162
163 void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel,
164                            unsigned int *r_map, unsigned int *g_map,
165                            unsigned int *b_map,
166                            bool csc_on)
167 {
168         unsigned int addr_port;
169         unsigned int data_port;
170         unsigned int ctrl_port;
171         int i;
172
173         if (lut_sel == VIU_LUT_OSD_EOTF) {
174                 addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT;
175                 data_port = VIU_OSD1_EOTF_LUT_DATA_PORT;
176                 ctrl_port = VIU_OSD1_EOTF_CTL;
177         } else if (lut_sel == VIU_LUT_OSD_OETF) {
178                 addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT;
179                 data_port = VIU_OSD1_OETF_LUT_DATA_PORT;
180                 ctrl_port = VIU_OSD1_OETF_CTL;
181         } else
182                 return;
183
184         if (lut_sel == VIU_LUT_OSD_OETF) {
185                 writel(0, priv->io_base + _REG(addr_port));
186
187                 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
188                         writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
189                                 priv->io_base + _REG(data_port));
190
191                 writel(r_map[OSD_OETF_LUT_SIZE - 1] | (g_map[0] << 16),
192                         priv->io_base + _REG(data_port));
193
194                 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
195                         writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
196                                 priv->io_base + _REG(data_port));
197
198                 for (i = 0; i < (OSD_OETF_LUT_SIZE / 2); i++)
199                         writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
200                                 priv->io_base + _REG(data_port));
201
202                 writel(b_map[OSD_OETF_LUT_SIZE - 1],
203                         priv->io_base + _REG(data_port));
204
205                 if (csc_on)
206                         writel_bits_relaxed(0x7 << 29, 7 << 29,
207                                             priv->io_base + _REG(ctrl_port));
208                 else
209                         writel_bits_relaxed(0x7 << 29, 0,
210                                             priv->io_base + _REG(ctrl_port));
211         } else if (lut_sel == VIU_LUT_OSD_EOTF) {
212                 writel(0, priv->io_base + _REG(addr_port));
213
214                 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
215                         writel(r_map[i * 2] | (r_map[i * 2 + 1] << 16),
216                                 priv->io_base + _REG(data_port));
217
218                 writel(r_map[OSD_EOTF_LUT_SIZE - 1] | (g_map[0] << 16),
219                         priv->io_base + _REG(data_port));
220
221                 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
222                         writel(g_map[i * 2 + 1] | (g_map[i * 2 + 2] << 16),
223                                 priv->io_base + _REG(data_port));
224
225                 for (i = 0; i < (OSD_EOTF_LUT_SIZE / 2); i++)
226                         writel(b_map[i * 2] | (b_map[i * 2 + 1] << 16),
227                                 priv->io_base + _REG(data_port));
228
229                 writel(b_map[OSD_EOTF_LUT_SIZE - 1],
230                         priv->io_base + _REG(data_port));
231
232                 if (csc_on)
233                         writel_bits_relaxed(7 << 27, 7 << 27,
234                                             priv->io_base + _REG(ctrl_port));
235                 else
236                         writel_bits_relaxed(7 << 27, 0,
237                                             priv->io_base + _REG(ctrl_port));
238
239                 writel_bits_relaxed(BIT(31), BIT(31),
240                                     priv->io_base + _REG(ctrl_port));
241         }
242 }
243
244 /* eotf lut: linear */
245 static unsigned int eotf_33_linear_mapping[OSD_EOTF_LUT_SIZE] = {
246         0x0000, 0x0200, 0x0400, 0x0600,
247         0x0800, 0x0a00, 0x0c00, 0x0e00,
248         0x1000, 0x1200, 0x1400, 0x1600,
249         0x1800, 0x1a00, 0x1c00, 0x1e00,
250         0x2000, 0x2200, 0x2400, 0x2600,
251         0x2800, 0x2a00, 0x2c00, 0x2e00,
252         0x3000, 0x3200, 0x3400, 0x3600,
253         0x3800, 0x3a00, 0x3c00, 0x3e00,
254         0x4000
255 };
256
257 /* osd oetf lut: linear */
258 static unsigned int oetf_41_linear_mapping[OSD_OETF_LUT_SIZE] = {
259         0, 0, 0, 0,
260         0, 32, 64, 96,
261         128, 160, 196, 224,
262         256, 288, 320, 352,
263         384, 416, 448, 480,
264         512, 544, 576, 608,
265         640, 672, 704, 736,
266         768, 800, 832, 864,
267         896, 928, 960, 992,
268         1023, 1023, 1023, 1023,
269         1023
270 };
271
272 static void meson_viu_load_matrix(struct meson_drm *priv)
273 {
274         /* eotf lut bypass */
275         meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
276                               eotf_33_linear_mapping, /* R */
277                               eotf_33_linear_mapping, /* G */
278                               eotf_33_linear_mapping, /* B */
279                               false);
280
281         /* eotf matrix bypass */
282         meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
283                                  eotf_bypass_coeff,
284                                  false);
285
286         /* oetf lut bypass */
287         meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
288                               oetf_41_linear_mapping, /* R */
289                               oetf_41_linear_mapping, /* G */
290                               oetf_41_linear_mapping, /* B */
291                               false);
292
293         /* osd matrix RGB709 to YUV709 limit */
294         meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
295                                  RGB709_to_YUV709l_coeff,
296                                  true);
297 }
298
299 void meson_viu_init(struct meson_drm *priv)
300 {
301         uint32_t reg;
302
303         /* Disable OSDs */
304         writel_bits_relaxed(BIT(0) | BIT(21), 0,
305                         priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
306         writel_bits_relaxed(BIT(0) | BIT(21), 0,
307                         priv->io_base + _REG(VIU_OSD2_CTRL_STAT));
308
309         /* On GXL/GXM, Use the 10bit HDR conversion matrix */
310         if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
311             meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
312                 meson_viu_load_matrix(priv);
313
314         /* Initialize OSD1 fifo control register */
315         reg = BIT(0) |  /* Urgent DDR request priority */
316               (4 << 5) | /* hold_fifo_lines */
317               (3 << 10) | /* burst length 64 */
318               (32 << 12) | /* fifo_depth_val: 32*8=256 */
319               (2 << 22) | /* 4 words in 1 burst */
320               (2 << 24);
321         writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
322         writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
323
324         /* Set OSD alpha replace value */
325         writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
326                             0xff << OSD_REPLACE_SHIFT,
327                             priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
328         writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
329                             0xff << OSD_REPLACE_SHIFT,
330                             priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
331
332         priv->viu.osd1_enabled = false;
333         priv->viu.osd1_commit = false;
334         priv->viu.osd1_interlace = false;
335 }