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