Home | History | Annotate | Download | only in video
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (c) 2015 Google, Inc
      4  * Copyright 2014 Rockchip Inc.
      5  * Copyright 2017 Jernej Skrabec <jernej.skrabec (at) siol.net>
      6  */
      7 
      8 #include <common.h>
      9 #include <fdtdec.h>
     10 #include <asm/io.h>
     11 #include "dw_hdmi.h"
     12 
     13 struct tmds_n_cts {
     14 	u32 tmds;
     15 	u32 cts;
     16 	u32 n;
     17 };
     18 
     19 static const struct tmds_n_cts n_cts_table[] = {
     20 	{
     21 		.tmds = 25175000, .n = 6144, .cts = 25175,
     22 	}, {
     23 		.tmds = 25200000, .n = 6144, .cts = 25200,
     24 	}, {
     25 		.tmds = 27000000, .n = 6144, .cts = 27000,
     26 	}, {
     27 		.tmds = 27027000, .n = 6144, .cts = 27027,
     28 	}, {
     29 		.tmds = 40000000, .n = 6144, .cts = 40000,
     30 	}, {
     31 		.tmds = 54000000, .n = 6144, .cts = 54000,
     32 	}, {
     33 		.tmds = 54054000, .n = 6144, .cts = 54054,
     34 	}, {
     35 		.tmds = 65000000, .n = 6144, .cts = 65000,
     36 	}, {
     37 		.tmds = 74176000, .n = 11648, .cts = 140625,
     38 	}, {
     39 		.tmds = 74250000, .n = 6144, .cts = 74250,
     40 	}, {
     41 		.tmds = 83500000, .n = 6144, .cts = 83500,
     42 	}, {
     43 		.tmds = 106500000, .n = 6144, .cts = 106500,
     44 	}, {
     45 		.tmds = 108000000, .n = 6144, .cts = 108000,
     46 	}, {
     47 		.tmds = 148352000, .n = 5824, .cts = 140625,
     48 	}, {
     49 		.tmds = 148500000, .n = 6144, .cts = 148500,
     50 	}, {
     51 		.tmds = 297000000, .n = 5120, .cts = 247500,
     52 	}
     53 };
     54 
     55 static void hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
     56 {
     57 	switch (hdmi->reg_io_width) {
     58 	case 1:
     59 		writeb(val, hdmi->ioaddr + offset);
     60 		break;
     61 	case 4:
     62 		writel(val, hdmi->ioaddr + (offset << 2));
     63 		break;
     64 	default:
     65 		debug("reg_io_width has unsupported width!\n");
     66 		break;
     67 	}
     68 }
     69 
     70 static u8 hdmi_read(struct dw_hdmi *hdmi, int offset)
     71 {
     72 	switch (hdmi->reg_io_width) {
     73 	case 1:
     74 		return readb(hdmi->ioaddr + offset);
     75 	case 4:
     76 		return readl(hdmi->ioaddr + (offset << 2));
     77 	default:
     78 		debug("reg_io_width has unsupported width!\n");
     79 		break;
     80 	}
     81 
     82 	return 0;
     83 }
     84 
     85 static void hdmi_mod(struct dw_hdmi *hdmi, unsigned reg, u8 mask, u8 data)
     86 {
     87 	u8 val = hdmi_read(hdmi, reg) & ~mask;
     88 
     89 	val |= data & mask;
     90 	hdmi_write(hdmi, val, reg);
     91 }
     92 
     93 static void hdmi_set_clock_regenerator(struct dw_hdmi *hdmi, u32 n, u32 cts)
     94 {
     95 	uint cts3;
     96 	uint n3;
     97 
     98 	/* first set ncts_atomic_write (if present) */
     99 	n3 = HDMI_AUD_N3_NCTS_ATOMIC_WRITE;
    100 	hdmi_write(hdmi, n3, HDMI_AUD_N3);
    101 
    102 	/* set cts_manual (if present) */
    103 	cts3 = HDMI_AUD_CTS3_CTS_MANUAL;
    104 
    105 	cts3 |= HDMI_AUD_CTS3_N_SHIFT_1 << HDMI_AUD_CTS3_N_SHIFT_OFFSET;
    106 	cts3 |= (cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK;
    107 
    108 	/* write cts values; cts3 must be written first */
    109 	hdmi_write(hdmi, cts3, HDMI_AUD_CTS3);
    110 	hdmi_write(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
    111 	hdmi_write(hdmi, cts & 0xff, HDMI_AUD_CTS1);
    112 
    113 	/* write n values; n1 must be written last */
    114 	n3 |= (n >> 16) & HDMI_AUD_N3_AUDN19_16_MASK;
    115 	hdmi_write(hdmi, n3, HDMI_AUD_N3);
    116 	hdmi_write(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
    117 	hdmi_write(hdmi, n & 0xff, HDMI_AUD_N3);
    118 
    119 	hdmi_write(hdmi, HDMI_AUD_INPUTCLKFS_128, HDMI_AUD_INPUTCLKFS);
    120 }
    121 
    122 static int hdmi_lookup_n_cts(u32 pixel_clk)
    123 {
    124 	int i;
    125 
    126 	for (i = 0; i < ARRAY_SIZE(n_cts_table); i++)
    127 		if (pixel_clk <= n_cts_table[i].tmds)
    128 			break;
    129 
    130 	if (i >= ARRAY_SIZE(n_cts_table))
    131 		return -1;
    132 
    133 	return i;
    134 }
    135 
    136 static void hdmi_audio_set_samplerate(struct dw_hdmi *hdmi, u32 pixel_clk)
    137 {
    138 	u32 clk_n, clk_cts;
    139 	int index;
    140 
    141 	index = hdmi_lookup_n_cts(pixel_clk);
    142 	if (index == -1) {
    143 		debug("audio not supported for pixel clk %d\n", pixel_clk);
    144 		return;
    145 	}
    146 
    147 	clk_n = n_cts_table[index].n;
    148 	clk_cts = n_cts_table[index].cts;
    149 	hdmi_set_clock_regenerator(hdmi, clk_n, clk_cts);
    150 }
    151 
    152 /*
    153  * this submodule is responsible for the video data synchronization.
    154  * for example, for rgb 4:4:4 input, the data map is defined as
    155  *			pin{47~40} <==> r[7:0]
    156  *			pin{31~24} <==> g[7:0]
    157  *			pin{15~8}  <==> b[7:0]
    158  */
    159 static void hdmi_video_sample(struct dw_hdmi *hdmi)
    160 {
    161 	u32 color_format = 0x01;
    162 	uint val;
    163 
    164 	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
    165 	      ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
    166 	      HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
    167 
    168 	hdmi_write(hdmi, val, HDMI_TX_INVID0);
    169 
    170 	/* enable tx stuffing: when de is inactive, fix the output data to 0 */
    171 	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
    172 	      HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
    173 	      HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
    174 	hdmi_write(hdmi, val, HDMI_TX_INSTUFFING);
    175 	hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA0);
    176 	hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA1);
    177 	hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA0);
    178 	hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA1);
    179 	hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA0);
    180 	hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA1);
    181 }
    182 
    183 static void hdmi_video_packetize(struct dw_hdmi *hdmi)
    184 {
    185 	u32 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
    186 	u32 remap_size = HDMI_VP_REMAP_YCC422_16BIT;
    187 	u32 color_depth = 0;
    188 	uint val, vp_conf;
    189 
    190 	/* set the packetizer registers */
    191 	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
    192 		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
    193 		((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
    194 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
    195 	hdmi_write(hdmi, val, HDMI_VP_PR_CD);
    196 
    197 	hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PR_STUFFING_MASK,
    198 		 HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE);
    199 
    200 	/* data from pixel repeater block */
    201 	vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
    202 		  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
    203 
    204 	hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_PR_EN_MASK |
    205 		 HDMI_VP_CONF_BYPASS_SELECT_MASK, vp_conf);
    206 
    207 	hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
    208 		 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET);
    209 
    210 	hdmi_write(hdmi, remap_size, HDMI_VP_REMAP);
    211 
    212 	vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
    213 		  HDMI_VP_CONF_PP_EN_DISABLE |
    214 		  HDMI_VP_CONF_YCC422_EN_DISABLE;
    215 
    216 	hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_BYPASS_EN_MASK |
    217 		 HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK,
    218 		 vp_conf);
    219 
    220 	hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PP_STUFFING_MASK |
    221 		 HDMI_VP_STUFF_YCC422_STUFFING_MASK,
    222 		 HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
    223 		 HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE);
    224 
    225 	hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
    226 		 output_select);
    227 }
    228 
    229 static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, uint bit)
    230 {
    231 	hdmi_mod(hdmi, HDMI_PHY_TST0, HDMI_PHY_TST0_TSTCLR_MASK,
    232 		 bit << HDMI_PHY_TST0_TSTCLR_OFFSET);
    233 }
    234 
    235 static int hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, u32 msec)
    236 {
    237 	ulong start;
    238 	u32 val;
    239 
    240 	start = get_timer(0);
    241 	do {
    242 		val = hdmi_read(hdmi, HDMI_IH_I2CMPHY_STAT0);
    243 		if (val & 0x3) {
    244 			hdmi_write(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
    245 			return 0;
    246 		}
    247 
    248 		udelay(100);
    249 	} while (get_timer(start) < msec);
    250 
    251 	return 1;
    252 }
    253 
    254 static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, uint data, uint addr)
    255 {
    256 	hdmi_write(hdmi, 0xff, HDMI_IH_I2CMPHY_STAT0);
    257 	hdmi_write(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
    258 	hdmi_write(hdmi, (u8)(data >> 8), HDMI_PHY_I2CM_DATAO_1_ADDR);
    259 	hdmi_write(hdmi, (u8)(data >> 0), HDMI_PHY_I2CM_DATAO_0_ADDR);
    260 	hdmi_write(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
    261 		   HDMI_PHY_I2CM_OPERATION_ADDR);
    262 
    263 	hdmi_phy_wait_i2c_done(hdmi, 1000);
    264 }
    265 
    266 static void hdmi_phy_enable_power(struct dw_hdmi *hdmi, uint enable)
    267 {
    268 	hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_PDZ_MASK,
    269 		 enable << HDMI_PHY_CONF0_PDZ_OFFSET);
    270 }
    271 
    272 static void hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, uint enable)
    273 {
    274 	hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_ENTMDS_MASK,
    275 		 enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
    276 }
    277 
    278 static void hdmi_phy_enable_spare(struct dw_hdmi *hdmi, uint enable)
    279 {
    280 	hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SPARECTRL_MASK,
    281 		 enable << HDMI_PHY_CONF0_SPARECTRL_OFFSET);
    282 }
    283 
    284 static void hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, uint enable)
    285 {
    286 	hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK,
    287 		 enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
    288 }
    289 
    290 static void hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, uint enable)
    291 {
    292 	hdmi_mod(hdmi, HDMI_PHY_CONF0,
    293 		 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK,
    294 		 enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
    295 }
    296 
    297 static void hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, uint enable)
    298 {
    299 	hdmi_mod(hdmi, HDMI_PHY_CONF0,
    300 		 HDMI_PHY_CONF0_SELDATAENPOL_MASK,
    301 		 enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
    302 }
    303 
    304 static void hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi,
    305 					   uint enable)
    306 {
    307 	hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SELDIPIF_MASK,
    308 		 enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
    309 }
    310 
    311 static int hdmi_phy_configure(struct dw_hdmi *hdmi, u32 mpixelclock)
    312 {
    313 	ulong start;
    314 	uint i, val;
    315 
    316 	if (!hdmi->mpll_cfg || !hdmi->phy_cfg)
    317 		return -1;
    318 
    319 	/* gen2 tx power off */
    320 	hdmi_phy_gen2_txpwron(hdmi, 0);
    321 
    322 	/* gen2 pddq */
    323 	hdmi_phy_gen2_pddq(hdmi, 1);
    324 
    325 	/* phy reset */
    326 	hdmi_write(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
    327 	hdmi_write(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
    328 	hdmi_write(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
    329 
    330 	hdmi_phy_test_clear(hdmi, 1);
    331 	hdmi_write(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
    332 		   HDMI_PHY_I2CM_SLAVE_ADDR);
    333 	hdmi_phy_test_clear(hdmi, 0);
    334 
    335 	/* pll/mpll cfg - always match on final entry */
    336 	for (i = 0; hdmi->mpll_cfg[i].mpixelclock != (~0ul); i++)
    337 		if (mpixelclock <= hdmi->mpll_cfg[i].mpixelclock)
    338 			break;
    339 
    340 	hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].cpce, PHY_OPMODE_PLLCFG);
    341 	hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].gmp, PHY_PLLGMPCTRL);
    342 	hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].curr, PHY_PLLCURRCTRL);
    343 
    344 	hdmi_phy_i2c_write(hdmi, 0x0000, PHY_PLLPHBYCTRL);
    345 	hdmi_phy_i2c_write(hdmi, 0x0006, PHY_PLLCLKBISTPHASE);
    346 
    347 	for (i = 0; hdmi->phy_cfg[i].mpixelclock != (~0ul); i++)
    348 		if (mpixelclock <= hdmi->phy_cfg[i].mpixelclock)
    349 			break;
    350 
    351 	/*
    352 	 * resistance term 133ohm cfg
    353 	 * preemp cgf 0.00
    354 	 * tx/ck lvl 10
    355 	 */
    356 	hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].term, PHY_TXTERM);
    357 	hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].sym_ctr, PHY_CKSYMTXCTRL);
    358 	hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].vlev_ctr, PHY_VLEVCTRL);
    359 
    360 	/* remove clk term */
    361 	hdmi_phy_i2c_write(hdmi, 0x8000, PHY_CKCALCTRL);
    362 
    363 	hdmi_phy_enable_power(hdmi, 1);
    364 
    365 	/* toggle tmds enable */
    366 	hdmi_phy_enable_tmds(hdmi, 0);
    367 	hdmi_phy_enable_tmds(hdmi, 1);
    368 
    369 	/* gen2 tx power on */
    370 	hdmi_phy_gen2_txpwron(hdmi, 1);
    371 	hdmi_phy_gen2_pddq(hdmi, 0);
    372 
    373 	hdmi_phy_enable_spare(hdmi, 1);
    374 
    375 	/* wait for phy pll lock */
    376 	start = get_timer(0);
    377 	do {
    378 		val = hdmi_read(hdmi, HDMI_PHY_STAT0);
    379 		if (!(val & HDMI_PHY_TX_PHY_LOCK))
    380 			return 0;
    381 
    382 		udelay(100);
    383 	} while (get_timer(start) < 5);
    384 
    385 	return -1;
    386 }
    387 
    388 static void hdmi_av_composer(struct dw_hdmi *hdmi,
    389 			     const struct display_timing *edid)
    390 {
    391 	bool mdataenablepolarity = true;
    392 	uint inv_val;
    393 	uint hbl;
    394 	uint vbl;
    395 
    396 	hbl = edid->hback_porch.typ + edid->hfront_porch.typ +
    397 			edid->hsync_len.typ;
    398 	vbl = edid->vback_porch.typ + edid->vfront_porch.typ +
    399 			edid->vsync_len.typ;
    400 
    401 	/* set up hdmi_fc_invidconf */
    402 	inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE;
    403 
    404 	inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
    405 		   HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
    406 		   HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
    407 
    408 	inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
    409 		   HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
    410 		   HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
    411 
    412 	inv_val |= (mdataenablepolarity ?
    413 		   HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
    414 		   HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
    415 
    416 	inv_val |= (edid->hdmi_monitor ?
    417 		   HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
    418 		   HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
    419 
    420 	inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW;
    421 
    422 	inv_val |= HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
    423 
    424 	hdmi_write(hdmi, inv_val, HDMI_FC_INVIDCONF);
    425 
    426 	/* set up horizontal active pixel width */
    427 	hdmi_write(hdmi, edid->hactive.typ >> 8, HDMI_FC_INHACTV1);
    428 	hdmi_write(hdmi, edid->hactive.typ, HDMI_FC_INHACTV0);
    429 
    430 	/* set up vertical active lines */
    431 	hdmi_write(hdmi, edid->vactive.typ >> 8, HDMI_FC_INVACTV1);
    432 	hdmi_write(hdmi, edid->vactive.typ, HDMI_FC_INVACTV0);
    433 
    434 	/* set up horizontal blanking pixel region width */
    435 	hdmi_write(hdmi, hbl >> 8, HDMI_FC_INHBLANK1);
    436 	hdmi_write(hdmi, hbl, HDMI_FC_INHBLANK0);
    437 
    438 	/* set up vertical blanking pixel region width */
    439 	hdmi_write(hdmi, vbl, HDMI_FC_INVBLANK);
    440 
    441 	/* set up hsync active edge delay width (in pixel clks) */
    442 	hdmi_write(hdmi, edid->hfront_porch.typ >> 8, HDMI_FC_HSYNCINDELAY1);
    443 	hdmi_write(hdmi, edid->hfront_porch.typ, HDMI_FC_HSYNCINDELAY0);
    444 
    445 	/* set up vsync active edge delay (in lines) */
    446 	hdmi_write(hdmi, edid->vfront_porch.typ, HDMI_FC_VSYNCINDELAY);
    447 
    448 	/* set up hsync active pulse width (in pixel clks) */
    449 	hdmi_write(hdmi, edid->hsync_len.typ >> 8, HDMI_FC_HSYNCINWIDTH1);
    450 	hdmi_write(hdmi, edid->hsync_len.typ, HDMI_FC_HSYNCINWIDTH0);
    451 
    452 	/* set up vsync active edge delay (in lines) */
    453 	hdmi_write(hdmi, edid->vsync_len.typ, HDMI_FC_VSYNCINWIDTH);
    454 }
    455 
    456 /* hdmi initialization step b.4 */
    457 static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
    458 {
    459 	uint clkdis;
    460 
    461 	/* control period minimum duration */
    462 	hdmi_write(hdmi, 12, HDMI_FC_CTRLDUR);
    463 	hdmi_write(hdmi, 32, HDMI_FC_EXCTRLDUR);
    464 	hdmi_write(hdmi, 1, HDMI_FC_EXCTRLSPAC);
    465 
    466 	/* set to fill tmds data channels */
    467 	hdmi_write(hdmi, 0x0b, HDMI_FC_CH0PREAM);
    468 	hdmi_write(hdmi, 0x16, HDMI_FC_CH1PREAM);
    469 	hdmi_write(hdmi, 0x21, HDMI_FC_CH2PREAM);
    470 
    471 	hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
    472 		   HDMI_MC_FLOWCTRL);
    473 
    474 	/* enable pixel clock and tmds data path */
    475 	clkdis = 0x7f;
    476 	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
    477 	hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
    478 
    479 	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
    480 	hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
    481 
    482 	if (audio) {
    483 		clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
    484 		hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
    485 	}
    486 }
    487 
    488 /* workaround to clear the overflow condition */
    489 static void hdmi_clear_overflow(struct dw_hdmi *hdmi)
    490 {
    491 	uint val, count;
    492 
    493 	/* tmds software reset */
    494 	hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
    495 
    496 	val = hdmi_read(hdmi, HDMI_FC_INVIDCONF);
    497 
    498 	for (count = 0; count < 4; count++)
    499 		hdmi_write(hdmi, val, HDMI_FC_INVIDCONF);
    500 }
    501 
    502 static void hdmi_audio_set_format(struct dw_hdmi *hdmi)
    503 {
    504 	hdmi_write(hdmi, HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_IN_EN_0,
    505 		   HDMI_AUD_CONF0);
    506 
    507 
    508 	hdmi_write(hdmi, HDMI_AUD_CONF1_I2S_MODE_STANDARD_MODE |
    509 		   HDMI_AUD_CONF1_I2S_WIDTH_16BIT, HDMI_AUD_CONF1);
    510 
    511 	hdmi_write(hdmi, 0x00, HDMI_AUD_CONF2);
    512 }
    513 
    514 static void hdmi_audio_fifo_reset(struct dw_hdmi *hdmi)
    515 {
    516 	hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_II2SSWRST_REQ, HDMI_MC_SWRSTZ);
    517 	hdmi_write(hdmi, HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST, HDMI_AUD_CONF0);
    518 
    519 	hdmi_write(hdmi, 0x00, HDMI_AUD_INT);
    520 	hdmi_write(hdmi, 0x00, HDMI_AUD_INT1);
    521 }
    522 
    523 static int hdmi_get_plug_in_status(struct dw_hdmi *hdmi)
    524 {
    525 	uint val = hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD;
    526 
    527 	return !!val;
    528 }
    529 
    530 static int hdmi_ddc_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
    531 {
    532 	u32 val;
    533 	ulong start;
    534 
    535 	start = get_timer(0);
    536 	do {
    537 		val = hdmi_read(hdmi, HDMI_IH_I2CM_STAT0);
    538 		if (val & 0x2) {
    539 			hdmi_write(hdmi, val, HDMI_IH_I2CM_STAT0);
    540 			return 0;
    541 		}
    542 
    543 		udelay(100);
    544 	} while (get_timer(start) < msec);
    545 
    546 	return 1;
    547 }
    548 
    549 static void hdmi_ddc_reset(struct dw_hdmi *hdmi)
    550 {
    551 	hdmi_mod(hdmi, HDMI_I2CM_SOFTRSTZ, HDMI_I2CM_SOFTRSTZ_MASK, 0);
    552 }
    553 
    554 static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff)
    555 {
    556 	int shift = (block % 2) * 0x80;
    557 	int edid_read_err = 0;
    558 	u32 trytime = 5;
    559 	u32 n;
    560 
    561 	/* set ddc i2c clk which devided from ddc_clk to 100khz */
    562 	hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
    563 	hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
    564 	hdmi_mod(hdmi, HDMI_I2CM_DIV, HDMI_I2CM_DIV_FAST_STD_MODE,
    565 		 HDMI_I2CM_DIV_STD_MODE);
    566 
    567 	hdmi_write(hdmi, HDMI_I2CM_SLAVE_DDC_ADDR, HDMI_I2CM_SLAVE);
    568 	hdmi_write(hdmi, HDMI_I2CM_SEGADDR_DDC, HDMI_I2CM_SEGADDR);
    569 	hdmi_write(hdmi, block >> 1, HDMI_I2CM_SEGPTR);
    570 
    571 	while (trytime--) {
    572 		edid_read_err = 0;
    573 
    574 		for (n = 0; n < HDMI_EDID_BLOCK_SIZE; n++) {
    575 			hdmi_write(hdmi, shift + n, HDMI_I2CM_ADDRESS);
    576 
    577 			if (block == 0)
    578 				hdmi_write(hdmi, HDMI_I2CM_OP_RD8,
    579 					   HDMI_I2CM_OPERATION);
    580 			else
    581 				hdmi_write(hdmi, HDMI_I2CM_OP_RD8_EXT,
    582 					   HDMI_I2CM_OPERATION);
    583 
    584 			if (hdmi_ddc_wait_i2c_done(hdmi, 10)) {
    585 				hdmi_ddc_reset(hdmi);
    586 				edid_read_err = 1;
    587 				break;
    588 			}
    589 
    590 			buff[n] = hdmi_read(hdmi, HDMI_I2CM_DATAI);
    591 		}
    592 
    593 		if (!edid_read_err)
    594 			break;
    595 	}
    596 
    597 	return edid_read_err;
    598 }
    599 
    600 static const u8 pre_buf[] = {
    601 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
    602 	0x04, 0x69, 0xfa, 0x23, 0xc8, 0x28, 0x01, 0x00,
    603 	0x10, 0x17, 0x01, 0x03, 0x80, 0x33, 0x1d, 0x78,
    604 	0x2a, 0xd9, 0x45, 0xa2, 0x55, 0x4d, 0xa0, 0x27,
    605 	0x12, 0x50, 0x54, 0xb7, 0xef, 0x00, 0x71, 0x4f,
    606 	0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00,
    607 	0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x00, 0x02, 0x3a,
    608 	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
    609 	0x45, 0x00, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
    610 	0x00, 0x00, 0x00, 0xff, 0x00, 0x44, 0x34, 0x4c,
    611 	0x4d, 0x54, 0x46, 0x30, 0x37, 0x35, 0x39, 0x37,
    612 	0x36, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
    613 	0x4b, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20,
    614 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
    615 	0x00, 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x53,
    616 	0x32, 0x33, 0x38, 0x0a, 0x20, 0x20, 0x01, 0xb0,
    617 	0x02, 0x03, 0x22, 0x71, 0x4f, 0x01, 0x02, 0x03,
    618 	0x11, 0x12, 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f,
    619 	0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, 0x17, 0x07,
    620 	0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0c, 0x00,
    621 	0x10, 0x00, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0,
    622 	0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xfd, 0x1e,
    623 	0x11, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72,
    624 	0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
    625 	0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d,
    626 	0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28,
    627 	0x55, 0x40, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
    628 	0x8c, 0x0a, 0xd0, 0x90, 0x20, 0x40, 0x31, 0x20,
    629 	0x0c, 0x40, 0x55, 0x00, 0xfd, 0x1e, 0x11, 0x00,
    630 	0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    631 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    632 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9,
    633 };
    634 
    635 int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
    636 {
    637 	int i, ret;
    638 
    639 	/* hdmi phy spec says to do the phy initialization sequence twice */
    640 	for (i = 0; i < 2; i++) {
    641 		hdmi_phy_sel_data_en_pol(hdmi, 1);
    642 		hdmi_phy_sel_interface_control(hdmi, 0);
    643 		hdmi_phy_enable_tmds(hdmi, 0);
    644 		hdmi_phy_enable_power(hdmi, 0);
    645 
    646 		ret = hdmi_phy_configure(hdmi, mpixelclock);
    647 		if (ret) {
    648 			debug("hdmi phy config failure %d\n", ret);
    649 			return ret;
    650 		}
    651 	}
    652 
    653 	return 0;
    654 }
    655 
    656 int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi)
    657 {
    658 	ulong start;
    659 
    660 	start = get_timer(0);
    661 	do {
    662 		if (hdmi_get_plug_in_status(hdmi))
    663 			return 0;
    664 		udelay(100);
    665 	} while (get_timer(start) < 300);
    666 
    667 	return -1;
    668 }
    669 
    670 void dw_hdmi_phy_init(struct dw_hdmi *hdmi)
    671 {
    672 	/* enable phy i2cm done irq */
    673 	hdmi_write(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
    674 		   HDMI_PHY_I2CM_INT_ADDR);
    675 
    676 	/* enable phy i2cm nack & arbitration error irq */
    677 	hdmi_write(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
    678 		   HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
    679 		   HDMI_PHY_I2CM_CTLINT_ADDR);
    680 
    681 	/* enable cable hot plug irq */
    682 	hdmi_write(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
    683 
    684 	/* clear hotplug interrupts */
    685 	hdmi_write(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
    686 }
    687 
    688 int dw_hdmi_read_edid(struct dw_hdmi *hdmi, u8 *buf, int buf_size)
    689 {
    690 	u32 edid_size = HDMI_EDID_BLOCK_SIZE;
    691 	int ret;
    692 
    693 	if (0) {
    694 		edid_size = sizeof(pre_buf);
    695 		memcpy(buf, pre_buf, edid_size);
    696 	} else {
    697 		ret = hdmi_read_edid(hdmi, 0, buf);
    698 		if (ret) {
    699 			debug("failed to read edid.\n");
    700 			return -1;
    701 		}
    702 
    703 		if (buf[0x7e] != 0) {
    704 			hdmi_read_edid(hdmi, 1, buf + HDMI_EDID_BLOCK_SIZE);
    705 			edid_size += HDMI_EDID_BLOCK_SIZE;
    706 		}
    707 	}
    708 
    709 	return edid_size;
    710 }
    711 
    712 int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
    713 {
    714 	int ret;
    715 
    716 	debug("%s, mode info : clock %d hdis %d vdis %d\n",
    717 	      edid->hdmi_monitor ? "hdmi" : "dvi",
    718 	      edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ);
    719 
    720 	hdmi_av_composer(hdmi, edid);
    721 
    722 	ret = hdmi->phy_set(hdmi, edid->pixelclock.typ);
    723 	if (ret)
    724 		return ret;
    725 
    726 	hdmi_enable_video_path(hdmi, edid->hdmi_monitor);
    727 
    728 	if (edid->hdmi_monitor) {
    729 		hdmi_audio_fifo_reset(hdmi);
    730 		hdmi_audio_set_format(hdmi);
    731 		hdmi_audio_set_samplerate(hdmi, edid->pixelclock.typ);
    732 	}
    733 
    734 	hdmi_video_packetize(hdmi);
    735 	hdmi_video_sample(hdmi);
    736 
    737 	hdmi_clear_overflow(hdmi);
    738 
    739 	return 0;
    740 }
    741 
    742 void dw_hdmi_init(struct dw_hdmi *hdmi)
    743 {
    744 	uint ih_mute;
    745 
    746 	/*
    747 	 * boot up defaults are:
    748 	 * hdmi_ih_mute   = 0x03 (disabled)
    749 	 * hdmi_ih_mute_* = 0x00 (enabled)
    750 	 *
    751 	 * disable top level interrupt bits in hdmi block
    752 	 */
    753 	ih_mute = /*hdmi_read(hdmi, HDMI_IH_MUTE) |*/
    754 		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
    755 		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
    756 
    757 	hdmi_write(hdmi, ih_mute, HDMI_IH_MUTE);
    758 
    759 	/* enable i2c master done irq */
    760 	hdmi_write(hdmi, ~0x04, HDMI_I2CM_INT);
    761 
    762 	/* enable i2c client nack % arbitration error irq */
    763 	hdmi_write(hdmi, ~0x44, HDMI_I2CM_CTLINT);
    764 }
    765