1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58enum viu_matrix_sel_e {
59 VIU_MATRIX_OSD_EOTF = 0,
60 VIU_MATRIX_OSD,
61};
62
63enum 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
75static int RGB709_to_YUV709l_coeff[MATRIX_5X3_COEF_SIZE] = {
76 0, 0, 0,
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,
81 0, 0, 0,
82 64, 512, 512,
83 0, 0, 0
84};
85
86
87static 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
92};
93
94void 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
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
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
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
163void 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 < 20; 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 < 20; 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 < 20; 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 < 20; 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 < 20; 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 < 20; 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
245static 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
258static 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
272static void meson_viu_load_matrix(struct meson_drm *priv)
273{
274
275 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_EOTF,
276 eotf_33_linear_mapping,
277 eotf_33_linear_mapping,
278 eotf_33_linear_mapping,
279 false);
280
281
282 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD_EOTF,
283 eotf_bypass_coeff,
284 false);
285
286
287 meson_viu_set_osd_lut(priv, VIU_LUT_OSD_OETF,
288 oetf_41_linear_mapping,
289 oetf_41_linear_mapping,
290 oetf_41_linear_mapping,
291 false);
292
293
294 meson_viu_set_osd_matrix(priv, VIU_MATRIX_OSD,
295 RGB709_to_YUV709l_coeff,
296 true);
297}
298
299void meson_viu_init(struct meson_drm *priv)
300{
301 uint32_t reg;
302
303
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
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
315 reg = BIT(0) |
316 (4 << 5) |
317 (3 << 10) |
318 (32 << 12) |
319 (2 << 22) |
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
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}
336