Loading...
Note: File does not exist in v3.1.
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 * 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
54enum viu_matrix_sel_e {
55 VIU_MATRIX_OSD_EOTF = 0,
56 VIU_MATRIX_OSD,
57};
58
59enum 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
71static 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 */
83static 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
90void 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
159void 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 */
241static 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 */
254static 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
268static 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
295void 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}