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