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