blob: daf0024c6404102f3474b8da7339c42e0da409dd [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>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Jernej Skrabeccc232a92017-03-20 23:01:22 +010011#include <asm/io.h>
Niklas Schulze60a62ac2019-07-27 12:07:13 +000012#include <i2c.h>
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +010013#include <media_bus_format.h>
Jernej Skrabeccc232a92017-03-20 23:01:22 +010014#include "dw_hdmi.h"
15
16struct tmds_n_cts {
17 u32 tmds;
18 u32 cts;
19 u32 n;
20};
21
22static const struct tmds_n_cts n_cts_table[] = {
23 {
24 .tmds = 25175000, .n = 6144, .cts = 25175,
25 }, {
26 .tmds = 25200000, .n = 6144, .cts = 25200,
27 }, {
28 .tmds = 27000000, .n = 6144, .cts = 27000,
29 }, {
30 .tmds = 27027000, .n = 6144, .cts = 27027,
31 }, {
32 .tmds = 40000000, .n = 6144, .cts = 40000,
33 }, {
34 .tmds = 54000000, .n = 6144, .cts = 54000,
35 }, {
36 .tmds = 54054000, .n = 6144, .cts = 54054,
37 }, {
38 .tmds = 65000000, .n = 6144, .cts = 65000,
39 }, {
40 .tmds = 74176000, .n = 11648, .cts = 140625,
41 }, {
42 .tmds = 74250000, .n = 6144, .cts = 74250,
43 }, {
44 .tmds = 83500000, .n = 6144, .cts = 83500,
45 }, {
46 .tmds = 106500000, .n = 6144, .cts = 106500,
47 }, {
48 .tmds = 108000000, .n = 6144, .cts = 108000,
49 }, {
50 .tmds = 148352000, .n = 5824, .cts = 140625,
51 }, {
52 .tmds = 148500000, .n = 6144, .cts = 148500,
53 }, {
54 .tmds = 297000000, .n = 5120, .cts = 247500,
55 }
56};
57
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +010058static const u16 csc_coeff_default[3][4] = {
59 { 0x2000, 0x0000, 0x0000, 0x0000 },
60 { 0x0000, 0x2000, 0x0000, 0x0000 },
61 { 0x0000, 0x0000, 0x2000, 0x0000 }
62};
63
64static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
65 { 0x2591, 0x1322, 0x074b, 0x0000 },
66 { 0x6535, 0x2000, 0x7acc, 0x0200 },
67 { 0x6acd, 0x7534, 0x2000, 0x0200 }
68};
69
70static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
71 { 0x2000, 0x6926, 0x74fd, 0x010e },
72 { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
73 { 0x2000, 0x0000, 0x38b4, 0x7e3b }
74};
75
Jorge Ramirez-Ortizfd998412018-11-08 16:51:01 +010076static void dw_hdmi_write(struct dw_hdmi *hdmi, u8 val, int offset)
Jernej Skrabeccc232a92017-03-20 23:01:22 +010077{
78 switch (hdmi->reg_io_width) {
79 case 1:
80 writeb(val, hdmi->ioaddr + offset);
81 break;
82 case 4:
83 writel(val, hdmi->ioaddr + (offset << 2));
84 break;
85 default:
86 debug("reg_io_width has unsupported width!\n");
87 break;
88 }
89}
90
Jorge Ramirez-Ortizfd998412018-11-08 16:51:01 +010091static u8 dw_hdmi_read(struct dw_hdmi *hdmi, int offset)
Jernej Skrabeccc232a92017-03-20 23:01:22 +010092{
93 switch (hdmi->reg_io_width) {
94 case 1:
95 return readb(hdmi->ioaddr + offset);
96 case 4:
97 return readl(hdmi->ioaddr + (offset << 2));
98 default:
99 debug("reg_io_width has unsupported width!\n");
100 break;
101 }
102
103 return 0;
104}
105
Jorge Ramirez-Ortizfd998412018-11-08 16:51:01 +0100106static u8 (*hdmi_read)(struct dw_hdmi *hdmi, int offset) = dw_hdmi_read;
107static void (*hdmi_write)(struct dw_hdmi *hdmi, u8 val, int offset) =
108 dw_hdmi_write;
109
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100110static void hdmi_mod(struct dw_hdmi *hdmi, unsigned reg, u8 mask, u8 data)
111{
112 u8 val = hdmi_read(hdmi, reg) & ~mask;
113
114 val |= data & mask;
115 hdmi_write(hdmi, val, reg);
116}
117
118static void hdmi_set_clock_regenerator(struct dw_hdmi *hdmi, u32 n, u32 cts)
119{
120 uint cts3;
121 uint n3;
122
123 /* first set ncts_atomic_write (if present) */
124 n3 = HDMI_AUD_N3_NCTS_ATOMIC_WRITE;
125 hdmi_write(hdmi, n3, HDMI_AUD_N3);
126
127 /* set cts_manual (if present) */
128 cts3 = HDMI_AUD_CTS3_CTS_MANUAL;
129
130 cts3 |= HDMI_AUD_CTS3_N_SHIFT_1 << HDMI_AUD_CTS3_N_SHIFT_OFFSET;
131 cts3 |= (cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK;
132
133 /* write cts values; cts3 must be written first */
134 hdmi_write(hdmi, cts3, HDMI_AUD_CTS3);
135 hdmi_write(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
136 hdmi_write(hdmi, cts & 0xff, HDMI_AUD_CTS1);
137
138 /* write n values; n1 must be written last */
139 n3 |= (n >> 16) & HDMI_AUD_N3_AUDN19_16_MASK;
140 hdmi_write(hdmi, n3, HDMI_AUD_N3);
141 hdmi_write(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
142 hdmi_write(hdmi, n & 0xff, HDMI_AUD_N3);
143
144 hdmi_write(hdmi, HDMI_AUD_INPUTCLKFS_128, HDMI_AUD_INPUTCLKFS);
145}
146
147static int hdmi_lookup_n_cts(u32 pixel_clk)
148{
149 int i;
150
151 for (i = 0; i < ARRAY_SIZE(n_cts_table); i++)
152 if (pixel_clk <= n_cts_table[i].tmds)
153 break;
154
155 if (i >= ARRAY_SIZE(n_cts_table))
156 return -1;
157
158 return i;
159}
160
161static void hdmi_audio_set_samplerate(struct dw_hdmi *hdmi, u32 pixel_clk)
162{
163 u32 clk_n, clk_cts;
164 int index;
165
166 index = hdmi_lookup_n_cts(pixel_clk);
167 if (index == -1) {
168 debug("audio not supported for pixel clk %d\n", pixel_clk);
169 return;
170 }
171
172 clk_n = n_cts_table[index].n;
173 clk_cts = n_cts_table[index].cts;
174 hdmi_set_clock_regenerator(hdmi, clk_n, clk_cts);
175}
176
177/*
178 * this submodule is responsible for the video data synchronization.
179 * for example, for rgb 4:4:4 input, the data map is defined as
180 * pin{47~40} <==> r[7:0]
181 * pin{31~24} <==> g[7:0]
182 * pin{15~8} <==> b[7:0]
183 */
184static void hdmi_video_sample(struct dw_hdmi *hdmi)
185{
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +0100186 u32 color_format;
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100187 uint val;
188
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +0100189 switch (hdmi->hdmi_data.enc_in_bus_format) {
190 case MEDIA_BUS_FMT_RGB888_1X24:
191 color_format = 0x01;
192 break;
193 case MEDIA_BUS_FMT_RGB101010_1X30:
194 color_format = 0x03;
195 break;
196 case MEDIA_BUS_FMT_RGB121212_1X36:
197 color_format = 0x05;
198 break;
199 case MEDIA_BUS_FMT_RGB161616_1X48:
200 color_format = 0x07;
201 break;
202 case MEDIA_BUS_FMT_YUV8_1X24:
203 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
204 color_format = 0x09;
205 break;
206 case MEDIA_BUS_FMT_YUV10_1X30:
207 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
208 color_format = 0x0B;
209 break;
210 case MEDIA_BUS_FMT_YUV12_1X36:
211 case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
212 color_format = 0x0D;
213 break;
214 case MEDIA_BUS_FMT_YUV16_1X48:
215 case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
216 color_format = 0x0F;
217 break;
218 case MEDIA_BUS_FMT_UYVY8_1X16:
219 color_format = 0x16;
220 break;
221 case MEDIA_BUS_FMT_UYVY10_1X20:
222 color_format = 0x14;
223 break;
224 case MEDIA_BUS_FMT_UYVY12_1X24:
225 color_format = 0x12;
226 break;
227 default:
228 color_format = 0x01;
229 break;
230 }
231
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100232 val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
233 ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
234 HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
235
236 hdmi_write(hdmi, val, HDMI_TX_INVID0);
237
238 /* enable tx stuffing: when de is inactive, fix the output data to 0 */
239 val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
240 HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
241 HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
242 hdmi_write(hdmi, val, HDMI_TX_INSTUFFING);
243 hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA0);
244 hdmi_write(hdmi, 0x0, HDMI_TX_GYDATA1);
245 hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA0);
246 hdmi_write(hdmi, 0x0, HDMI_TX_RCRDATA1);
247 hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA0);
248 hdmi_write(hdmi, 0x0, HDMI_TX_BCBDATA1);
249}
250
251static void hdmi_video_packetize(struct dw_hdmi *hdmi)
252{
253 u32 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
254 u32 remap_size = HDMI_VP_REMAP_YCC422_16BIT;
255 u32 color_depth = 0;
256 uint val, vp_conf;
257
258 /* set the packetizer registers */
259 val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
260 HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
261 ((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
262 HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
263 hdmi_write(hdmi, val, HDMI_VP_PR_CD);
264
265 hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PR_STUFFING_MASK,
266 HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE);
267
268 /* data from pixel repeater block */
269 vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
270 HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
271
272 hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_PR_EN_MASK |
273 HDMI_VP_CONF_BYPASS_SELECT_MASK, vp_conf);
274
275 hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
276 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET);
277
278 hdmi_write(hdmi, remap_size, HDMI_VP_REMAP);
279
280 vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
281 HDMI_VP_CONF_PP_EN_DISABLE |
282 HDMI_VP_CONF_YCC422_EN_DISABLE;
283
284 hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_BYPASS_EN_MASK |
285 HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK,
286 vp_conf);
287
288 hdmi_mod(hdmi, HDMI_VP_STUFF, HDMI_VP_STUFF_PP_STUFFING_MASK |
289 HDMI_VP_STUFF_YCC422_STUFFING_MASK,
290 HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
291 HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE);
292
293 hdmi_mod(hdmi, HDMI_VP_CONF, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
294 output_select);
295}
296
297static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi, uint bit)
298{
299 hdmi_mod(hdmi, HDMI_PHY_TST0, HDMI_PHY_TST0_TSTCLR_MASK,
300 bit << HDMI_PHY_TST0_TSTCLR_OFFSET);
301}
302
303static int hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, u32 msec)
304{
305 ulong start;
306 u32 val;
307
308 start = get_timer(0);
309 do {
310 val = hdmi_read(hdmi, HDMI_IH_I2CMPHY_STAT0);
311 if (val & 0x3) {
312 hdmi_write(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
313 return 0;
314 }
315
316 udelay(100);
317 } while (get_timer(start) < msec);
318
319 return 1;
320}
321
322static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, uint data, uint addr)
323{
324 hdmi_write(hdmi, 0xff, HDMI_IH_I2CMPHY_STAT0);
325 hdmi_write(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
326 hdmi_write(hdmi, (u8)(data >> 8), HDMI_PHY_I2CM_DATAO_1_ADDR);
327 hdmi_write(hdmi, (u8)(data >> 0), HDMI_PHY_I2CM_DATAO_0_ADDR);
328 hdmi_write(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
329 HDMI_PHY_I2CM_OPERATION_ADDR);
330
331 hdmi_phy_wait_i2c_done(hdmi, 1000);
332}
333
334static void hdmi_phy_enable_power(struct dw_hdmi *hdmi, uint enable)
335{
336 hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_PDZ_MASK,
337 enable << HDMI_PHY_CONF0_PDZ_OFFSET);
338}
339
340static void hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, uint enable)
341{
342 hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_ENTMDS_MASK,
343 enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
344}
345
346static void hdmi_phy_enable_spare(struct dw_hdmi *hdmi, uint enable)
347{
348 hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SPARECTRL_MASK,
349 enable << HDMI_PHY_CONF0_SPARECTRL_OFFSET);
350}
351
352static void hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, uint enable)
353{
354 hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK,
355 enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
356}
357
358static void hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, uint enable)
359{
360 hdmi_mod(hdmi, HDMI_PHY_CONF0,
361 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK,
362 enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
363}
364
365static void hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, uint enable)
366{
367 hdmi_mod(hdmi, HDMI_PHY_CONF0,
368 HDMI_PHY_CONF0_SELDATAENPOL_MASK,
369 enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
370}
371
372static void hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi,
373 uint enable)
374{
375 hdmi_mod(hdmi, HDMI_PHY_CONF0, HDMI_PHY_CONF0_SELDIPIF_MASK,
376 enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
377}
378
379static int hdmi_phy_configure(struct dw_hdmi *hdmi, u32 mpixelclock)
380{
381 ulong start;
382 uint i, val;
383
384 if (!hdmi->mpll_cfg || !hdmi->phy_cfg)
385 return -1;
386
387 /* gen2 tx power off */
388 hdmi_phy_gen2_txpwron(hdmi, 0);
389
390 /* gen2 pddq */
391 hdmi_phy_gen2_pddq(hdmi, 1);
392
393 /* phy reset */
394 hdmi_write(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
395 hdmi_write(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
396 hdmi_write(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
397
398 hdmi_phy_test_clear(hdmi, 1);
399 hdmi_write(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
400 HDMI_PHY_I2CM_SLAVE_ADDR);
401 hdmi_phy_test_clear(hdmi, 0);
402
403 /* pll/mpll cfg - always match on final entry */
404 for (i = 0; hdmi->mpll_cfg[i].mpixelclock != (~0ul); i++)
405 if (mpixelclock <= hdmi->mpll_cfg[i].mpixelclock)
406 break;
407
408 hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].cpce, PHY_OPMODE_PLLCFG);
409 hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].gmp, PHY_PLLGMPCTRL);
410 hdmi_phy_i2c_write(hdmi, hdmi->mpll_cfg[i].curr, PHY_PLLCURRCTRL);
411
412 hdmi_phy_i2c_write(hdmi, 0x0000, PHY_PLLPHBYCTRL);
413 hdmi_phy_i2c_write(hdmi, 0x0006, PHY_PLLCLKBISTPHASE);
414
415 for (i = 0; hdmi->phy_cfg[i].mpixelclock != (~0ul); i++)
416 if (mpixelclock <= hdmi->phy_cfg[i].mpixelclock)
417 break;
418
419 /*
420 * resistance term 133ohm cfg
421 * preemp cgf 0.00
422 * tx/ck lvl 10
423 */
424 hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].term, PHY_TXTERM);
425 hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].sym_ctr, PHY_CKSYMTXCTRL);
426 hdmi_phy_i2c_write(hdmi, hdmi->phy_cfg[i].vlev_ctr, PHY_VLEVCTRL);
427
428 /* remove clk term */
429 hdmi_phy_i2c_write(hdmi, 0x8000, PHY_CKCALCTRL);
430
431 hdmi_phy_enable_power(hdmi, 1);
432
433 /* toggle tmds enable */
434 hdmi_phy_enable_tmds(hdmi, 0);
435 hdmi_phy_enable_tmds(hdmi, 1);
436
437 /* gen2 tx power on */
438 hdmi_phy_gen2_txpwron(hdmi, 1);
439 hdmi_phy_gen2_pddq(hdmi, 0);
440
441 hdmi_phy_enable_spare(hdmi, 1);
442
443 /* wait for phy pll lock */
444 start = get_timer(0);
445 do {
446 val = hdmi_read(hdmi, HDMI_PHY_STAT0);
447 if (!(val & HDMI_PHY_TX_PHY_LOCK))
448 return 0;
449
450 udelay(100);
451 } while (get_timer(start) < 5);
452
453 return -1;
454}
455
456static void hdmi_av_composer(struct dw_hdmi *hdmi,
457 const struct display_timing *edid)
458{
459 bool mdataenablepolarity = true;
460 uint inv_val;
461 uint hbl;
462 uint vbl;
463
464 hbl = edid->hback_porch.typ + edid->hfront_porch.typ +
465 edid->hsync_len.typ;
466 vbl = edid->vback_porch.typ + edid->vfront_porch.typ +
467 edid->vsync_len.typ;
468
469 /* set up hdmi_fc_invidconf */
470 inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE;
471
Vasily Khoruzhick1005e4e2018-05-14 13:49:53 -0700472 inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100473 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
474 HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
475
Vasily Khoruzhick1005e4e2018-05-14 13:49:53 -0700476 inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100477 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
478 HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
479
480 inv_val |= (mdataenablepolarity ?
481 HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
482 HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
483
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200484 inv_val |= (edid->hdmi_monitor ?
485 HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
486 HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100487
488 inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW;
489
490 inv_val |= HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
491
492 hdmi_write(hdmi, inv_val, HDMI_FC_INVIDCONF);
493
494 /* set up horizontal active pixel width */
495 hdmi_write(hdmi, edid->hactive.typ >> 8, HDMI_FC_INHACTV1);
496 hdmi_write(hdmi, edid->hactive.typ, HDMI_FC_INHACTV0);
497
498 /* set up vertical active lines */
499 hdmi_write(hdmi, edid->vactive.typ >> 8, HDMI_FC_INVACTV1);
500 hdmi_write(hdmi, edid->vactive.typ, HDMI_FC_INVACTV0);
501
502 /* set up horizontal blanking pixel region width */
503 hdmi_write(hdmi, hbl >> 8, HDMI_FC_INHBLANK1);
504 hdmi_write(hdmi, hbl, HDMI_FC_INHBLANK0);
505
506 /* set up vertical blanking pixel region width */
507 hdmi_write(hdmi, vbl, HDMI_FC_INVBLANK);
508
509 /* set up hsync active edge delay width (in pixel clks) */
510 hdmi_write(hdmi, edid->hfront_porch.typ >> 8, HDMI_FC_HSYNCINDELAY1);
511 hdmi_write(hdmi, edid->hfront_porch.typ, HDMI_FC_HSYNCINDELAY0);
512
513 /* set up vsync active edge delay (in lines) */
514 hdmi_write(hdmi, edid->vfront_porch.typ, HDMI_FC_VSYNCINDELAY);
515
516 /* set up hsync active pulse width (in pixel clks) */
517 hdmi_write(hdmi, edid->hsync_len.typ >> 8, HDMI_FC_HSYNCINWIDTH1);
518 hdmi_write(hdmi, edid->hsync_len.typ, HDMI_FC_HSYNCINWIDTH0);
519
520 /* set up vsync active edge delay (in lines) */
521 hdmi_write(hdmi, edid->vsync_len.typ, HDMI_FC_VSYNCINWIDTH);
522}
523
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +0100524static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
525{
526 switch (bus_format) {
527 case MEDIA_BUS_FMT_RGB888_1X24:
528 case MEDIA_BUS_FMT_RGB101010_1X30:
529 case MEDIA_BUS_FMT_RGB121212_1X36:
530 case MEDIA_BUS_FMT_RGB161616_1X48:
531 return true;
532
533 default:
534 return false;
535 }
536}
537
538static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
539{
540 switch (bus_format) {
541 case MEDIA_BUS_FMT_YUV8_1X24:
542 case MEDIA_BUS_FMT_YUV10_1X30:
543 case MEDIA_BUS_FMT_YUV12_1X36:
544 case MEDIA_BUS_FMT_YUV16_1X48:
545 return true;
546
547 default:
548 return false;
549 }
550}
551
552static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
553{
554 switch (bus_format) {
555 case MEDIA_BUS_FMT_UYVY8_1X16:
556 case MEDIA_BUS_FMT_UYVY10_1X20:
557 case MEDIA_BUS_FMT_UYVY12_1X24:
558 return true;
559
560 default:
561 return false;
562 }
563}
564
565static int is_color_space_interpolation(struct dw_hdmi *hdmi)
566{
567 if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format))
568 return 0;
569
570 if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
571 hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
572 return 1;
573
574 return 0;
575}
576
577static int is_color_space_decimation(struct dw_hdmi *hdmi)
578{
579 if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
580 return 0;
581
582 if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) ||
583 hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format))
584 return 1;
585
586 return 0;
587}
588
589static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
590{
591 switch (bus_format) {
592 case MEDIA_BUS_FMT_RGB888_1X24:
593 case MEDIA_BUS_FMT_YUV8_1X24:
594 case MEDIA_BUS_FMT_UYVY8_1X16:
595 case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
596 return 8;
597
598 case MEDIA_BUS_FMT_RGB101010_1X30:
599 case MEDIA_BUS_FMT_YUV10_1X30:
600 case MEDIA_BUS_FMT_UYVY10_1X20:
601 case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
602 return 10;
603
604 case MEDIA_BUS_FMT_RGB121212_1X36:
605 case MEDIA_BUS_FMT_YUV12_1X36:
606 case MEDIA_BUS_FMT_UYVY12_1X24:
607 case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
608 return 12;
609
610 case MEDIA_BUS_FMT_RGB161616_1X48:
611 case MEDIA_BUS_FMT_YUV16_1X48:
612 case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
613 return 16;
614
615 default:
616 return 0;
617 }
618}
619
620static int is_color_space_conversion(struct dw_hdmi *hdmi)
621{
622 return hdmi->hdmi_data.enc_in_bus_format !=
623 hdmi->hdmi_data.enc_out_bus_format;
624}
625
626static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
627{
628 const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
629 unsigned int i;
630 u32 csc_scale = 1;
631
632 if (is_color_space_conversion(hdmi)) {
633 if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
634 csc_coeff = &csc_coeff_rgb_out_eitu601;
635 } else if (hdmi_bus_fmt_is_rgb(
636 hdmi->hdmi_data.enc_in_bus_format)) {
637 csc_coeff = &csc_coeff_rgb_in_eitu601;
638 csc_scale = 0;
639 }
640 }
641
642 /* The CSC registers are sequential, alternating MSB then LSB */
643 for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
644 u16 coeff_a = (*csc_coeff)[0][i];
645 u16 coeff_b = (*csc_coeff)[1][i];
646 u16 coeff_c = (*csc_coeff)[2][i];
647
648 hdmi_write(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
649 hdmi_write(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
650 hdmi_write(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
651 hdmi_write(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
652 hdmi_write(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
653 hdmi_write(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
654 }
655
656 hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSCSCALE_MASK, csc_scale);
657}
658
659static void hdmi_video_csc(struct dw_hdmi *hdmi)
660{
661 int color_depth = 0;
662 int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
663 int decimation = 0;
664
665 /* YCC422 interpolation to 444 mode */
666 if (is_color_space_interpolation(hdmi))
667 interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
668 else if (is_color_space_decimation(hdmi))
669 decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
670
671 switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) {
672 case 8:
673 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
674 break;
675 case 10:
676 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
677 break;
678 case 12:
679 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
680 break;
681 case 16:
682 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
683 break;
684
685 default:
686 return;
687 }
688
689 /* Configure the CSC registers */
690 hdmi_write(hdmi, interpolation | decimation, HDMI_CSC_CFG);
691
692 hdmi_mod(hdmi, HDMI_CSC_SCALE, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
693 color_depth);
694
695 dw_hdmi_update_csc_coeffs(hdmi);
696}
697
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100698/* hdmi initialization step b.4 */
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200699static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100700{
701 uint clkdis;
702
703 /* control period minimum duration */
704 hdmi_write(hdmi, 12, HDMI_FC_CTRLDUR);
705 hdmi_write(hdmi, 32, HDMI_FC_EXCTRLDUR);
706 hdmi_write(hdmi, 1, HDMI_FC_EXCTRLSPAC);
707
708 /* set to fill tmds data channels */
709 hdmi_write(hdmi, 0x0b, HDMI_FC_CH0PREAM);
710 hdmi_write(hdmi, 0x16, HDMI_FC_CH1PREAM);
711 hdmi_write(hdmi, 0x21, HDMI_FC_CH2PREAM);
712
713 hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
714 HDMI_MC_FLOWCTRL);
715
716 /* enable pixel clock and tmds data path */
717 clkdis = 0x7f;
718 clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
719 hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
720
721 clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
722 hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
723
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +0100724 /* Enable csc path */
725 if (is_color_space_conversion(hdmi)) {
726 clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
727 hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
728 }
729
730 /* Enable color space conversion if needed */
731 if (is_color_space_conversion(hdmi))
732 hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
733 HDMI_MC_FLOWCTRL);
734 else
735 hdmi_write(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
736 HDMI_MC_FLOWCTRL);
737
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200738 if (audio) {
739 clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
740 hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
741 }
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100742}
743
744/* workaround to clear the overflow condition */
745static void hdmi_clear_overflow(struct dw_hdmi *hdmi)
746{
747 uint val, count;
748
749 /* tmds software reset */
750 hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
751
752 val = hdmi_read(hdmi, HDMI_FC_INVIDCONF);
753
754 for (count = 0; count < 4; count++)
755 hdmi_write(hdmi, val, HDMI_FC_INVIDCONF);
756}
757
758static void hdmi_audio_set_format(struct dw_hdmi *hdmi)
759{
760 hdmi_write(hdmi, HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_IN_EN_0,
761 HDMI_AUD_CONF0);
762
763
764 hdmi_write(hdmi, HDMI_AUD_CONF1_I2S_MODE_STANDARD_MODE |
765 HDMI_AUD_CONF1_I2S_WIDTH_16BIT, HDMI_AUD_CONF1);
766
767 hdmi_write(hdmi, 0x00, HDMI_AUD_CONF2);
768}
769
770static void hdmi_audio_fifo_reset(struct dw_hdmi *hdmi)
771{
772 hdmi_write(hdmi, (u8)~HDMI_MC_SWRSTZ_II2SSWRST_REQ, HDMI_MC_SWRSTZ);
773 hdmi_write(hdmi, HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST, HDMI_AUD_CONF0);
774
775 hdmi_write(hdmi, 0x00, HDMI_AUD_INT);
776 hdmi_write(hdmi, 0x00, HDMI_AUD_INT1);
777}
778
779static int hdmi_get_plug_in_status(struct dw_hdmi *hdmi)
780{
781 uint val = hdmi_read(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD;
782
783 return !!val;
784}
785
786static int hdmi_ddc_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
787{
788 u32 val;
789 ulong start;
790
791 start = get_timer(0);
792 do {
793 val = hdmi_read(hdmi, HDMI_IH_I2CM_STAT0);
794 if (val & 0x2) {
795 hdmi_write(hdmi, val, HDMI_IH_I2CM_STAT0);
796 return 0;
797 }
798
799 udelay(100);
800 } while (get_timer(start) < msec);
801
802 return 1;
803}
804
805static void hdmi_ddc_reset(struct dw_hdmi *hdmi)
806{
807 hdmi_mod(hdmi, HDMI_I2CM_SOFTRSTZ, HDMI_I2CM_SOFTRSTZ_MASK, 0);
808}
809
810static int hdmi_read_edid(struct dw_hdmi *hdmi, int block, u8 *buff)
811{
812 int shift = (block % 2) * 0x80;
813 int edid_read_err = 0;
814 u32 trytime = 5;
815 u32 n;
816
Niklas Schulze60a62ac2019-07-27 12:07:13 +0000817 if (CONFIG_IS_ENABLED(DM_I2C) && hdmi->ddc_bus) {
818 struct udevice *chip;
819
820 edid_read_err = i2c_get_chip(hdmi->ddc_bus,
821 HDMI_I2CM_SLAVE_DDC_ADDR,
822 1, &chip);
823 if (edid_read_err)
824 return edid_read_err;
825
826 return dm_i2c_read(chip, shift, buff, HDMI_EDID_BLOCK_SIZE);
827 }
828
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100829 /* set ddc i2c clk which devided from ddc_clk to 100khz */
830 hdmi_write(hdmi, hdmi->i2c_clk_high, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
831 hdmi_write(hdmi, hdmi->i2c_clk_low, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
832 hdmi_mod(hdmi, HDMI_I2CM_DIV, HDMI_I2CM_DIV_FAST_STD_MODE,
833 HDMI_I2CM_DIV_STD_MODE);
834
835 hdmi_write(hdmi, HDMI_I2CM_SLAVE_DDC_ADDR, HDMI_I2CM_SLAVE);
836 hdmi_write(hdmi, HDMI_I2CM_SEGADDR_DDC, HDMI_I2CM_SEGADDR);
837 hdmi_write(hdmi, block >> 1, HDMI_I2CM_SEGPTR);
838
839 while (trytime--) {
840 edid_read_err = 0;
841
842 for (n = 0; n < HDMI_EDID_BLOCK_SIZE; n++) {
843 hdmi_write(hdmi, shift + n, HDMI_I2CM_ADDRESS);
844
845 if (block == 0)
846 hdmi_write(hdmi, HDMI_I2CM_OP_RD8,
847 HDMI_I2CM_OPERATION);
848 else
849 hdmi_write(hdmi, HDMI_I2CM_OP_RD8_EXT,
850 HDMI_I2CM_OPERATION);
851
852 if (hdmi_ddc_wait_i2c_done(hdmi, 10)) {
853 hdmi_ddc_reset(hdmi);
854 edid_read_err = 1;
855 break;
856 }
857
858 buff[n] = hdmi_read(hdmi, HDMI_I2CM_DATAI);
859 }
860
861 if (!edid_read_err)
862 break;
863 }
864
865 return edid_read_err;
866}
867
868static const u8 pre_buf[] = {
869 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
870 0x04, 0x69, 0xfa, 0x23, 0xc8, 0x28, 0x01, 0x00,
871 0x10, 0x17, 0x01, 0x03, 0x80, 0x33, 0x1d, 0x78,
872 0x2a, 0xd9, 0x45, 0xa2, 0x55, 0x4d, 0xa0, 0x27,
873 0x12, 0x50, 0x54, 0xb7, 0xef, 0x00, 0x71, 0x4f,
874 0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00,
875 0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x00, 0x02, 0x3a,
876 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
877 0x45, 0x00, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
878 0x00, 0x00, 0x00, 0xff, 0x00, 0x44, 0x34, 0x4c,
879 0x4d, 0x54, 0x46, 0x30, 0x37, 0x35, 0x39, 0x37,
880 0x36, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
881 0x4b, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20,
882 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
883 0x00, 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x53,
884 0x32, 0x33, 0x38, 0x0a, 0x20, 0x20, 0x01, 0xb0,
885 0x02, 0x03, 0x22, 0x71, 0x4f, 0x01, 0x02, 0x03,
886 0x11, 0x12, 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f,
887 0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, 0x17, 0x07,
888 0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0c, 0x00,
889 0x10, 0x00, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0,
890 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xfd, 0x1e,
891 0x11, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72,
892 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
893 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d,
894 0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28,
895 0x55, 0x40, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
896 0x8c, 0x0a, 0xd0, 0x90, 0x20, 0x40, 0x31, 0x20,
897 0x0c, 0x40, 0x55, 0x00, 0xfd, 0x1e, 0x11, 0x00,
898 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
899 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
900 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9,
901};
902
903int dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
904{
905 int i, ret;
906
907 /* hdmi phy spec says to do the phy initialization sequence twice */
908 for (i = 0; i < 2; i++) {
909 hdmi_phy_sel_data_en_pol(hdmi, 1);
910 hdmi_phy_sel_interface_control(hdmi, 0);
911 hdmi_phy_enable_tmds(hdmi, 0);
912 hdmi_phy_enable_power(hdmi, 0);
913
914 ret = hdmi_phy_configure(hdmi, mpixelclock);
915 if (ret) {
916 debug("hdmi phy config failure %d\n", ret);
917 return ret;
918 }
919 }
920
921 return 0;
922}
923
924int dw_hdmi_phy_wait_for_hpd(struct dw_hdmi *hdmi)
925{
926 ulong start;
927
928 start = get_timer(0);
929 do {
930 if (hdmi_get_plug_in_status(hdmi))
931 return 0;
932 udelay(100);
933 } while (get_timer(start) < 300);
934
935 return -1;
936}
937
938void dw_hdmi_phy_init(struct dw_hdmi *hdmi)
939{
940 /* enable phy i2cm done irq */
941 hdmi_write(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
942 HDMI_PHY_I2CM_INT_ADDR);
943
944 /* enable phy i2cm nack & arbitration error irq */
945 hdmi_write(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
946 HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
947 HDMI_PHY_I2CM_CTLINT_ADDR);
948
949 /* enable cable hot plug irq */
950 hdmi_write(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
951
952 /* clear hotplug interrupts */
953 hdmi_write(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
954}
955
956int dw_hdmi_read_edid(struct dw_hdmi *hdmi, u8 *buf, int buf_size)
957{
958 u32 edid_size = HDMI_EDID_BLOCK_SIZE;
959 int ret;
960
961 if (0) {
962 edid_size = sizeof(pre_buf);
963 memcpy(buf, pre_buf, edid_size);
964 } else {
965 ret = hdmi_read_edid(hdmi, 0, buf);
966 if (ret) {
967 debug("failed to read edid.\n");
968 return -1;
969 }
970
971 if (buf[0x7e] != 0) {
972 hdmi_read_edid(hdmi, 1, buf + HDMI_EDID_BLOCK_SIZE);
973 edid_size += HDMI_EDID_BLOCK_SIZE;
974 }
975 }
976
977 return edid_size;
978}
979
980int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
981{
982 int ret;
983
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200984 debug("%s, mode info : clock %d hdis %d vdis %d\n",
985 edid->hdmi_monitor ? "hdmi" : "dvi",
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100986 edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ);
987
988 hdmi_av_composer(hdmi, edid);
989
990 ret = hdmi->phy_set(hdmi, edid->pixelclock.typ);
991 if (ret)
992 return ret;
993
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200994 hdmi_enable_video_path(hdmi, edid->hdmi_monitor);
Jernej Skrabeccc232a92017-03-20 23:01:22 +0100995
Jernej Skrabec4f4e1b62017-04-29 14:43:37 +0200996 if (edid->hdmi_monitor) {
997 hdmi_audio_fifo_reset(hdmi);
998 hdmi_audio_set_format(hdmi);
999 hdmi_audio_set_samplerate(hdmi, edid->pixelclock.typ);
1000 }
Jernej Skrabeccc232a92017-03-20 23:01:22 +01001001
1002 hdmi_video_packetize(hdmi);
Jorge Ramirez-Ortiz56dd8d82018-11-15 10:32:03 +01001003 hdmi_video_csc(hdmi);
Jernej Skrabeccc232a92017-03-20 23:01:22 +01001004 hdmi_video_sample(hdmi);
1005
1006 hdmi_clear_overflow(hdmi);
1007
1008 return 0;
1009}
1010
1011void dw_hdmi_init(struct dw_hdmi *hdmi)
1012{
1013 uint ih_mute;
1014
1015 /*
1016 * boot up defaults are:
1017 * hdmi_ih_mute = 0x03 (disabled)
1018 * hdmi_ih_mute_* = 0x00 (enabled)
1019 *
1020 * disable top level interrupt bits in hdmi block
1021 */
1022 ih_mute = /*hdmi_read(hdmi, HDMI_IH_MUTE) |*/
1023 HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
1024 HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
1025
Jorge Ramirez-Ortizfd998412018-11-08 16:51:01 +01001026 if (hdmi->write_reg)
1027 hdmi_write = hdmi->write_reg;
1028
1029 if (hdmi->read_reg)
1030 hdmi_read = hdmi->read_reg;
1031
Jernej Skrabeccc232a92017-03-20 23:01:22 +01001032 hdmi_write(hdmi, ih_mute, HDMI_IH_MUTE);
1033
1034 /* enable i2c master done irq */
1035 hdmi_write(hdmi, ~0x04, HDMI_I2CM_INT);
1036
1037 /* enable i2c client nack % arbitration error irq */
1038 hdmi_write(hdmi, ~0x44, HDMI_I2CM_CTLINT);
1039}