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