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