1c2539483SSimon Glass /*
2c2539483SSimon Glass  * Copyright (c) 2015 Google, Inc
3c2539483SSimon Glass  * Copyright 2014 Rockchip Inc.
4c2539483SSimon Glass  *
5c2539483SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
6c2539483SSimon Glass  */
7c2539483SSimon Glass 
8c2539483SSimon Glass #include <common.h>
9c2539483SSimon Glass #include <clk.h>
10c2539483SSimon Glass #include <display.h>
11c2539483SSimon Glass #include <dm.h>
12c2539483SSimon Glass #include <edid.h>
13c2539483SSimon Glass #include <regmap.h>
14c2539483SSimon Glass #include <syscon.h>
15c2539483SSimon Glass #include <asm/gpio.h>
16c2539483SSimon Glass #include <asm/io.h>
17c2539483SSimon Glass #include <asm/arch/clock.h>
18c2539483SSimon Glass #include <asm/arch/grf_rk3288.h>
19c2539483SSimon Glass #include <asm/arch/hdmi_rk3288.h>
20c2539483SSimon Glass #include <power/regulator.h>
21c2539483SSimon Glass 
22c2539483SSimon Glass struct tmds_n_cts {
23c2539483SSimon Glass 	u32 tmds;
24c2539483SSimon Glass 	u32 cts;
25c2539483SSimon Glass 	u32 n;
26c2539483SSimon Glass };
27c2539483SSimon Glass 
28c2539483SSimon Glass struct rk_hdmi_priv {
29c2539483SSimon Glass 	struct rk3288_hdmi *regs;
30c2539483SSimon Glass 	struct rk3288_grf *grf;
31c2539483SSimon Glass };
32c2539483SSimon Glass 
33c2539483SSimon Glass static const struct tmds_n_cts n_cts_table[] = {
34c2539483SSimon Glass 	{
35c2539483SSimon Glass 		.tmds = 25175, .n = 6144, .cts = 25175,
36c2539483SSimon Glass 	}, {
37c2539483SSimon Glass 		.tmds = 25200, .n = 6144, .cts = 25200,
38c2539483SSimon Glass 	}, {
39c2539483SSimon Glass 		.tmds = 27000, .n = 6144, .cts = 27000,
40c2539483SSimon Glass 	}, {
41c2539483SSimon Glass 		.tmds = 27027, .n = 6144, .cts = 27027,
42c2539483SSimon Glass 	}, {
43c2539483SSimon Glass 		.tmds = 40000, .n = 6144, .cts = 40000,
44c2539483SSimon Glass 	}, {
45c2539483SSimon Glass 		.tmds = 54000, .n = 6144, .cts = 54000,
46c2539483SSimon Glass 	}, {
47c2539483SSimon Glass 		.tmds = 54054, .n = 6144, .cts = 54054,
48c2539483SSimon Glass 	}, {
49c2539483SSimon Glass 		.tmds = 65000, .n = 6144, .cts = 65000,
50c2539483SSimon Glass 	}, {
51c2539483SSimon Glass 		.tmds = 74176, .n = 11648, .cts = 140625,
52c2539483SSimon Glass 	}, {
53c2539483SSimon Glass 		.tmds = 74250, .n = 6144, .cts = 74250,
54c2539483SSimon Glass 	}, {
55c2539483SSimon Glass 		.tmds = 83500, .n = 6144, .cts = 83500,
56c2539483SSimon Glass 	}, {
57c2539483SSimon Glass 		.tmds = 106500, .n = 6144, .cts = 106500,
58c2539483SSimon Glass 	}, {
59c2539483SSimon Glass 		.tmds = 108000, .n = 6144, .cts = 108000,
60c2539483SSimon Glass 	}, {
61c2539483SSimon Glass 		.tmds = 148352, .n = 5824, .cts = 140625,
62c2539483SSimon Glass 	}, {
63c2539483SSimon Glass 		.tmds = 148500, .n = 6144, .cts = 148500,
64c2539483SSimon Glass 	}, {
65c2539483SSimon Glass 		.tmds = 297000, .n = 5120, .cts = 247500,
66c2539483SSimon Glass 	}
67c2539483SSimon Glass };
68c2539483SSimon Glass 
69c2539483SSimon Glass struct hdmi_mpll_config {
70c2539483SSimon Glass 	u64 mpixelclock;
71c2539483SSimon Glass 	/* Mode of Operation and PLL Dividers Control Register */
72c2539483SSimon Glass 	u32 cpce;
73c2539483SSimon Glass 	/* PLL Gmp Control Register */
74c2539483SSimon Glass 	u32 gmp;
75c2539483SSimon Glass 	/* PLL Current COntrol Register */
76c2539483SSimon Glass 	u32 curr;
77c2539483SSimon Glass };
78c2539483SSimon Glass 
79c2539483SSimon Glass struct hdmi_phy_config {
80c2539483SSimon Glass 	u64 mpixelclock;
81c2539483SSimon Glass 	u32 sym_ctr;    /* clock symbol and transmitter control */
82c2539483SSimon Glass 	u32 term;       /* transmission termination value */
83c2539483SSimon Glass 	u32 vlev_ctr;   /* voltage level control */
84c2539483SSimon Glass };
85c2539483SSimon Glass 
86c2539483SSimon Glass static const struct hdmi_phy_config rockchip_phy_config[] = {
87c2539483SSimon Glass 	{
88c2539483SSimon Glass 		.mpixelclock = 74250,
89c2539483SSimon Glass 		.sym_ctr = 0x8009, .term = 0x0004, .vlev_ctr = 0x0272,
90c2539483SSimon Glass 	}, {
91c2539483SSimon Glass 		.mpixelclock = 148500,
92c2539483SSimon Glass 		.sym_ctr = 0x802b, .term = 0x0004, .vlev_ctr = 0x028d,
93c2539483SSimon Glass 	}, {
94c2539483SSimon Glass 		.mpixelclock = 297000,
95c2539483SSimon Glass 		.sym_ctr = 0x8039, .term = 0x0005, .vlev_ctr = 0x028d,
96c2539483SSimon Glass 	}, {
97c2539483SSimon Glass 		.mpixelclock = ~0ul,
98c2539483SSimon Glass 		.sym_ctr = 0x0000, .term = 0x0000, .vlev_ctr = 0x0000,
99c2539483SSimon Glass 	}
100c2539483SSimon Glass };
101c2539483SSimon Glass 
102c2539483SSimon Glass static const struct hdmi_mpll_config rockchip_mpll_cfg[] = {
103c2539483SSimon Glass 	{
104c2539483SSimon Glass 		.mpixelclock = 40000,
105c2539483SSimon Glass 		.cpce = 0x00b3, .gmp = 0x0000, .curr = 0x0018,
106c2539483SSimon Glass 	}, {
107c2539483SSimon Glass 		.mpixelclock = 65000,
108c2539483SSimon Glass 		.cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028,
109c2539483SSimon Glass 	}, {
110c2539483SSimon Glass 		.mpixelclock = 66000,
111c2539483SSimon Glass 		.cpce = 0x013e, .gmp = 0x0003, .curr = 0x0038,
112c2539483SSimon Glass 	}, {
113c2539483SSimon Glass 		.mpixelclock = 83500,
114c2539483SSimon Glass 		.cpce = 0x0072, .gmp = 0x0001, .curr = 0x0028,
115c2539483SSimon Glass 	}, {
116c2539483SSimon Glass 		.mpixelclock = 146250,
117c2539483SSimon Glass 		.cpce = 0x0051, .gmp = 0x0002, .curr = 0x0038,
118c2539483SSimon Glass 	}, {
119c2539483SSimon Glass 		.mpixelclock = 148500,
120c2539483SSimon Glass 		.cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000,
121c2539483SSimon Glass 	}, {
122c2539483SSimon Glass 		.mpixelclock = ~0ul,
123c2539483SSimon Glass 		.cpce = 0x0051, .gmp = 0x0003, .curr = 0x0000,
124c2539483SSimon Glass 	}
125c2539483SSimon Glass };
126c2539483SSimon Glass 
127c2539483SSimon Glass static const u32 csc_coeff_default[3][4] = {
128c2539483SSimon Glass 	{ 0x2000, 0x0000, 0x0000, 0x0000 },
129c2539483SSimon Glass 	{ 0x0000, 0x2000, 0x0000, 0x0000 },
130c2539483SSimon Glass 	{ 0x0000, 0x0000, 0x2000, 0x0000 }
131c2539483SSimon Glass };
132c2539483SSimon Glass 
133c2539483SSimon Glass static void hdmi_set_clock_regenerator(struct rk3288_hdmi *regs, u32 n, u32 cts)
134c2539483SSimon Glass {
135c2539483SSimon Glass 	u8 cts3;
136c2539483SSimon Glass 	u8 n3;
137c2539483SSimon Glass 
138c2539483SSimon Glass 	/* first set ncts_atomic_write (if present) */
139c2539483SSimon Glass 	n3 = HDMI_AUD_N3_NCTS_ATOMIC_WRITE;
140c2539483SSimon Glass 	writel(n3, &regs->aud_n3);
141c2539483SSimon Glass 
142c2539483SSimon Glass 	/* set cts_manual (if present) */
143c2539483SSimon Glass 	cts3 = HDMI_AUD_CTS3_CTS_MANUAL;
144c2539483SSimon Glass 
145c2539483SSimon Glass 	cts3 |= HDMI_AUD_CTS3_N_SHIFT_1 << HDMI_AUD_CTS3_N_SHIFT_OFFSET;
146c2539483SSimon Glass 	cts3 |= (cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK;
147c2539483SSimon Glass 
148c2539483SSimon Glass 	/* write cts values; cts3 must be written first */
149c2539483SSimon Glass 	writel(cts3, &regs->aud_cts3);
150c2539483SSimon Glass 	writel((cts >> 8) & 0xff, &regs->aud_cts2);
151c2539483SSimon Glass 	writel(cts & 0xff, &regs->aud_cts1);
152c2539483SSimon Glass 
153c2539483SSimon Glass 	/* write n values; n1 must be written last */
154c2539483SSimon Glass 	n3 |= (n >> 16) & HDMI_AUD_N3_AUDN19_16_MASK;
155c2539483SSimon Glass 	writel(n3, &regs->aud_n3);
156c2539483SSimon Glass 	writel((n >> 8) & 0xff, &regs->aud_n2);
157c2539483SSimon Glass 	writel(n & 0xff, &regs->aud_n1);
158c2539483SSimon Glass 
159c2539483SSimon Glass 	writel(HDMI_AUD_INPUTCLKFS_128, &regs->aud_inputclkfs);
160c2539483SSimon Glass }
161c2539483SSimon Glass 
162c2539483SSimon Glass static int hdmi_lookup_n_cts(u32 pixel_clk)
163c2539483SSimon Glass {
164c2539483SSimon Glass 	int i;
165c2539483SSimon Glass 
166c2539483SSimon Glass 	for (i = 0; i < ARRAY_SIZE(n_cts_table); i++)
167c2539483SSimon Glass 		if (pixel_clk <= n_cts_table[i].tmds)
168c2539483SSimon Glass 			break;
169c2539483SSimon Glass 
170c2539483SSimon Glass 	if (i >= ARRAY_SIZE(n_cts_table))
171c2539483SSimon Glass 		return -1;
172c2539483SSimon Glass 
173c2539483SSimon Glass 	return i;
174c2539483SSimon Glass }
175c2539483SSimon Glass 
176c2539483SSimon Glass static void hdmi_audio_set_samplerate(struct rk3288_hdmi *regs, u32 pixel_clk)
177c2539483SSimon Glass {
178c2539483SSimon Glass 	u32 clk_n, clk_cts;
179c2539483SSimon Glass 	int index;
180c2539483SSimon Glass 
181c2539483SSimon Glass 	index = hdmi_lookup_n_cts(pixel_clk);
182c2539483SSimon Glass 	if (index == -1) {
183c2539483SSimon Glass 		debug("audio not supported for pixel clk %d\n", pixel_clk);
184c2539483SSimon Glass 		return;
185c2539483SSimon Glass 	}
186c2539483SSimon Glass 
187c2539483SSimon Glass 	clk_n = n_cts_table[index].n;
188c2539483SSimon Glass 	clk_cts = n_cts_table[index].cts;
189c2539483SSimon Glass 	hdmi_set_clock_regenerator(regs, clk_n, clk_cts);
190c2539483SSimon Glass }
191c2539483SSimon Glass 
192c2539483SSimon Glass /*
193c2539483SSimon Glass  * this submodule is responsible for the video data synchronization.
194c2539483SSimon Glass  * for example, for rgb 4:4:4 input, the data map is defined as
195c2539483SSimon Glass  *			pin{47~40} <==> r[7:0]
196c2539483SSimon Glass  *			pin{31~24} <==> g[7:0]
197c2539483SSimon Glass  *			pin{15~8}  <==> b[7:0]
198c2539483SSimon Glass  */
199c2539483SSimon Glass static void hdmi_video_sample(struct rk3288_hdmi *regs)
200c2539483SSimon Glass {
201c2539483SSimon Glass 	u32 color_format = 0x01;
202c2539483SSimon Glass 	u8 val;
203c2539483SSimon Glass 
204c2539483SSimon Glass 	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
205c2539483SSimon Glass 	      ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
206c2539483SSimon Glass 	      HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
207c2539483SSimon Glass 
208c2539483SSimon Glass 	writel(val, &regs->tx_invid0);
209c2539483SSimon Glass 
210c2539483SSimon Glass 	/* enable tx stuffing: when de is inactive, fix the output data to 0 */
211c2539483SSimon Glass 	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
212c2539483SSimon Glass 	      HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
213c2539483SSimon Glass 	      HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
214c2539483SSimon Glass 	writel(val, &regs->tx_instuffing);
215c2539483SSimon Glass 	writel(0x0, &regs->tx_gydata0);
216c2539483SSimon Glass 	writel(0x0, &regs->tx_gydata1);
217c2539483SSimon Glass 	writel(0x0, &regs->tx_rcrdata0);
218c2539483SSimon Glass 	writel(0x0, &regs->tx_rcrdata1);
219c2539483SSimon Glass 	writel(0x0, &regs->tx_bcbdata0);
220c2539483SSimon Glass 	writel(0x0, &regs->tx_bcbdata1);
221c2539483SSimon Glass }
222c2539483SSimon Glass 
223c2539483SSimon Glass static void hdmi_update_csc_coeffs(struct rk3288_hdmi *regs)
224c2539483SSimon Glass {
225c2539483SSimon Glass 	u32 i, j;
226c2539483SSimon Glass 	u32 csc_scale = 1;
227c2539483SSimon Glass 
228c2539483SSimon Glass 	/* the csc registers are sequential, alternating msb then lsb */
229c2539483SSimon Glass 	for (i = 0; i < ARRAY_SIZE(csc_coeff_default); i++) {
230c2539483SSimon Glass 		for (j = 0; j < ARRAY_SIZE(csc_coeff_default[0]); j++) {
231c2539483SSimon Glass 			u32 coeff = csc_coeff_default[i][j];
232c2539483SSimon Glass 			writel(coeff >> 8, &regs->csc_coef[i][j].msb);
233c2539483SSimon Glass 			writel(coeff && 0xff, &regs->csc_coef[i][j].lsb);
234c2539483SSimon Glass 		}
235c2539483SSimon Glass 	}
236c2539483SSimon Glass 
237c2539483SSimon Glass 	clrsetbits_le32(&regs->csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
238c2539483SSimon Glass 			csc_scale);
239c2539483SSimon Glass }
240c2539483SSimon Glass 
241c2539483SSimon Glass static void hdmi_video_csc(struct rk3288_hdmi *regs)
242c2539483SSimon Glass {
243c2539483SSimon Glass 	u32 color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
244c2539483SSimon Glass 	u32 interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
245c2539483SSimon Glass 
246c2539483SSimon Glass 	/* configure the csc registers */
247c2539483SSimon Glass 	writel(interpolation, &regs->csc_cfg);
248c2539483SSimon Glass 	clrsetbits_le32(&regs->csc_scale,
249c2539483SSimon Glass 			HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, color_depth);
250c2539483SSimon Glass 
251c2539483SSimon Glass 	hdmi_update_csc_coeffs(regs);
252c2539483SSimon Glass }
253c2539483SSimon Glass 
254c2539483SSimon Glass static void hdmi_video_packetize(struct rk3288_hdmi *regs)
255c2539483SSimon Glass {
256c2539483SSimon Glass 	u32 output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
257c2539483SSimon Glass 	u32 remap_size = HDMI_VP_REMAP_YCC422_16BIT;
258c2539483SSimon Glass 	u32 color_depth = 0;
259c2539483SSimon Glass 	u8 val, vp_conf;
260c2539483SSimon Glass 
261c2539483SSimon Glass 	/* set the packetizer registers */
262c2539483SSimon Glass 	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
263c2539483SSimon Glass 		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
264c2539483SSimon Glass 		((0 << HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
265c2539483SSimon Glass 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
266c2539483SSimon Glass 	writel(val, &regs->vp_pr_cd);
267c2539483SSimon Glass 
268c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_stuff, HDMI_VP_STUFF_PR_STUFFING_MASK,
269c2539483SSimon Glass 			HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE);
270c2539483SSimon Glass 
271c2539483SSimon Glass 	/* data from pixel repeater block */
272c2539483SSimon Glass 	vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
273c2539483SSimon Glass 		  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
274c2539483SSimon Glass 
275c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_conf, HDMI_VP_CONF_PR_EN_MASK |
276c2539483SSimon Glass 			HDMI_VP_CONF_BYPASS_SELECT_MASK, vp_conf);
277c2539483SSimon Glass 
278c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_stuff, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
279c2539483SSimon Glass 			1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET);
280c2539483SSimon Glass 
281c2539483SSimon Glass 	writel(remap_size, &regs->vp_remap);
282c2539483SSimon Glass 
283c2539483SSimon Glass 	vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
284c2539483SSimon Glass 		  HDMI_VP_CONF_PP_EN_DISABLE |
285c2539483SSimon Glass 		  HDMI_VP_CONF_YCC422_EN_DISABLE;
286c2539483SSimon Glass 
287c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_conf, HDMI_VP_CONF_BYPASS_EN_MASK |
288c2539483SSimon Glass 			HDMI_VP_CONF_PP_EN_ENMASK | HDMI_VP_CONF_YCC422_EN_MASK,
289c2539483SSimon Glass 			vp_conf);
290c2539483SSimon Glass 
291c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_stuff, HDMI_VP_STUFF_PP_STUFFING_MASK |
292c2539483SSimon Glass 			HDMI_VP_STUFF_YCC422_STUFFING_MASK,
293c2539483SSimon Glass 			HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
294c2539483SSimon Glass 			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE);
295c2539483SSimon Glass 
296c2539483SSimon Glass 	clrsetbits_le32(&regs->vp_conf, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
297c2539483SSimon Glass 			output_select);
298c2539483SSimon Glass }
299c2539483SSimon Glass 
300c2539483SSimon Glass static inline void hdmi_phy_test_clear(struct rk3288_hdmi *regs, u8 bit)
301c2539483SSimon Glass {
302c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_tst0, HDMI_PHY_TST0_TSTCLR_MASK,
303c2539483SSimon Glass 			bit << HDMI_PHY_TST0_TSTCLR_OFFSET);
304c2539483SSimon Glass }
305c2539483SSimon Glass 
306c2539483SSimon Glass static int hdmi_phy_wait_i2c_done(struct rk3288_hdmi *regs, u32 msec)
307c2539483SSimon Glass {
308c2539483SSimon Glass 	ulong start;
309c2539483SSimon Glass 	u32 val;
310c2539483SSimon Glass 
311c2539483SSimon Glass 	start = get_timer(0);
312c2539483SSimon Glass 	do {
313c2539483SSimon Glass 		val = readl(&regs->ih_i2cmphy_stat0);
314c2539483SSimon Glass 		if (val & 0x3) {
315c2539483SSimon Glass 			writel(val, &regs->ih_i2cmphy_stat0);
316c2539483SSimon Glass 			return 0;
317c2539483SSimon Glass 		}
318c2539483SSimon Glass 
319c2539483SSimon Glass 		udelay(100);
320c2539483SSimon Glass 	} while (get_timer(start) < msec);
321c2539483SSimon Glass 
322c2539483SSimon Glass 	return 1;
323c2539483SSimon Glass }
324c2539483SSimon Glass 
325c2539483SSimon Glass static void hdmi_phy_i2c_write(struct rk3288_hdmi *regs, uint data, uint addr)
326c2539483SSimon Glass {
327c2539483SSimon Glass 	writel(0xff, &regs->ih_i2cmphy_stat0);
328c2539483SSimon Glass 	writel(addr, &regs->phy_i2cm_address_addr);
329c2539483SSimon Glass 	writel((u8)(data >> 8), &regs->phy_i2cm_datao_1_addr);
330c2539483SSimon Glass 	writel((u8)(data >> 0), &regs->phy_i2cm_datao_0_addr);
331c2539483SSimon Glass 	writel(HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
332c2539483SSimon Glass 	       &regs->phy_i2cm_operation_addr);
333c2539483SSimon Glass 
334c2539483SSimon Glass 	hdmi_phy_wait_i2c_done(regs, 1000);
335c2539483SSimon Glass }
336c2539483SSimon Glass 
337c2539483SSimon Glass static void hdmi_phy_enable_power(struct rk3288_hdmi *regs, uint enable)
338c2539483SSimon Glass {
339c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0, HDMI_PHY_CONF0_PDZ_MASK,
340c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_PDZ_OFFSET);
341c2539483SSimon Glass }
342c2539483SSimon Glass 
343c2539483SSimon Glass static void hdmi_phy_enable_tmds(struct rk3288_hdmi *regs, uint enable)
344c2539483SSimon Glass {
345c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0, HDMI_PHY_CONF0_ENTMDS_MASK,
346c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_ENTMDS_OFFSET);
347c2539483SSimon Glass }
348c2539483SSimon Glass 
349c2539483SSimon Glass static void hdmi_phy_enable_spare(struct rk3288_hdmi *regs, uint enable)
350c2539483SSimon Glass {
351c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0, HDMI_PHY_CONF0_SPARECTRL_MASK,
352c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_SPARECTRL_OFFSET);
353c2539483SSimon Glass }
354c2539483SSimon Glass 
355c2539483SSimon Glass static void hdmi_phy_gen2_pddq(struct rk3288_hdmi *regs, uint enable)
356c2539483SSimon Glass {
357c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0, HDMI_PHY_CONF0_GEN2_PDDQ_MASK,
358c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET);
359c2539483SSimon Glass }
360c2539483SSimon Glass 
361c2539483SSimon Glass static void hdmi_phy_gen2_txpwron(struct rk3288_hdmi *regs, uint enable)
362c2539483SSimon Glass {
363c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0,
364c2539483SSimon Glass 			HDMI_PHY_CONF0_GEN2_TXPWRON_MASK,
365c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET);
366c2539483SSimon Glass }
367c2539483SSimon Glass 
368c2539483SSimon Glass static void hdmi_phy_sel_data_en_pol(struct rk3288_hdmi *regs, uint enable)
369c2539483SSimon Glass {
370c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0,
371c2539483SSimon Glass 			HDMI_PHY_CONF0_SELDATAENPOL_MASK,
372c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_SELDATAENPOL_OFFSET);
373c2539483SSimon Glass }
374c2539483SSimon Glass 
375c2539483SSimon Glass static void hdmi_phy_sel_interface_control(struct rk3288_hdmi *regs,
376c2539483SSimon Glass 					   uint enable)
377c2539483SSimon Glass {
378c2539483SSimon Glass 	clrsetbits_le32(&regs->phy_conf0, HDMI_PHY_CONF0_SELDIPIF_MASK,
379c2539483SSimon Glass 			enable << HDMI_PHY_CONF0_SELDIPIF_OFFSET);
380c2539483SSimon Glass }
381c2539483SSimon Glass 
382c2539483SSimon Glass static int hdmi_phy_configure(struct rk3288_hdmi *regs, u32 mpixelclock)
383c2539483SSimon Glass {
384c2539483SSimon Glass 	ulong start;
385c2539483SSimon Glass 	u8 i, val;
386c2539483SSimon Glass 
387c2539483SSimon Glass 	writel(HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
388c2539483SSimon Glass 	       &regs->mc_flowctrl);
389c2539483SSimon Glass 
390c2539483SSimon Glass 	/* gen2 tx power off */
391c2539483SSimon Glass 	hdmi_phy_gen2_txpwron(regs, 0);
392c2539483SSimon Glass 
393c2539483SSimon Glass 	/* gen2 pddq */
394c2539483SSimon Glass 	hdmi_phy_gen2_pddq(regs, 1);
395c2539483SSimon Glass 
396c2539483SSimon Glass 	/* phy reset */
397c2539483SSimon Glass 	writel(HDMI_MC_PHYRSTZ_DEASSERT, &regs->mc_phyrstz);
398c2539483SSimon Glass 	writel(HDMI_MC_PHYRSTZ_ASSERT, &regs->mc_phyrstz);
399c2539483SSimon Glass 	writel(HDMI_MC_HEACPHY_RST_ASSERT, &regs->mc_heacphy_rst);
400c2539483SSimon Glass 
401c2539483SSimon Glass 	hdmi_phy_test_clear(regs, 1);
402c2539483SSimon Glass 	writel(HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, &regs->phy_i2cm_slave_addr);
403c2539483SSimon Glass 	hdmi_phy_test_clear(regs, 0);
404c2539483SSimon Glass 
405c2539483SSimon Glass 	/* pll/mpll cfg - always match on final entry */
406c2539483SSimon Glass 	for (i = 0; rockchip_mpll_cfg[i].mpixelclock != (~0ul); i++)
407c2539483SSimon Glass 		if (mpixelclock <= rockchip_mpll_cfg[i].mpixelclock)
408c2539483SSimon Glass 			break;
409c2539483SSimon Glass 
410c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].cpce, PHY_OPMODE_PLLCFG);
411c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].gmp, PHY_PLLGMPCTRL);
412c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_mpll_cfg[i].curr, PHY_PLLCURRCTRL);
413c2539483SSimon Glass 
414c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, 0x0000, PHY_PLLPHBYCTRL);
415c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, 0x0006, PHY_PLLCLKBISTPHASE);
416c2539483SSimon Glass 
417c2539483SSimon Glass 	for (i = 0; rockchip_phy_config[i].mpixelclock != (~0ul); i++)
418c2539483SSimon Glass 		if (mpixelclock <= rockchip_phy_config[i].mpixelclock)
419c2539483SSimon Glass 			break;
420c2539483SSimon Glass 
421c2539483SSimon Glass 	/*
422c2539483SSimon Glass 	 * resistance term 133ohm cfg
423c2539483SSimon Glass 	 * preemp cgf 0.00
424c2539483SSimon Glass 	 * tx/ck lvl 10
425c2539483SSimon Glass 	 */
426c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_phy_config[i].term, PHY_TXTERM);
427c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_phy_config[i].sym_ctr,
428c2539483SSimon Glass 			   PHY_CKSYMTXCTRL);
429c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, rockchip_phy_config[i].vlev_ctr, PHY_VLEVCTRL);
430c2539483SSimon Glass 
431c2539483SSimon Glass 	/* remove clk term */
432c2539483SSimon Glass 	hdmi_phy_i2c_write(regs, 0x8000, PHY_CKCALCTRL);
433c2539483SSimon Glass 
434c2539483SSimon Glass 	hdmi_phy_enable_power(regs, 1);
435c2539483SSimon Glass 
436c2539483SSimon Glass 	/* toggle tmds enable */
437c2539483SSimon Glass 	hdmi_phy_enable_tmds(regs, 0);
438c2539483SSimon Glass 	hdmi_phy_enable_tmds(regs, 1);
439c2539483SSimon Glass 
440c2539483SSimon Glass 	/* gen2 tx power on */
441c2539483SSimon Glass 	hdmi_phy_gen2_txpwron(regs, 1);
442c2539483SSimon Glass 	hdmi_phy_gen2_pddq(regs, 0);
443c2539483SSimon Glass 
444c2539483SSimon Glass 	hdmi_phy_enable_spare(regs, 1);
445c2539483SSimon Glass 
446c2539483SSimon Glass 	/* wait for phy pll lock */
447c2539483SSimon Glass 	start = get_timer(0);
448c2539483SSimon Glass 	do {
449c2539483SSimon Glass 		val = readl(&regs->phy_stat0);
450c2539483SSimon Glass 		if (!(val & HDMI_PHY_TX_PHY_LOCK))
451c2539483SSimon Glass 			return 0;
452c2539483SSimon Glass 
453c2539483SSimon Glass 		udelay(100);
454c2539483SSimon Glass 	} while (get_timer(start) < 5);
455c2539483SSimon Glass 
456c2539483SSimon Glass 	return -1;
457c2539483SSimon Glass }
458c2539483SSimon Glass 
459c2539483SSimon Glass static int hdmi_phy_init(struct rk3288_hdmi *regs, uint mpixelclock)
460c2539483SSimon Glass {
461c2539483SSimon Glass 	int i, ret;
462c2539483SSimon Glass 
463c2539483SSimon Glass 	/* hdmi phy spec says to do the phy initialization sequence twice */
464c2539483SSimon Glass 	for (i = 0; i < 2; i++) {
465c2539483SSimon Glass 		hdmi_phy_sel_data_en_pol(regs, 1);
466c2539483SSimon Glass 		hdmi_phy_sel_interface_control(regs, 0);
467c2539483SSimon Glass 		hdmi_phy_enable_tmds(regs, 0);
468c2539483SSimon Glass 		hdmi_phy_enable_power(regs, 0);
469c2539483SSimon Glass 
470c2539483SSimon Glass 		/* enable csc */
471c2539483SSimon Glass 		ret = hdmi_phy_configure(regs, mpixelclock);
472c2539483SSimon Glass 		if (ret) {
473c2539483SSimon Glass 			debug("hdmi phy config failure %d\n", ret);
474c2539483SSimon Glass 			return ret;
475c2539483SSimon Glass 		}
476c2539483SSimon Glass 	}
477c2539483SSimon Glass 
478c2539483SSimon Glass 	return 0;
479c2539483SSimon Glass }
480c2539483SSimon Glass 
481c2539483SSimon Glass static void hdmi_av_composer(struct rk3288_hdmi *regs,
482c2539483SSimon Glass 			     const struct display_timing *edid)
483c2539483SSimon Glass {
484c2539483SSimon Glass 	u8 mdataenablepolarity = 1;
485c2539483SSimon Glass 	u8 inv_val;
486c2539483SSimon Glass 	uint hbl;
487c2539483SSimon Glass 	uint vbl;
488c2539483SSimon Glass 
489c2539483SSimon Glass 	hbl = edid->hback_porch.typ + edid->hfront_porch.typ +
490c2539483SSimon Glass 			edid->hsync_len.typ;
491c2539483SSimon Glass 	vbl = edid->vback_porch.typ + edid->vfront_porch.typ +
492c2539483SSimon Glass 			edid->vsync_len.typ;
493c2539483SSimon Glass 
494c2539483SSimon Glass 	/* set up hdmi_fc_invidconf */
495c2539483SSimon Glass 	inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE;
496c2539483SSimon Glass 
497c2539483SSimon Glass 	inv_val |= (edid->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
498c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
499c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
500c2539483SSimon Glass 
501c2539483SSimon Glass 	inv_val |= (edid->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
502c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
503c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
504c2539483SSimon Glass 
505c2539483SSimon Glass 	inv_val |= (mdataenablepolarity ?
506c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
507c2539483SSimon Glass 		   HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
508c2539483SSimon Glass 
509c2539483SSimon Glass 	/*
510c2539483SSimon Glass 	 * TODO(sjg@chromium.org>: Need to check for HDMI / DVI
511c2539483SSimon Glass 	 * inv_val |= (edid->hdmi_monitor_detected ?
512c2539483SSimon Glass 	 *	   HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
513c2539483SSimon Glass 	 *	   HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
514c2539483SSimon Glass 	 */
515c2539483SSimon Glass 	inv_val |= HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE;
516c2539483SSimon Glass 
517c2539483SSimon Glass 	inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW;
518c2539483SSimon Glass 
519c2539483SSimon Glass 	inv_val |= HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE;
520c2539483SSimon Glass 
521c2539483SSimon Glass 	writel(inv_val, &regs->fc_invidconf);
522c2539483SSimon Glass 
523c2539483SSimon Glass 	/* set up horizontal active pixel width */
524c2539483SSimon Glass 	writel(edid->hactive.typ >> 8, &regs->fc_inhactv1);
525c2539483SSimon Glass 	writel(edid->hactive.typ, &regs->fc_inhactv0);
526c2539483SSimon Glass 
527c2539483SSimon Glass 	/* set up vertical active lines */
528c2539483SSimon Glass 	writel(edid->vactive.typ >> 8, &regs->fc_invactv1);
529c2539483SSimon Glass 	writel(edid->vactive.typ, &regs->fc_invactv0);
530c2539483SSimon Glass 
531c2539483SSimon Glass 	/* set up horizontal blanking pixel region width */
532c2539483SSimon Glass 	writel(hbl >> 8, &regs->fc_inhblank1);
533c2539483SSimon Glass 	writel(hbl, &regs->fc_inhblank0);
534c2539483SSimon Glass 
535c2539483SSimon Glass 	/* set up vertical blanking pixel region width */
536c2539483SSimon Glass 	writel(vbl, &regs->fc_invblank);
537c2539483SSimon Glass 
538c2539483SSimon Glass 	/* set up hsync active edge delay width (in pixel clks) */
539c2539483SSimon Glass 	writel(edid->hfront_porch.typ >> 8, &regs->fc_hsyncindelay1);
540c2539483SSimon Glass 	writel(edid->hfront_porch.typ, &regs->fc_hsyncindelay0);
541c2539483SSimon Glass 
542c2539483SSimon Glass 	/* set up vsync active edge delay (in lines) */
543c2539483SSimon Glass 	writel(edid->vfront_porch.typ, &regs->fc_vsyncindelay);
544c2539483SSimon Glass 
545c2539483SSimon Glass 	/* set up hsync active pulse width (in pixel clks) */
546c2539483SSimon Glass 	writel(edid->hsync_len.typ >> 8, &regs->fc_hsyncinwidth1);
547c2539483SSimon Glass 	writel(edid->hsync_len.typ, &regs->fc_hsyncinwidth0);
548c2539483SSimon Glass 
549c2539483SSimon Glass 	/* set up vsync active edge delay (in lines) */
550c2539483SSimon Glass 	writel(edid->vsync_len.typ, &regs->fc_vsyncinwidth);
551c2539483SSimon Glass }
552c2539483SSimon Glass 
553c2539483SSimon Glass /* hdmi initialization step b.4 */
554c2539483SSimon Glass static void hdmi_enable_video_path(struct rk3288_hdmi *regs)
555c2539483SSimon Glass {
556c2539483SSimon Glass 	u8 clkdis;
557c2539483SSimon Glass 
558c2539483SSimon Glass 	/* control period minimum duration */
559c2539483SSimon Glass 	writel(12, &regs->fc_ctrldur);
560c2539483SSimon Glass 	writel(32, &regs->fc_exctrldur);
561c2539483SSimon Glass 	writel(1, &regs->fc_exctrlspac);
562c2539483SSimon Glass 
563c2539483SSimon Glass 	/* set to fill tmds data channels */
564c2539483SSimon Glass 	writel(0x0b, &regs->fc_ch0pream);
565c2539483SSimon Glass 	writel(0x16, &regs->fc_ch1pream);
566c2539483SSimon Glass 	writel(0x21, &regs->fc_ch2pream);
567c2539483SSimon Glass 
568c2539483SSimon Glass 	/* enable pixel clock and tmds data path */
569c2539483SSimon Glass 	clkdis = 0x7f;
570c2539483SSimon Glass 	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
571c2539483SSimon Glass 	writel(clkdis, &regs->mc_clkdis);
572c2539483SSimon Glass 
573c2539483SSimon Glass 	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
574c2539483SSimon Glass 	writel(clkdis, &regs->mc_clkdis);
575c2539483SSimon Glass 
576c2539483SSimon Glass 	clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
577c2539483SSimon Glass 	writel(clkdis, &regs->mc_clkdis);
578c2539483SSimon Glass }
579c2539483SSimon Glass 
580c2539483SSimon Glass /* workaround to clear the overflow condition */
581c2539483SSimon Glass static void hdmi_clear_overflow(struct rk3288_hdmi *regs)
582c2539483SSimon Glass {
583c2539483SSimon Glass 	u8 val, count;
584c2539483SSimon Glass 
585c2539483SSimon Glass 	/* tmds software reset */
586c2539483SSimon Glass 	writel((u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, &regs->mc_swrstz);
587c2539483SSimon Glass 
588c2539483SSimon Glass 	val = readl(&regs->fc_invidconf);
589c2539483SSimon Glass 
590c2539483SSimon Glass 	for (count = 0; count < 4; count++)
591c2539483SSimon Glass 		writel(val, &regs->fc_invidconf);
592c2539483SSimon Glass }
593c2539483SSimon Glass 
594c2539483SSimon Glass static void hdmi_audio_set_format(struct rk3288_hdmi *regs)
595c2539483SSimon Glass {
596c2539483SSimon Glass 	writel(HDMI_AUD_CONF0_I2S_SELECT | HDMI_AUD_CONF0_I2S_IN_EN_0,
597c2539483SSimon Glass 	       &regs->aud_conf0);
598c2539483SSimon Glass 
599c2539483SSimon Glass 
600c2539483SSimon Glass 	writel(HDMI_AUD_CONF1_I2S_MODE_STANDARD_MODE |
601c2539483SSimon Glass 	       HDMI_AUD_CONF1_I2S_WIDTH_16BIT, &regs->aud_conf1);
602c2539483SSimon Glass 
603c2539483SSimon Glass 	writel(0x00, &regs->aud_conf2);
604c2539483SSimon Glass }
605c2539483SSimon Glass 
606c2539483SSimon Glass static void hdmi_audio_fifo_reset(struct rk3288_hdmi *regs)
607c2539483SSimon Glass {
608c2539483SSimon Glass 	writel((u8)~HDMI_MC_SWRSTZ_II2SSWRST_REQ, &regs->mc_swrstz);
609c2539483SSimon Glass 	writel(HDMI_AUD_CONF0_SW_AUDIO_FIFO_RST, &regs->aud_conf0);
610c2539483SSimon Glass 
611c2539483SSimon Glass 	writel(0x00, &regs->aud_int);
612c2539483SSimon Glass 	writel(0x00, &regs->aud_int1);
613c2539483SSimon Glass }
614c2539483SSimon Glass 
615c2539483SSimon Glass static void hdmi_init_interrupt(struct rk3288_hdmi *regs)
616c2539483SSimon Glass {
617c2539483SSimon Glass 	u8 ih_mute;
618c2539483SSimon Glass 
619c2539483SSimon Glass 	/*
620c2539483SSimon Glass 	 * boot up defaults are:
621c2539483SSimon Glass 	 * hdmi_ih_mute   = 0x03 (disabled)
622c2539483SSimon Glass 	 * hdmi_ih_mute_* = 0x00 (enabled)
623c2539483SSimon Glass 	 *
624c2539483SSimon Glass 	 * disable top level interrupt bits in hdmi block
625c2539483SSimon Glass 	 */
626c2539483SSimon Glass 	ih_mute = readl(&regs->ih_mute) |
627c2539483SSimon Glass 		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
628c2539483SSimon Glass 		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
629c2539483SSimon Glass 
630c2539483SSimon Glass 	writel(ih_mute, &regs->ih_mute);
631c2539483SSimon Glass 
632c2539483SSimon Glass 	/* enable i2c master done irq */
633c2539483SSimon Glass 	writel(~0x04, &regs->i2cm_int);
634c2539483SSimon Glass 
635c2539483SSimon Glass 	/* enable i2c client nack % arbitration error irq */
636c2539483SSimon Glass 	writel(~0x44, &regs->i2cm_ctlint);
637c2539483SSimon Glass 
638c2539483SSimon Glass 	/* enable phy i2cm done irq */
639c2539483SSimon Glass 	writel(HDMI_PHY_I2CM_INT_ADDR_DONE_POL, &regs->phy_i2cm_int_addr);
640c2539483SSimon Glass 
641c2539483SSimon Glass 	/* enable phy i2cm nack & arbitration error irq */
642c2539483SSimon Glass 	writel(HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
643c2539483SSimon Glass 		HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
644c2539483SSimon Glass 		&regs->phy_i2cm_ctlint_addr);
645c2539483SSimon Glass 
646c2539483SSimon Glass 	/* enable cable hot plug irq */
647c2539483SSimon Glass 	writel((u8)~HDMI_PHY_HPD, &regs->phy_mask0);
648c2539483SSimon Glass 
649c2539483SSimon Glass 	/* clear hotplug interrupts */
650c2539483SSimon Glass 	writel(HDMI_IH_PHY_STAT0_HPD, &regs->ih_phy_stat0);
651c2539483SSimon Glass }
652c2539483SSimon Glass 
653c2539483SSimon Glass static u8 hdmi_get_plug_in_status(struct rk3288_hdmi *regs)
654c2539483SSimon Glass {
655c2539483SSimon Glass 	u8 val = readl(&regs->phy_stat0) & HDMI_PHY_HPD;
656c2539483SSimon Glass 
657c2539483SSimon Glass 	return !!(val);
658c2539483SSimon Glass }
659c2539483SSimon Glass 
660c2539483SSimon Glass static int hdmi_wait_for_hpd(struct rk3288_hdmi *regs)
661c2539483SSimon Glass {
662c2539483SSimon Glass 	ulong start;
663c2539483SSimon Glass 
664c2539483SSimon Glass 	start = get_timer(0);
665c2539483SSimon Glass 	do {
666c2539483SSimon Glass 		if (hdmi_get_plug_in_status(regs))
667c2539483SSimon Glass 			return 0;
668c2539483SSimon Glass 		udelay(100);
66970c440e5SSjoerd Simons 	} while (get_timer(start) < 300);
670c2539483SSimon Glass 
671c2539483SSimon Glass 	return -1;
672c2539483SSimon Glass }
673c2539483SSimon Glass 
674c2539483SSimon Glass static int hdmi_ddc_wait_i2c_done(struct rk3288_hdmi *regs, int msec)
675c2539483SSimon Glass {
676c2539483SSimon Glass 	u32 val;
677c2539483SSimon Glass 	ulong start;
678c2539483SSimon Glass 
679c2539483SSimon Glass 	start = get_timer(0);
680c2539483SSimon Glass 	do {
681c2539483SSimon Glass 		val = readl(&regs->ih_i2cm_stat0);
682c2539483SSimon Glass 		if (val & 0x2) {
683c2539483SSimon Glass 			writel(val, &regs->ih_i2cm_stat0);
684c2539483SSimon Glass 			return 0;
685c2539483SSimon Glass 		}
686c2539483SSimon Glass 
687c2539483SSimon Glass 		udelay(100);
688c2539483SSimon Glass 	} while (get_timer(start) < msec);
689c2539483SSimon Glass 
690c2539483SSimon Glass 	return 1;
691c2539483SSimon Glass }
692c2539483SSimon Glass 
693c2539483SSimon Glass static void hdmi_ddc_reset(struct rk3288_hdmi *regs)
694c2539483SSimon Glass {
695c2539483SSimon Glass 	clrbits_le32(&regs->i2cm_softrstz, HDMI_I2CM_SOFTRSTZ);
696c2539483SSimon Glass }
697c2539483SSimon Glass 
698c2539483SSimon Glass static int hdmi_read_edid(struct rk3288_hdmi *regs, int block, u8 *buff)
699c2539483SSimon Glass {
700c2539483SSimon Glass 	int shift = (block % 2) * 0x80;
701c2539483SSimon Glass 	int edid_read_err = 0;
702c2539483SSimon Glass 	u32 trytime = 5;
703c2539483SSimon Glass 	u32 n, j, val;
704c2539483SSimon Glass 
705c2539483SSimon Glass 	/* set ddc i2c clk which devided from ddc_clk to 100khz */
706c2539483SSimon Glass 	writel(0x7a, &regs->i2cm_ss_scl_hcnt_0_addr);
707c2539483SSimon Glass 	writel(0x8d, &regs->i2cm_ss_scl_lcnt_0_addr);
708c2539483SSimon Glass 
709c2539483SSimon Glass 	/*
710c2539483SSimon Glass 	 * TODO(sjg@chromium.org): The above values don't work - these ones
711c2539483SSimon Glass 	 * work better, but generate lots of errors in the data.
712c2539483SSimon Glass 	 */
713c2539483SSimon Glass 	writel(0x0d, &regs->i2cm_ss_scl_hcnt_0_addr);
714c2539483SSimon Glass 	writel(0x0d, &regs->i2cm_ss_scl_lcnt_0_addr);
715c2539483SSimon Glass 	clrsetbits_le32(&regs->i2cm_div, HDMI_I2CM_DIV_FAST_STD_MODE,
716c2539483SSimon Glass 			HDMI_I2CM_DIV_STD_MODE);
717c2539483SSimon Glass 
718c2539483SSimon Glass 	writel(HDMI_I2CM_SLAVE_DDC_ADDR, &regs->i2cm_slave);
719c2539483SSimon Glass 	writel(HDMI_I2CM_SEGADDR_DDC, &regs->i2cm_segaddr);
720c2539483SSimon Glass 	writel(block >> 1, &regs->i2cm_segptr);
721c2539483SSimon Glass 
722c2539483SSimon Glass 	while (trytime--) {
723c2539483SSimon Glass 		edid_read_err = 0;
724c2539483SSimon Glass 
725c2539483SSimon Glass 		for (n = 0; n < HDMI_EDID_BLOCK_SIZE / 8; n++) {
726c2539483SSimon Glass 			writel(shift + 8 * n, &regs->i2c_address);
727c2539483SSimon Glass 
728c2539483SSimon Glass 			if (block == 0)
729c2539483SSimon Glass 				clrsetbits_le32(&regs->i2cm_operation,
730c2539483SSimon Glass 						HDMI_I2CM_OPT_RD8,
731c2539483SSimon Glass 						HDMI_I2CM_OPT_RD8);
732c2539483SSimon Glass 			else
733c2539483SSimon Glass 				clrsetbits_le32(&regs->i2cm_operation,
734c2539483SSimon Glass 						HDMI_I2CM_OPT_RD8_EXT,
735c2539483SSimon Glass 						HDMI_I2CM_OPT_RD8_EXT);
736c2539483SSimon Glass 
737c2539483SSimon Glass 			if (hdmi_ddc_wait_i2c_done(regs, 10)) {
738c2539483SSimon Glass 				hdmi_ddc_reset(regs);
739c2539483SSimon Glass 				edid_read_err = 1;
740c2539483SSimon Glass 				break;
741c2539483SSimon Glass 			}
742c2539483SSimon Glass 
743c2539483SSimon Glass 			for (j = 0; j < 8; j++) {
744c2539483SSimon Glass 				val = readl(&regs->i2cm_buf0 + j);
745c2539483SSimon Glass 				buff[8 * n + j] = val;
746c2539483SSimon Glass 			}
747c2539483SSimon Glass 		}
748c2539483SSimon Glass 
749c2539483SSimon Glass 		if (!edid_read_err)
750c2539483SSimon Glass 			break;
751c2539483SSimon Glass 	}
752c2539483SSimon Glass 
753c2539483SSimon Glass 	return edid_read_err;
754c2539483SSimon Glass }
755c2539483SSimon Glass 
756c2539483SSimon Glass static u8 pre_buf[] = {
757c2539483SSimon Glass 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
758c2539483SSimon Glass 	0x04, 0x69, 0xfa, 0x23, 0xc8, 0x28, 0x01, 0x00,
759c2539483SSimon Glass 	0x10, 0x17, 0x01, 0x03, 0x80, 0x33, 0x1d, 0x78,
760c2539483SSimon Glass 	0x2a, 0xd9, 0x45, 0xa2, 0x55, 0x4d, 0xa0, 0x27,
761c2539483SSimon Glass 	0x12, 0x50, 0x54, 0xb7, 0xef, 0x00, 0x71, 0x4f,
762c2539483SSimon Glass 	0x81, 0x40, 0x81, 0x80, 0x95, 0x00, 0xb3, 0x00,
763c2539483SSimon Glass 	0xd1, 0xc0, 0x81, 0xc0, 0x81, 0x00, 0x02, 0x3a,
764c2539483SSimon Glass 	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
765c2539483SSimon Glass 	0x45, 0x00, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
766c2539483SSimon Glass 	0x00, 0x00, 0x00, 0xff, 0x00, 0x44, 0x34, 0x4c,
767c2539483SSimon Glass 	0x4d, 0x54, 0x46, 0x30, 0x37, 0x35, 0x39, 0x37,
768c2539483SSimon Glass 	0x36, 0x0a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32,
769c2539483SSimon Glass 	0x4b, 0x18, 0x53, 0x11, 0x00, 0x0a, 0x20, 0x20,
770c2539483SSimon Glass 	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
771c2539483SSimon Glass 	0x00, 0x41, 0x53, 0x55, 0x53, 0x20, 0x56, 0x53,
772c2539483SSimon Glass 	0x32, 0x33, 0x38, 0x0a, 0x20, 0x20, 0x01, 0xb0,
773c2539483SSimon Glass 	0x02, 0x03, 0x22, 0x71, 0x4f, 0x01, 0x02, 0x03,
774c2539483SSimon Glass 	0x11, 0x12, 0x13, 0x04, 0x14, 0x05, 0x0e, 0x0f,
775c2539483SSimon Glass 	0x1d, 0x1e, 0x1f, 0x10, 0x23, 0x09, 0x17, 0x07,
776c2539483SSimon Glass 	0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0c, 0x00,
777c2539483SSimon Glass 	0x10, 0x00, 0x8c, 0x0a, 0xd0, 0x8a, 0x20, 0xe0,
778c2539483SSimon Glass 	0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xfd, 0x1e,
779c2539483SSimon Glass 	0x11, 0x00, 0x00, 0x18, 0x01, 0x1d, 0x00, 0x72,
780c2539483SSimon Glass 	0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
781c2539483SSimon Glass 	0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d,
782c2539483SSimon Glass 	0x00, 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28,
783c2539483SSimon Glass 	0x55, 0x40, 0xfd, 0x1e, 0x11, 0x00, 0x00, 0x1e,
784c2539483SSimon Glass 	0x8c, 0x0a, 0xd0, 0x90, 0x20, 0x40, 0x31, 0x20,
785c2539483SSimon Glass 	0x0c, 0x40, 0x55, 0x00, 0xfd, 0x1e, 0x11, 0x00,
786c2539483SSimon Glass 	0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787c2539483SSimon Glass 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788c2539483SSimon Glass 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9,
789c2539483SSimon Glass };
790c2539483SSimon Glass 
791c2539483SSimon Glass static int rk_hdmi_read_edid(struct udevice *dev, u8 *buf, int buf_size)
792c2539483SSimon Glass {
793c2539483SSimon Glass 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
794c2539483SSimon Glass 	u32 edid_size = HDMI_EDID_BLOCK_SIZE;
795c2539483SSimon Glass 	int ret;
796c2539483SSimon Glass 
797c2539483SSimon Glass 	if (0) {
798c2539483SSimon Glass 		edid_size = sizeof(pre_buf);
799c2539483SSimon Glass 		memcpy(buf, pre_buf, edid_size);
800c2539483SSimon Glass 	} else {
801c2539483SSimon Glass 		ret = hdmi_read_edid(priv->regs, 0, buf);
802c2539483SSimon Glass 		if (ret) {
803c2539483SSimon Glass 			debug("failed to read edid.\n");
804c2539483SSimon Glass 			return -1;
805c2539483SSimon Glass 		}
806c2539483SSimon Glass 
807c2539483SSimon Glass 		if (buf[0x7e] != 0) {
808c2539483SSimon Glass 			hdmi_read_edid(priv->regs, 1,
809c2539483SSimon Glass 				       buf + HDMI_EDID_BLOCK_SIZE);
810c2539483SSimon Glass 			edid_size += HDMI_EDID_BLOCK_SIZE;
811c2539483SSimon Glass 		}
812c2539483SSimon Glass 	}
813c2539483SSimon Glass 
814c2539483SSimon Glass 	return edid_size;
815c2539483SSimon Glass }
816c2539483SSimon Glass 
817c2539483SSimon Glass static int rk_hdmi_enable(struct udevice *dev, int panel_bpp,
818c2539483SSimon Glass 			  const struct display_timing *edid)
819c2539483SSimon Glass {
820c2539483SSimon Glass 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
821c2539483SSimon Glass 	struct rk3288_hdmi *regs = priv->regs;
822c2539483SSimon Glass 	int ret;
823c2539483SSimon Glass 
824c2539483SSimon Glass 	debug("hdmi, mode info : clock %d hdis %d vdis %d\n",
825c2539483SSimon Glass 	      edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ);
826c2539483SSimon Glass 
827c2539483SSimon Glass 	hdmi_av_composer(regs, edid);
828c2539483SSimon Glass 
829c2539483SSimon Glass 	ret = hdmi_phy_init(regs, edid->pixelclock.typ);
830c2539483SSimon Glass 	if (ret)
831c2539483SSimon Glass 		return ret;
832c2539483SSimon Glass 
833c2539483SSimon Glass 	hdmi_enable_video_path(regs);
834c2539483SSimon Glass 
835c2539483SSimon Glass 	hdmi_audio_fifo_reset(regs);
836c2539483SSimon Glass 	hdmi_audio_set_format(regs);
837c2539483SSimon Glass 	hdmi_audio_set_samplerate(regs, edid->pixelclock.typ);
838c2539483SSimon Glass 
839c2539483SSimon Glass 	hdmi_video_packetize(regs);
840c2539483SSimon Glass 	hdmi_video_csc(regs);
841c2539483SSimon Glass 	hdmi_video_sample(regs);
842c2539483SSimon Glass 
843c2539483SSimon Glass 	hdmi_clear_overflow(regs);
844c2539483SSimon Glass 
845c2539483SSimon Glass 	return 0;
846c2539483SSimon Glass }
847c2539483SSimon Glass 
848c2539483SSimon Glass static int rk_hdmi_ofdata_to_platdata(struct udevice *dev)
849c2539483SSimon Glass {
850c2539483SSimon Glass 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
851c2539483SSimon Glass 
852c2539483SSimon Glass 	priv->regs = (struct rk3288_hdmi *)dev_get_addr(dev);
853c2539483SSimon Glass 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
854c2539483SSimon Glass 
855c2539483SSimon Glass 	return 0;
856c2539483SSimon Glass }
857c2539483SSimon Glass 
858c2539483SSimon Glass static int rk_hdmi_probe(struct udevice *dev)
859c2539483SSimon Glass {
860c2539483SSimon Glass 	struct display_plat *uc_plat = dev_get_uclass_platdata(dev);
861c2539483SSimon Glass 	struct rk_hdmi_priv *priv = dev_get_priv(dev);
862135aa950SStephen Warren 	struct udevice *reg;
863135aa950SStephen Warren 	struct clk clk;
864c2539483SSimon Glass 	int ret;
865c2539483SSimon Glass 	int vop_id = uc_plat->source_id;
866c2539483SSimon Glass 
867c2539483SSimon Glass 	ret = clk_get_by_index(dev, 0, &clk);
868c2539483SSimon Glass 	if (ret >= 0) {
869135aa950SStephen Warren 		ret = clk_set_rate(&clk, 0);
870135aa950SStephen Warren 		clk_free(&clk);
871c2539483SSimon Glass 	}
872c2539483SSimon Glass 	if (ret) {
873c2539483SSimon Glass 		debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret);
874c2539483SSimon Glass 		return ret;
875c2539483SSimon Glass 	}
876c2539483SSimon Glass 
877c2539483SSimon Glass 	/*
878c2539483SSimon Glass 	 * Configure the maximum clock to permit whatever resolution the
879c2539483SSimon Glass 	 * monitor wants
880c2539483SSimon Glass 	 */
881c2539483SSimon Glass 	ret = clk_get_by_index(uc_plat->src_dev, 0, &clk);
882c2539483SSimon Glass 	if (ret >= 0) {
883135aa950SStephen Warren 		ret = clk_set_rate(&clk, 384000000);
884135aa950SStephen Warren 		clk_free(&clk);
885c2539483SSimon Glass 	}
886c2539483SSimon Glass 	if (ret < 0) {
887c2539483SSimon Glass 		debug("%s: Failed to set clock in source device '%s': ret=%d\n",
888c2539483SSimon Glass 		      __func__, uc_plat->src_dev->name, ret);
889c2539483SSimon Glass 		return ret;
890c2539483SSimon Glass 	}
891c2539483SSimon Glass 
892c2539483SSimon Glass 	ret = regulator_get_by_platname("vcc50_hdmi", &reg);
893c2539483SSimon Glass 	if (!ret)
894c2539483SSimon Glass 		ret = regulator_set_enable(reg, true);
895c2539483SSimon Glass 	if (ret)
896c2539483SSimon Glass 		debug("%s: Cannot set regulator vcc50_hdmi\n", __func__);
897c2539483SSimon Glass 
898c2539483SSimon Glass 	/* hdmi source select hdmi controller */
899c2539483SSimon Glass 	rk_setreg(&priv->grf->soc_con6, 1 << 15);
900c2539483SSimon Glass 
901c2539483SSimon Glass 	/* hdmi data from vop id */
902*e4ab3d71SSimon Glass 	rk_clrsetreg(&priv->grf->soc_con6, 1 << 4,
903*e4ab3d71SSimon Glass 		     (vop_id == 1) ? (1 << 4) : 0);
904c2539483SSimon Glass 
905c2539483SSimon Glass 	ret = hdmi_wait_for_hpd(priv->regs);
906c2539483SSimon Glass 	if (ret < 0) {
907c2539483SSimon Glass 		debug("hdmi can not get hpd signal\n");
908c2539483SSimon Glass 		return -1;
909c2539483SSimon Glass 	}
910c2539483SSimon Glass 
911c2539483SSimon Glass 	hdmi_init_interrupt(priv->regs);
912c2539483SSimon Glass 
913c2539483SSimon Glass 	return 0;
914c2539483SSimon Glass }
915c2539483SSimon Glass 
916c2539483SSimon Glass static const struct dm_display_ops rk_hdmi_ops = {
917c2539483SSimon Glass 	.read_edid = rk_hdmi_read_edid,
918c2539483SSimon Glass 	.enable = rk_hdmi_enable,
919c2539483SSimon Glass };
920c2539483SSimon Glass 
921c2539483SSimon Glass static const struct udevice_id rk_hdmi_ids[] = {
922c2539483SSimon Glass 	{ .compatible = "rockchip,rk3288-dw-hdmi" },
923c2539483SSimon Glass 	{ }
924c2539483SSimon Glass };
925c2539483SSimon Glass 
926c2539483SSimon Glass U_BOOT_DRIVER(hdmi_rockchip) = {
927c2539483SSimon Glass 	.name	= "hdmi_rockchip",
928c2539483SSimon Glass 	.id	= UCLASS_DISPLAY,
929c2539483SSimon Glass 	.of_match = rk_hdmi_ids,
930c2539483SSimon Glass 	.ops	= &rk_hdmi_ops,
931c2539483SSimon Glass 	.ofdata_to_platdata	= rk_hdmi_ofdata_to_platdata,
932c2539483SSimon Glass 	.probe	= rk_hdmi_probe,
933c2539483SSimon Glass 	.priv_auto_alloc_size	 = sizeof(struct rk_hdmi_priv),
934c2539483SSimon Glass };
935