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