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