1 // SPDX-License-Identifier: GPL-2.0+ 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. 11 */ 12 13 /* #define DEBUG */ 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 24 enum csc_type_t { 25 RGB2YUV = 0, 26 YUV2RGB, 27 RGB2RGB, 28 YUV2YUV, 29 CSC_NONE, 30 CSC_NUM 31 }; 32 33 struct dp_csc_param_t { 34 int mode; 35 const int (*coeff)[5][3]; 36 }; 37 38 #define SYNC_WAVE 0 39 40 /* DC display ID assignments */ 41 #define DC_DISP_ID_SYNC(di) (di) 42 #define DC_DISP_ID_SERIAL 2 43 #define DC_DISP_ID_ASYNC 3 44 45 int dmfc_type_setup; 46 static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23; 47 int g_di1_tvout; 48 49 extern struct clk *g_ipu_clk; 50 extern struct clk *g_ldb_clk; 51 extern struct clk *g_di_clk[2]; 52 extern struct clk *g_pixel_clk[2]; 53 54 extern unsigned char g_ipu_clk_enabled; 55 extern unsigned char g_dc_di_assignment[]; 56 57 void 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 /* disable DMFC-IC channel*/ 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 /* 1 - segment 0~3; 77 * 5B - segement 4, 5; 78 * 5F - segement 6, 7; 79 * 1C, 2C and 6B, 6F unused; 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 /* 1 - segment 0, 1; 91 * 5B - segement 2~5; 92 * 5F - segement 6,7; 93 * 1C, 2C and 6B, 6F unused; 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 /* 5B - segement 0~3; 105 * 5F - segement 4~7; 106 * 1, 1C, 2C and 6B, 6F unused; 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 /* 1 - segment 0, 1; 118 * 5B - segement 4, 5; 119 * 5F - segement 6, 7; 120 * 1C, 2C and 6B, 6F unused; 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 /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */ 135 __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF); 136 } 137 138 void 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) { /*5B*/ 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) { /*6B*/ 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) { /*5F*/ 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) { /*1*/ 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) { /*6F*/ 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 179 static 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 189 static 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 202 static 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 /* Enable auto reload */ 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 237 static 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 253 static 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 260 static 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 279 static 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 /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; 290 * U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.; 291 * V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.; 292 */ 293 static const int rgb2ycbcr_coeff[5][3] = { 294 {0x4D, 0x96, 0x1D}, 295 {0x3D5, 0x3AB, 0x80}, 296 {0x80, 0x395, 0x3EB}, 297 {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */ 298 {0x2, 0x2, 0x2}, /* S0, S1, S2 */ 299 }; 300 301 /* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); 302 * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); 303 * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); 304 */ 305 static const int ycbcr2rgb_coeff[5][3] = { 306 {0x095, 0x000, 0x0CC}, 307 {0x095, 0x3CE, 0x398}, 308 {0x095, 0x0FF, 0x000}, 309 {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */ 310 {0x1, 0x1, 0x1}, /*S0,S1,S2 */ 311 }; 312 313 #define mask_a(a) ((u32)(a) & 0x3FF) 314 #define mask_b(b) ((u32)(b) & 0x3FFF) 315 316 /* Pls keep S0, S1 and S2 as 0x2 by using this convertion */ 317 static 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 * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE 336 * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE 337 */ 338 static 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 376 static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE; 377 static int color_key_4rgb = 1; 378 379 static 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 417 int 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 /* Transform color key from rgb to yuv if CSC is enabled */ 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 504 void 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 530 void 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 /* async channels */ 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 579 void 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 607 void 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 /* Enable FG channel */ 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 /* Make sure other DC sync channel is not assigned same DI */ 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 647 static unsigned char dc_swap; 648 649 void 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 /* Disable FG channel */ 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 * Wait for DC triple buffer to empty, 684 * this check is useful for tv overlay. 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 /* Swap DC channel 1 and 5 settings, and disable old dc chan */ 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 /* Make sure that we leave at the irq starting edge */ 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 /* Clock is already off because it must be done quickly, but 733 we need to fix the ref count */ 734 clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); 735 } 736 } 737 738 void ipu_init_dc_mappings(void) 739 { 740 /* IPU_PIX_FMT_RGB24 */ 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 /* IPU_PIX_FMT_RGB666 */ 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 /* IPU_PIX_FMT_YUV444 */ 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 /* IPU_PIX_FMT_RGB565 */ 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 /* IPU_PIX_FMT_LVDS666 */ 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 771 static 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 * This function is called to initialize a synchronous LCD panel. 792 * 793 * @param disp The DI the panel is attached to. 794 * 795 * @param pixel_clk Desired pixel clock frequency in Hz. 796 * 797 * @param pixel_fmt Input parameter for pixel format of buffer. 798 * Pixel format is a FOURCC ASCII code. 799 * 800 * @param width The width of panel in pixels. 801 * 802 * @param height The height of panel in pixels. 803 * 804 * @param hStartWidth The number of pixel clocks between the HSYNC 805 * signal pulse and the start of valid data. 806 * 807 * @param hSyncWidth The width of the HSYNC signal in units of pixel 808 * clocks. 809 * 810 * @param hEndWidth The number of pixel clocks between the end of 811 * valid data and the HSYNC signal for next line. 812 * 813 * @param vStartWidth The number of lines between the VSYNC 814 * signal pulse and the start of valid data. 815 * 816 * @param vSyncWidth The width of the VSYNC signal in units of lines 817 * 818 * @param vEndWidth The number of lines between the end of valid 819 * data and the VSYNC signal for next frame. 820 * 821 * @param sig Bitfield of signal polarities for LCD interface. 822 * 823 * @return This function returns 0 on success or negative error code on 824 * fail. 825 */ 826 827 int32_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 /* adapt panel to ipu restricitions */ 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 /* Init clocking */ 857 debug("pixel clk = %dHz\n", pixel_clk); 858 859 if (sig.ext_clk) { 860 if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/ 861 /* 862 * Set the PLL to be an even multiple 863 * of the pixel clock. 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 /* Get integer portion of divider */ 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 /* Setup internal HSYNC waveform */ 910 ipu_di_sync_config( 911 disp, /* display */ 912 1, /* counter */ 913 h_total / 2 - 1,/* run count */ 914 DI_SYNC_CLK, /* run_resolution */ 915 0, /* offset */ 916 DI_SYNC_NONE, /* offset resolution */ 917 0, /* repeat count */ 918 DI_SYNC_NONE, /* CNT_CLR_SEL */ 919 0, /* CNT_POLARITY_GEN_EN */ 920 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 921 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 922 0, /* COUNT UP */ 923 0 /* COUNT DOWN */ 924 ); 925 926 /* Field 1 VSYNC waveform */ 927 ipu_di_sync_config( 928 disp, /* display */ 929 2, /* counter */ 930 h_total - 1, /* run count */ 931 DI_SYNC_CLK, /* run_resolution */ 932 0, /* offset */ 933 DI_SYNC_NONE, /* offset resolution */ 934 0, /* repeat count */ 935 DI_SYNC_NONE, /* CNT_CLR_SEL */ 936 0, /* CNT_POLARITY_GEN_EN */ 937 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 938 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 939 0, /* COUNT UP */ 940 4 /* COUNT DOWN */ 941 ); 942 943 /* Setup internal HSYNC waveform */ 944 ipu_di_sync_config( 945 disp, /* display */ 946 3, /* counter */ 947 v_total * 2 - 1,/* run count */ 948 DI_SYNC_INT_HSYNC, /* run_resolution */ 949 1, /* offset */ 950 DI_SYNC_INT_HSYNC, /* offset resolution */ 951 0, /* repeat count */ 952 DI_SYNC_NONE, /* CNT_CLR_SEL */ 953 0, /* CNT_POLARITY_GEN_EN */ 954 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 955 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 956 0, /* COUNT UP */ 957 4 /* COUNT DOWN */ 958 ); 959 960 /* Active Field ? */ 961 ipu_di_sync_config( 962 disp, /* display */ 963 4, /* counter */ 964 v_total / 2 - 1,/* run count */ 965 DI_SYNC_HSYNC, /* run_resolution */ 966 v_start_width, /* offset */ 967 DI_SYNC_HSYNC, /* offset resolution */ 968 2, /* repeat count */ 969 DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 970 0, /* CNT_POLARITY_GEN_EN */ 971 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 972 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 973 0, /* COUNT UP */ 974 0 /* COUNT DOWN */ 975 ); 976 977 /* Active Line */ 978 ipu_di_sync_config( 979 disp, /* display */ 980 5, /* counter */ 981 0, /* run count */ 982 DI_SYNC_HSYNC, /* run_resolution */ 983 0, /* offset */ 984 DI_SYNC_NONE, /* offset resolution */ 985 height / 2, /* repeat count */ 986 4, /* CNT_CLR_SEL */ 987 0, /* CNT_POLARITY_GEN_EN */ 988 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 989 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 990 0, /* COUNT UP */ 991 0 /* COUNT DOWN */ 992 ); 993 994 /* Field 0 VSYNC waveform */ 995 ipu_di_sync_config( 996 disp, /* display */ 997 6, /* counter */ 998 v_total - 1, /* run count */ 999 DI_SYNC_HSYNC, /* run_resolution */ 1000 0, /* offset */ 1001 DI_SYNC_NONE, /* offset resolution */ 1002 0, /* repeat count */ 1003 DI_SYNC_NONE, /* CNT_CLR_SEL */ 1004 0, /* CNT_POLARITY_GEN_EN */ 1005 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1006 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1007 0, /* COUNT UP */ 1008 0 /* COUNT DOWN */ 1009 ); 1010 1011 /* DC VSYNC waveform */ 1012 vsync_cnt = 7; 1013 ipu_di_sync_config( 1014 disp, /* display */ 1015 7, /* counter */ 1016 v_total / 2 - 1,/* run count */ 1017 DI_SYNC_HSYNC, /* run_resolution */ 1018 9, /* offset */ 1019 DI_SYNC_HSYNC, /* offset resolution */ 1020 2, /* repeat count */ 1021 DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 1022 0, /* CNT_POLARITY_GEN_EN */ 1023 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1024 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1025 0, /* COUNT UP */ 1026 0 /* COUNT DOWN */ 1027 ); 1028 1029 /* active pixel waveform */ 1030 ipu_di_sync_config( 1031 disp, /* display */ 1032 8, /* counter */ 1033 0, /* run count */ 1034 DI_SYNC_CLK, /* run_resolution */ 1035 h_start_width, /* offset */ 1036 DI_SYNC_CLK, /* offset resolution */ 1037 width, /* repeat count */ 1038 5, /* CNT_CLR_SEL */ 1039 0, /* CNT_POLARITY_GEN_EN */ 1040 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1041 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1042 0, /* COUNT UP */ 1043 0 /* COUNT DOWN */ 1044 ); 1045 1046 ipu_di_sync_config( 1047 disp, /* display */ 1048 9, /* counter */ 1049 v_total - 1, /* run count */ 1050 DI_SYNC_INT_HSYNC,/* run_resolution */ 1051 v_total / 2, /* offset */ 1052 DI_SYNC_INT_HSYNC,/* offset resolution */ 1053 0, /* repeat count */ 1054 DI_SYNC_HSYNC, /* CNT_CLR_SEL */ 1055 0, /* CNT_POLARITY_GEN_EN */ 1056 DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1057 DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1058 0, /* COUNT UP */ 1059 4 /* COUNT DOWN */ 1060 ); 1061 1062 /* set gentime select and tag sel */ 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 /* set y_sel = 1 */ 1071 di_gen |= 0x10000000; 1072 di_gen |= DI_GEN_POLARITY_5; 1073 di_gen |= DI_GEN_POLARITY_8; 1074 } else { 1075 /* Setup internal HSYNC waveform */ 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 /* Setup external (delayed) HSYNC waveform */ 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 /* Setup VSYNC waveform */ 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 /* Setup active data waveform to sync with DC */ 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 /* reset all unused counters */ 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 /* Init template microcode */ 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 * This function sets the foreground and background plane global alpha blending 1162 * modes. This function also sets the DP graphic plane according to the 1163 * parameter of IPUv3 DP channel. 1164 * 1165 * @param channel IPUv3 DP channel 1166 * 1167 * @param enable Boolean to enable or disable global alpha 1168 * blending. If disabled, local blending is used. 1169 * 1170 * @param alpha Global alpha value. 1171 * 1172 * @return Returns 0 on success or negative error code on fail 1173 */ 1174 int32_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 * This function sets the transparent color key for SDC graphic plane. 1226 * 1227 * @param channel Input parameter for the logical channel ID. 1228 * 1229 * @param enable Boolean to enable or disable color key 1230 * 1231 * @param colorKey 24-bit RGB color for transparent color key. 1232 * 1233 * @return Returns 0 on success or negative error code on fail 1234 */ 1235 int32_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 /* Transform color key from rgb to yuv if CSC is enabled */ 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