1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2015 Broadcom |
4 | * Copyright (c) 2014 The Linux Foundation. All rights reserved. |
5 | * Copyright (C) 2013 Red Hat |
6 | * Author: Rob Clark <robdclark@gmail.com> |
7 | */ |
8 | |
9 | #include "vc4_hdmi.h" |
10 | #include "vc4_regs.h" |
11 | #include "vc4_hdmi_regs.h" |
12 | |
13 | #define VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB BIT(5) |
14 | #define VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB BIT(4) |
15 | #define VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET BIT(3) |
16 | #define VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET BIT(2) |
17 | #define VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET BIT(1) |
18 | #define VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET BIT(0) |
19 | |
20 | #define VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN BIT(4) |
21 | |
22 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_SHIFT 29 |
23 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP_MASK VC4_MASK(31, 29) |
24 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_SHIFT 24 |
25 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV_MASK VC4_MASK(28, 24) |
26 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_SHIFT 21 |
27 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP_MASK VC4_MASK(23, 21) |
28 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_SHIFT 16 |
29 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV_MASK VC4_MASK(20, 16) |
30 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_SHIFT 13 |
31 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP_MASK VC4_MASK(15, 13) |
32 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_SHIFT 8 |
33 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV_MASK VC4_MASK(12, 8) |
34 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_SHIFT 5 |
35 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP_MASK VC4_MASK(7, 5) |
36 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_SHIFT 0 |
37 | #define VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV_MASK VC4_MASK(4, 0) |
38 | |
39 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_SHIFT 15 |
40 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2_MASK VC4_MASK(19, 15) |
41 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_SHIFT 10 |
42 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1_MASK VC4_MASK(14, 10) |
43 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_SHIFT 5 |
44 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0_MASK VC4_MASK(9, 5) |
45 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_SHIFT 0 |
46 | #define VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK_MASK VC4_MASK(4, 0) |
47 | |
48 | #define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_SHIFT 16 |
49 | #define VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN_MASK VC4_MASK(19, 16) |
50 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_SHIFT 12 |
51 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2_MASK VC4_MASK(15, 12) |
52 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_SHIFT 8 |
53 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1_MASK VC4_MASK(11, 8) |
54 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_SHIFT 4 |
55 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0_MASK VC4_MASK(7, 4) |
56 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_SHIFT 0 |
57 | #define VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK_MASK VC4_MASK(3, 0) |
58 | |
59 | #define VC4_HDMI_TX_PHY_CTL_3_RP_SHIFT 17 |
60 | #define VC4_HDMI_TX_PHY_CTL_3_RP_MASK VC4_MASK(19, 17) |
61 | #define VC4_HDMI_TX_PHY_CTL_3_RZ_SHIFT 12 |
62 | #define VC4_HDMI_TX_PHY_CTL_3_RZ_MASK VC4_MASK(16, 12) |
63 | #define VC4_HDMI_TX_PHY_CTL_3_CP1_SHIFT 10 |
64 | #define VC4_HDMI_TX_PHY_CTL_3_CP1_MASK VC4_MASK(11, 10) |
65 | #define VC4_HDMI_TX_PHY_CTL_3_CP_SHIFT 8 |
66 | #define VC4_HDMI_TX_PHY_CTL_3_CP_MASK VC4_MASK(9, 8) |
67 | #define VC4_HDMI_TX_PHY_CTL_3_CZ_SHIFT 6 |
68 | #define VC4_HDMI_TX_PHY_CTL_3_CZ_MASK VC4_MASK(7, 6) |
69 | #define VC4_HDMI_TX_PHY_CTL_3_ICP_SHIFT 0 |
70 | #define VC4_HDMI_TX_PHY_CTL_3_ICP_MASK VC4_MASK(5, 0) |
71 | |
72 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE BIT(13) |
73 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VC_RANGE_EN BIT(12) |
74 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_LOW BIT(11) |
75 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_EMULATE_VC_HIGH BIT(10) |
76 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_SHIFT 9 |
77 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL_MASK VC4_MASK(9, 9) |
78 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_FB_DIV2 BIT(8) |
79 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_POST_DIV2 BIT(7) |
80 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN BIT(6) |
81 | #define VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK BIT(5) |
82 | |
83 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_SHIFT 16 |
84 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_CPP_MASK VC4_MASK(27, 16) |
85 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_SHIFT 14 |
86 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY_MASK VC4_MASK(15, 14) |
87 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE BIT(13) |
88 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_SHIFT 11 |
89 | #define VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL_MASK VC4_MASK(12, 11) |
90 | |
91 | #define VC4_HDMI_TX_PHY_CLK_DIV_VCO_SHIFT 8 |
92 | #define VC4_HDMI_TX_PHY_CLK_DIV_VCO_MASK VC4_MASK(15, 8) |
93 | |
94 | #define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_SHIFT 0 |
95 | #define VC4_HDMI_TX_PHY_PLL_CFG_PDIV_MASK VC4_MASK(3, 0) |
96 | |
97 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_MASK VC4_MASK(13, 12) |
98 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL_SHIFT 12 |
99 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_MASK VC4_MASK(9, 8) |
100 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL_SHIFT 8 |
101 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_MASK VC4_MASK(5, 4) |
102 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL_SHIFT 4 |
103 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_MASK VC4_MASK(1, 0) |
104 | #define VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL_SHIFT 0 |
105 | |
106 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK VC4_MASK(27, 0) |
107 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_SHIFT 0 |
108 | |
109 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK VC4_MASK(27, 0) |
110 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_SHIFT 0 |
111 | |
112 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_MASK VC4_MASK(31, 16) |
113 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD_SHIFT 16 |
114 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_MASK VC4_MASK(15, 0) |
115 | #define VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD_SHIFT 0 |
116 | |
117 | #define VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS BIT(19) |
118 | #define VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR BIT(17) |
119 | #define VC4_HDMI_RM_CONTROL_FREE_RUN BIT(4) |
120 | |
121 | #define VC4_HDMI_RM_OFFSET_ONLY BIT(31) |
122 | #define VC4_HDMI_RM_OFFSET_OFFSET_SHIFT 0 |
123 | #define VC4_HDMI_RM_OFFSET_OFFSET_MASK VC4_MASK(30, 0) |
124 | |
125 | #define VC4_HDMI_RM_FORMAT_SHIFT_SHIFT 24 |
126 | #define VC4_HDMI_RM_FORMAT_SHIFT_MASK VC4_MASK(25, 24) |
127 | |
128 | #define OSCILLATOR_FREQUENCY 54000000 |
129 | |
130 | void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, |
131 | struct vc4_hdmi_connector_state *conn_state) |
132 | { |
133 | unsigned long flags; |
134 | |
135 | /* PHY should be in reset, like |
136 | * vc4_hdmi_encoder_disable() does. |
137 | */ |
138 | |
139 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
140 | |
141 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); |
142 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0); |
143 | |
144 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
145 | } |
146 | |
147 | void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) |
148 | { |
149 | unsigned long flags; |
150 | |
151 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
152 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0xf << 16); |
153 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
154 | } |
155 | |
156 | void vc4_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) |
157 | { |
158 | unsigned long flags; |
159 | |
160 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
161 | HDMI_WRITE(HDMI_TX_PHY_CTL_0, |
162 | HDMI_READ(HDMI_TX_PHY_CTL_0) & |
163 | ~VC4_HDMI_TX_PHY_RNG_PWRDN); |
164 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
165 | } |
166 | |
167 | void vc4_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) |
168 | { |
169 | unsigned long flags; |
170 | |
171 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
172 | HDMI_WRITE(HDMI_TX_PHY_CTL_0, |
173 | HDMI_READ(HDMI_TX_PHY_CTL_0) | |
174 | VC4_HDMI_TX_PHY_RNG_PWRDN); |
175 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
176 | } |
177 | |
178 | static unsigned long long |
179 | phy_get_vco_freq(unsigned long long clock, u8 *vco_sel, u8 *vco_div) |
180 | { |
181 | unsigned long long vco_freq = clock; |
182 | unsigned int _vco_div = 0; |
183 | unsigned int _vco_sel = 0; |
184 | |
185 | while (vco_freq < 3000000000ULL) { |
186 | _vco_div++; |
187 | vco_freq = clock * _vco_div * 10; |
188 | } |
189 | |
190 | if (vco_freq > 4500000000ULL) |
191 | _vco_sel = 1; |
192 | |
193 | *vco_sel = _vco_sel; |
194 | *vco_div = _vco_div; |
195 | |
196 | return vco_freq; |
197 | } |
198 | |
199 | static u8 phy_get_cp_current(unsigned long vco_freq) |
200 | { |
201 | if (vco_freq < 3700000000ULL) |
202 | return 0x1c; |
203 | |
204 | return 0x18; |
205 | } |
206 | |
207 | static u32 phy_get_rm_offset(unsigned long long vco_freq) |
208 | { |
209 | unsigned long long fref = OSCILLATOR_FREQUENCY; |
210 | u64 offset = 0; |
211 | |
212 | /* RM offset is stored as 9.22 format */ |
213 | offset = vco_freq * 2; |
214 | offset = offset << 22; |
215 | do_div(offset, fref); |
216 | offset >>= 2; |
217 | |
218 | return offset; |
219 | } |
220 | |
221 | static u8 phy_get_vco_gain(unsigned long long vco_freq) |
222 | { |
223 | if (vco_freq < 3350000000ULL) |
224 | return 0xf; |
225 | |
226 | if (vco_freq < 3700000000ULL) |
227 | return 0xc; |
228 | |
229 | if (vco_freq < 4050000000ULL) |
230 | return 0x6; |
231 | |
232 | if (vco_freq < 4800000000ULL) |
233 | return 0x5; |
234 | |
235 | if (vco_freq < 5200000000ULL) |
236 | return 0x7; |
237 | |
238 | return 0x2; |
239 | } |
240 | |
241 | struct phy_lane_settings { |
242 | struct { |
243 | u8 preemphasis; |
244 | u8 main_driver; |
245 | } amplitude; |
246 | |
247 | u8 res_sel_data; |
248 | u8 term_res_sel_data; |
249 | }; |
250 | |
251 | struct phy_settings { |
252 | unsigned long long min_rate; |
253 | unsigned long long max_rate; |
254 | struct phy_lane_settings channel[3]; |
255 | struct phy_lane_settings clock; |
256 | }; |
257 | |
258 | static const struct phy_settings vc5_hdmi_phy_settings[] = { |
259 | { |
260 | 0, 50000000, |
261 | { |
262 | {{0x0, 0x0A}, 0x12, 0x0}, |
263 | {{0x0, 0x0A}, 0x12, 0x0}, |
264 | {{0x0, 0x0A}, 0x12, 0x0} |
265 | }, |
266 | {{0x0, 0x0A}, 0x18, 0x0}, |
267 | }, |
268 | { |
269 | 50000001, 75000000, |
270 | { |
271 | {{0x0, 0x09}, 0x12, 0x0}, |
272 | {{0x0, 0x09}, 0x12, 0x0}, |
273 | {{0x0, 0x09}, 0x12, 0x0} |
274 | }, |
275 | {{0x0, 0x0C}, 0x18, 0x3}, |
276 | }, |
277 | { |
278 | 75000001, 165000000, |
279 | { |
280 | {{0x0, 0x09}, 0x12, 0x0}, |
281 | {{0x0, 0x09}, 0x12, 0x0}, |
282 | {{0x0, 0x09}, 0x12, 0x0} |
283 | }, |
284 | {{0x0, 0x0C}, 0x18, 0x3}, |
285 | }, |
286 | { |
287 | 165000001, 250000000, |
288 | { |
289 | {{0x0, 0x0F}, 0x12, 0x1}, |
290 | {{0x0, 0x0F}, 0x12, 0x1}, |
291 | {{0x0, 0x0F}, 0x12, 0x1} |
292 | }, |
293 | {{0x0, 0x0C}, 0x18, 0x3}, |
294 | }, |
295 | { |
296 | 250000001, 340000000, |
297 | { |
298 | {{0x2, 0x0D}, 0x12, 0x1}, |
299 | {{0x2, 0x0D}, 0x12, 0x1}, |
300 | {{0x2, 0x0D}, 0x12, 0x1} |
301 | }, |
302 | {{0x0, 0x0C}, 0x18, 0xF}, |
303 | }, |
304 | { |
305 | 340000001, 450000000, |
306 | { |
307 | {{0x0, 0x1B}, 0x12, 0xF}, |
308 | {{0x0, 0x1B}, 0x12, 0xF}, |
309 | {{0x0, 0x1B}, 0x12, 0xF} |
310 | }, |
311 | {{0x0, 0x0A}, 0x12, 0xF}, |
312 | }, |
313 | { |
314 | 450000001, 600000000, |
315 | { |
316 | {{0x0, 0x1C}, 0x12, 0xF}, |
317 | {{0x0, 0x1C}, 0x12, 0xF}, |
318 | {{0x0, 0x1C}, 0x12, 0xF} |
319 | }, |
320 | {{0x0, 0x0B}, 0x13, 0xF}, |
321 | }, |
322 | }; |
323 | |
324 | static const struct phy_settings *phy_get_settings(unsigned long long tmds_rate) |
325 | { |
326 | unsigned int count = ARRAY_SIZE(vc5_hdmi_phy_settings); |
327 | unsigned int i; |
328 | |
329 | for (i = 0; i < count; i++) { |
330 | const struct phy_settings *s = &vc5_hdmi_phy_settings[i]; |
331 | |
332 | if (tmds_rate >= s->min_rate && tmds_rate <= s->max_rate) |
333 | return s; |
334 | } |
335 | |
336 | /* |
337 | * If the pixel clock exceeds our max setting, try the max |
338 | * setting anyway. |
339 | */ |
340 | return &vc5_hdmi_phy_settings[count - 1]; |
341 | } |
342 | |
343 | static const struct phy_lane_settings * |
344 | phy_get_channel_settings(enum vc4_hdmi_phy_channel chan, |
345 | unsigned long long tmds_rate) |
346 | { |
347 | const struct phy_settings *settings = phy_get_settings(tmds_rate); |
348 | |
349 | if (chan == PHY_LANE_CK) |
350 | return &settings->clock; |
351 | |
352 | return &settings->channel[chan]; |
353 | } |
354 | |
355 | static void vc5_hdmi_reset_phy(struct vc4_hdmi *vc4_hdmi) |
356 | { |
357 | lockdep_assert_held(&vc4_hdmi->hw_lock); |
358 | |
359 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, 0x0f); |
360 | HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, BIT(10)); |
361 | } |
362 | |
363 | void vc5_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, |
364 | struct vc4_hdmi_connector_state *conn_state) |
365 | { |
366 | const struct phy_lane_settings *chan0_settings, *chan1_settings, *chan2_settings, *clock_settings; |
367 | const struct vc4_hdmi_variant *variant = vc4_hdmi->variant; |
368 | unsigned long long pixel_freq = conn_state->tmds_char_rate; |
369 | unsigned long long vco_freq; |
370 | unsigned char word_sel; |
371 | unsigned long flags; |
372 | u8 vco_sel, vco_div; |
373 | |
374 | vco_freq = phy_get_vco_freq(clock: pixel_freq, vco_sel: &vco_sel, vco_div: &vco_div); |
375 | |
376 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
377 | |
378 | vc5_hdmi_reset_phy(vc4_hdmi); |
379 | |
380 | HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, |
381 | VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); |
382 | |
383 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, |
384 | HDMI_READ(HDMI_TX_PHY_RESET_CTL) & |
385 | ~VC4_HDMI_TX_PHY_RESET_CTL_TX_0_RESET & |
386 | ~VC4_HDMI_TX_PHY_RESET_CTL_TX_1_RESET & |
387 | ~VC4_HDMI_TX_PHY_RESET_CTL_TX_2_RESET & |
388 | ~VC4_HDMI_TX_PHY_RESET_CTL_TX_CK_RESET); |
389 | |
390 | HDMI_WRITE(HDMI_RM_CONTROL, |
391 | HDMI_READ(HDMI_RM_CONTROL) | |
392 | VC4_HDMI_RM_CONTROL_EN_FREEZE_COUNTERS | |
393 | VC4_HDMI_RM_CONTROL_EN_LOAD_INTEGRATOR | |
394 | VC4_HDMI_RM_CONTROL_FREE_RUN); |
395 | |
396 | HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1, |
397 | (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1) & |
398 | ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT_MASK) | |
399 | VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_1_MIN_LIMIT)); |
400 | |
401 | HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2, |
402 | (HDMI_READ(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2) & |
403 | ~VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT_MASK) | |
404 | VC4_SET_FIELD(0, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_2_MAX_LIMIT)); |
405 | |
406 | HDMI_WRITE(HDMI_RM_OFFSET, |
407 | VC4_SET_FIELD(phy_get_rm_offset(vco_freq), |
408 | VC4_HDMI_RM_OFFSET_OFFSET) | |
409 | VC4_HDMI_RM_OFFSET_ONLY); |
410 | |
411 | HDMI_WRITE(HDMI_TX_PHY_CLK_DIV, |
412 | VC4_SET_FIELD(vco_div, VC4_HDMI_TX_PHY_CLK_DIV_VCO)); |
413 | |
414 | HDMI_WRITE(HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4, |
415 | VC4_SET_FIELD(0xe147, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_HOLD_THRESHOLD) | |
416 | VC4_SET_FIELD(0xe14, VC4_HDMI_TX_PHY_PLL_CALIBRATION_CONFIG_4_STABLE_THRESHOLD)); |
417 | |
418 | HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_0, |
419 | VC4_HDMI_TX_PHY_PLL_CTL_0_ENA_VCO_CLK | |
420 | VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_CONT_EN | |
421 | VC4_HDMI_TX_PHY_PLL_CTL_0_MASH11_MODE | |
422 | VC4_SET_FIELD(vco_sel, VC4_HDMI_TX_PHY_PLL_CTL_0_VCO_SEL)); |
423 | |
424 | HDMI_WRITE(HDMI_TX_PHY_PLL_CTL_1, |
425 | HDMI_READ(HDMI_TX_PHY_PLL_CTL_1) | |
426 | VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_ENABLE | |
427 | VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_PLL_CTL_1_POST_RST_SEL) | |
428 | VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CTL_1_FREQ_DOUBLER_DELAY) | |
429 | VC4_SET_FIELD(0x8a, VC4_HDMI_TX_PHY_PLL_CTL_1_CPP)); |
430 | |
431 | HDMI_WRITE(HDMI_RM_FORMAT, |
432 | HDMI_READ(HDMI_RM_FORMAT) | |
433 | VC4_SET_FIELD(2, VC4_HDMI_RM_FORMAT_SHIFT)); |
434 | |
435 | HDMI_WRITE(HDMI_TX_PHY_PLL_CFG, |
436 | HDMI_READ(HDMI_TX_PHY_PLL_CFG) | |
437 | VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_PLL_CFG_PDIV)); |
438 | |
439 | if (pixel_freq >= 340000000) |
440 | word_sel = 3; |
441 | else |
442 | word_sel = 0; |
443 | HDMI_WRITE(HDMI_TX_PHY_TMDS_CLK_WORD_SEL, word_sel); |
444 | |
445 | HDMI_WRITE(HDMI_TX_PHY_CTL_3, |
446 | VC4_SET_FIELD(phy_get_cp_current(vco_freq), |
447 | VC4_HDMI_TX_PHY_CTL_3_ICP) | |
448 | VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP) | |
449 | VC4_SET_FIELD(1, VC4_HDMI_TX_PHY_CTL_3_CP1) | |
450 | VC4_SET_FIELD(3, VC4_HDMI_TX_PHY_CTL_3_CZ) | |
451 | VC4_SET_FIELD(4, VC4_HDMI_TX_PHY_CTL_3_RP) | |
452 | VC4_SET_FIELD(6, VC4_HDMI_TX_PHY_CTL_3_RZ)); |
453 | |
454 | chan0_settings = |
455 | phy_get_channel_settings(chan: variant->phy_lane_mapping[PHY_LANE_0], |
456 | tmds_rate: pixel_freq); |
457 | chan1_settings = |
458 | phy_get_channel_settings(chan: variant->phy_lane_mapping[PHY_LANE_1], |
459 | tmds_rate: pixel_freq); |
460 | chan2_settings = |
461 | phy_get_channel_settings(chan: variant->phy_lane_mapping[PHY_LANE_2], |
462 | tmds_rate: pixel_freq); |
463 | clock_settings = |
464 | phy_get_channel_settings(chan: variant->phy_lane_mapping[PHY_LANE_CK], |
465 | tmds_rate: pixel_freq); |
466 | |
467 | HDMI_WRITE(HDMI_TX_PHY_CTL_0, |
468 | VC4_SET_FIELD(chan0_settings->amplitude.preemphasis, |
469 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_PREEMP) | |
470 | VC4_SET_FIELD(chan0_settings->amplitude.main_driver, |
471 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_0_MAINDRV) | |
472 | VC4_SET_FIELD(chan1_settings->amplitude.preemphasis, |
473 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_PREEMP) | |
474 | VC4_SET_FIELD(chan1_settings->amplitude.main_driver, |
475 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_1_MAINDRV) | |
476 | VC4_SET_FIELD(chan2_settings->amplitude.preemphasis, |
477 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_PREEMP) | |
478 | VC4_SET_FIELD(chan2_settings->amplitude.main_driver, |
479 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_2_MAINDRV) | |
480 | VC4_SET_FIELD(clock_settings->amplitude.preemphasis, |
481 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_PREEMP) | |
482 | VC4_SET_FIELD(clock_settings->amplitude.main_driver, |
483 | VC4_HDMI_TX_PHY_CTL_0_PREEMP_CK_MAINDRV)); |
484 | |
485 | HDMI_WRITE(HDMI_TX_PHY_CTL_1, |
486 | HDMI_READ(HDMI_TX_PHY_CTL_1) | |
487 | VC4_SET_FIELD(chan0_settings->res_sel_data, |
488 | VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA0) | |
489 | VC4_SET_FIELD(chan1_settings->res_sel_data, |
490 | VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA1) | |
491 | VC4_SET_FIELD(chan2_settings->res_sel_data, |
492 | VC4_HDMI_TX_PHY_CTL_1_RES_SEL_DATA2) | |
493 | VC4_SET_FIELD(clock_settings->res_sel_data, |
494 | VC4_HDMI_TX_PHY_CTL_1_RES_SEL_CK)); |
495 | |
496 | HDMI_WRITE(HDMI_TX_PHY_CTL_2, |
497 | VC4_SET_FIELD(chan0_settings->term_res_sel_data, |
498 | VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA0) | |
499 | VC4_SET_FIELD(chan1_settings->term_res_sel_data, |
500 | VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA1) | |
501 | VC4_SET_FIELD(chan2_settings->term_res_sel_data, |
502 | VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELDATA2) | |
503 | VC4_SET_FIELD(clock_settings->term_res_sel_data, |
504 | VC4_HDMI_TX_PHY_CTL_2_TERM_RES_SELCK) | |
505 | VC4_SET_FIELD(phy_get_vco_gain(vco_freq), |
506 | VC4_HDMI_TX_PHY_CTL_2_VCO_GAIN)); |
507 | |
508 | HDMI_WRITE(HDMI_TX_PHY_CHANNEL_SWAP, |
509 | VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_0], |
510 | VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX0_OUT_SEL) | |
511 | VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_1], |
512 | VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX1_OUT_SEL) | |
513 | VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_2], |
514 | VC4_HDMI_TX_PHY_CHANNEL_SWAP_TX2_OUT_SEL) | |
515 | VC4_SET_FIELD(variant->phy_lane_mapping[PHY_LANE_CK], |
516 | VC4_HDMI_TX_PHY_CHANNEL_SWAP_TXCK_OUT_SEL)); |
517 | |
518 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, |
519 | HDMI_READ(HDMI_TX_PHY_RESET_CTL) & |
520 | ~(VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | |
521 | VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB)); |
522 | |
523 | HDMI_WRITE(HDMI_TX_PHY_RESET_CTL, |
524 | HDMI_READ(HDMI_TX_PHY_RESET_CTL) | |
525 | VC4_HDMI_TX_PHY_RESET_CTL_PLL_RESETB | |
526 | VC4_HDMI_TX_PHY_RESET_CTL_PLLDIV_RESETB); |
527 | |
528 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
529 | } |
530 | |
531 | void vc5_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi) |
532 | { |
533 | unsigned long flags; |
534 | |
535 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
536 | vc5_hdmi_reset_phy(vc4_hdmi); |
537 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
538 | } |
539 | |
540 | void vc5_hdmi_phy_rng_enable(struct vc4_hdmi *vc4_hdmi) |
541 | { |
542 | unsigned long flags; |
543 | |
544 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
545 | HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, |
546 | HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) & |
547 | ~VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); |
548 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
549 | } |
550 | |
551 | void vc5_hdmi_phy_rng_disable(struct vc4_hdmi *vc4_hdmi) |
552 | { |
553 | unsigned long flags; |
554 | |
555 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
556 | HDMI_WRITE(HDMI_TX_PHY_POWERDOWN_CTL, |
557 | HDMI_READ(HDMI_TX_PHY_POWERDOWN_CTL) | |
558 | VC4_HDMI_TX_PHY_POWERDOWN_CTL_RNDGEN_PWRDN); |
559 | spin_unlock_irqrestore(lock: &vc4_hdmi->hw_lock, flags); |
560 | } |
561 | |