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