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 * 11*1a459660SWolfgang 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; 36575001e4SStefano Babic void *coeff; 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; 669575001e4SStefano Babic 670575001e4SStefano Babic dc_swap = swap; 671575001e4SStefano Babic 672575001e4SStefano Babic if (channel == MEM_DC_SYNC) { 673575001e4SStefano Babic dc_chan = 1; 674575001e4SStefano Babic } else if (channel == MEM_BG_SYNC) { 675575001e4SStefano Babic dc_chan = 5; 676575001e4SStefano Babic } else if (channel == MEM_FG_SYNC) { 677575001e4SStefano Babic /* Disable FG channel */ 678575001e4SStefano Babic dc_chan = 5; 679575001e4SStefano Babic 680564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 681575001e4SStefano Babic csc = reg & DP_COM_CONF_CSC_DEF_MASK; 682575001e4SStefano Babic if (csc == DP_COM_CONF_CSC_DEF_FG) 683575001e4SStefano Babic reg &= ~DP_COM_CONF_CSC_DEF_MASK; 684575001e4SStefano Babic 685575001e4SStefano Babic reg &= ~DP_COM_CONF_FG_EN; 686564964bdSMarek Vasut __raw_writel(reg, DP_COM_CONF()); 687575001e4SStefano Babic 688575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 689575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 690575001e4SStefano Babic 691575001e4SStefano Babic timeout = 50; 692575001e4SStefano Babic 693575001e4SStefano Babic /* 694575001e4SStefano Babic * Wait for DC triple buffer to empty, 695575001e4SStefano Babic * this check is useful for tv overlay. 696575001e4SStefano Babic */ 697575001e4SStefano Babic if (g_dc_di_assignment[dc_chan] == 0) 698575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000002) 699575001e4SStefano Babic != 0x00000002) { 700575001e4SStefano Babic udelay(2000); 701575001e4SStefano Babic timeout -= 2; 702575001e4SStefano Babic if (timeout <= 0) 703575001e4SStefano Babic break; 704575001e4SStefano Babic } 705575001e4SStefano Babic else if (g_dc_di_assignment[dc_chan] == 1) 706575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000020) 707575001e4SStefano Babic != 0x00000020) { 708575001e4SStefano Babic udelay(2000); 709575001e4SStefano Babic timeout -= 2; 710575001e4SStefano Babic if (timeout <= 0) 711575001e4SStefano Babic break; 712575001e4SStefano Babic } 713575001e4SStefano Babic return; 714575001e4SStefano Babic } else { 715575001e4SStefano Babic return; 716575001e4SStefano Babic } 717575001e4SStefano Babic 718575001e4SStefano Babic if (dc_swap) { 719575001e4SStefano Babic /* Swap DC channel 1 and 5 settings, and disable old dc chan */ 720575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); 721575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan)); 722575001e4SStefano Babic reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; 723575001e4SStefano Babic reg ^= DC_WR_CH_CONF_PROG_DI_ID; 724575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 725575001e4SStefano Babic } else { 726575001e4SStefano Babic timeout = 50; 727575001e4SStefano Babic 728575001e4SStefano Babic /* Wait for DC triple buffer to empty */ 729575001e4SStefano Babic if (g_dc_di_assignment[dc_chan] == 0) 730575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000002) 731575001e4SStefano Babic != 0x00000002) { 732575001e4SStefano Babic udelay(2000); 733575001e4SStefano Babic timeout -= 2; 734575001e4SStefano Babic if (timeout <= 0) 735575001e4SStefano Babic break; 736575001e4SStefano Babic } 737575001e4SStefano Babic else if (g_dc_di_assignment[dc_chan] == 1) 738575001e4SStefano Babic while ((__raw_readl(DC_STAT) & 0x00000020) 739575001e4SStefano Babic != 0x00000020) { 740575001e4SStefano Babic udelay(2000); 741575001e4SStefano Babic timeout -= 2; 742575001e4SStefano Babic if (timeout <= 0) 743575001e4SStefano Babic break; 744575001e4SStefano Babic } 745575001e4SStefano Babic 746575001e4SStefano Babic reg = __raw_readl(DC_WR_CH_CONF(dc_chan)); 747575001e4SStefano Babic reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; 748575001e4SStefano Babic __raw_writel(reg, DC_WR_CH_CONF(dc_chan)); 749575001e4SStefano Babic 750575001e4SStefano Babic reg = __raw_readl(IPU_DISP_GEN); 751575001e4SStefano Babic if (g_dc_di_assignment[dc_chan]) 752575001e4SStefano Babic reg &= ~DI1_COUNTER_RELEASE; 753575001e4SStefano Babic else 754575001e4SStefano Babic reg &= ~DI0_COUNTER_RELEASE; 755575001e4SStefano Babic __raw_writel(reg, IPU_DISP_GEN); 756575001e4SStefano Babic 757575001e4SStefano Babic /* Clock is already off because it must be done quickly, but 758575001e4SStefano Babic we need to fix the ref count */ 759575001e4SStefano Babic clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]); 760575001e4SStefano Babic } 761575001e4SStefano Babic } 762575001e4SStefano Babic 763575001e4SStefano Babic void ipu_init_dc_mappings(void) 764575001e4SStefano Babic { 765575001e4SStefano Babic /* IPU_PIX_FMT_RGB24 */ 766575001e4SStefano Babic ipu_dc_map_clear(0); 767575001e4SStefano Babic ipu_dc_map_config(0, 0, 7, 0xFF); 768575001e4SStefano Babic ipu_dc_map_config(0, 1, 15, 0xFF); 769575001e4SStefano Babic ipu_dc_map_config(0, 2, 23, 0xFF); 770575001e4SStefano Babic 771575001e4SStefano Babic /* IPU_PIX_FMT_RGB666 */ 772575001e4SStefano Babic ipu_dc_map_clear(1); 773575001e4SStefano Babic ipu_dc_map_config(1, 0, 5, 0xFC); 774575001e4SStefano Babic ipu_dc_map_config(1, 1, 11, 0xFC); 775575001e4SStefano Babic ipu_dc_map_config(1, 2, 17, 0xFC); 776575001e4SStefano Babic 777575001e4SStefano Babic /* IPU_PIX_FMT_YUV444 */ 778575001e4SStefano Babic ipu_dc_map_clear(2); 779575001e4SStefano Babic ipu_dc_map_config(2, 0, 15, 0xFF); 780575001e4SStefano Babic ipu_dc_map_config(2, 1, 23, 0xFF); 781575001e4SStefano Babic ipu_dc_map_config(2, 2, 7, 0xFF); 782575001e4SStefano Babic 783575001e4SStefano Babic /* IPU_PIX_FMT_RGB565 */ 784575001e4SStefano Babic ipu_dc_map_clear(3); 785575001e4SStefano Babic ipu_dc_map_config(3, 0, 4, 0xF8); 786575001e4SStefano Babic ipu_dc_map_config(3, 1, 10, 0xFC); 787575001e4SStefano Babic ipu_dc_map_config(3, 2, 15, 0xF8); 788575001e4SStefano Babic 789575001e4SStefano Babic /* IPU_PIX_FMT_LVDS666 */ 790575001e4SStefano Babic ipu_dc_map_clear(4); 791575001e4SStefano Babic ipu_dc_map_config(4, 0, 5, 0xFC); 792575001e4SStefano Babic ipu_dc_map_config(4, 1, 13, 0xFC); 793575001e4SStefano Babic ipu_dc_map_config(4, 2, 21, 0xFC); 794575001e4SStefano Babic } 795575001e4SStefano Babic 796575001e4SStefano Babic int ipu_pixfmt_to_map(uint32_t fmt) 797575001e4SStefano Babic { 798575001e4SStefano Babic switch (fmt) { 799575001e4SStefano Babic case IPU_PIX_FMT_GENERIC: 800575001e4SStefano Babic case IPU_PIX_FMT_RGB24: 801575001e4SStefano Babic return 0; 802575001e4SStefano Babic case IPU_PIX_FMT_RGB666: 803575001e4SStefano Babic return 1; 804575001e4SStefano Babic case IPU_PIX_FMT_YUV444: 805575001e4SStefano Babic return 2; 806575001e4SStefano Babic case IPU_PIX_FMT_RGB565: 807575001e4SStefano Babic return 3; 808575001e4SStefano Babic case IPU_PIX_FMT_LVDS666: 809575001e4SStefano Babic return 4; 810575001e4SStefano Babic } 811575001e4SStefano Babic 812575001e4SStefano Babic return -1; 813575001e4SStefano Babic } 814575001e4SStefano Babic 815575001e4SStefano Babic /* 816575001e4SStefano Babic * This function is called to adapt synchronous LCD panel to IPU restriction. 817575001e4SStefano Babic */ 818575001e4SStefano Babic void adapt_panel_to_ipu_restricitions(uint32_t *pixel_clk, 819575001e4SStefano Babic uint16_t width, uint16_t height, 820575001e4SStefano Babic uint16_t h_start_width, 821575001e4SStefano Babic uint16_t h_end_width, 822575001e4SStefano Babic uint16_t v_start_width, 823575001e4SStefano Babic uint16_t *v_end_width) 824575001e4SStefano Babic { 825575001e4SStefano Babic if (*v_end_width < 2) { 826575001e4SStefano Babic uint16_t total_width = width + h_start_width + h_end_width; 827575001e4SStefano Babic uint16_t total_height_old = height + v_start_width + 828575001e4SStefano Babic (*v_end_width); 829575001e4SStefano Babic uint16_t total_height_new = height + v_start_width + 2; 830575001e4SStefano Babic *v_end_width = 2; 831575001e4SStefano Babic *pixel_clk = (*pixel_clk) * total_width * total_height_new / 832575001e4SStefano Babic (total_width * total_height_old); 833575001e4SStefano Babic printf("WARNING: adapt panel end blank lines\n"); 834575001e4SStefano Babic } 835575001e4SStefano Babic } 836575001e4SStefano Babic 837575001e4SStefano Babic /* 838575001e4SStefano Babic * This function is called to initialize a synchronous LCD panel. 839575001e4SStefano Babic * 840575001e4SStefano Babic * @param disp The DI the panel is attached to. 841575001e4SStefano Babic * 842575001e4SStefano Babic * @param pixel_clk Desired pixel clock frequency in Hz. 843575001e4SStefano Babic * 844575001e4SStefano Babic * @param pixel_fmt Input parameter for pixel format of buffer. 845575001e4SStefano Babic * Pixel format is a FOURCC ASCII code. 846575001e4SStefano Babic * 847575001e4SStefano Babic * @param width The width of panel in pixels. 848575001e4SStefano Babic * 849575001e4SStefano Babic * @param height The height of panel in pixels. 850575001e4SStefano Babic * 851575001e4SStefano Babic * @param hStartWidth The number of pixel clocks between the HSYNC 852575001e4SStefano Babic * signal pulse and the start of valid data. 853575001e4SStefano Babic * 854575001e4SStefano Babic * @param hSyncWidth The width of the HSYNC signal in units of pixel 855575001e4SStefano Babic * clocks. 856575001e4SStefano Babic * 857575001e4SStefano Babic * @param hEndWidth The number of pixel clocks between the end of 858575001e4SStefano Babic * valid data and the HSYNC signal for next line. 859575001e4SStefano Babic * 860575001e4SStefano Babic * @param vStartWidth The number of lines between the VSYNC 861575001e4SStefano Babic * signal pulse and the start of valid data. 862575001e4SStefano Babic * 863575001e4SStefano Babic * @param vSyncWidth The width of the VSYNC signal in units of lines 864575001e4SStefano Babic * 865575001e4SStefano Babic * @param vEndWidth The number of lines between the end of valid 866575001e4SStefano Babic * data and the VSYNC signal for next frame. 867575001e4SStefano Babic * 868575001e4SStefano Babic * @param sig Bitfield of signal polarities for LCD interface. 869575001e4SStefano Babic * 870575001e4SStefano Babic * @return This function returns 0 on success or negative error code on 871575001e4SStefano Babic * fail. 872575001e4SStefano Babic */ 873575001e4SStefano Babic 874575001e4SStefano Babic int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk, 875575001e4SStefano Babic uint16_t width, uint16_t height, 876575001e4SStefano Babic uint32_t pixel_fmt, 877575001e4SStefano Babic uint16_t h_start_width, uint16_t h_sync_width, 878575001e4SStefano Babic uint16_t h_end_width, uint16_t v_start_width, 879575001e4SStefano Babic uint16_t v_sync_width, uint16_t v_end_width, 880575001e4SStefano Babic uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig) 881575001e4SStefano Babic { 882575001e4SStefano Babic uint32_t reg; 883575001e4SStefano Babic uint32_t di_gen, vsync_cnt; 884575001e4SStefano Babic uint32_t div, rounded_pixel_clk; 885575001e4SStefano Babic uint32_t h_total, v_total; 886575001e4SStefano Babic int map; 887575001e4SStefano Babic struct clk *di_parent; 888575001e4SStefano Babic 889575001e4SStefano Babic debug("panel size = %d x %d\n", width, height); 890575001e4SStefano Babic 891575001e4SStefano Babic if ((v_sync_width == 0) || (h_sync_width == 0)) 892575001e4SStefano Babic return EINVAL; 893575001e4SStefano Babic 894575001e4SStefano Babic adapt_panel_to_ipu_restricitions(&pixel_clk, width, height, 895575001e4SStefano Babic h_start_width, h_end_width, 896575001e4SStefano Babic v_start_width, &v_end_width); 897575001e4SStefano Babic h_total = width + h_sync_width + h_start_width + h_end_width; 898575001e4SStefano Babic v_total = height + v_sync_width + v_start_width + v_end_width; 899575001e4SStefano Babic 900575001e4SStefano Babic /* Init clocking */ 901575001e4SStefano Babic debug("pixel clk = %d\n", pixel_clk); 902575001e4SStefano Babic 903575001e4SStefano Babic if (sig.ext_clk) { 904575001e4SStefano Babic if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/ 905575001e4SStefano Babic /* 906575001e4SStefano Babic * Set the PLL to be an even multiple 907575001e4SStefano Babic * of the pixel clock. 908575001e4SStefano Babic */ 909575001e4SStefano Babic if ((clk_get_usecount(g_pixel_clk[0]) == 0) && 910575001e4SStefano Babic (clk_get_usecount(g_pixel_clk[1]) == 0)) { 911575001e4SStefano Babic di_parent = clk_get_parent(g_di_clk[disp]); 912575001e4SStefano Babic rounded_pixel_clk = 913575001e4SStefano Babic clk_round_rate(g_pixel_clk[disp], 914575001e4SStefano Babic pixel_clk); 915575001e4SStefano Babic div = clk_get_rate(di_parent) / 916575001e4SStefano Babic rounded_pixel_clk; 917575001e4SStefano Babic if (div % 2) 918575001e4SStefano Babic div++; 919575001e4SStefano Babic if (clk_get_rate(di_parent) != div * 920575001e4SStefano Babic rounded_pixel_clk) 921575001e4SStefano Babic clk_set_rate(di_parent, 922575001e4SStefano Babic div * rounded_pixel_clk); 923575001e4SStefano Babic udelay(10000); 924575001e4SStefano Babic clk_set_rate(g_di_clk[disp], 925575001e4SStefano Babic 2 * rounded_pixel_clk); 926575001e4SStefano Babic udelay(10000); 927575001e4SStefano Babic } 928575001e4SStefano Babic } 929cf65d478SEric Nelson clk_set_parent(g_pixel_clk[disp], g_ldb_clk); 930575001e4SStefano Babic } else { 931575001e4SStefano Babic if (clk_get_usecount(g_pixel_clk[disp]) != 0) 932575001e4SStefano Babic clk_set_parent(g_pixel_clk[disp], g_ipu_clk); 933575001e4SStefano Babic } 934575001e4SStefano Babic rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk); 935575001e4SStefano Babic clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk); 936575001e4SStefano Babic udelay(5000); 937575001e4SStefano Babic /* Get integer portion of divider */ 938575001e4SStefano Babic div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) / 939575001e4SStefano Babic rounded_pixel_clk; 940575001e4SStefano Babic 941575001e4SStefano Babic ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1); 942575001e4SStefano Babic ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); 943575001e4SStefano Babic 944575001e4SStefano Babic map = ipu_pixfmt_to_map(pixel_fmt); 945575001e4SStefano Babic if (map < 0) { 946575001e4SStefano Babic debug("IPU_DISP: No MAP\n"); 947575001e4SStefano Babic return -EINVAL; 948575001e4SStefano Babic } 949575001e4SStefano Babic 950575001e4SStefano Babic di_gen = __raw_readl(DI_GENERAL(disp)); 951575001e4SStefano Babic 952575001e4SStefano Babic if (sig.interlaced) { 953575001e4SStefano Babic /* Setup internal HSYNC waveform */ 954575001e4SStefano Babic ipu_di_sync_config( 955575001e4SStefano Babic disp, /* display */ 956575001e4SStefano Babic 1, /* counter */ 957575001e4SStefano Babic h_total / 2 - 1,/* run count */ 958575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 959575001e4SStefano Babic 0, /* offset */ 960575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 961575001e4SStefano Babic 0, /* repeat count */ 962575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 963575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 964575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 965575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 966575001e4SStefano Babic 0, /* COUNT UP */ 967575001e4SStefano Babic 0 /* COUNT DOWN */ 968575001e4SStefano Babic ); 969575001e4SStefano Babic 970575001e4SStefano Babic /* Field 1 VSYNC waveform */ 971575001e4SStefano Babic ipu_di_sync_config( 972575001e4SStefano Babic disp, /* display */ 973575001e4SStefano Babic 2, /* counter */ 974575001e4SStefano Babic h_total - 1, /* run count */ 975575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 976575001e4SStefano Babic 0, /* offset */ 977575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 978575001e4SStefano Babic 0, /* repeat count */ 979575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 980575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 981575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 982575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 983575001e4SStefano Babic 0, /* COUNT UP */ 984575001e4SStefano Babic 4 /* COUNT DOWN */ 985575001e4SStefano Babic ); 986575001e4SStefano Babic 987575001e4SStefano Babic /* Setup internal HSYNC waveform */ 988575001e4SStefano Babic ipu_di_sync_config( 989575001e4SStefano Babic disp, /* display */ 990575001e4SStefano Babic 3, /* counter */ 991575001e4SStefano Babic v_total * 2 - 1,/* run count */ 992575001e4SStefano Babic DI_SYNC_INT_HSYNC, /* run_resolution */ 993575001e4SStefano Babic 1, /* offset */ 994575001e4SStefano Babic DI_SYNC_INT_HSYNC, /* offset resolution */ 995575001e4SStefano Babic 0, /* repeat count */ 996575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 997575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 998575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 999575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1000575001e4SStefano Babic 0, /* COUNT UP */ 1001575001e4SStefano Babic 4 /* COUNT DOWN */ 1002575001e4SStefano Babic ); 1003575001e4SStefano Babic 1004575001e4SStefano Babic /* Active Field ? */ 1005575001e4SStefano Babic ipu_di_sync_config( 1006575001e4SStefano Babic disp, /* display */ 1007575001e4SStefano Babic 4, /* counter */ 1008575001e4SStefano Babic v_total / 2 - 1,/* run count */ 1009575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1010575001e4SStefano Babic v_start_width, /* offset */ 1011575001e4SStefano Babic DI_SYNC_HSYNC, /* offset resolution */ 1012575001e4SStefano Babic 2, /* repeat count */ 1013575001e4SStefano Babic DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 1014575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1015575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1016575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1017575001e4SStefano Babic 0, /* COUNT UP */ 1018575001e4SStefano Babic 0 /* COUNT DOWN */ 1019575001e4SStefano Babic ); 1020575001e4SStefano Babic 1021575001e4SStefano Babic /* Active Line */ 1022575001e4SStefano Babic ipu_di_sync_config( 1023575001e4SStefano Babic disp, /* display */ 1024575001e4SStefano Babic 5, /* counter */ 1025575001e4SStefano Babic 0, /* run count */ 1026575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1027575001e4SStefano Babic 0, /* offset */ 1028575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 1029575001e4SStefano Babic height / 2, /* repeat count */ 1030575001e4SStefano Babic 4, /* CNT_CLR_SEL */ 1031575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1032575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1033575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1034575001e4SStefano Babic 0, /* COUNT UP */ 1035575001e4SStefano Babic 0 /* COUNT DOWN */ 1036575001e4SStefano Babic ); 1037575001e4SStefano Babic 1038575001e4SStefano Babic /* Field 0 VSYNC waveform */ 1039575001e4SStefano Babic ipu_di_sync_config( 1040575001e4SStefano Babic disp, /* display */ 1041575001e4SStefano Babic 6, /* counter */ 1042575001e4SStefano Babic v_total - 1, /* run count */ 1043575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1044575001e4SStefano Babic 0, /* offset */ 1045575001e4SStefano Babic DI_SYNC_NONE, /* offset resolution */ 1046575001e4SStefano Babic 0, /* repeat count */ 1047575001e4SStefano Babic DI_SYNC_NONE, /* CNT_CLR_SEL */ 1048575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1049575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1050575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1051575001e4SStefano Babic 0, /* COUNT UP */ 1052575001e4SStefano Babic 0 /* COUNT DOWN */ 1053575001e4SStefano Babic ); 1054575001e4SStefano Babic 1055575001e4SStefano Babic /* DC VSYNC waveform */ 1056575001e4SStefano Babic vsync_cnt = 7; 1057575001e4SStefano Babic ipu_di_sync_config( 1058575001e4SStefano Babic disp, /* display */ 1059575001e4SStefano Babic 7, /* counter */ 1060575001e4SStefano Babic v_total / 2 - 1,/* run count */ 1061575001e4SStefano Babic DI_SYNC_HSYNC, /* run_resolution */ 1062575001e4SStefano Babic 9, /* offset */ 1063575001e4SStefano Babic DI_SYNC_HSYNC, /* offset resolution */ 1064575001e4SStefano Babic 2, /* repeat count */ 1065575001e4SStefano Babic DI_SYNC_VSYNC, /* CNT_CLR_SEL */ 1066575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1067575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1068575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1069575001e4SStefano Babic 0, /* COUNT UP */ 1070575001e4SStefano Babic 0 /* COUNT DOWN */ 1071575001e4SStefano Babic ); 1072575001e4SStefano Babic 1073575001e4SStefano Babic /* active pixel waveform */ 1074575001e4SStefano Babic ipu_di_sync_config( 1075575001e4SStefano Babic disp, /* display */ 1076575001e4SStefano Babic 8, /* counter */ 1077575001e4SStefano Babic 0, /* run count */ 1078575001e4SStefano Babic DI_SYNC_CLK, /* run_resolution */ 1079575001e4SStefano Babic h_start_width, /* offset */ 1080575001e4SStefano Babic DI_SYNC_CLK, /* offset resolution */ 1081575001e4SStefano Babic width, /* repeat count */ 1082575001e4SStefano Babic 5, /* CNT_CLR_SEL */ 1083575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1084575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1085575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1086575001e4SStefano Babic 0, /* COUNT UP */ 1087575001e4SStefano Babic 0 /* COUNT DOWN */ 1088575001e4SStefano Babic ); 1089575001e4SStefano Babic 1090575001e4SStefano Babic ipu_di_sync_config( 1091575001e4SStefano Babic disp, /* display */ 1092575001e4SStefano Babic 9, /* counter */ 1093575001e4SStefano Babic v_total - 1, /* run count */ 1094575001e4SStefano Babic DI_SYNC_INT_HSYNC,/* run_resolution */ 1095575001e4SStefano Babic v_total / 2, /* offset */ 1096575001e4SStefano Babic DI_SYNC_INT_HSYNC,/* offset resolution */ 1097575001e4SStefano Babic 0, /* repeat count */ 1098575001e4SStefano Babic DI_SYNC_HSYNC, /* CNT_CLR_SEL */ 1099575001e4SStefano Babic 0, /* CNT_POLARITY_GEN_EN */ 1100575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */ 1101575001e4SStefano Babic DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */ 1102575001e4SStefano Babic 0, /* COUNT UP */ 1103575001e4SStefano Babic 4 /* COUNT DOWN */ 1104575001e4SStefano Babic ); 1105575001e4SStefano Babic 1106575001e4SStefano Babic /* set gentime select and tag sel */ 1107575001e4SStefano Babic reg = __raw_readl(DI_SW_GEN1(disp, 9)); 1108575001e4SStefano Babic reg &= 0x1FFFFFFF; 1109575001e4SStefano Babic reg |= (3 - 1)<<29 | 0x00008000; 1110575001e4SStefano Babic __raw_writel(reg, DI_SW_GEN1(disp, 9)); 1111575001e4SStefano Babic 1112575001e4SStefano Babic __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp)); 1113575001e4SStefano Babic 1114575001e4SStefano Babic /* set y_sel = 1 */ 1115575001e4SStefano Babic di_gen |= 0x10000000; 1116575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_5; 1117575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_8; 1118575001e4SStefano Babic } else { 1119575001e4SStefano Babic /* Setup internal HSYNC waveform */ 1120575001e4SStefano Babic ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK, 1121575001e4SStefano Babic 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 1122575001e4SStefano Babic 0, DI_SYNC_NONE, 1123575001e4SStefano Babic DI_SYNC_NONE, 0, 0); 1124575001e4SStefano Babic 1125575001e4SStefano Babic /* Setup external (delayed) HSYNC waveform */ 1126575001e4SStefano Babic ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1, 1127575001e4SStefano Babic DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK, 1128575001e4SStefano Babic 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, 1129575001e4SStefano Babic DI_SYNC_CLK, 0, h_sync_width * 2); 1130575001e4SStefano Babic /* Setup VSYNC waveform */ 1131575001e4SStefano Babic vsync_cnt = DI_SYNC_VSYNC; 1132575001e4SStefano Babic ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1, 1133575001e4SStefano Babic DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0, 1134575001e4SStefano Babic DI_SYNC_NONE, 1, DI_SYNC_NONE, 1135575001e4SStefano Babic DI_SYNC_INT_HSYNC, 0, v_sync_width * 2); 1136575001e4SStefano Babic __raw_writel(v_total - 1, DI_SCR_CONF(disp)); 1137575001e4SStefano Babic 1138575001e4SStefano Babic /* Setup active data waveform to sync with DC */ 1139575001e4SStefano Babic ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC, 1140575001e4SStefano Babic v_sync_width + v_start_width, DI_SYNC_HSYNC, 1141575001e4SStefano Babic height, 1142575001e4SStefano Babic DI_SYNC_VSYNC, 0, DI_SYNC_NONE, 1143575001e4SStefano Babic DI_SYNC_NONE, 0, 0); 1144575001e4SStefano Babic ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK, 1145575001e4SStefano Babic h_sync_width + h_start_width, DI_SYNC_CLK, 1146575001e4SStefano Babic width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 1147575001e4SStefano Babic 0); 1148575001e4SStefano Babic 1149575001e4SStefano Babic /* reset all unused counters */ 1150575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 6)); 1151575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 6)); 1152575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 7)); 1153575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 7)); 1154575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 8)); 1155575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 8)); 1156575001e4SStefano Babic __raw_writel(0, DI_SW_GEN0(disp, 9)); 1157575001e4SStefano Babic __raw_writel(0, DI_SW_GEN1(disp, 9)); 1158575001e4SStefano Babic 1159575001e4SStefano Babic reg = __raw_readl(DI_STP_REP(disp, 6)); 1160575001e4SStefano Babic reg &= 0x0000FFFF; 1161575001e4SStefano Babic __raw_writel(reg, DI_STP_REP(disp, 6)); 1162575001e4SStefano Babic __raw_writel(0, DI_STP_REP(disp, 7)); 1163575001e4SStefano Babic __raw_writel(0, DI_STP_REP(disp, 9)); 1164575001e4SStefano Babic 1165575001e4SStefano Babic /* Init template microcode */ 1166575001e4SStefano Babic if (disp) { 1167575001e4SStefano Babic ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5); 1168575001e4SStefano Babic ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5); 1169575001e4SStefano Babic ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5); 1170575001e4SStefano Babic } else { 1171575001e4SStefano Babic ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5); 1172575001e4SStefano Babic ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5); 1173575001e4SStefano Babic ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5); 1174575001e4SStefano Babic } 1175575001e4SStefano Babic 1176575001e4SStefano Babic if (sig.Hsync_pol) 1177575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_2; 1178575001e4SStefano Babic if (sig.Vsync_pol) 1179575001e4SStefano Babic di_gen |= DI_GEN_POLARITY_3; 1180575001e4SStefano Babic 1181575001e4SStefano Babic if (sig.clk_pol) 1182575001e4SStefano Babic di_gen |= DI_GEN_POL_CLK; 1183575001e4SStefano Babic 1184575001e4SStefano Babic } 1185575001e4SStefano Babic 1186575001e4SStefano Babic __raw_writel(di_gen, DI_GENERAL(disp)); 1187575001e4SStefano Babic 1188575001e4SStefano Babic __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 1189575001e4SStefano Babic 0x00000002, DI_SYNC_AS_GEN(disp)); 1190575001e4SStefano Babic 1191575001e4SStefano Babic reg = __raw_readl(DI_POL(disp)); 1192575001e4SStefano Babic reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); 1193575001e4SStefano Babic if (sig.enable_pol) 1194575001e4SStefano Babic reg |= DI_POL_DRDY_POLARITY_15; 1195575001e4SStefano Babic if (sig.data_pol) 1196575001e4SStefano Babic reg |= DI_POL_DRDY_DATA_POLARITY; 1197575001e4SStefano Babic __raw_writel(reg, DI_POL(disp)); 1198575001e4SStefano Babic 1199575001e4SStefano Babic __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp))); 1200575001e4SStefano Babic 1201575001e4SStefano Babic return 0; 1202575001e4SStefano Babic } 1203575001e4SStefano Babic 1204575001e4SStefano Babic /* 1205575001e4SStefano Babic * This function sets the foreground and background plane global alpha blending 1206575001e4SStefano Babic * modes. This function also sets the DP graphic plane according to the 1207575001e4SStefano Babic * parameter of IPUv3 DP channel. 1208575001e4SStefano Babic * 1209575001e4SStefano Babic * @param channel IPUv3 DP channel 1210575001e4SStefano Babic * 1211575001e4SStefano Babic * @param enable Boolean to enable or disable global alpha 1212575001e4SStefano Babic * blending. If disabled, local blending is used. 1213575001e4SStefano Babic * 1214575001e4SStefano Babic * @param alpha Global alpha value. 1215575001e4SStefano Babic * 1216575001e4SStefano Babic * @return Returns 0 on success or negative error code on fail 1217575001e4SStefano Babic */ 1218575001e4SStefano Babic int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable, 1219575001e4SStefano Babic uint8_t alpha) 1220575001e4SStefano Babic { 1221575001e4SStefano Babic uint32_t reg; 1222575001e4SStefano Babic 1223575001e4SStefano Babic unsigned char bg_chan; 1224575001e4SStefano Babic 1225564964bdSMarek Vasut if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || 1226564964bdSMarek Vasut (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || 1227564964bdSMarek Vasut (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) 1228575001e4SStefano Babic return -EINVAL; 1229575001e4SStefano Babic 1230575001e4SStefano Babic if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 || 1231575001e4SStefano Babic channel == MEM_BG_ASYNC1) 1232575001e4SStefano Babic bg_chan = 1; 1233575001e4SStefano Babic else 1234575001e4SStefano Babic bg_chan = 0; 1235575001e4SStefano Babic 1236575001e4SStefano Babic if (!g_ipu_clk_enabled) 1237575001e4SStefano Babic clk_enable(g_ipu_clk); 1238575001e4SStefano Babic 1239575001e4SStefano Babic if (bg_chan) { 1240564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1241564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF()); 1242575001e4SStefano Babic } else { 1243564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1244564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF()); 1245575001e4SStefano Babic } 1246575001e4SStefano Babic 1247575001e4SStefano Babic if (enable) { 1248564964bdSMarek Vasut reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0x00FFFFFFL; 1249575001e4SStefano Babic __raw_writel(reg | ((uint32_t) alpha << 24), 1250564964bdSMarek Vasut DP_GRAPH_WIND_CTRL()); 1251575001e4SStefano Babic 1252564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1253564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF()); 1254575001e4SStefano Babic } else { 1255564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1256564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF()); 1257575001e4SStefano Babic } 1258575001e4SStefano Babic 1259575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 1260575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 1261575001e4SStefano Babic 1262575001e4SStefano Babic if (!g_ipu_clk_enabled) 1263575001e4SStefano Babic clk_disable(g_ipu_clk); 1264575001e4SStefano Babic 1265575001e4SStefano Babic return 0; 1266575001e4SStefano Babic } 1267575001e4SStefano Babic 1268575001e4SStefano Babic /* 1269575001e4SStefano Babic * This function sets the transparent color key for SDC graphic plane. 1270575001e4SStefano Babic * 1271575001e4SStefano Babic * @param channel Input parameter for the logical channel ID. 1272575001e4SStefano Babic * 1273575001e4SStefano Babic * @param enable Boolean to enable or disable color key 1274575001e4SStefano Babic * 1275575001e4SStefano Babic * @param colorKey 24-bit RGB color for transparent color key. 1276575001e4SStefano Babic * 1277575001e4SStefano Babic * @return Returns 0 on success or negative error code on fail 1278575001e4SStefano Babic */ 1279575001e4SStefano Babic int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable, 1280575001e4SStefano Babic uint32_t color_key) 1281575001e4SStefano Babic { 1282564964bdSMarek Vasut uint32_t reg; 1283575001e4SStefano Babic int y, u, v; 1284575001e4SStefano Babic int red, green, blue; 1285575001e4SStefano Babic 1286564964bdSMarek Vasut if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) || 1287564964bdSMarek Vasut (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) || 1288564964bdSMarek Vasut (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1))) 1289575001e4SStefano Babic return -EINVAL; 1290575001e4SStefano Babic 1291575001e4SStefano Babic if (!g_ipu_clk_enabled) 1292575001e4SStefano Babic clk_enable(g_ipu_clk); 1293575001e4SStefano Babic 1294575001e4SStefano Babic color_key_4rgb = 1; 1295575001e4SStefano Babic /* Transform color key from rgb to yuv if CSC is enabled */ 1296575001e4SStefano Babic if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) || 1297575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) || 1298575001e4SStefano Babic ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) || 1299575001e4SStefano Babic ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) { 1300575001e4SStefano Babic 1301575001e4SStefano Babic debug("color key 0x%x need change to yuv fmt\n", color_key); 1302575001e4SStefano Babic 1303575001e4SStefano Babic red = (color_key >> 16) & 0xFF; 1304575001e4SStefano Babic green = (color_key >> 8) & 0xFF; 1305575001e4SStefano Babic blue = color_key & 0xFF; 1306575001e4SStefano Babic 1307575001e4SStefano Babic y = rgb_to_yuv(0, red, green, blue); 1308575001e4SStefano Babic u = rgb_to_yuv(1, red, green, blue); 1309575001e4SStefano Babic v = rgb_to_yuv(2, red, green, blue); 1310575001e4SStefano Babic color_key = (y << 16) | (u << 8) | v; 1311575001e4SStefano Babic 1312575001e4SStefano Babic color_key_4rgb = 0; 1313575001e4SStefano Babic 1314575001e4SStefano Babic debug("color key change to yuv fmt 0x%x\n", color_key); 1315575001e4SStefano Babic } 1316575001e4SStefano Babic 1317575001e4SStefano Babic if (enable) { 1318564964bdSMarek Vasut reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L; 1319564964bdSMarek Vasut __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL()); 1320575001e4SStefano Babic 1321564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1322564964bdSMarek Vasut __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF()); 1323575001e4SStefano Babic } else { 1324564964bdSMarek Vasut reg = __raw_readl(DP_COM_CONF()); 1325564964bdSMarek Vasut __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF()); 1326575001e4SStefano Babic } 1327575001e4SStefano Babic 1328575001e4SStefano Babic reg = __raw_readl(IPU_SRM_PRI2) | 0x8; 1329575001e4SStefano Babic __raw_writel(reg, IPU_SRM_PRI2); 1330575001e4SStefano Babic 1331575001e4SStefano Babic if (!g_ipu_clk_enabled) 1332575001e4SStefano Babic clk_disable(g_ipu_clk); 1333575001e4SStefano Babic 1334575001e4SStefano Babic return 0; 1335575001e4SStefano Babic } 1336