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