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