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