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