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