]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
575001e4 SB |
2 | /* |
3 | * Porting to u-boot: | |
4 | * | |
5 | * (C) Copyright 2010 | |
6 | * Stefano Babic, DENX Software Engineering, sbabic@denx.de | |
7 | * | |
8 | * Linux IPU driver for MX51: | |
9 | * | |
10 | * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. | |
575001e4 SB |
11 | */ |
12 | ||
13 | /* #define DEBUG */ | |
14 | ||
d678a59d | 15 | #include <common.h> |
f7ae49fc | 16 | #include <log.h> |
c05ed00a | 17 | #include <linux/delay.h> |
575001e4 | 18 | #include <linux/types.h> |
1221ce45 | 19 | #include <linux/errno.h> |
575001e4 SB |
20 | #include <asm/io.h> |
21 | #include <asm/arch/imx-regs.h> | |
22 | #include <asm/arch/sys_proto.h> | |
23 | #include "ipu.h" | |
24 | #include "ipu_regs.h" | |
25 | ||
26 | enum csc_type_t { | |
27 | RGB2YUV = 0, | |
28 | YUV2RGB, | |
29 | RGB2RGB, | |
30 | YUV2YUV, | |
31 | CSC_NONE, | |
32 | CSC_NUM | |
33 | }; | |
34 | ||
35 | struct dp_csc_param_t { | |
36 | int mode; | |
e6e9cff2 | 37 | const int (*coeff)[5][3]; |
575001e4 SB |
38 | }; |
39 | ||
40 | #define SYNC_WAVE 0 | |
41 | ||
42 | /* DC display ID assignments */ | |
43 | #define DC_DISP_ID_SYNC(di) (di) | |
44 | #define DC_DISP_ID_SERIAL 2 | |
45 | #define DC_DISP_ID_ASYNC 3 | |
46 | ||
47 | int dmfc_type_setup; | |
48 | static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23; | |
49 | int g_di1_tvout; | |
50 | ||
51 | extern struct clk *g_ipu_clk; | |
cf65d478 | 52 | extern struct clk *g_ldb_clk; |
575001e4 SB |
53 | extern struct clk *g_di_clk[2]; |
54 | extern struct clk *g_pixel_clk[2]; | |
55 | ||
56 | extern unsigned char g_ipu_clk_enabled; | |
57 | extern unsigned char g_dc_di_assignment[]; | |
58 | ||
59 | void ipu_dmfc_init(int dmfc_type, int first) | |
60 | { | |
61 | u32 dmfc_wr_chan, dmfc_dp_chan; | |
62 | ||
63 | if (first) { | |
64 | if (dmfc_type_setup > dmfc_type) | |
65 | dmfc_type = dmfc_type_setup; | |
66 | else | |
67 | dmfc_type_setup = dmfc_type; | |
68 | ||
69 | /* disable DMFC-IC channel*/ | |
70 | __raw_writel(0x2, DMFC_IC_CTRL); | |
71 | } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) { | |
72 | printf("DMFC high resolution has set, will not change\n"); | |
73 | return; | |
74 | } else | |
75 | dmfc_type_setup = dmfc_type; | |
76 | ||
77 | if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) { | |
78 | /* 1 - segment 0~3; | |
79 | * 5B - segement 4, 5; | |
80 | * 5F - segement 6, 7; | |
81 | * 1C, 2C and 6B, 6F unused; | |
82 | */ | |
83 | debug("IPU DMFC DC HIGH RES: 1(0~3), 5B(4,5), 5F(6,7)\n"); | |
84 | dmfc_wr_chan = 0x00000088; | |
85 | dmfc_dp_chan = 0x00009694; | |
86 | dmfc_size_28 = 256 * 4; | |
87 | dmfc_size_29 = 0; | |
88 | dmfc_size_24 = 0; | |
89 | dmfc_size_27 = 128 * 4; | |
90 | dmfc_size_23 = 128 * 4; | |
91 | } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) { | |
92 | /* 1 - segment 0, 1; | |
93 | * 5B - segement 2~5; | |
94 | * 5F - segement 6,7; | |
95 | * 1C, 2C and 6B, 6F unused; | |
96 | */ | |
97 | debug("IPU DMFC DP HIGH RES: 1(0,1), 5B(2~5), 5F(6,7)\n"); | |
98 | dmfc_wr_chan = 0x00000090; | |
99 | dmfc_dp_chan = 0x0000968a; | |
100 | dmfc_size_28 = 128 * 4; | |
101 | dmfc_size_29 = 0; | |
102 | dmfc_size_24 = 0; | |
103 | dmfc_size_27 = 128 * 4; | |
104 | dmfc_size_23 = 256 * 4; | |
105 | } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) { | |
106 | /* 5B - segement 0~3; | |
107 | * 5F - segement 4~7; | |
108 | * 1, 1C, 2C and 6B, 6F unused; | |
109 | */ | |
110 | debug("IPU DMFC ONLY-DP HIGH RES: 5B(0~3), 5F(4~7)\n"); | |
111 | dmfc_wr_chan = 0x00000000; | |
112 | dmfc_dp_chan = 0x00008c88; | |
113 | dmfc_size_28 = 0; | |
114 | dmfc_size_29 = 0; | |
115 | dmfc_size_24 = 0; | |
116 | dmfc_size_27 = 256 * 4; | |
117 | dmfc_size_23 = 256 * 4; | |
118 | } else { | |
119 | /* 1 - segment 0, 1; | |
120 | * 5B - segement 4, 5; | |
121 | * 5F - segement 6, 7; | |
122 | * 1C, 2C and 6B, 6F unused; | |
123 | */ | |
124 | debug("IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n"); | |
125 | dmfc_wr_chan = 0x00000090; | |
126 | dmfc_dp_chan = 0x00009694; | |
127 | dmfc_size_28 = 128 * 4; | |
128 | dmfc_size_29 = 0; | |
129 | dmfc_size_24 = 0; | |
130 | dmfc_size_27 = 128 * 4; | |
131 | dmfc_size_23 = 128 * 4; | |
132 | } | |
133 | __raw_writel(dmfc_wr_chan, DMFC_WR_CHAN); | |
134 | __raw_writel(0x202020F6, DMFC_WR_CHAN_DEF); | |
135 | __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN); | |
136 | /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */ | |
137 | __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF); | |
138 | } | |
139 | ||
140 | void ipu_dmfc_set_wait4eot(int dma_chan, int width) | |
141 | { | |
142 | u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1); | |
143 | ||
144 | if (width >= HIGH_RESOLUTION_WIDTH) { | |
145 | if (dma_chan == 23) | |
146 | ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0); | |
147 | else if (dma_chan == 28) | |
148 | ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0); | |
149 | } | |
150 | ||
151 | if (dma_chan == 23) { /*5B*/ | |
152 | if (dmfc_size_23 / width > 3) | |
153 | dmfc_gen1 |= 1UL << 20; | |
154 | else | |
155 | dmfc_gen1 &= ~(1UL << 20); | |
156 | } else if (dma_chan == 24) { /*6B*/ | |
157 | if (dmfc_size_24 / width > 1) | |
158 | dmfc_gen1 |= 1UL << 22; | |
159 | else | |
160 | dmfc_gen1 &= ~(1UL << 22); | |
161 | } else if (dma_chan == 27) { /*5F*/ | |
162 | if (dmfc_size_27 / width > 2) | |
163 | dmfc_gen1 |= 1UL << 21; | |
164 | else | |
165 | dmfc_gen1 &= ~(1UL << 21); | |
166 | } else if (dma_chan == 28) { /*1*/ | |
167 | if (dmfc_size_28 / width > 2) | |
168 | dmfc_gen1 |= 1UL << 16; | |
169 | else | |
170 | dmfc_gen1 &= ~(1UL << 16); | |
171 | } else if (dma_chan == 29) { /*6F*/ | |
172 | if (dmfc_size_29 / width > 1) | |
173 | dmfc_gen1 |= 1UL << 23; | |
174 | else | |
175 | dmfc_gen1 &= ~(1UL << 23); | |
176 | } | |
177 | ||
178 | __raw_writel(dmfc_gen1, DMFC_GENERAL1); | |
179 | } | |
180 | ||
181 | static void ipu_di_data_wave_config(int di, | |
182 | int wave_gen, | |
183 | int access_size, int component_size) | |
184 | { | |
185 | u32 reg; | |
186 | reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | | |
187 | (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); | |
188 | __raw_writel(reg, DI_DW_GEN(di, wave_gen)); | |
189 | } | |
190 | ||
191 | static void ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set, | |
192 | int up, int down) | |
193 | { | |
194 | u32 reg; | |
195 | ||
196 | reg = __raw_readl(DI_DW_GEN(di, wave_gen)); | |
197 | reg &= ~(0x3 << (di_pin * 2)); | |
198 | reg |= set << (di_pin * 2); | |
199 | __raw_writel(reg, DI_DW_GEN(di, wave_gen)); | |
200 | ||
201 | __raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set)); | |
202 | } | |
203 | ||
204 | static void ipu_di_sync_config(int di, int wave_gen, | |
205 | int run_count, int run_src, | |
206 | int offset_count, int offset_src, | |
207 | int repeat_count, int cnt_clr_src, | |
208 | int cnt_polarity_gen_en, | |
209 | int cnt_polarity_clr_src, | |
210 | int cnt_polarity_trigger_src, | |
211 | int cnt_up, int cnt_down) | |
212 | { | |
213 | u32 reg; | |
214 | ||
215 | if ((run_count >= 0x1000) || (offset_count >= 0x1000) || | |
216 | (repeat_count >= 0x1000) || | |
217 | (cnt_up >= 0x400) || (cnt_down >= 0x400)) { | |
218 | printf("DI%d counters out of range.\n", di); | |
219 | return; | |
220 | } | |
221 | ||
222 | reg = (run_count << 19) | (++run_src << 16) | | |
223 | (offset_count << 3) | ++offset_src; | |
224 | __raw_writel(reg, DI_SW_GEN0(di, wave_gen)); | |
225 | reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) | | |
226 | (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9); | |
227 | reg |= (cnt_down << 16) | cnt_up; | |
228 | if (repeat_count == 0) { | |
229 | /* Enable auto reload */ | |
230 | reg |= 0x10000000; | |
231 | } | |
232 | __raw_writel(reg, DI_SW_GEN1(di, wave_gen)); | |
233 | reg = __raw_readl(DI_STP_REP(di, wave_gen)); | |
234 | reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1))); | |
235 | reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1)); | |
236 | __raw_writel(reg, DI_STP_REP(di, wave_gen)); | |
237 | } | |
238 | ||
239 | static void ipu_dc_map_config(int map, int byte_num, int offset, int mask) | |
240 | { | |
241 | int ptr = map * 3 + byte_num; | |
242 | u32 reg; | |
243 | ||
244 | reg = __raw_readl(DC_MAP_CONF_VAL(ptr)); | |
245 | reg &= ~(0xFFFF << (16 * (ptr & 0x1))); | |
246 | reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1)); | |
247 | __raw_writel(reg, DC_MAP_CONF_VAL(ptr)); | |
248 | ||
249 | reg = __raw_readl(DC_MAP_CONF_PTR(map)); | |
250 | reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num))); | |
251 | reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num)); | |
252 | __raw_writel(reg, DC_MAP_CONF_PTR(map)); | |
253 | } | |
254 | ||
255 | static void ipu_dc_map_clear(int map) | |
256 | { | |
257 | u32 reg = __raw_readl(DC_MAP_CONF_PTR(map)); | |
258 | __raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))), | |
259 | DC_MAP_CONF_PTR(map)); | |
260 | } | |
261 | ||
262 | static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, | |
263 | int wave, int glue, int sync) | |
264 | { | |
265 | u32 reg; | |
266 | int stop = 1; | |
267 | ||
268 | reg = sync; | |
269 | reg |= (glue << 4); | |
270 | reg |= (++wave << 11); | |
271 | reg |= (++map << 15); | |
272 | reg |= (operand << 20) & 0xFFF00000; | |
273 | __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); | |
274 | ||
275 | reg = (operand >> 12); | |
276 | reg |= opcode << 4; | |
277 | reg |= (stop << 9); | |
278 | __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); | |
279 | } | |
280 | ||
281 | static void ipu_dc_link_event(int chan, int event, int addr, int priority) | |
282 | { | |
283 | u32 reg; | |
284 | ||
285 | reg = __raw_readl(DC_RL_CH(chan, event)); | |
286 | reg &= ~(0xFFFF << (16 * (event & 0x1))); | |
287 | reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); | |
288 | __raw_writel(reg, DC_RL_CH(chan, event)); | |
289 | } | |
290 | ||
291 | /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; | |
292 | * U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.; | |
293 | * V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.; | |
294 | */ | |
295 | static const int rgb2ycbcr_coeff[5][3] = { | |
296 | {0x4D, 0x96, 0x1D}, | |
297 | {0x3D5, 0x3AB, 0x80}, | |
298 | {0x80, 0x395, 0x3EB}, | |
299 | {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */ | |
300 | {0x2, 0x2, 0x2}, /* S0, S1, S2 */ | |
301 | }; | |
302 | ||
303 | /* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); | |
304 | * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); | |
305 | * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); | |
306 | */ | |
307 | static const int ycbcr2rgb_coeff[5][3] = { | |
308 | {0x095, 0x000, 0x0CC}, | |
309 | {0x095, 0x3CE, 0x398}, | |
310 | {0x095, 0x0FF, 0x000}, | |
311 | {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */ | |
312 | {0x1, 0x1, 0x1}, /*S0,S1,S2 */ | |
313 | }; | |
314 | ||
315 | #define mask_a(a) ((u32)(a) & 0x3FF) | |
316 | #define mask_b(b) ((u32)(b) & 0x3FFF) | |
317 | ||
318 | /* Pls keep S0, S1 and S2 as 0x2 by using this convertion */ | |
319 | static int rgb_to_yuv(int n, int red, int green, int blue) | |
320 | { | |
321 | int c; | |
322 | c = red * rgb2ycbcr_coeff[n][0]; | |
323 | c += green * rgb2ycbcr_coeff[n][1]; | |
324 | c += blue * rgb2ycbcr_coeff[n][2]; | |
325 | c /= 16; | |
326 | c += rgb2ycbcr_coeff[3][n] * 4; | |
327 | c += 8; | |
328 | c /= 16; | |
329 | if (c < 0) | |
330 | c = 0; | |
331 | if (c > 255) | |
332 | c = 255; | |
333 | return c; | |
334 | } | |
335 | ||
336 | /* | |
337 | * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE | |
338 | * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE | |
339 | */ | |
340 | static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = { | |
341 | { | |
342 | {DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff}, | |
343 | {0, 0}, | |
344 | {0, 0}, | |
345 | {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}, | |
346 | {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff} | |
347 | }, | |
348 | { | |
349 | {0, 0}, | |
350 | {DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff}, | |
351 | {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}, | |
352 | {0, 0}, | |
353 | {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff} | |
354 | }, | |
355 | { | |
356 | {0, 0}, | |
357 | {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, | |
358 | {0, 0}, | |
359 | {0, 0}, | |
360 | {0, 0} | |
361 | }, | |
362 | { | |
363 | {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, | |
364 | {0, 0}, | |
365 | {0, 0}, | |
366 | {0, 0}, | |
367 | {0, 0} | |
368 | }, | |
369 | { | |
370 | {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, | |
371 | {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, | |
372 | {0, 0}, | |
373 | {0, 0}, | |
374 | {0, 0} | |
375 | } | |
376 | }; | |
377 | ||
378 | static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE; | |
379 | static int color_key_4rgb = 1; | |
380 | ||
c5fe2532 | 381 | static void ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param, |
575001e4 SB |
382 | unsigned char srm_mode_update) |
383 | { | |
384 | u32 reg; | |
385 | const int (*coeff)[5][3]; | |
386 | ||
387 | if (dp_csc_param.mode >= 0) { | |
564964bd | 388 | reg = __raw_readl(DP_COM_CONF()); |
575001e4 SB |
389 | reg &= ~DP_COM_CONF_CSC_DEF_MASK; |
390 | reg |= dp_csc_param.mode; | |
564964bd | 391 | __raw_writel(reg, DP_COM_CONF()); |
575001e4 SB |
392 | } |
393 | ||
394 | coeff = dp_csc_param.coeff; | |
395 | ||
396 | if (coeff) { | |
397 | __raw_writel(mask_a((*coeff)[0][0]) | | |
564964bd | 398 | (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0()); |
575001e4 | 399 | __raw_writel(mask_a((*coeff)[0][2]) | |
564964bd | 400 | (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1()); |
575001e4 | 401 | __raw_writel(mask_a((*coeff)[1][1]) | |
564964bd | 402 | (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2()); |
575001e4 | 403 | __raw_writel(mask_a((*coeff)[2][0]) | |
564964bd | 404 | (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3()); |
575001e4 SB |
405 | __raw_writel(mask_a((*coeff)[2][2]) | |
406 | (mask_b((*coeff)[3][0]) << 16) | | |
564964bd | 407 | ((*coeff)[4][0] << 30), DP_CSC_0()); |
575001e4 SB |
408 | __raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) | |
409 | (mask_b((*coeff)[3][2]) << 16) | | |
564964bd | 410 | ((*coeff)[4][2] << 30), DP_CSC_1()); |
575001e4 SB |
411 | } |
412 | ||
413 | if (srm_mode_update) { | |
414 | reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
415 | __raw_writel(reg, IPU_SRM_PRI2); | |
416 | } | |
417 | } | |
418 | ||
419 | int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, | |
420 | uint32_t out_pixel_fmt) | |
421 | { | |
422 | int in_fmt, out_fmt; | |
423 | int dp; | |
424 | int partial = 0; | |
425 | uint32_t reg; | |
426 | ||
427 | if (channel == MEM_FG_SYNC) { | |
428 | dp = DP_SYNC; | |
429 | partial = 1; | |
430 | } else if (channel == MEM_BG_SYNC) { | |
431 | dp = DP_SYNC; | |
432 | partial = 0; | |
433 | } else if (channel == MEM_BG_ASYNC0) { | |
434 | dp = DP_ASYNC0; | |
435 | partial = 0; | |
436 | } else { | |
437 | return -EINVAL; | |
438 | } | |
439 | ||
440 | in_fmt = format_to_colorspace(in_pixel_fmt); | |
441 | out_fmt = format_to_colorspace(out_pixel_fmt); | |
442 | ||
443 | if (partial) { | |
444 | if (in_fmt == RGB) { | |
445 | if (out_fmt == RGB) | |
446 | fg_csc_type = RGB2RGB; | |
447 | else | |
448 | fg_csc_type = RGB2YUV; | |
449 | } else { | |
450 | if (out_fmt == RGB) | |
451 | fg_csc_type = YUV2RGB; | |
452 | else | |
453 | fg_csc_type = YUV2YUV; | |
454 | } | |
455 | } else { | |
456 | if (in_fmt == RGB) { | |
457 | if (out_fmt == RGB) | |
458 | bg_csc_type = RGB2RGB; | |
459 | else | |
460 | bg_csc_type = RGB2YUV; | |
461 | } else { | |
462 | if (out_fmt == RGB) | |
463 | bg_csc_type = YUV2RGB; | |
464 | else | |
465 | bg_csc_type = YUV2YUV; | |
466 | } | |
467 | } | |
468 | ||
469 | /* Transform color key from rgb to yuv if CSC is enabled */ | |
564964bd | 470 | reg = __raw_readl(DP_COM_CONF()); |
575001e4 SB |
471 | if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) && |
472 | (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || | |
473 | ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || | |
474 | ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || | |
475 | ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) { | |
476 | int red, green, blue; | |
477 | int y, u, v; | |
564964bd | 478 | uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL()) & |
575001e4 SB |
479 | 0xFFFFFFL; |
480 | ||
481 | debug("_ipu_dp_init color key 0x%x need change to yuv fmt!\n", | |
482 | color_key); | |
483 | ||
484 | red = (color_key >> 16) & 0xFF; | |
485 | green = (color_key >> 8) & 0xFF; | |
486 | blue = color_key & 0xFF; | |
487 | ||
488 | y = rgb_to_yuv(0, red, green, blue); | |
489 | u = rgb_to_yuv(1, red, green, blue); | |
490 | v = rgb_to_yuv(2, red, green, blue); | |
491 | color_key = (y << 16) | (u << 8) | v; | |
492 | ||
564964bd MV |
493 | reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L; |
494 | __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL()); | |
575001e4 SB |
495 | color_key_4rgb = 0; |
496 | ||
497 | debug("_ipu_dp_init color key change to yuv fmt 0x%x!\n", | |
498 | color_key); | |
499 | } | |
500 | ||
501 | ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 1); | |
502 | ||
503 | return 0; | |
504 | } | |
505 | ||
506 | void ipu_dp_uninit(ipu_channel_t channel) | |
507 | { | |
508 | int dp; | |
509 | int partial = 0; | |
510 | ||
511 | if (channel == MEM_FG_SYNC) { | |
512 | dp = DP_SYNC; | |
513 | partial = 1; | |
514 | } else if (channel == MEM_BG_SYNC) { | |
515 | dp = DP_SYNC; | |
516 | partial = 0; | |
517 | } else if (channel == MEM_BG_ASYNC0) { | |
518 | dp = DP_ASYNC0; | |
519 | partial = 0; | |
520 | } else { | |
521 | return; | |
522 | } | |
523 | ||
524 | if (partial) | |
525 | fg_csc_type = CSC_NONE; | |
526 | else | |
527 | bg_csc_type = CSC_NONE; | |
528 | ||
529 | ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0); | |
530 | } | |
531 | ||
532 | void ipu_dc_init(int dc_chan, int di, unsigned char interlaced) | |
533 | { | |
534 | u32 reg = 0; | |
535 | ||
536 | if ((dc_chan == 1) || (dc_chan == 5)) { | |
537 | if (interlaced) { | |
538 | ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3); | |
539 | ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2); | |
540 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1); | |
541 | } else { | |
542 | if (di) { | |
543 | ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); | |
544 | ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); | |
545 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, | |
546 | 4, 1); | |
547 | } else { | |
548 | ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); | |
549 | ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); | |
550 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, | |
551 | 7, 1); | |
552 | } | |
553 | } | |
554 | ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); | |
555 | ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); | |
556 | ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); | |
557 | ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); | |
558 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); | |
559 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); | |
560 | ||
561 | reg = 0x2; | |
562 | reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; | |
563 | reg |= di << 2; | |
564 | if (interlaced) | |
565 | reg |= DC_WR_CH_CONF_FIELD_MODE; | |
566 | } else if ((dc_chan == 8) || (dc_chan == 9)) { | |
567 | /* async channels */ | |
568 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1); | |
569 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1); | |
570 | ||
571 | reg = 0x3; | |
572 | reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; | |
573 | } | |
574 | __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
575 | ||
576 | __raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan)); | |
577 | ||
578 | __raw_writel(0x00000084, DC_GEN); | |
579 | } | |
580 | ||
581 | void ipu_dc_uninit(int dc_chan) | |
582 | { | |
583 | if ((dc_chan == 1) || (dc_chan == 5)) { | |
584 | ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0); | |
585 | ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0); | |
586 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0); | |
587 | ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); | |
588 | ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); | |
589 | ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); | |
590 | ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); | |
591 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); | |
592 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); | |
593 | } else if ((dc_chan == 8) || (dc_chan == 9)) { | |
594 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0); | |
595 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0); | |
596 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0); | |
597 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0); | |
598 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0); | |
599 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0); | |
600 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0); | |
601 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0); | |
602 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0); | |
603 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0); | |
604 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0); | |
605 | ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0); | |
606 | } | |
607 | } | |
608 | ||
575001e4 SB |
609 | void ipu_dp_dc_enable(ipu_channel_t channel) |
610 | { | |
611 | int di; | |
612 | uint32_t reg; | |
613 | uint32_t dc_chan; | |
614 | ||
575001e4 SB |
615 | if (channel == MEM_DC_SYNC) |
616 | dc_chan = 1; | |
cd8f09d9 | 617 | else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC)) |
575001e4 SB |
618 | dc_chan = 5; |
619 | else | |
620 | return; | |
621 | ||
622 | if (channel == MEM_FG_SYNC) { | |
623 | /* Enable FG channel */ | |
564964bd MV |
624 | reg = __raw_readl(DP_COM_CONF()); |
625 | __raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF()); | |
575001e4 SB |
626 | |
627 | reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
628 | __raw_writel(reg, IPU_SRM_PRI2); | |
629 | return; | |
630 | } | |
631 | ||
632 | di = g_dc_di_assignment[dc_chan]; | |
633 | ||
634 | /* Make sure other DC sync channel is not assigned same DI */ | |
635 | reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan)); | |
636 | if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) { | |
637 | reg &= ~DC_WR_CH_CONF_PROG_DI_ID; | |
638 | reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID; | |
639 | __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); | |
640 | } | |
641 | ||
642 | reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
643 | reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET; | |
644 | __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
645 | ||
646 | clk_enable(g_pixel_clk[di]); | |
647 | } | |
648 | ||
649 | static unsigned char dc_swap; | |
650 | ||
651 | void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap) | |
652 | { | |
653 | uint32_t reg; | |
654 | uint32_t csc; | |
655 | uint32_t dc_chan = 0; | |
656 | int timeout = 50; | |
e66866c5 | 657 | int irq = 0; |
575001e4 SB |
658 | |
659 | dc_swap = swap; | |
660 | ||
661 | if (channel == MEM_DC_SYNC) { | |
662 | dc_chan = 1; | |
e66866c5 | 663 | irq = IPU_IRQ_DC_FC_1; |
575001e4 SB |
664 | } else if (channel == MEM_BG_SYNC) { |
665 | dc_chan = 5; | |
e66866c5 | 666 | irq = IPU_IRQ_DP_SF_END; |
575001e4 SB |
667 | } else if (channel == MEM_FG_SYNC) { |
668 | /* Disable FG channel */ | |
669 | dc_chan = 5; | |
670 | ||
564964bd | 671 | reg = __raw_readl(DP_COM_CONF()); |
575001e4 SB |
672 | csc = reg & DP_COM_CONF_CSC_DEF_MASK; |
673 | if (csc == DP_COM_CONF_CSC_DEF_FG) | |
674 | reg &= ~DP_COM_CONF_CSC_DEF_MASK; | |
675 | ||
676 | reg &= ~DP_COM_CONF_FG_EN; | |
564964bd | 677 | __raw_writel(reg, DP_COM_CONF()); |
575001e4 SB |
678 | |
679 | reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
680 | __raw_writel(reg, IPU_SRM_PRI2); | |
681 | ||
682 | timeout = 50; | |
683 | ||
684 | /* | |
685 | * Wait for DC triple buffer to empty, | |
686 | * this check is useful for tv overlay. | |
687 | */ | |
688 | if (g_dc_di_assignment[dc_chan] == 0) | |
689 | while ((__raw_readl(DC_STAT) & 0x00000002) | |
690 | != 0x00000002) { | |
691 | udelay(2000); | |
692 | timeout -= 2; | |
693 | if (timeout <= 0) | |
694 | break; | |
695 | } | |
696 | else if (g_dc_di_assignment[dc_chan] == 1) | |
697 | while ((__raw_readl(DC_STAT) & 0x00000020) | |
698 | != 0x00000020) { | |
699 | udelay(2000); | |
700 | timeout -= 2; | |
701 | if (timeout <= 0) | |
702 | break; | |
703 | } | |
704 | return; | |
705 | } else { | |
706 | return; | |
707 | } | |
708 | ||
709 | if (dc_swap) { | |
710 | /* Swap DC channel 1 and 5 settings, and disable old dc chan */ | |
711 | reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
712 | __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); | |
713 | reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; | |
714 | reg ^= DC_WR_CH_CONF_PROG_DI_ID; | |
715 | __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
716 | } else { | |
e66866c5 LY |
717 | /* Make sure that we leave at the irq starting edge */ |
718 | __raw_writel(IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq)); | |
719 | do { | |
720 | reg = __raw_readl(IPUIRQ_2_STATREG(irq)); | |
721 | } while (!(reg & IPUIRQ_2_MASK(irq))); | |
575001e4 SB |
722 | |
723 | reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); | |
724 | reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; | |
725 | __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); | |
726 | ||
727 | reg = __raw_readl(IPU_DISP_GEN); | |
728 | if (g_dc_di_assignment[dc_chan]) | |
729 | reg &= ~DI1_COUNTER_RELEASE; | |
730 | else | |
731 | reg &= ~DI0_COUNTER_RELEASE; | |
732 | __raw_writel(reg, IPU_DISP_GEN); | |
733 | ||
734 | /* Clock is already off because it must be done quickly, but | |
735 | we need to fix the ref count */ | |
736 | clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); | |
737 | } | |
738 | } | |
739 | ||
740 | void ipu_init_dc_mappings(void) | |
741 | { | |
742 | /* IPU_PIX_FMT_RGB24 */ | |
743 | ipu_dc_map_clear(0); | |
744 | ipu_dc_map_config(0, 0, 7, 0xFF); | |
745 | ipu_dc_map_config(0, 1, 15, 0xFF); | |
746 | ipu_dc_map_config(0, 2, 23, 0xFF); | |
747 | ||
748 | /* IPU_PIX_FMT_RGB666 */ | |
749 | ipu_dc_map_clear(1); | |
750 | ipu_dc_map_config(1, 0, 5, 0xFC); | |
751 | ipu_dc_map_config(1, 1, 11, 0xFC); | |
752 | ipu_dc_map_config(1, 2, 17, 0xFC); | |
753 | ||
754 | /* IPU_PIX_FMT_YUV444 */ | |
755 | ipu_dc_map_clear(2); | |
756 | ipu_dc_map_config(2, 0, 15, 0xFF); | |
757 | ipu_dc_map_config(2, 1, 23, 0xFF); | |
758 | ipu_dc_map_config(2, 2, 7, 0xFF); | |
759 | ||
760 | /* IPU_PIX_FMT_RGB565 */ | |
761 | ipu_dc_map_clear(3); | |
762 | ipu_dc_map_config(3, 0, 4, 0xF8); | |
763 | ipu_dc_map_config(3, 1, 10, 0xFC); | |
764 | ipu_dc_map_config(3, 2, 15, 0xF8); | |
765 | ||
766 | /* IPU_PIX_FMT_LVDS666 */ | |
767 | ipu_dc_map_clear(4); | |
768 | ipu_dc_map_config(4, 0, 5, 0xFC); | |
769 | ipu_dc_map_config(4, 1, 13, 0xFC); | |
770 | ipu_dc_map_config(4, 2, 21, 0xFC); | |
771 | } | |
772 | ||
c5fe2532 | 773 | static int ipu_pixfmt_to_map(uint32_t fmt) |
575001e4 SB |
774 | { |
775 | switch (fmt) { | |
776 | case IPU_PIX_FMT_GENERIC: | |
777 | case IPU_PIX_FMT_RGB24: | |
778 | return 0; | |
779 | case IPU_PIX_FMT_RGB666: | |
780 | return 1; | |
781 | case IPU_PIX_FMT_YUV444: | |
782 | return 2; | |
783 | case IPU_PIX_FMT_RGB565: | |
784 | return 3; | |
785 | case IPU_PIX_FMT_LVDS666: | |
786 | return 4; | |
787 | } | |
788 | ||
789 | return -1; | |
790 | } | |
791 | ||
575001e4 SB |
792 | /* |
793 | * This function is called to initialize a synchronous LCD panel. | |
794 | * | |
795 | * @param disp The DI the panel is attached to. | |
796 | * | |
797 | * @param pixel_clk Desired pixel clock frequency in Hz. | |
798 | * | |
799 | * @param pixel_fmt Input parameter for pixel format of buffer. | |
800 | * Pixel format is a FOURCC ASCII code. | |
801 | * | |
802 | * @param width The width of panel in pixels. | |
803 | * | |
804 | * @param height The height of panel in pixels. | |
805 | * | |
806 | * @param hStartWidth The number of pixel clocks between the HSYNC | |
807 | * signal pulse and the start of valid data. | |
808 | * | |
809 | * @param hSyncWidth The width of the HSYNC signal in units of pixel | |
810 | * clocks. | |
811 | * | |
812 | * @param hEndWidth The number of pixel clocks between the end of | |
813 | * valid data and the HSYNC signal for next line. | |
814 | * | |
815 | * @param vStartWidth The number of lines between the VSYNC | |
816 | * signal pulse and the start of valid data. | |
817 | * | |
818 | * @param vSyncWidth The width of the VSYNC signal in units of lines | |
819 | * | |
820 | * @param vEndWidth The number of lines between the end of valid | |
821 | * data and the VSYNC signal for next frame. | |
822 | * | |
823 | * @param sig Bitfield of signal polarities for LCD interface. | |
824 | * | |
185f812c | 825 | * Return: This function returns 0 on success or negative error code on |
575001e4 SB |
826 | * fail. |
827 | */ | |
828 | ||
829 | int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, | |
830 | uint16_t width, uint16_t height, | |
831 | uint32_t pixel_fmt, | |
832 | uint16_t h_start_width, uint16_t h_sync_width, | |
833 | uint16_t h_end_width, uint16_t v_start_width, | |
834 | uint16_t v_sync_width, uint16_t v_end_width, | |
835 | uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig) | |
836 | { | |
837 | uint32_t reg; | |
838 | uint32_t di_gen, vsync_cnt; | |
839 | uint32_t div, rounded_pixel_clk; | |
840 | uint32_t h_total, v_total; | |
841 | int map; | |
842 | struct clk *di_parent; | |
843 | ||
844 | debug("panel size = %d x %d\n", width, height); | |
845 | ||
846 | if ((v_sync_width == 0) || (h_sync_width == 0)) | |
d1486e33 | 847 | return -EINVAL; |
575001e4 | 848 | |
3e780af1 JH |
849 | /* adapt panel to ipu restricitions */ |
850 | if (v_end_width < 2) { | |
851 | v_end_width = 2; | |
852 | puts("WARNING: v_end_width (lower_margin) must be >= 2, adjusted\n"); | |
853 | } | |
854 | ||
575001e4 SB |
855 | h_total = width + h_sync_width + h_start_width + h_end_width; |
856 | v_total = height + v_sync_width + v_start_width + v_end_width; | |
857 | ||
858 | /* Init clocking */ | |
c1420328 | 859 | debug("pixel clk = %dHz\n", pixel_clk); |
575001e4 SB |
860 | |
861 | if (sig.ext_clk) { | |
862 | if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/ | |
863 | /* | |
864 | * Set the PLL to be an even multiple | |
865 | * of the pixel clock. | |
866 | */ | |
867 | if ((clk_get_usecount(g_pixel_clk[0]) == 0) && | |
868 | (clk_get_usecount(g_pixel_clk[1]) == 0)) { | |
869 | di_parent = clk_get_parent(g_di_clk[disp]); | |
870 | rounded_pixel_clk = | |
871 | clk_round_rate(g_pixel_clk[disp], | |
872 | pixel_clk); | |
873 | div = clk_get_rate(di_parent) / | |
874 | rounded_pixel_clk; | |
875 | if (div % 2) | |
876 | div++; | |
877 | if (clk_get_rate(di_parent) != div * | |
878 | rounded_pixel_clk) | |
879 | clk_set_rate(di_parent, | |
880 | div * rounded_pixel_clk); | |
881 | udelay(10000); | |
882 | clk_set_rate(g_di_clk[disp], | |
883 | 2 * rounded_pixel_clk); | |
884 | udelay(10000); | |
885 | } | |
886 | } | |
cf65d478 | 887 | clk_set_parent(g_pixel_clk[disp], g_ldb_clk); |
575001e4 SB |
888 | } else { |
889 | if (clk_get_usecount(g_pixel_clk[disp]) != 0) | |
890 | clk_set_parent(g_pixel_clk[disp], g_ipu_clk); | |
891 | } | |
892 | rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk); | |
893 | clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk); | |
894 | udelay(5000); | |
895 | /* Get integer portion of divider */ | |
896 | div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) / | |
897 | rounded_pixel_clk; | |
898 | ||
899 | ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1); | |
900 | ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); | |
901 | ||
902 | map = ipu_pixfmt_to_map(pixel_fmt); | |
903 | if (map < 0) { | |
904 | debug("IPU_DISP: No MAP\n"); | |
905 | return -EINVAL; | |
906 | } | |
907 | ||
908 | di_gen = __raw_readl(DI_GENERAL(disp)); | |
909 | ||
910 | if (sig.interlaced) { | |
911 | /* Setup internal HSYNC waveform */ | |
912 | ipu_di_sync_config( | |
913 | disp, /* display */ | |
914 | 1, /* counter */ | |
915 | h_total / 2 - 1,/* run count */ | |
916 | DI_SYNC_CLK, /* run_resolution */ | |
917 | 0, /* offset */ | |
918 | DI_SYNC_NONE, /* offset resolution */ | |
919 | 0, /* repeat count */ | |
920 | DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
921 | 0, /* CNT_POLARITY_GEN_EN */ | |
922 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
923 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
924 | 0, /* COUNT UP */ | |
925 | 0 /* COUNT DOWN */ | |
926 | ); | |
927 | ||
928 | /* Field 1 VSYNC waveform */ | |
929 | ipu_di_sync_config( | |
930 | disp, /* display */ | |
931 | 2, /* counter */ | |
932 | h_total - 1, /* run count */ | |
933 | DI_SYNC_CLK, /* run_resolution */ | |
934 | 0, /* offset */ | |
935 | DI_SYNC_NONE, /* offset resolution */ | |
936 | 0, /* repeat count */ | |
937 | DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
938 | 0, /* CNT_POLARITY_GEN_EN */ | |
939 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
940 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
941 | 0, /* COUNT UP */ | |
942 | 4 /* COUNT DOWN */ | |
943 | ); | |
944 | ||
945 | /* Setup internal HSYNC waveform */ | |
946 | ipu_di_sync_config( | |
947 | disp, /* display */ | |
948 | 3, /* counter */ | |
949 | v_total * 2 - 1,/* run count */ | |
950 | DI_SYNC_INT_HSYNC, /* run_resolution */ | |
951 | 1, /* offset */ | |
952 | DI_SYNC_INT_HSYNC, /* offset resolution */ | |
953 | 0, /* repeat count */ | |
954 | DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
955 | 0, /* CNT_POLARITY_GEN_EN */ | |
956 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
957 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
958 | 0, /* COUNT UP */ | |
959 | 4 /* COUNT DOWN */ | |
960 | ); | |
961 | ||
962 | /* Active Field ? */ | |
963 | ipu_di_sync_config( | |
964 | disp, /* display */ | |
965 | 4, /* counter */ | |
966 | v_total / 2 - 1,/* run count */ | |
967 | DI_SYNC_HSYNC, /* run_resolution */ | |
968 | v_start_width, /* offset */ | |
969 | DI_SYNC_HSYNC, /* offset resolution */ | |
970 | 2, /* repeat count */ | |
971 | DI_SYNC_VSYNC, /* CNT_CLR_SEL */ | |
972 | 0, /* CNT_POLARITY_GEN_EN */ | |
973 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
974 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
975 | 0, /* COUNT UP */ | |
976 | 0 /* COUNT DOWN */ | |
977 | ); | |
978 | ||
979 | /* Active Line */ | |
980 | ipu_di_sync_config( | |
981 | disp, /* display */ | |
982 | 5, /* counter */ | |
983 | 0, /* run count */ | |
984 | DI_SYNC_HSYNC, /* run_resolution */ | |
985 | 0, /* offset */ | |
986 | DI_SYNC_NONE, /* offset resolution */ | |
987 | height / 2, /* repeat count */ | |
988 | 4, /* CNT_CLR_SEL */ | |
989 | 0, /* CNT_POLARITY_GEN_EN */ | |
990 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
991 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
992 | 0, /* COUNT UP */ | |
993 | 0 /* COUNT DOWN */ | |
994 | ); | |
995 | ||
996 | /* Field 0 VSYNC waveform */ | |
997 | ipu_di_sync_config( | |
998 | disp, /* display */ | |
999 | 6, /* counter */ | |
1000 | v_total - 1, /* run count */ | |
1001 | DI_SYNC_HSYNC, /* run_resolution */ | |
1002 | 0, /* offset */ | |
1003 | DI_SYNC_NONE, /* offset resolution */ | |
1004 | 0, /* repeat count */ | |
1005 | DI_SYNC_NONE, /* CNT_CLR_SEL */ | |
1006 | 0, /* CNT_POLARITY_GEN_EN */ | |
1007 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1008 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1009 | 0, /* COUNT UP */ | |
1010 | 0 /* COUNT DOWN */ | |
1011 | ); | |
1012 | ||
1013 | /* DC VSYNC waveform */ | |
1014 | vsync_cnt = 7; | |
1015 | ipu_di_sync_config( | |
1016 | disp, /* display */ | |
1017 | 7, /* counter */ | |
1018 | v_total / 2 - 1,/* run count */ | |
1019 | DI_SYNC_HSYNC, /* run_resolution */ | |
1020 | 9, /* offset */ | |
1021 | DI_SYNC_HSYNC, /* offset resolution */ | |
1022 | 2, /* repeat count */ | |
1023 | DI_SYNC_VSYNC, /* CNT_CLR_SEL */ | |
1024 | 0, /* CNT_POLARITY_GEN_EN */ | |
1025 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1026 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1027 | 0, /* COUNT UP */ | |
1028 | 0 /* COUNT DOWN */ | |
1029 | ); | |
1030 | ||
1031 | /* active pixel waveform */ | |
1032 | ipu_di_sync_config( | |
1033 | disp, /* display */ | |
1034 | 8, /* counter */ | |
1035 | 0, /* run count */ | |
1036 | DI_SYNC_CLK, /* run_resolution */ | |
1037 | h_start_width, /* offset */ | |
1038 | DI_SYNC_CLK, /* offset resolution */ | |
1039 | width, /* repeat count */ | |
1040 | 5, /* CNT_CLR_SEL */ | |
1041 | 0, /* CNT_POLARITY_GEN_EN */ | |
1042 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1043 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1044 | 0, /* COUNT UP */ | |
1045 | 0 /* COUNT DOWN */ | |
1046 | ); | |
1047 | ||
1048 | ipu_di_sync_config( | |
1049 | disp, /* display */ | |
1050 | 9, /* counter */ | |
1051 | v_total - 1, /* run count */ | |
1052 | DI_SYNC_INT_HSYNC,/* run_resolution */ | |
1053 | v_total / 2, /* offset */ | |
1054 | DI_SYNC_INT_HSYNC,/* offset resolution */ | |
1055 | 0, /* repeat count */ | |
1056 | DI_SYNC_HSYNC, /* CNT_CLR_SEL */ | |
1057 | 0, /* CNT_POLARITY_GEN_EN */ | |
1058 | DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ | |
1059 | DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ | |
1060 | 0, /* COUNT UP */ | |
1061 | 4 /* COUNT DOWN */ | |
1062 | ); | |
1063 | ||
1064 | /* set gentime select and tag sel */ | |
1065 | reg = __raw_readl(DI_SW_GEN1(disp, 9)); | |
1066 | reg &= 0x1FFFFFFF; | |
1067 | reg |= (3 - 1)<<29 | 0x00008000; | |
1068 | __raw_writel(reg, DI_SW_GEN1(disp, 9)); | |
1069 | ||
1070 | __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp)); | |
1071 | ||
1072 | /* set y_sel = 1 */ | |
1073 | di_gen |= 0x10000000; | |
1074 | di_gen |= DI_GEN_POLARITY_5; | |
1075 | di_gen |= DI_GEN_POLARITY_8; | |
1076 | } else { | |
1077 | /* Setup internal HSYNC waveform */ | |
1078 | ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK, | |
1079 | 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, | |
1080 | 0, DI_SYNC_NONE, | |
1081 | DI_SYNC_NONE, 0, 0); | |
1082 | ||
1083 | /* Setup external (delayed) HSYNC waveform */ | |
1084 | ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1, | |
1085 | DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK, | |
1086 | 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, | |
1087 | DI_SYNC_CLK, 0, h_sync_width * 2); | |
1088 | /* Setup VSYNC waveform */ | |
1089 | vsync_cnt = DI_SYNC_VSYNC; | |
1090 | ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1, | |
1091 | DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0, | |
1092 | DI_SYNC_NONE, 1, DI_SYNC_NONE, | |
1093 | DI_SYNC_INT_HSYNC, 0, v_sync_width * 2); | |
1094 | __raw_writel(v_total - 1, DI_SCR_CONF(disp)); | |
1095 | ||
1096 | /* Setup active data waveform to sync with DC */ | |
1097 | ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC, | |
1098 | v_sync_width + v_start_width, DI_SYNC_HSYNC, | |
1099 | height, | |
1100 | DI_SYNC_VSYNC, 0, DI_SYNC_NONE, | |
1101 | DI_SYNC_NONE, 0, 0); | |
1102 | ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK, | |
1103 | h_sync_width + h_start_width, DI_SYNC_CLK, | |
1104 | width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, | |
1105 | 0); | |
1106 | ||
1107 | /* reset all unused counters */ | |
1108 | __raw_writel(0, DI_SW_GEN0(disp, 6)); | |
1109 | __raw_writel(0, DI_SW_GEN1(disp, 6)); | |
1110 | __raw_writel(0, DI_SW_GEN0(disp, 7)); | |
1111 | __raw_writel(0, DI_SW_GEN1(disp, 7)); | |
1112 | __raw_writel(0, DI_SW_GEN0(disp, 8)); | |
1113 | __raw_writel(0, DI_SW_GEN1(disp, 8)); | |
1114 | __raw_writel(0, DI_SW_GEN0(disp, 9)); | |
1115 | __raw_writel(0, DI_SW_GEN1(disp, 9)); | |
1116 | ||
1117 | reg = __raw_readl(DI_STP_REP(disp, 6)); | |
1118 | reg &= 0x0000FFFF; | |
1119 | __raw_writel(reg, DI_STP_REP(disp, 6)); | |
1120 | __raw_writel(0, DI_STP_REP(disp, 7)); | |
3dbdb4dd | 1121 | __raw_writel(0, DI_STP_REP9(disp)); |
575001e4 SB |
1122 | |
1123 | /* Init template microcode */ | |
1124 | if (disp) { | |
1125 | ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); | |
1126 | ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); | |
1127 | ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); | |
1128 | } else { | |
1129 | ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); | |
1130 | ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); | |
1131 | ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); | |
1132 | } | |
1133 | ||
1134 | if (sig.Hsync_pol) | |
1135 | di_gen |= DI_GEN_POLARITY_2; | |
1136 | if (sig.Vsync_pol) | |
1137 | di_gen |= DI_GEN_POLARITY_3; | |
1138 | ||
2740e5de | 1139 | if (!sig.clk_pol) |
575001e4 SB |
1140 | di_gen |= DI_GEN_POL_CLK; |
1141 | ||
1142 | } | |
1143 | ||
1144 | __raw_writel(di_gen, DI_GENERAL(disp)); | |
1145 | ||
1146 | __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) | | |
1147 | 0x00000002, DI_SYNC_AS_GEN(disp)); | |
1148 | ||
1149 | reg = __raw_readl(DI_POL(disp)); | |
1150 | reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); | |
1151 | if (sig.enable_pol) | |
1152 | reg |= DI_POL_DRDY_POLARITY_15; | |
1153 | if (sig.data_pol) | |
1154 | reg |= DI_POL_DRDY_DATA_POLARITY; | |
1155 | __raw_writel(reg, DI_POL(disp)); | |
1156 | ||
1157 | __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp))); | |
1158 | ||
1159 | return 0; | |
1160 | } | |
1161 | ||
1162 | /* | |
1163 | * This function sets the foreground and background plane global alpha blending | |
1164 | * modes. This function also sets the DP graphic plane according to the | |
1165 | * parameter of IPUv3 DP channel. | |
1166 | * | |
1167 | * @param channel IPUv3 DP channel | |
1168 | * | |
1169 | * @param enable Boolean to enable or disable global alpha | |
1170 | * blending. If disabled, local blending is used. | |
1171 | * | |
1172 | * @param alpha Global alpha value. | |
1173 | * | |
185f812c | 1174 | * Return: Returns 0 on success or negative error code on fail |
575001e4 SB |
1175 | */ |
1176 | int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable, | |
1177 | uint8_t alpha) | |
1178 | { | |
1179 | uint32_t reg; | |
575001e4 SB |
1180 | |
1181 | unsigned char bg_chan; | |
1182 | ||
564964bd MV |
1183 | if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || |
1184 | (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || | |
1185 | (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) | |
575001e4 SB |
1186 | return -EINVAL; |
1187 | ||
1188 | if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 || | |
1189 | channel == MEM_BG_ASYNC1) | |
1190 | bg_chan = 1; | |
1191 | else | |
1192 | bg_chan = 0; | |
1193 | ||
575001e4 | 1194 | if (bg_chan) { |
564964bd MV |
1195 | reg = __raw_readl(DP_COM_CONF()); |
1196 | __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF()); | |
575001e4 | 1197 | } else { |
564964bd MV |
1198 | reg = __raw_readl(DP_COM_CONF()); |
1199 | __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF()); | |
575001e4 SB |
1200 | } |
1201 | ||
1202 | if (enable) { | |
564964bd | 1203 | reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0x00FFFFFFL; |
575001e4 | 1204 | __raw_writel(reg | ((uint32_t) alpha << 24), |
564964bd | 1205 | DP_GRAPH_WIND_CTRL()); |
575001e4 | 1206 | |
564964bd MV |
1207 | reg = __raw_readl(DP_COM_CONF()); |
1208 | __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF()); | |
575001e4 | 1209 | } else { |
564964bd MV |
1210 | reg = __raw_readl(DP_COM_CONF()); |
1211 | __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF()); | |
575001e4 SB |
1212 | } |
1213 | ||
1214 | reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
1215 | __raw_writel(reg, IPU_SRM_PRI2); | |
1216 | ||
575001e4 SB |
1217 | return 0; |
1218 | } | |
1219 | ||
1220 | /* | |
1221 | * This function sets the transparent color key for SDC graphic plane. | |
1222 | * | |
1223 | * @param channel Input parameter for the logical channel ID. | |
1224 | * | |
1225 | * @param enable Boolean to enable or disable color key | |
1226 | * | |
1227 | * @param colorKey 24-bit RGB color for transparent color key. | |
1228 | * | |
185f812c | 1229 | * Return: Returns 0 on success or negative error code on fail |
575001e4 SB |
1230 | */ |
1231 | int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable, | |
1232 | uint32_t color_key) | |
1233 | { | |
564964bd | 1234 | uint32_t reg; |
575001e4 SB |
1235 | int y, u, v; |
1236 | int red, green, blue; | |
1237 | ||
564964bd MV |
1238 | if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || |
1239 | (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || | |
1240 | (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) | |
575001e4 SB |
1241 | return -EINVAL; |
1242 | ||
575001e4 SB |
1243 | color_key_4rgb = 1; |
1244 | /* Transform color key from rgb to yuv if CSC is enabled */ | |
1245 | if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || | |
1246 | ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || | |
1247 | ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || | |
1248 | ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) { | |
1249 | ||
1250 | debug("color key 0x%x need change to yuv fmt\n", color_key); | |
1251 | ||
1252 | red = (color_key >> 16) & 0xFF; | |
1253 | green = (color_key >> 8) & 0xFF; | |
1254 | blue = color_key & 0xFF; | |
1255 | ||
1256 | y = rgb_to_yuv(0, red, green, blue); | |
1257 | u = rgb_to_yuv(1, red, green, blue); | |
1258 | v = rgb_to_yuv(2, red, green, blue); | |
1259 | color_key = (y << 16) | (u << 8) | v; | |
1260 | ||
1261 | color_key_4rgb = 0; | |
1262 | ||
1263 | debug("color key change to yuv fmt 0x%x\n", color_key); | |
1264 | } | |
1265 | ||
1266 | if (enable) { | |
564964bd MV |
1267 | reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L; |
1268 | __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL()); | |
575001e4 | 1269 | |
564964bd MV |
1270 | reg = __raw_readl(DP_COM_CONF()); |
1271 | __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF()); | |
575001e4 | 1272 | } else { |
564964bd MV |
1273 | reg = __raw_readl(DP_COM_CONF()); |
1274 | __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF()); | |
575001e4 SB |
1275 | } |
1276 | ||
1277 | reg = __raw_readl(IPU_SRM_PRI2) | 0x8; | |
1278 | __raw_writel(reg, IPU_SRM_PRI2); | |
1279 | ||
575001e4 SB |
1280 | return 0; |
1281 | } |