1575001e4SStefano Babic /* 2575001e4SStefano Babic * Porting to u-boot: 3575001e4SStefano Babic * 4575001e4SStefano Babic * (C) Copyright 2010 5575001e4SStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de 6575001e4SStefano Babic * 7575001e4SStefano Babic * Linux IPU driver for MX51: 8575001e4SStefano Babic * 9575001e4SStefano Babic * (C) Copyright 2005-2010 Freescale Semiconductor, Inc. 10575001e4SStefano Babic * 111a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 12575001e4SStefano Babic */ 13575001e4SStefano Babic 14575001e4SStefano Babic /* #define DEBUG */ 15575001e4SStefano Babic 16575001e4SStefano Babic #include <common.h> 17575001e4SStefano Babic #include <linux/types.h> 18575001e4SStefano Babic #include <asm/errno.h> 19575001e4SStefano Babic #include <asm/io.h> 20575001e4SStefano Babic #include <asm/arch/imx-regs.h> 21575001e4SStefano Babic #include <asm/arch/sys_proto.h> 22575001e4SStefano Babic #include "ipu.h" 23575001e4SStefano Babic #include "ipu_regs.h" 24575001e4SStefano Babic 25575001e4SStefano Babic enum csc_type_t { 26575001e4SStefano Babic RGB2YUV = 0, 27575001e4SStefano Babic YUV2RGB, 28575001e4SStefano Babic RGB2RGB, 29575001e4SStefano Babic YUV2YUV, 30575001e4SStefano Babic CSC_NONE, 31575001e4SStefano Babic CSC_NUM 32575001e4SStefano Babic }; 33575001e4SStefano Babic 34575001e4SStefano Babic struct dp_csc_param_t { 35575001e4SStefano Babic int mode; 36e6e9cff2SJeroen Hofstee const int (*coeff)[5][3]; 37575001e4SStefano Babic }; 38575001e4SStefano Babic 39575001e4SStefano Babic #define SYNC_WAVE 0 40575001e4SStefano Babic 41575001e4SStefano Babic /* DC display ID assignments */ 42575001e4SStefano Babic #define DC_DISP_ID_SYNC(di) (di) 43575001e4SStefano Babic #define DC_DISP_ID_SERIAL 2 44575001e4SStefano Babic #define DC_DISP_ID_ASYNC 3 45575001e4SStefano Babic 46575001e4SStefano Babic int dmfc_type_setup; 47575001e4SStefano Babic static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23; 48575001e4SStefano Babic int g_di1_tvout; 49575001e4SStefano Babic 50575001e4SStefano Babic extern struct clk *g_ipu_clk; 51cf65d478SEric Nelson extern struct clk *g_ldb_clk; 52575001e4SStefano Babic extern struct clk *g_di_clk[2]; 53575001e4SStefano Babic extern struct clk *g_pixel_clk[2]; 54575001e4SStefano Babic 55575001e4SStefano Babic extern unsigned char g_ipu_clk_enabled; 56575001e4SStefano Babic extern unsigned char g_dc_di_assignment[]; 57575001e4SStefano Babic 58575001e4SStefano Babic void ipu_dmfc_init(int dmfc_type, int first) 59575001e4SStefano Babic { 60575001e4SStefano Babic u32 dmfc_wr_chan, dmfc_dp_chan; 61575001e4SStefano Babic 62575001e4SStefano Babic if (first) { 63575001e4SStefano Babic if (dmfc_type_setup > dmfc_type) 64575001e4SStefano Babic dmfc_type = dmfc_type_setup; 65575001e4SStefano Babic else 66575001e4SStefano Babic dmfc_type_setup = dmfc_type; 67575001e4SStefano Babic 68575001e4SStefano Babic /* disable DMFC-IC channel*/ 69575001e4SStefano Babic __raw_writel(0x2, DMFC_IC_CTRL); 70575001e4SStefano Babic } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) { 71575001e4SStefano Babic printf("DMFC high resolution has set, will not change\n"); 72575001e4SStefano Babic return; 73575001e4SStefano Babic } else 74575001e4SStefano Babic dmfc_type_setup = dmfc_type; 75575001e4SStefano Babic 76575001e4SStefano Babic if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) { 77575001e4SStefano Babic /* 1 - segment 0~3; 78575001e4SStefano Babic * 5B - segement 4, 5; 79575001e4SStefano Babic * 5F - segement 6, 7; 80575001e4SStefano Babic * 1C, 2C and 6B, 6F unused; 81575001e4SStefano Babic */ 82575001e4SStefano Babic debug("IPU DMFC DC HIGH RES: 1(0~3), 5B(4,5), 5F(6,7)\n"); 83575001e4SStefano Babic dmfc_wr_chan = 0x00000088; 84575001e4SStefano Babic dmfc_dp_chan = 0x00009694; 85575001e4SStefano Babic dmfc_size_28 = 256 * 4; 86575001e4SStefano Babic dmfc_size_29 = 0; 87575001e4SStefano Babic dmfc_size_24 = 0; 88575001e4SStefano Babic dmfc_size_27 = 128 * 4; 89575001e4SStefano Babic dmfc_size_23 = 128 * 4; 90575001e4SStefano Babic } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) { 91575001e4SStefano Babic /* 1 - segment 0, 1; 92575001e4SStefano Babic * 5B - segement 2~5; 93575001e4SStefano Babic * 5F - segement 6,7; 94575001e4SStefano Babic * 1C, 2C and 6B, 6F unused; 95575001e4SStefano Babic */ 96575001e4SStefano Babic debug("IPU DMFC DP HIGH RES: 1(0,1), 5B(2~5), 5F(6,7)\n"); 97575001e4SStefano Babic dmfc_wr_chan = 0x00000090; 98575001e4SStefano Babic dmfc_dp_chan = 0x0000968a; 99575001e4SStefano Babic dmfc_size_28 = 128 * 4; 100575001e4SStefano Babic dmfc_size_29 = 0; 101575001e4SStefano Babic dmfc_size_24 = 0; 102575001e4SStefano Babic dmfc_size_27 = 128 * 4; 103575001e4SStefano Babic dmfc_size_23 = 256 * 4; 104575001e4SStefano Babic } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) { 105575001e4SStefano Babic /* 5B - segement 0~3; 106575001e4SStefano Babic * 5F - segement 4~7; 107575001e4SStefano Babic * 1, 1C, 2C and 6B, 6F unused; 108575001e4SStefano Babic */ 109575001e4SStefano Babic debug("IPU DMFC ONLY-DP HIGH RES: 5B(0~3), 5F(4~7)\n"); 110575001e4SStefano Babic dmfc_wr_chan = 0x00000000; 111575001e4SStefano Babic dmfc_dp_chan = 0x00008c88; 112575001e4SStefano Babic dmfc_size_28 = 0; 113575001e4SStefano Babic dmfc_size_29 = 0; 114575001e4SStefano Babic dmfc_size_24 = 0; 115575001e4SStefano Babic dmfc_size_27 = 256 * 4; 116575001e4SStefano Babic dmfc_size_23 = 256 * 4; 117575001e4SStefano Babic } else { 118575001e4SStefano Babic /* 1 - segment 0, 1; 119575001e4SStefano Babic * 5B - segement 4, 5; 120575001e4SStefano Babic * 5F - segement 6, 7; 121575001e4SStefano Babic * 1C, 2C and 6B, 6F unused; 122575001e4SStefano Babic */ 123575001e4SStefano Babic debug("IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n"); 124575001e4SStefano Babic dmfc_wr_chan = 0x00000090; 125575001e4SStefano Babic dmfc_dp_chan = 0x00009694; 126575001e4SStefano Babic dmfc_size_28 = 128 * 4; 127575001e4SStefano Babic dmfc_size_29 = 0; 128575001e4SStefano Babic dmfc_size_24 = 0; 129575001e4SStefano Babic dmfc_size_27 = 128 * 4; 130575001e4SStefano Babic dmfc_size_23 = 128 * 4; 131575001e4SStefano Babic } 132575001e4SStefano Babic __raw_writel(dmfc_wr_chan, DMFC_WR_CHAN); 133575001e4SStefano Babic __raw_writel(0x202020F6, DMFC_WR_CHAN_DEF); 134575001e4SStefano Babic __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN); 135575001e4SStefano Babic /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */ 136575001e4SStefano Babic __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF); 137575001e4SStefano Babic } 138575001e4SStefano Babic 139575001e4SStefano Babic void ipu_dmfc_set_wait4eot(int dma_chan, int width) 140575001e4SStefano Babic { 141575001e4SStefano Babic u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1); 142575001e4SStefano Babic 143575001e4SStefano Babic if (width >= HIGH_RESOLUTION_WIDTH) { 144575001e4SStefano Babic if (dma_chan == 23) 145575001e4SStefano Babic ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0); 146575001e4SStefano Babic else if (dma_chan == 28) 147575001e4SStefano Babic ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0); 148575001e4SStefano Babic } 149575001e4SStefano Babic 150575001e4SStefano Babic if (dma_chan == 23) { /*5B*/ 151575001e4SStefano Babic if (dmfc_size_23 / width > 3) 152575001e4SStefano Babic dmfc_gen1 |= 1UL << 20; 153575001e4SStefano Babic else 154575001e4SStefano Babic dmfc_gen1 &= ~(1UL << 20); 155575001e4SStefano Babic } else if (dma_chan == 24) { /*6B*/ 156575001e4SStefano Babic if (dmfc_size_24 / width > 1) 157575001e4SStefano Babic dmfc_gen1 |= 1UL << 22; 158575001e4SStefano Babic else 159575001e4SStefano Babic dmfc_gen1 &= ~(1UL << 22); 160575001e4SStefano Babic } else if (dma_chan == 27) { /*5F*/ 161575001e4SStefano Babic if (dmfc_size_27 / width > 2) 162575001e4SStefano Babic dmfc_gen1 |= 1UL << 21; 163575001e4SStefano Babic else 164575001e4SStefano Babic dmfc_gen1 &= ~(1UL << 21); 165575001e4SStefano Babic } else if (dma_chan == 28) { /*1*/ 166575001e4SStefano Babic if (dmfc_size_28 / width > 2) 167575001e4SStefano Babic dmfc_gen1 |= 1UL << 16; 168575001e4SStefano Babic else 169575001e4SStefano Babic dmfc_gen1 &= ~(1UL << 16); 170575001e4SStefano Babic } else if (dma_chan == 29) { /*6F*/ 171575001e4SStefano Babic if (dmfc_size_29 / width > 1) 172575001e4SStefano Babic dmfc_gen1 |= 1UL << 23; 173575001e4SStefano Babic else 174575001e4SStefano Babic dmfc_gen1 &= ~(1UL << 23); 175575001e4SStefano Babic } 176575001e4SStefano Babic 177575001e4SStefano Babic __raw_writel(dmfc_gen1, DMFC_GENERAL1); 178575001e4SStefano Babic } 179575001e4SStefano Babic 180575001e4SStefano Babic static void ipu_di_data_wave_config(int di, 181575001e4SStefano Babic int wave_gen, 182575001e4SStefano Babic int access_size, int component_size) 183575001e4SStefano Babic { 184575001e4SStefano Babic u32 reg; 185575001e4SStefano Babic reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | 186575001e4SStefano Babic (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); 187575001e4SStefano Babic __raw_writel(reg, DI_DW_GEN(di, wave_gen)); 188575001e4SStefano Babic } 189575001e4SStefano Babic 190575001e4SStefano Babic static void ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set, 191575001e4SStefano Babic int up, int down) 192575001e4SStefano Babic { 193575001e4SStefano Babic u32 reg; 194575001e4SStefano Babic 195575001e4SStefano Babic reg = __raw_readl(DI_DW_GEN(di, wave_gen)); 196575001e4SStefano Babic reg &= ~(0x3 << (di_pin * 2)); 197575001e4SStefano Babic reg |= set << (di_pin * 2); 198575001e4SStefano Babic __raw_writel(reg, DI_DW_GEN(di, wave_gen)); 199575001e4SStefano Babic 200575001e4SStefano Babic __raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set)); 201575001e4SStefano Babic } 202575001e4SStefano Babic 203575001e4SStefano Babic static void ipu_di_sync_config(int di, int wave_gen, 204575001e4SStefano Babic int run_count, int run_src, 205575001e4SStefano Babic int offset_count, int offset_src, 206575001e4SStefano Babic int repeat_count, int cnt_clr_src, 207575001e4SStefano Babic int cnt_polarity_gen_en, 208575001e4SStefano Babic int cnt_polarity_clr_src, 209575001e4SStefano Babic int cnt_polarity_trigger_src, 210575001e4SStefano Babic int cnt_up, int cnt_down) 211575001e4SStefano Babic { 212575001e4SStefano Babic u32 reg; 213575001e4SStefano Babic 214575001e4SStefano Babic if ((run_count >= 0x1000) || (offset_count >= 0x1000) || 215575001e4SStefano Babic (repeat_count >= 0x1000) || 216575001e4SStefano Babic (cnt_up >= 0x400) || (cnt_down >= 0x400)) { 217575001e4SStefano Babic printf("DI%d counters out of range.\n", di); 218575001e4SStefano Babic return; 219575001e4SStefano Babic } 220575001e4SStefano Babic 221575001e4SStefano Babic reg = (run_count << 19) | (++run_src << 16) | 222575001e4SStefano Babic (offset_count << 3) | ++offset_src; 223575001e4SStefano Babic __raw_writel(reg, DI_SW_GEN0(di, wave_gen)); 224575001e4SStefano Babic reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) | 225575001e4SStefano Babic (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9); 226575001e4SStefano Babic reg |= (cnt_down << 16) | cnt_up; 227575001e4SStefano Babic if (repeat_count == 0) { 228575001e4SStefano Babic /* Enable auto reload */ 229575001e4SStefano Babic reg |= 0x10000000; 230575001e4SStefano Babic } 231575001e4SStefano Babic __raw_writel(reg, DI_SW_GEN1(di, wave_gen)); 232575001e4SStefano Babic reg = __raw_readl(DI_STP_REP(di, wave_gen)); 233575001e4SStefano Babic reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1))); 234575001e4SStefano Babic reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1)); 235575001e4SStefano Babic __raw_writel(reg, DI_STP_REP(di, wave_gen)); 236575001e4SStefano Babic } 237575001e4SStefano Babic 238575001e4SStefano Babic static void ipu_dc_map_config(int map, int byte_num, int offset, int mask) 239575001e4SStefano Babic { 240575001e4SStefano Babic int ptr = map * 3 + byte_num; 241575001e4SStefano Babic u32 reg; 242575001e4SStefano Babic 243575001e4SStefano Babic reg = __raw_readl(DC_MAP_CONF_VAL(ptr)); 244575001e4SStefano Babic reg &= ~(0xFFFF << (16 * (ptr & 0x1))); 245575001e4SStefano Babic reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1)); 246575001e4SStefano Babic __raw_writel(reg, DC_MAP_CONF_VAL(ptr)); 247575001e4SStefano Babic 248575001e4SStefano Babic reg = __raw_readl(DC_MAP_CONF_PTR(map)); 249575001e4SStefano Babic reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num))); 250575001e4SStefano Babic reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num)); 251575001e4SStefano Babic __raw_writel(reg, DC_MAP_CONF_PTR(map)); 252575001e4SStefano Babic } 253575001e4SStefano Babic 254575001e4SStefano Babic static void ipu_dc_map_clear(int map) 255575001e4SStefano Babic { 256575001e4SStefano Babic u32 reg = __raw_readl(DC_MAP_CONF_PTR(map)); 257575001e4SStefano Babic __raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))), 258575001e4SStefano Babic DC_MAP_CONF_PTR(map)); 259575001e4SStefano Babic } 260575001e4SStefano Babic 261575001e4SStefano Babic static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map, 262575001e4SStefano Babic int wave, int glue, int sync) 263575001e4SStefano Babic { 264575001e4SStefano Babic u32 reg; 265575001e4SStefano Babic int stop = 1; 266575001e4SStefano Babic 267575001e4SStefano Babic reg = sync; 268575001e4SStefano Babic reg |= (glue << 4); 269575001e4SStefano Babic reg |= (++wave << 11); 270575001e4SStefano Babic reg |= (++map << 15); 271575001e4SStefano Babic reg |= (operand << 20) & 0xFFF00000; 272575001e4SStefano Babic __raw_writel(reg, ipu_dc_tmpl_reg + word * 2); 273575001e4SStefano Babic 274575001e4SStefano Babic reg = (operand >> 12); 275575001e4SStefano Babic reg |= opcode << 4; 276575001e4SStefano Babic reg |= (stop << 9); 277575001e4SStefano Babic __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1); 278575001e4SStefano Babic } 279575001e4SStefano Babic 280575001e4SStefano Babic static void ipu_dc_link_event(int chan, int event, int addr, int priority) 281575001e4SStefano Babic { 282575001e4SStefano Babic u32 reg; 283575001e4SStefano Babic 284575001e4SStefano Babic reg = __raw_readl(DC_RL_CH(chan, event)); 285575001e4SStefano Babic reg &= ~(0xFFFF << (16 * (event & 0x1))); 286575001e4SStefano Babic reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); 287575001e4SStefano Babic __raw_writel(reg, DC_RL_CH(chan, event)); 288575001e4SStefano Babic } 289575001e4SStefano Babic 290575001e4SStefano Babic /* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250; 291575001e4SStefano Babic * U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.; 292575001e4SStefano Babic * V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.; 293575001e4SStefano Babic */ 294575001e4SStefano Babic static const int rgb2ycbcr_coeff[5][3] = { 295575001e4SStefano Babic {0x4D, 0x96, 0x1D}, 296575001e4SStefano Babic {0x3D5, 0x3AB, 0x80}, 297575001e4SStefano Babic {0x80, 0x395, 0x3EB}, 298575001e4SStefano Babic {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */ 299575001e4SStefano Babic {0x2, 0x2, 0x2}, /* S0, S1, S2 */ 300575001e4SStefano Babic }; 301575001e4SStefano Babic 302575001e4SStefano Babic /* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128)); 303575001e4SStefano Babic * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128)); 304575001e4SStefano Babic * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); 305575001e4SStefano Babic */ 306575001e4SStefano Babic static const int ycbcr2rgb_coeff[5][3] = { 307575001e4SStefano Babic {0x095, 0x000, 0x0CC}, 308575001e4SStefano Babic {0x095, 0x3CE, 0x398}, 309575001e4SStefano Babic {0x095, 0x0FF, 0x000}, 310575001e4SStefano Babic {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */ 311575001e4SStefano Babic {0x1, 0x1, 0x1}, /*S0,S1,S2 */ 312575001e4SStefano Babic }; 313575001e4SStefano Babic 314575001e4SStefano Babic #define mask_a(a) ((u32)(a) & 0x3FF) 315575001e4SStefano Babic #define mask_b(b) ((u32)(b) & 0x3FFF) 316575001e4SStefano Babic 317575001e4SStefano Babic /* Pls keep S0, S1 and S2 as 0x2 by using this convertion */ 318575001e4SStefano Babic static int rgb_to_yuv(int n, int red, int green, int blue) 319575001e4SStefano Babic { 320575001e4SStefano Babic int c; 321575001e4SStefano Babic c = red * rgb2ycbcr_coeff[n][0]; 322575001e4SStefano Babic c += green * rgb2ycbcr_coeff[n][1]; 323575001e4SStefano Babic c += blue * rgb2ycbcr_coeff[n][2]; 324575001e4SStefano Babic c /= 16; 325575001e4SStefano Babic c += rgb2ycbcr_coeff[3][n] * 4; 326575001e4SStefano Babic c += 8; 327575001e4SStefano Babic c /= 16; 328575001e4SStefano Babic if (c < 0) 329575001e4SStefano Babic c = 0; 330575001e4SStefano Babic if (c > 255) 331575001e4SStefano Babic c = 255; 332575001e4SStefano Babic return c; 333575001e4SStefano Babic } 334575001e4SStefano Babic 335575001e4SStefano Babic /* 336575001e4SStefano Babic * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE 337575001e4SStefano Babic * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE 338575001e4SStefano Babic */ 339575001e4SStefano Babic static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = { 340575001e4SStefano Babic { 341575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff}, 342575001e4SStefano Babic {0, 0}, 343575001e4SStefano Babic {0, 0}, 344575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}, 345575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff} 346575001e4SStefano Babic }, 347575001e4SStefano Babic { 348575001e4SStefano Babic {0, 0}, 349575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff}, 350575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}, 351575001e4SStefano Babic {0, 0}, 352575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff} 353575001e4SStefano Babic }, 354575001e4SStefano Babic { 355575001e4SStefano Babic {0, 0}, 356575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, 357575001e4SStefano Babic {0, 0}, 358575001e4SStefano Babic {0, 0}, 359575001e4SStefano Babic {0, 0} 360575001e4SStefano Babic }, 361575001e4SStefano Babic { 362575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, 363575001e4SStefano Babic {0, 0}, 364575001e4SStefano Babic {0, 0}, 365575001e4SStefano Babic {0, 0}, 366575001e4SStefano Babic {0, 0} 367575001e4SStefano Babic }, 368575001e4SStefano Babic { 369575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff}, 370575001e4SStefano Babic {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff}, 371575001e4SStefano Babic {0, 0}, 372575001e4SStefano Babic {0, 0}, 373575001e4SStefano Babic {0, 0} 374575001e4SStefano Babic } 375575001e4SStefano Babic }; 376575001e4SStefano Babic 377575001e4SStefano Babic static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE; 378575001e4SStefano Babic static int color_key_4rgb = 1; 379575001e4SStefano Babic 380575001e4SStefano Babic void ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param, 381575001e4SStefano Babic unsigned char srm_mode_update) 382575001e4SStefano Babic { 383575001e4SStefano Babic u32 reg; 384575001e4SStefano Babic const int (*coeff)[5][3]; 385575001e4SStefano Babic 386575001e4SStefano Babic if (dp_csc_param.mode >= 0) { 387564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 388575001e4SStefano Babic reg &= ~DP_COM_CONF_CSC_DEF_MASK; 389575001e4SStefano Babic reg |= dp_csc_param.mode; 390564964bdSMarek Vasut __raw_writel(reg, DP_COM_CONF()); 391575001e4SStefano Babic } 392575001e4SStefano Babic 393575001e4SStefano Babic coeff = dp_csc_param.coeff; 394575001e4SStefano Babic 395575001e4SStefano Babic if (coeff) { 396575001e4SStefano Babic __raw_writel(mask_a((*coeff)[0][0]) | 397564964bdSMarek Vasut (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0()); 398575001e4SStefano Babic __raw_writel(mask_a((*coeff)[0][2]) | 399564964bdSMarek Vasut (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1()); 400575001e4SStefano Babic __raw_writel(mask_a((*coeff)[1][1]) | 401564964bdSMarek Vasut (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2()); 402575001e4SStefano Babic __raw_writel(mask_a((*coeff)[2][0]) | 403564964bdSMarek Vasut (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3()); 404575001e4SStefano Babic __raw_writel(mask_a((*coeff)[2][2]) | 405575001e4SStefano Babic (mask_b((*coeff)[3][0]) << 16) | 406564964bdSMarek Vasut ((*coeff)[4][0] << 30), DP_CSC_0()); 407575001e4SStefano Babic __raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) | 408575001e4SStefano Babic (mask_b((*coeff)[3][2]) << 16) | 409564964bdSMarek Vasut ((*coeff)[4][2] << 30), DP_CSC_1()); 410575001e4SStefano Babic } 411575001e4SStefano Babic 412575001e4SStefano Babic if (srm_mode_update) { 413575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 414575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 415575001e4SStefano Babic } 416575001e4SStefano Babic } 417575001e4SStefano Babic 418575001e4SStefano Babic int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt, 419575001e4SStefano Babic uint32_t out_pixel_fmt) 420575001e4SStefano Babic { 421575001e4SStefano Babic int in_fmt, out_fmt; 422575001e4SStefano Babic int dp; 423575001e4SStefano Babic int partial = 0; 424575001e4SStefano Babic uint32_t reg; 425575001e4SStefano Babic 426575001e4SStefano Babic if (channel == MEM_FG_SYNC) { 427575001e4SStefano Babic dp = DP_SYNC; 428575001e4SStefano Babic partial = 1; 429575001e4SStefano Babic } else if (channel == MEM_BG_SYNC) { 430575001e4SStefano Babic dp = DP_SYNC; 431575001e4SStefano Babic partial = 0; 432575001e4SStefano Babic } else if (channel == MEM_BG_ASYNC0) { 433575001e4SStefano Babic dp = DP_ASYNC0; 434575001e4SStefano Babic partial = 0; 435575001e4SStefano Babic } else { 436575001e4SStefano Babic return -EINVAL; 437575001e4SStefano Babic } 438575001e4SStefano Babic 439575001e4SStefano Babic in_fmt = format_to_colorspace(in_pixel_fmt); 440575001e4SStefano Babic out_fmt = format_to_colorspace(out_pixel_fmt); 441575001e4SStefano Babic 442575001e4SStefano Babic if (partial) { 443575001e4SStefano Babic if (in_fmt == RGB) { 444575001e4SStefano Babic if (out_fmt == RGB) 445575001e4SStefano Babic fg_csc_type = RGB2RGB; 446575001e4SStefano Babic else 447575001e4SStefano Babic fg_csc_type = RGB2YUV; 448575001e4SStefano Babic } else { 449575001e4SStefano Babic if (out_fmt == RGB) 450575001e4SStefano Babic fg_csc_type = YUV2RGB; 451575001e4SStefano Babic else 452575001e4SStefano Babic fg_csc_type = YUV2YUV; 453575001e4SStefano Babic } 454575001e4SStefano Babic } else { 455575001e4SStefano Babic if (in_fmt == RGB) { 456575001e4SStefano Babic if (out_fmt == RGB) 457575001e4SStefano Babic bg_csc_type = RGB2RGB; 458575001e4SStefano Babic else 459575001e4SStefano Babic bg_csc_type = RGB2YUV; 460575001e4SStefano Babic } else { 461575001e4SStefano Babic if (out_fmt == RGB) 462575001e4SStefano Babic bg_csc_type = YUV2RGB; 463575001e4SStefano Babic else 464575001e4SStefano Babic bg_csc_type = YUV2YUV; 465575001e4SStefano Babic } 466575001e4SStefano Babic } 467575001e4SStefano Babic 468575001e4SStefano Babic /* Transform color key from rgb to yuv if CSC is enabled */ 469564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 470575001e4SStefano Babic if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) && 471575001e4SStefano Babic (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || 472575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || 473575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || 474575001e4SStefano Babic ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) { 475575001e4SStefano Babic int red, green, blue; 476575001e4SStefano Babic int y, u, v; 477564964bdSMarek Vasut uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL()) & 478575001e4SStefano Babic 0xFFFFFFL; 479575001e4SStefano Babic 480575001e4SStefano Babic debug("_ipu_dp_init color key 0x%x need change to yuv fmt!\n", 481575001e4SStefano Babic color_key); 482575001e4SStefano Babic 483575001e4SStefano Babic red = (color_key >> 16) & 0xFF; 484575001e4SStefano Babic green = (color_key >> 8) & 0xFF; 485575001e4SStefano Babic blue = color_key & 0xFF; 486575001e4SStefano Babic 487575001e4SStefano Babic y = rgb_to_yuv(0, red, green, blue); 488575001e4SStefano Babic u = rgb_to_yuv(1, red, green, blue); 489575001e4SStefano Babic v = rgb_to_yuv(2, red, green, blue); 490575001e4SStefano Babic color_key = (y << 16) | (u << 8) | v; 491575001e4SStefano Babic 492564964bdSMarek Vasut reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L; 493564964bdSMarek Vasut __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL()); 494575001e4SStefano Babic color_key_4rgb = 0; 495575001e4SStefano Babic 496575001e4SStefano Babic debug("_ipu_dp_init color key change to yuv fmt 0x%x!\n", 497575001e4SStefano Babic color_key); 498575001e4SStefano Babic } 499575001e4SStefano Babic 500575001e4SStefano Babic ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 1); 501575001e4SStefano Babic 502575001e4SStefano Babic return 0; 503575001e4SStefano Babic } 504575001e4SStefano Babic 505575001e4SStefano Babic void ipu_dp_uninit(ipu_channel_t channel) 506575001e4SStefano Babic { 507575001e4SStefano Babic int dp; 508575001e4SStefano Babic int partial = 0; 509575001e4SStefano Babic 510575001e4SStefano Babic if (channel == MEM_FG_SYNC) { 511575001e4SStefano Babic dp = DP_SYNC; 512575001e4SStefano Babic partial = 1; 513575001e4SStefano Babic } else if (channel == MEM_BG_SYNC) { 514575001e4SStefano Babic dp = DP_SYNC; 515575001e4SStefano Babic partial = 0; 516575001e4SStefano Babic } else if (channel == MEM_BG_ASYNC0) { 517575001e4SStefano Babic dp = DP_ASYNC0; 518575001e4SStefano Babic partial = 0; 519575001e4SStefano Babic } else { 520575001e4SStefano Babic return; 521575001e4SStefano Babic } 522575001e4SStefano Babic 523575001e4SStefano Babic if (partial) 524575001e4SStefano Babic fg_csc_type = CSC_NONE; 525575001e4SStefano Babic else 526575001e4SStefano Babic bg_csc_type = CSC_NONE; 527575001e4SStefano Babic 528575001e4SStefano Babic ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0); 529575001e4SStefano Babic } 530575001e4SStefano Babic 531575001e4SStefano Babic void ipu_dc_init(int dc_chan, int di, unsigned char interlaced) 532575001e4SStefano Babic { 533575001e4SStefano Babic u32 reg = 0; 534575001e4SStefano Babic 535575001e4SStefano Babic if ((dc_chan == 1) || (dc_chan == 5)) { 536575001e4SStefano Babic if (interlaced) { 537575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3); 538575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2); 539575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1); 540575001e4SStefano Babic } else { 541575001e4SStefano Babic if (di) { 542575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3); 543575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2); 544575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 545575001e4SStefano Babic 4, 1); 546575001e4SStefano Babic } else { 547575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3); 548575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2); 549575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 550575001e4SStefano Babic 7, 1); 551575001e4SStefano Babic } 552575001e4SStefano Babic } 553575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); 554575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); 555575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); 556575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); 557575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); 558575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); 559575001e4SStefano Babic 560575001e4SStefano Babic reg = 0x2; 561575001e4SStefano Babic reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; 562575001e4SStefano Babic reg |= di << 2; 563575001e4SStefano Babic if (interlaced) 564575001e4SStefano Babic reg |= DC_WR_CH_CONF_FIELD_MODE; 565575001e4SStefano Babic } else if ((dc_chan == 8) || (dc_chan == 9)) { 566575001e4SStefano Babic /* async channels */ 567575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1); 568575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1); 569575001e4SStefano Babic 570575001e4SStefano Babic reg = 0x3; 571575001e4SStefano Babic reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET; 572575001e4SStefano Babic } 573575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 574575001e4SStefano Babic 575575001e4SStefano Babic __raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan)); 576575001e4SStefano Babic 577575001e4SStefano Babic __raw_writel(0x00000084, DC_GEN); 578575001e4SStefano Babic } 579575001e4SStefano Babic 580575001e4SStefano Babic void ipu_dc_uninit(int dc_chan) 581575001e4SStefano Babic { 582575001e4SStefano Babic if ((dc_chan == 1) || (dc_chan == 5)) { 583575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0); 584575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0); 585575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0); 586575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0); 587575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0); 588575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0); 589575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0); 590575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0); 591575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0); 592575001e4SStefano Babic } else if ((dc_chan == 8) || (dc_chan == 9)) { 593575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0); 594575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0); 595575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0); 596575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0); 597575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0); 598575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0); 599575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0); 600575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0); 601575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0); 602575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0); 603575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0); 604575001e4SStefano Babic ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0); 605575001e4SStefano Babic } 606575001e4SStefano Babic } 607575001e4SStefano Babic 608575001e4SStefano Babic int ipu_chan_is_interlaced(ipu_channel_t channel) 609575001e4SStefano Babic { 610575001e4SStefano Babic if (channel == MEM_DC_SYNC) 611575001e4SStefano Babic return !!(__raw_readl(DC_WR_CH_CONF_1) & 612575001e4SStefano Babic DC_WR_CH_CONF_FIELD_MODE); 613575001e4SStefano Babic else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC)) 614575001e4SStefano Babic return !!(__raw_readl(DC_WR_CH_CONF_5) & 615575001e4SStefano Babic DC_WR_CH_CONF_FIELD_MODE); 616575001e4SStefano Babic return 0; 617575001e4SStefano Babic } 618575001e4SStefano Babic 619575001e4SStefano Babic void ipu_dp_dc_enable(ipu_channel_t channel) 620575001e4SStefano Babic { 621575001e4SStefano Babic int di; 622575001e4SStefano Babic uint32_t reg; 623575001e4SStefano Babic uint32_t dc_chan; 624575001e4SStefano Babic 625575001e4SStefano Babic if (channel == MEM_FG_SYNC) 626575001e4SStefano Babic dc_chan = 5; 627575001e4SStefano Babic if (channel == MEM_DC_SYNC) 628575001e4SStefano Babic dc_chan = 1; 629575001e4SStefano Babic else if (channel == MEM_BG_SYNC) 630575001e4SStefano Babic dc_chan = 5; 631575001e4SStefano Babic else 632575001e4SStefano Babic return; 633575001e4SStefano Babic 634575001e4SStefano Babic if (channel == MEM_FG_SYNC) { 635575001e4SStefano Babic /* Enable FG channel */ 636564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 637564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF()); 638575001e4SStefano Babic 639575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 640575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 641575001e4SStefano Babic return; 642575001e4SStefano Babic } 643575001e4SStefano Babic 644575001e4SStefano Babic di = g_dc_di_assignment[dc_chan]; 645575001e4SStefano Babic 646575001e4SStefano Babic /* Make sure other DC sync channel is not assigned same DI */ 647575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan)); 648575001e4SStefano Babic if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) { 649575001e4SStefano Babic reg &= ~DC_WR_CH_CONF_PROG_DI_ID; 650575001e4SStefano Babic reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID; 651575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); 652575001e4SStefano Babic } 653575001e4SStefano Babic 654575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); 655575001e4SStefano Babic reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET; 656575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 657575001e4SStefano Babic 658575001e4SStefano Babic clk_enable(g_pixel_clk[di]); 659575001e4SStefano Babic } 660575001e4SStefano Babic 661575001e4SStefano Babic static unsigned char dc_swap; 662575001e4SStefano Babic 663575001e4SStefano Babic void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap) 664575001e4SStefano Babic { 665575001e4SStefano Babic uint32_t reg; 666575001e4SStefano Babic uint32_t csc; 667575001e4SStefano Babic uint32_t dc_chan = 0; 668575001e4SStefano Babic int timeout = 50; 669e66866c5SLiu Ying int irq = 0; 670575001e4SStefano Babic 671575001e4SStefano Babic dc_swap = swap; 672575001e4SStefano Babic 673575001e4SStefano Babic if (channel == MEM_DC_SYNC) { 674575001e4SStefano Babic dc_chan = 1; 675e66866c5SLiu Ying irq = IPU_IRQ_DC_FC_1; 676575001e4SStefano Babic } else if (channel == MEM_BG_SYNC) { 677575001e4SStefano Babic dc_chan = 5; 678e66866c5SLiu Ying irq = IPU_IRQ_DP_SF_END; 679575001e4SStefano Babic } else if (channel == MEM_FG_SYNC) { 680575001e4SStefano Babic /* Disable FG channel */ 681575001e4SStefano Babic dc_chan = 5; 682575001e4SStefano Babic 683564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 684575001e4SStefano Babic csc = reg & DP_COM_CONF_CSC_DEF_MASK; 685575001e4SStefano Babic if (csc == DP_COM_CONF_CSC_DEF_FG) 686575001e4SStefano Babic reg &= ~DP_COM_CONF_CSC_DEF_MASK; 687575001e4SStefano Babic 688575001e4SStefano Babic reg &= ~DP_COM_CONF_FG_EN; 689564964bdSMarek Vasut __raw_writel(reg, DP_COM_CONF()); 690575001e4SStefano Babic 691575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 692575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 693575001e4SStefano Babic 694575001e4SStefano Babic timeout = 50; 695575001e4SStefano Babic 696575001e4SStefano Babic /* 697575001e4SStefano Babic * Wait for DC triple buffer to empty, 698575001e4SStefano Babic * this check is useful for tv overlay. 699575001e4SStefano Babic */ 700575001e4SStefano Babic if (g_dc_di_assignment[dc_chan] == 0) 701575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000002) 702575001e4SStefano Babic != 0x00000002) { 703575001e4SStefano Babic udelay(2000); 704575001e4SStefano Babic timeout -= 2; 705575001e4SStefano Babic if (timeout <= 0) 706575001e4SStefano Babic break; 707575001e4SStefano Babic } 708575001e4SStefano Babic else if (g_dc_di_assignment[dc_chan] == 1) 709575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000020) 710575001e4SStefano Babic != 0x00000020) { 711575001e4SStefano Babic udelay(2000); 712575001e4SStefano Babic timeout -= 2; 713575001e4SStefano Babic if (timeout <= 0) 714575001e4SStefano Babic break; 715575001e4SStefano Babic } 716575001e4SStefano Babic return; 717575001e4SStefano Babic } else { 718575001e4SStefano Babic return; 719575001e4SStefano Babic } 720575001e4SStefano Babic 721575001e4SStefano Babic if (dc_swap) { 722575001e4SStefano Babic /* Swap DC channel 1 and 5 settings, and disable old dc chan */ 723575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); 724575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); 725575001e4SStefano Babic reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; 726575001e4SStefano Babic reg ^= DC_WR_CH_CONF_PROG_DI_ID; 727575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 728575001e4SStefano Babic } else { 729e66866c5SLiu Ying /* Make sure that we leave at the irq starting edge */ 730e66866c5SLiu Ying __raw_writel(IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq)); 731e66866c5SLiu Ying do { 732e66866c5SLiu Ying reg = __raw_readl(IPUIRQ_2_STATREG(irq)); 733e66866c5SLiu Ying } while (!(reg & IPUIRQ_2_MASK(irq))); 734575001e4SStefano Babic 735575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); 736575001e4SStefano Babic reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; 737575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 738575001e4SStefano Babic 739575001e4SStefano Babic reg = __raw_readl(IPU_DISP_GEN); 740575001e4SStefano Babic if (g_dc_di_assignment[dc_chan]) 741575001e4SStefano Babic reg &= ~DI1_COUNTER_RELEASE; 742575001e4SStefano Babic else 743575001e4SStefano Babic reg &= ~DI0_COUNTER_RELEASE; 744575001e4SStefano Babic __raw_writel(reg, IPU_DISP_GEN); 745575001e4SStefano Babic 746575001e4SStefano Babic /* Clock is already off because it must be done quickly, but 747575001e4SStefano Babic we need to fix the ref count */ 748575001e4SStefano Babic clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); 749575001e4SStefano Babic } 750575001e4SStefano Babic } 751575001e4SStefano Babic 752575001e4SStefano Babic void ipu_init_dc_mappings(void) 753575001e4SStefano Babic { 754575001e4SStefano Babic /* IPU_PIX_FMT_RGB24 */ 755575001e4SStefano Babic ipu_dc_map_clear(0); 756575001e4SStefano Babic ipu_dc_map_config(0, 0, 7, 0xFF); 757575001e4SStefano Babic ipu_dc_map_config(0, 1, 15, 0xFF); 758575001e4SStefano Babic ipu_dc_map_config(0, 2, 23, 0xFF); 759575001e4SStefano Babic 760575001e4SStefano Babic /* IPU_PIX_FMT_RGB666 */ 761575001e4SStefano Babic ipu_dc_map_clear(1); 762575001e4SStefano Babic ipu_dc_map_config(1, 0, 5, 0xFC); 763575001e4SStefano Babic ipu_dc_map_config(1, 1, 11, 0xFC); 764575001e4SStefano Babic ipu_dc_map_config(1, 2, 17, 0xFC); 765575001e4SStefano Babic 766575001e4SStefano Babic /* IPU_PIX_FMT_YUV444 */ 767575001e4SStefano Babic ipu_dc_map_clear(2); 768575001e4SStefano Babic ipu_dc_map_config(2, 0, 15, 0xFF); 769575001e4SStefano Babic ipu_dc_map_config(2, 1, 23, 0xFF); 770575001e4SStefano Babic ipu_dc_map_config(2, 2, 7, 0xFF); 771575001e4SStefano Babic 772575001e4SStefano Babic /* IPU_PIX_FMT_RGB565 */ 773575001e4SStefano Babic ipu_dc_map_clear(3); 774575001e4SStefano Babic ipu_dc_map_config(3, 0, 4, 0xF8); 775575001e4SStefano Babic ipu_dc_map_config(3, 1, 10, 0xFC); 776575001e4SStefano Babic ipu_dc_map_config(3, 2, 15, 0xF8); 777575001e4SStefano Babic 778575001e4SStefano Babic /* IPU_PIX_FMT_LVDS666 */ 779575001e4SStefano Babic ipu_dc_map_clear(4); 780575001e4SStefano Babic ipu_dc_map_config(4, 0, 5, 0xFC); 781575001e4SStefano Babic ipu_dc_map_config(4, 1, 13, 0xFC); 782575001e4SStefano Babic ipu_dc_map_config(4, 2, 21, 0xFC); 783575001e4SStefano Babic } 784575001e4SStefano Babic 785575001e4SStefano Babic int ipu_pixfmt_to_map(uint32_t fmt) 786575001e4SStefano Babic { 787575001e4SStefano Babic switch (fmt) { 788575001e4SStefano Babic case IPU_PIX_FMT_GENERIC: 789575001e4SStefano Babic case IPU_PIX_FMT_RGB24: 790575001e4SStefano Babic return 0; 791575001e4SStefano Babic case IPU_PIX_FMT_RGB666: 792575001e4SStefano Babic return 1; 793575001e4SStefano Babic case IPU_PIX_FMT_YUV444: 794575001e4SStefano Babic return 2; 795575001e4SStefano Babic case IPU_PIX_FMT_RGB565: 796575001e4SStefano Babic return 3; 797575001e4SStefano Babic case IPU_PIX_FMT_LVDS666: 798575001e4SStefano Babic return 4; 799575001e4SStefano Babic } 800575001e4SStefano Babic 801575001e4SStefano Babic return -1; 802575001e4SStefano Babic } 803575001e4SStefano Babic 804575001e4SStefano Babic /* 805575001e4SStefano Babic * This function is called to adapt synchronous LCD panel to IPU restriction. 806575001e4SStefano Babic */ 807575001e4SStefano Babic void adapt_panel_to_ipu_restricitions(uint32_t *pixel_clk, 808575001e4SStefano Babic uint16_t width, uint16_t height, 809575001e4SStefano Babic uint16_t h_start_width, 810575001e4SStefano Babic uint16_t h_end_width, 811575001e4SStefano Babic uint16_t v_start_width, 812575001e4SStefano Babic uint16_t *v_end_width) 813575001e4SStefano Babic { 814575001e4SStefano Babic if (*v_end_width < 2) { 815575001e4SStefano Babic uint16_t total_width = width + h_start_width + h_end_width; 816575001e4SStefano Babic uint16_t total_height_old = height + v_start_width + 817575001e4SStefano Babic (*v_end_width); 818575001e4SStefano Babic uint16_t total_height_new = height + v_start_width + 2; 819575001e4SStefano Babic *v_end_width = 2; 820575001e4SStefano Babic *pixel_clk = (*pixel_clk) * total_width * total_height_new / 821575001e4SStefano Babic (total_width * total_height_old); 822575001e4SStefano Babic printf("WARNING: adapt panel end blank lines\n"); 823575001e4SStefano Babic } 824575001e4SStefano Babic } 825575001e4SStefano Babic 826575001e4SStefano Babic /* 827575001e4SStefano Babic * This function is called to initialize a synchronous LCD panel. 828575001e4SStefano Babic * 829575001e4SStefano Babic * @param disp The DI the panel is attached to. 830575001e4SStefano Babic * 831575001e4SStefano Babic * @param pixel_clk Desired pixel clock frequency in Hz. 832575001e4SStefano Babic * 833575001e4SStefano Babic * @param pixel_fmt Input parameter for pixel format of buffer. 834575001e4SStefano Babic * Pixel format is a FOURCC ASCII code. 835575001e4SStefano Babic * 836575001e4SStefano Babic * @param width The width of panel in pixels. 837575001e4SStefano Babic * 838575001e4SStefano Babic * @param height The height of panel in pixels. 839575001e4SStefano Babic * 840575001e4SStefano Babic * @param hStartWidth The number of pixel clocks between the HSYNC 841575001e4SStefano Babic * signal pulse and the start of valid data. 842575001e4SStefano Babic * 843575001e4SStefano Babic * @param hSyncWidth The width of the HSYNC signal in units of pixel 844575001e4SStefano Babic * clocks. 845575001e4SStefano Babic * 846575001e4SStefano Babic * @param hEndWidth The number of pixel clocks between the end of 847575001e4SStefano Babic * valid data and the HSYNC signal for next line. 848575001e4SStefano Babic * 849575001e4SStefano Babic * @param vStartWidth The number of lines between the VSYNC 850575001e4SStefano Babic * signal pulse and the start of valid data. 851575001e4SStefano Babic * 852575001e4SStefano Babic * @param vSyncWidth The width of the VSYNC signal in units of lines 853575001e4SStefano Babic * 854575001e4SStefano Babic * @param vEndWidth The number of lines between the end of valid 855575001e4SStefano Babic * data and the VSYNC signal for next frame. 856575001e4SStefano Babic * 857575001e4SStefano Babic * @param sig Bitfield of signal polarities for LCD interface. 858575001e4SStefano Babic * 859575001e4SStefano Babic * @return This function returns 0 on success or negative error code on 860575001e4SStefano Babic * fail. 861575001e4SStefano Babic */ 862575001e4SStefano Babic 863575001e4SStefano Babic int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, 864575001e4SStefano Babic uint16_t width, uint16_t height, 865575001e4SStefano Babic uint32_t pixel_fmt, 866575001e4SStefano Babic uint16_t h_start_width, uint16_t h_sync_width, 867575001e4SStefano Babic uint16_t h_end_width, uint16_t v_start_width, 868575001e4SStefano Babic uint16_t v_sync_width, uint16_t v_end_width, 869575001e4SStefano Babic uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig) 870575001e4SStefano Babic { 871575001e4SStefano Babic uint32_t reg; 872575001e4SStefano Babic uint32_t di_gen, vsync_cnt; 873575001e4SStefano Babic uint32_t div, rounded_pixel_clk; 874575001e4SStefano Babic uint32_t h_total, v_total; 875575001e4SStefano Babic int map; 876575001e4SStefano Babic struct clk *di_parent; 877575001e4SStefano Babic 878575001e4SStefano Babic debug("panel size = %d x %d\n", width, height); 879575001e4SStefano Babic 880575001e4SStefano Babic if ((v_sync_width == 0) || (h_sync_width == 0)) 881d1486e33SFabio Estevam return -EINVAL; 882575001e4SStefano Babic 883575001e4SStefano Babic adapt_panel_to_ipu_restricitions(&pixel_clk, width, height, 884575001e4SStefano Babic h_start_width, h_end_width, 885575001e4SStefano Babic v_start_width, &v_end_width); 886575001e4SStefano Babic h_total = width + h_sync_width + h_start_width + h_end_width; 887575001e4SStefano Babic v_total = height + v_sync_width + v_start_width + v_end_width; 888575001e4SStefano Babic 889575001e4SStefano Babic /* Init clocking */ 890*c1420328SJeroen Hofstee debug("pixel clk = %dHz\n", pixel_clk); 891575001e4SStefano Babic 892575001e4SStefano Babic if (sig.ext_clk) { 893575001e4SStefano Babic if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/ 894575001e4SStefano Babic /* 895575001e4SStefano Babic * Set the PLL to be an even multiple 896575001e4SStefano Babic * of the pixel clock. 897575001e4SStefano Babic */ 898575001e4SStefano Babic if ((clk_get_usecount(g_pixel_clk[0]) == 0) && 899575001e4SStefano Babic (clk_get_usecount(g_pixel_clk[1]) == 0)) { 900575001e4SStefano Babic di_parent = clk_get_parent(g_di_clk[disp]); 901575001e4SStefano Babic rounded_pixel_clk = 902575001e4SStefano Babic clk_round_rate(g_pixel_clk[disp], 903575001e4SStefano Babic pixel_clk); 904575001e4SStefano Babic div = clk_get_rate(di_parent) / 905575001e4SStefano Babic rounded_pixel_clk; 906575001e4SStefano Babic if (div % 2) 907575001e4SStefano Babic div++; 908575001e4SStefano Babic if (clk_get_rate(di_parent) != div * 909575001e4SStefano Babic rounded_pixel_clk) 910575001e4SStefano Babic clk_set_rate(di_parent, 911575001e4SStefano Babic div * rounded_pixel_clk); 912575001e4SStefano Babic udelay(10000); 913575001e4SStefano Babic clk_set_rate(g_di_clk[disp], 914575001e4SStefano Babic 2 * rounded_pixel_clk); 915575001e4SStefano Babic udelay(10000); 916575001e4SStefano Babic } 917575001e4SStefano Babic } 918cf65d478SEric Nelson clk_set_parent(g_pixel_clk[disp], g_ldb_clk); 919575001e4SStefano Babic } else { 920575001e4SStefano Babic if (clk_get_usecount(g_pixel_clk[disp]) != 0) 921575001e4SStefano Babic clk_set_parent(g_pixel_clk[disp], g_ipu_clk); 922575001e4SStefano Babic } 923575001e4SStefano Babic rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk); 924575001e4SStefano Babic clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk); 925575001e4SStefano Babic udelay(5000); 926575001e4SStefano Babic /* Get integer portion of divider */ 927575001e4SStefano Babic div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) / 928575001e4SStefano Babic rounded_pixel_clk; 929575001e4SStefano Babic 930575001e4SStefano Babic ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1); 931575001e4SStefano Babic ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); 932575001e4SStefano Babic 933575001e4SStefano Babic map = ipu_pixfmt_to_map(pixel_fmt); 934575001e4SStefano Babic if (map < 0) { 935575001e4SStefano Babic debug("IPU_DISP: No MAP\n"); 936575001e4SStefano Babic return -EINVAL; 937575001e4SStefano Babic } 938575001e4SStefano Babic 939575001e4SStefano Babic di_gen = __raw_readl(DI_GENERAL(disp)); 940575001e4SStefano Babic 941575001e4SStefano Babic if (sig.interlaced) { 942575001e4SStefano Babic /* Setup internal HSYNC waveform */ 943575001e4SStefano Babic ipu_di_sync_config( 944575001e4SStefano Babic disp, /* display */ 945575001e4SStefano Babic 1, /* counter */ 946575001e4SStefano Babic h_total / 2 - 1,/* run count */ 947575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 948575001e4SStefano Babic 0, /* offset */ 949575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 950575001e4SStefano Babic 0, /* repeat count */ 951575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 952575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 953575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 954575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 955575001e4SStefano Babic 0, /* COUNT UP */ 956575001e4SStefano Babic 0 /* COUNT DOWN */ 957575001e4SStefano Babic ); 958575001e4SStefano Babic 959575001e4SStefano Babic /* Field 1 VSYNC waveform */ 960575001e4SStefano Babic ipu_di_sync_config( 961575001e4SStefano Babic disp, /* display */ 962575001e4SStefano Babic 2, /* counter */ 963575001e4SStefano Babic h_total - 1, /* run count */ 964575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 965575001e4SStefano Babic 0, /* offset */ 966575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 967575001e4SStefano Babic 0, /* repeat count */ 968575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 969575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 970575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 971575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 972575001e4SStefano Babic 0, /* COUNT UP */ 973575001e4SStefano Babic 4 /* COUNT DOWN */ 974575001e4SStefano Babic ); 975575001e4SStefano Babic 976575001e4SStefano Babic /* Setup internal HSYNC waveform */ 977575001e4SStefano Babic ipu_di_sync_config( 978575001e4SStefano Babic disp, /* display */ 979575001e4SStefano Babic 3, /* counter */ 980575001e4SStefano Babic v_total * 2 - 1,/* run count */ 981575001e4SStefano Babic DI_SYNC_INT_HSYNC, /* run_resolution */ 982575001e4SStefano Babic 1, /* offset */ 983575001e4SStefano Babic DI_SYNC_INT_HSYNC, /* offset resolution */ 984575001e4SStefano Babic 0, /* repeat count */ 985575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 986575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 987575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 988575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 989575001e4SStefano Babic 0, /* COUNT UP */ 990575001e4SStefano Babic 4 /* COUNT DOWN */ 991575001e4SStefano Babic ); 992575001e4SStefano Babic 993575001e4SStefano Babic /* Active Field ? */ 994575001e4SStefano Babic ipu_di_sync_config( 995575001e4SStefano Babic disp, /* display */ 996575001e4SStefano Babic 4, /* counter */ 997575001e4SStefano Babic v_total / 2 - 1,/* run count */ 998575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 999575001e4SStefano Babic v_start_width, /* offset */ 1000575001e4SStefano Babic DI_SYNC_HSYNC, /* offset resolution */ 1001575001e4SStefano Babic 2, /* repeat count */ 1002575001e4SStefano Babic DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 1003575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1004575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1005575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1006575001e4SStefano Babic 0, /* COUNT UP */ 1007575001e4SStefano Babic 0 /* COUNT DOWN */ 1008575001e4SStefano Babic ); 1009575001e4SStefano Babic 1010575001e4SStefano Babic /* Active Line */ 1011575001e4SStefano Babic ipu_di_sync_config( 1012575001e4SStefano Babic disp, /* display */ 1013575001e4SStefano Babic 5, /* counter */ 1014575001e4SStefano Babic 0, /* run count */ 1015575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1016575001e4SStefano Babic 0, /* offset */ 1017575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 1018575001e4SStefano Babic height / 2, /* repeat count */ 1019575001e4SStefano Babic 4, /* CNT_CLR_SEL */ 1020575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1021575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1022575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1023575001e4SStefano Babic 0, /* COUNT UP */ 1024575001e4SStefano Babic 0 /* COUNT DOWN */ 1025575001e4SStefano Babic ); 1026575001e4SStefano Babic 1027575001e4SStefano Babic /* Field 0 VSYNC waveform */ 1028575001e4SStefano Babic ipu_di_sync_config( 1029575001e4SStefano Babic disp, /* display */ 1030575001e4SStefano Babic 6, /* counter */ 1031575001e4SStefano Babic v_total - 1, /* run count */ 1032575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1033575001e4SStefano Babic 0, /* offset */ 1034575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 1035575001e4SStefano Babic 0, /* repeat count */ 1036575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 1037575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1038575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1039575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1040575001e4SStefano Babic 0, /* COUNT UP */ 1041575001e4SStefano Babic 0 /* COUNT DOWN */ 1042575001e4SStefano Babic ); 1043575001e4SStefano Babic 1044575001e4SStefano Babic /* DC VSYNC waveform */ 1045575001e4SStefano Babic vsync_cnt = 7; 1046575001e4SStefano Babic ipu_di_sync_config( 1047575001e4SStefano Babic disp, /* display */ 1048575001e4SStefano Babic 7, /* counter */ 1049575001e4SStefano Babic v_total / 2 - 1,/* run count */ 1050575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1051575001e4SStefano Babic 9, /* offset */ 1052575001e4SStefano Babic DI_SYNC_HSYNC, /* offset resolution */ 1053575001e4SStefano Babic 2, /* repeat count */ 1054575001e4SStefano Babic DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 1055575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1056575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1057575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1058575001e4SStefano Babic 0, /* COUNT UP */ 1059575001e4SStefano Babic 0 /* COUNT DOWN */ 1060575001e4SStefano Babic ); 1061575001e4SStefano Babic 1062575001e4SStefano Babic /* active pixel waveform */ 1063575001e4SStefano Babic ipu_di_sync_config( 1064575001e4SStefano Babic disp, /* display */ 1065575001e4SStefano Babic 8, /* counter */ 1066575001e4SStefano Babic 0, /* run count */ 1067575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 1068575001e4SStefano Babic h_start_width, /* offset */ 1069575001e4SStefano Babic DI_SYNC_CLK, /* offset resolution */ 1070575001e4SStefano Babic width, /* repeat count */ 1071575001e4SStefano Babic 5, /* CNT_CLR_SEL */ 1072575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1073575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1074575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1075575001e4SStefano Babic 0, /* COUNT UP */ 1076575001e4SStefano Babic 0 /* COUNT DOWN */ 1077575001e4SStefano Babic ); 1078575001e4SStefano Babic 1079575001e4SStefano Babic ipu_di_sync_config( 1080575001e4SStefano Babic disp, /* display */ 1081575001e4SStefano Babic 9, /* counter */ 1082575001e4SStefano Babic v_total - 1, /* run count */ 1083575001e4SStefano Babic DI_SYNC_INT_HSYNC,/* run_resolution */ 1084575001e4SStefano Babic v_total / 2, /* offset */ 1085575001e4SStefano Babic DI_SYNC_INT_HSYNC,/* offset resolution */ 1086575001e4SStefano Babic 0, /* repeat count */ 1087575001e4SStefano Babic DI_SYNC_HSYNC, /* CNT_CLR_SEL */ 1088575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1089575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1090575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1091575001e4SStefano Babic 0, /* COUNT UP */ 1092575001e4SStefano Babic 4 /* COUNT DOWN */ 1093575001e4SStefano Babic ); 1094575001e4SStefano Babic 1095575001e4SStefano Babic /* set gentime select and tag sel */ 1096575001e4SStefano Babic reg = __raw_readl(DI_SW_GEN1(disp, 9)); 1097575001e4SStefano Babic reg &= 0x1FFFFFFF; 1098575001e4SStefano Babic reg |= (3 - 1)<<29 | 0x00008000; 1099575001e4SStefano Babic __raw_writel(reg, DI_SW_GEN1(disp, 9)); 1100575001e4SStefano Babic 1101575001e4SStefano Babic __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp)); 1102575001e4SStefano Babic 1103575001e4SStefano Babic /* set y_sel = 1 */ 1104575001e4SStefano Babic di_gen |= 0x10000000; 1105575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_5; 1106575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_8; 1107575001e4SStefano Babic } else { 1108575001e4SStefano Babic /* Setup internal HSYNC waveform */ 1109575001e4SStefano Babic ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK, 1110575001e4SStefano Babic 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 1111575001e4SStefano Babic 0, DI_SYNC_NONE, 1112575001e4SStefano Babic DI_SYNC_NONE, 0, 0); 1113575001e4SStefano Babic 1114575001e4SStefano Babic /* Setup external (delayed) HSYNC waveform */ 1115575001e4SStefano Babic ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1, 1116575001e4SStefano Babic DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK, 1117575001e4SStefano Babic 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, 1118575001e4SStefano Babic DI_SYNC_CLK, 0, h_sync_width * 2); 1119575001e4SStefano Babic /* Setup VSYNC waveform */ 1120575001e4SStefano Babic vsync_cnt = DI_SYNC_VSYNC; 1121575001e4SStefano Babic ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1, 1122575001e4SStefano Babic DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0, 1123575001e4SStefano Babic DI_SYNC_NONE, 1, DI_SYNC_NONE, 1124575001e4SStefano Babic DI_SYNC_INT_HSYNC, 0, v_sync_width * 2); 1125575001e4SStefano Babic __raw_writel(v_total - 1, DI_SCR_CONF(disp)); 1126575001e4SStefano Babic 1127575001e4SStefano Babic /* Setup active data waveform to sync with DC */ 1128575001e4SStefano Babic ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC, 1129575001e4SStefano Babic v_sync_width + v_start_width, DI_SYNC_HSYNC, 1130575001e4SStefano Babic height, 1131575001e4SStefano Babic DI_SYNC_VSYNC, 0, DI_SYNC_NONE, 1132575001e4SStefano Babic DI_SYNC_NONE, 0, 0); 1133575001e4SStefano Babic ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK, 1134575001e4SStefano Babic h_sync_width + h_start_width, DI_SYNC_CLK, 1135575001e4SStefano Babic width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 1136575001e4SStefano Babic 0); 1137575001e4SStefano Babic 1138575001e4SStefano Babic /* reset all unused counters */ 1139575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 6)); 1140575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 6)); 1141575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 7)); 1142575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 7)); 1143575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 8)); 1144575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 8)); 1145575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 9)); 1146575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 9)); 1147575001e4SStefano Babic 1148575001e4SStefano Babic reg = __raw_readl(DI_STP_REP(disp, 6)); 1149575001e4SStefano Babic reg &= 0x0000FFFF; 1150575001e4SStefano Babic __raw_writel(reg, DI_STP_REP(disp, 6)); 1151575001e4SStefano Babic __raw_writel(0, DI_STP_REP(disp, 7)); 1152575001e4SStefano Babic __raw_writel(0, DI_STP_REP(disp, 9)); 1153575001e4SStefano Babic 1154575001e4SStefano Babic /* Init template microcode */ 1155575001e4SStefano Babic if (disp) { 1156575001e4SStefano Babic ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); 1157575001e4SStefano Babic ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); 1158575001e4SStefano Babic ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); 1159575001e4SStefano Babic } else { 1160575001e4SStefano Babic ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); 1161575001e4SStefano Babic ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); 1162575001e4SStefano Babic ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); 1163575001e4SStefano Babic } 1164575001e4SStefano Babic 1165575001e4SStefano Babic if (sig.Hsync_pol) 1166575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_2; 1167575001e4SStefano Babic if (sig.Vsync_pol) 1168575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_3; 1169575001e4SStefano Babic 11702740e5deSFabio Estevam if (!sig.clk_pol) 1171575001e4SStefano Babic di_gen |= DI_GEN_POL_CLK; 1172575001e4SStefano Babic 1173575001e4SStefano Babic } 1174575001e4SStefano Babic 1175575001e4SStefano Babic __raw_writel(di_gen, DI_GENERAL(disp)); 1176575001e4SStefano Babic 1177575001e4SStefano Babic __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 1178575001e4SStefano Babic 0x00000002, DI_SYNC_AS_GEN(disp)); 1179575001e4SStefano Babic 1180575001e4SStefano Babic reg = __raw_readl(DI_POL(disp)); 1181575001e4SStefano Babic reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); 1182575001e4SStefano Babic if (sig.enable_pol) 1183575001e4SStefano Babic reg |= DI_POL_DRDY_POLARITY_15; 1184575001e4SStefano Babic if (sig.data_pol) 1185575001e4SStefano Babic reg |= DI_POL_DRDY_DATA_POLARITY; 1186575001e4SStefano Babic __raw_writel(reg, DI_POL(disp)); 1187575001e4SStefano Babic 1188575001e4SStefano Babic __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp))); 1189575001e4SStefano Babic 1190575001e4SStefano Babic return 0; 1191575001e4SStefano Babic } 1192575001e4SStefano Babic 1193575001e4SStefano Babic /* 1194575001e4SStefano Babic * This function sets the foreground and background plane global alpha blending 1195575001e4SStefano Babic * modes. This function also sets the DP graphic plane according to the 1196575001e4SStefano Babic * parameter of IPUv3 DP channel. 1197575001e4SStefano Babic * 1198575001e4SStefano Babic * @param channel IPUv3 DP channel 1199575001e4SStefano Babic * 1200575001e4SStefano Babic * @param enable Boolean to enable or disable global alpha 1201575001e4SStefano Babic * blending. If disabled, local blending is used. 1202575001e4SStefano Babic * 1203575001e4SStefano Babic * @param alpha Global alpha value. 1204575001e4SStefano Babic * 1205575001e4SStefano Babic * @return Returns 0 on success or negative error code on fail 1206575001e4SStefano Babic */ 1207575001e4SStefano Babic int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable, 1208575001e4SStefano Babic uint8_t alpha) 1209575001e4SStefano Babic { 1210575001e4SStefano Babic uint32_t reg; 1211575001e4SStefano Babic 1212575001e4SStefano Babic unsigned char bg_chan; 1213575001e4SStefano Babic 1214564964bdSMarek Vasut if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || 1215564964bdSMarek Vasut (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || 1216564964bdSMarek Vasut (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) 1217575001e4SStefano Babic return -EINVAL; 1218575001e4SStefano Babic 1219575001e4SStefano Babic if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 || 1220575001e4SStefano Babic channel == MEM_BG_ASYNC1) 1221575001e4SStefano Babic bg_chan = 1; 1222575001e4SStefano Babic else 1223575001e4SStefano Babic bg_chan = 0; 1224575001e4SStefano Babic 1225575001e4SStefano Babic if (!g_ipu_clk_enabled) 1226575001e4SStefano Babic clk_enable(g_ipu_clk); 1227575001e4SStefano Babic 1228575001e4SStefano Babic if (bg_chan) { 1229564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1230564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF()); 1231575001e4SStefano Babic } else { 1232564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1233564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF()); 1234575001e4SStefano Babic } 1235575001e4SStefano Babic 1236575001e4SStefano Babic if (enable) { 1237564964bdSMarek Vasut reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0x00FFFFFFL; 1238575001e4SStefano Babic __raw_writel(reg | ((uint32_t) alpha << 24), 1239564964bdSMarek Vasut DP_GRAPH_WIND_CTRL()); 1240575001e4SStefano Babic 1241564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1242564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF()); 1243575001e4SStefano Babic } else { 1244564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1245564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF()); 1246575001e4SStefano Babic } 1247575001e4SStefano Babic 1248575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 1249575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 1250575001e4SStefano Babic 1251575001e4SStefano Babic if (!g_ipu_clk_enabled) 1252575001e4SStefano Babic clk_disable(g_ipu_clk); 1253575001e4SStefano Babic 1254575001e4SStefano Babic return 0; 1255575001e4SStefano Babic } 1256575001e4SStefano Babic 1257575001e4SStefano Babic /* 1258575001e4SStefano Babic * This function sets the transparent color key for SDC graphic plane. 1259575001e4SStefano Babic * 1260575001e4SStefano Babic * @param channel Input parameter for the logical channel ID. 1261575001e4SStefano Babic * 1262575001e4SStefano Babic * @param enable Boolean to enable or disable color key 1263575001e4SStefano Babic * 1264575001e4SStefano Babic * @param colorKey 24-bit RGB color for transparent color key. 1265575001e4SStefano Babic * 1266575001e4SStefano Babic * @return Returns 0 on success or negative error code on fail 1267575001e4SStefano Babic */ 1268575001e4SStefano Babic int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable, 1269575001e4SStefano Babic uint32_t color_key) 1270575001e4SStefano Babic { 1271564964bdSMarek Vasut uint32_t reg; 1272575001e4SStefano Babic int y, u, v; 1273575001e4SStefano Babic int red, green, blue; 1274575001e4SStefano Babic 1275564964bdSMarek Vasut if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || 1276564964bdSMarek Vasut (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || 1277564964bdSMarek Vasut (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) 1278575001e4SStefano Babic return -EINVAL; 1279575001e4SStefano Babic 1280575001e4SStefano Babic if (!g_ipu_clk_enabled) 1281575001e4SStefano Babic clk_enable(g_ipu_clk); 1282575001e4SStefano Babic 1283575001e4SStefano Babic color_key_4rgb = 1; 1284575001e4SStefano Babic /* Transform color key from rgb to yuv if CSC is enabled */ 1285575001e4SStefano Babic if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || 1286575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || 1287575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || 1288575001e4SStefano Babic ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) { 1289575001e4SStefano Babic 1290575001e4SStefano Babic debug("color key 0x%x need change to yuv fmt\n", color_key); 1291575001e4SStefano Babic 1292575001e4SStefano Babic red = (color_key >> 16) & 0xFF; 1293575001e4SStefano Babic green = (color_key >> 8) & 0xFF; 1294575001e4SStefano Babic blue = color_key & 0xFF; 1295575001e4SStefano Babic 1296575001e4SStefano Babic y = rgb_to_yuv(0, red, green, blue); 1297575001e4SStefano Babic u = rgb_to_yuv(1, red, green, blue); 1298575001e4SStefano Babic v = rgb_to_yuv(2, red, green, blue); 1299575001e4SStefano Babic color_key = (y << 16) | (u << 8) | v; 1300575001e4SStefano Babic 1301575001e4SStefano Babic color_key_4rgb = 0; 1302575001e4SStefano Babic 1303575001e4SStefano Babic debug("color key change to yuv fmt 0x%x\n", color_key); 1304575001e4SStefano Babic } 1305575001e4SStefano Babic 1306575001e4SStefano Babic if (enable) { 1307564964bdSMarek Vasut reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L; 1308564964bdSMarek Vasut __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL()); 1309575001e4SStefano Babic 1310564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1311564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF()); 1312575001e4SStefano Babic } else { 1313564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1314564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF()); 1315575001e4SStefano Babic } 1316575001e4SStefano Babic 1317575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 1318575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 1319575001e4SStefano Babic 1320575001e4SStefano Babic if (!g_ipu_clk_enabled) 1321575001e4SStefano Babic clk_disable(g_ipu_clk); 1322575001e4SStefano Babic 1323575001e4SStefano Babic return 0; 1324575001e4SStefano Babic } 1325