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