blob: 229bd63c97c8222b3ddbfbbb1985ddca47140a0b [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jernej Skrabeccc232a92017-03-20 23:01:22 +01002/*
3 * Copyright (c) 2015 Google, Inc
4 * Copyright 2014 Rockchip Inc.
5 * Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
Jernej Skrabeccc232a92017-03-20 23:01:22 +01006 */
7
8#include <common.h>
9#include <fdtdec.h>
10#include <asm/io.h>
11#include "dw_hdmi.h"
12
13struct tmds_n_cts {
14 u32 tmds;
15 u32 cts;
16 u32 n;
17};
18
19static 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
55static 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
70static 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
85static 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
93static 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
122static 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
136static 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 */
159static 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
183static 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
229static 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
235static 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
254static 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
266static 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
272static 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
278static 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
284static 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
290static 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
297static 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
304static 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
311static 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
388static 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
Vasily Khoruzhick1005e4e2018-05-14 13:49:53 -0700404 inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100405 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
406 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
407
Vasily Khoruzhick1005e4e2018-05-14 13:49:53 -0700408 inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100409 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
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200416 inv_val |= (edid->hdmi_monitor ?
417 HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
418 HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100419
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 */
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200457static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100458{
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
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200482 if (audio) {
483 clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
484 hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
485 }
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100486}
487
488/* workaround to clear the overflow condition */
489static 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
502static 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
514static 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
523static 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
530static 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
549static void hdmi_ddc_reset(struct dw_hdmi *hdmi)
550{
551 hdmi_mod(hdmi, HDMI_I2CM_SOFTRSTZ, HDMI_I2CM_SOFTRSTZ_MASK, 0);
552}
553
554static 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
600static 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
635int 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
656int 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
670void 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
688int 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
712int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
713{
714 int ret;
715
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200716 debug("%s, mode info : clock %d hdis %d vdis %d\n",
717 edid->hdmi_monitor ? "hdmi" : "dvi",
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100718 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
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200726 hdmi_enable_video_path(hdmi, edid->hdmi_monitor);
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100727
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200728 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 }
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100733
734 hdmi_video_packetize(hdmi);
735 hdmi_video_sample(hdmi);
736
737 hdmi_clear_overflow(hdmi);
738
739 return 0;
740}
741
742void 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}