1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Analogix DP (Display port) core register interface driver. |
4 | * |
5 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. |
6 | * Author: Jingoo Han <jg1.han@samsung.com> |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/io.h> |
13 | #include <linux/iopoll.h> |
14 | |
15 | #include <drm/bridge/analogix_dp.h> |
16 | |
17 | #include "analogix_dp_core.h" |
18 | #include "analogix_dp_reg.h" |
19 | |
20 | #define COMMON_INT_MASK_1 0 |
21 | #define COMMON_INT_MASK_2 0 |
22 | #define COMMON_INT_MASK_3 0 |
23 | #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) |
24 | #define INT_STA_MASK INT_HPD |
25 | |
26 | void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable) |
27 | { |
28 | u32 reg; |
29 | |
30 | if (enable) { |
31 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
32 | reg |= HDCP_VIDEO_MUTE; |
33 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
34 | } else { |
35 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
36 | reg &= ~HDCP_VIDEO_MUTE; |
37 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
38 | } |
39 | } |
40 | |
41 | void analogix_dp_stop_video(struct analogix_dp_device *dp) |
42 | { |
43 | u32 reg; |
44 | |
45 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
46 | reg &= ~VIDEO_EN; |
47 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
48 | } |
49 | |
50 | void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable) |
51 | { |
52 | u32 reg; |
53 | |
54 | if (enable) |
55 | reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | |
56 | LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; |
57 | else |
58 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | |
59 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; |
60 | |
61 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LANE_MAP); |
62 | } |
63 | |
64 | void analogix_dp_init_analog_param(struct analogix_dp_device *dp) |
65 | { |
66 | u32 reg; |
67 | |
68 | reg = TX_TERMINAL_CTRL_50_OHM; |
69 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_ANALOG_CTL_1); |
70 | |
71 | reg = SEL_24M | TX_DVDD_BIT_1_0625V; |
72 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2); |
73 | |
74 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) { |
75 | reg = REF_CLK_24M; |
76 | if (dp->plat_data->dev_type == RK3288_DP) |
77 | reg ^= REF_CLK_MASK; |
78 | |
79 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_PLL_REG_1); |
80 | writel(val: 0x95, addr: dp->reg_base + ANALOGIX_DP_PLL_REG_2); |
81 | writel(val: 0x40, addr: dp->reg_base + ANALOGIX_DP_PLL_REG_3); |
82 | writel(val: 0x58, addr: dp->reg_base + ANALOGIX_DP_PLL_REG_4); |
83 | writel(val: 0x22, addr: dp->reg_base + ANALOGIX_DP_PLL_REG_5); |
84 | } |
85 | |
86 | reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO; |
87 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_ANALOG_CTL_3); |
88 | |
89 | reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | |
90 | TX_CUR1_2X | TX_CUR_16_MA; |
91 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_PLL_FILTER_CTL_1); |
92 | |
93 | reg = CH3_AMP_400_MV | CH2_AMP_400_MV | |
94 | CH1_AMP_400_MV | CH0_AMP_400_MV; |
95 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TX_AMP_TUNING_CTL); |
96 | } |
97 | |
98 | void analogix_dp_init_interrupt(struct analogix_dp_device *dp) |
99 | { |
100 | /* Set interrupt pin assertion polarity as high */ |
101 | writel(INT_POL1 | INT_POL0, addr: dp->reg_base + ANALOGIX_DP_INT_CTL); |
102 | |
103 | /* Clear pending regisers */ |
104 | writel(val: 0xff, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); |
105 | writel(val: 0x4f, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_2); |
106 | writel(val: 0xe0, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_3); |
107 | writel(val: 0xe7, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); |
108 | writel(val: 0x63, addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
109 | |
110 | /* 0:mask,1: unmask */ |
111 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); |
112 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); |
113 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); |
114 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); |
115 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_INT_STA_MASK); |
116 | } |
117 | |
118 | void analogix_dp_reset(struct analogix_dp_device *dp) |
119 | { |
120 | u32 reg; |
121 | |
122 | analogix_dp_stop_video(dp); |
123 | analogix_dp_enable_video_mute(dp, enable: 0); |
124 | |
125 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
126 | reg = RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N | |
127 | SW_FUNC_EN_N; |
128 | else |
129 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | |
130 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | |
131 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; |
132 | |
133 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_1); |
134 | |
135 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | |
136 | SERDES_FIFO_FUNC_EN_N | |
137 | LS_CLK_DOMAIN_FUNC_EN_N; |
138 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
139 | |
140 | usleep_range(min: 20, max: 30); |
141 | |
142 | analogix_dp_lane_swap(dp, enable: 0); |
143 | |
144 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_1); |
145 | writel(val: 0x40, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_2); |
146 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
147 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
148 | |
149 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
150 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_HDCP_CTL); |
151 | |
152 | writel(val: 0x5e, addr: dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_L); |
153 | writel(val: 0x1a, addr: dp->reg_base + ANALOGIX_DP_HPD_DEGLITCH_H); |
154 | |
155 | writel(val: 0x10, addr: dp->reg_base + ANALOGIX_DP_LINK_DEBUG_CTL); |
156 | |
157 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_PHY_TEST); |
158 | |
159 | writel(val: 0x0, addr: dp->reg_base + ANALOGIX_DP_VIDEO_FIFO_THRD); |
160 | writel(val: 0x20, addr: dp->reg_base + ANALOGIX_DP_AUDIO_MARGIN); |
161 | |
162 | writel(val: 0x4, addr: dp->reg_base + ANALOGIX_DP_M_VID_GEN_FILTER_TH); |
163 | writel(val: 0x2, addr: dp->reg_base + ANALOGIX_DP_M_AUD_GEN_FILTER_TH); |
164 | |
165 | writel(val: 0x00000101, addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
166 | } |
167 | |
168 | void analogix_dp_swreset(struct analogix_dp_device *dp) |
169 | { |
170 | writel(RESET_DP_TX, addr: dp->reg_base + ANALOGIX_DP_TX_SW_RESET); |
171 | } |
172 | |
173 | void analogix_dp_config_interrupt(struct analogix_dp_device *dp) |
174 | { |
175 | u32 reg; |
176 | |
177 | /* 0: mask, 1: unmask */ |
178 | reg = COMMON_INT_MASK_1; |
179 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_1); |
180 | |
181 | reg = COMMON_INT_MASK_2; |
182 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_2); |
183 | |
184 | reg = COMMON_INT_MASK_3; |
185 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_3); |
186 | |
187 | reg = COMMON_INT_MASK_4; |
188 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); |
189 | |
190 | reg = INT_STA_MASK; |
191 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_INT_STA_MASK); |
192 | } |
193 | |
194 | void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp) |
195 | { |
196 | u32 reg; |
197 | |
198 | /* 0: mask, 1: unmask */ |
199 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); |
200 | reg &= ~COMMON_INT_MASK_4; |
201 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); |
202 | |
203 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_INT_STA_MASK); |
204 | reg &= ~INT_STA_MASK; |
205 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_INT_STA_MASK); |
206 | } |
207 | |
208 | void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp) |
209 | { |
210 | u32 reg; |
211 | |
212 | /* 0: mask, 1: unmask */ |
213 | reg = COMMON_INT_MASK_4; |
214 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_MASK_4); |
215 | |
216 | reg = INT_STA_MASK; |
217 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_INT_STA_MASK); |
218 | } |
219 | |
220 | enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp) |
221 | { |
222 | u32 reg; |
223 | |
224 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_DEBUG_CTL); |
225 | if (reg & PLL_LOCK) |
226 | return PLL_LOCKED; |
227 | else |
228 | return PLL_UNLOCKED; |
229 | } |
230 | |
231 | void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable) |
232 | { |
233 | u32 reg; |
234 | u32 mask = DP_PLL_PD; |
235 | u32 pd_addr = ANALOGIX_DP_PLL_CTL; |
236 | |
237 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) { |
238 | pd_addr = ANALOGIX_DP_PD; |
239 | mask = RK_PLL_PD; |
240 | } |
241 | |
242 | reg = readl(addr: dp->reg_base + pd_addr); |
243 | if (enable) |
244 | reg |= mask; |
245 | else |
246 | reg &= ~mask; |
247 | writel(val: reg, addr: dp->reg_base + pd_addr); |
248 | } |
249 | |
250 | void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp, |
251 | enum analog_power_block block, |
252 | bool enable) |
253 | { |
254 | u32 reg; |
255 | u32 phy_pd_addr = ANALOGIX_DP_PHY_PD; |
256 | u32 mask; |
257 | |
258 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
259 | phy_pd_addr = ANALOGIX_DP_PD; |
260 | |
261 | switch (block) { |
262 | case AUX_BLOCK: |
263 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
264 | mask = RK_AUX_PD; |
265 | else |
266 | mask = AUX_PD; |
267 | |
268 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
269 | if (enable) |
270 | reg |= mask; |
271 | else |
272 | reg &= ~mask; |
273 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
274 | break; |
275 | case CH0_BLOCK: |
276 | mask = CH0_PD; |
277 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
278 | |
279 | if (enable) |
280 | reg |= mask; |
281 | else |
282 | reg &= ~mask; |
283 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
284 | break; |
285 | case CH1_BLOCK: |
286 | mask = CH1_PD; |
287 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
288 | |
289 | if (enable) |
290 | reg |= mask; |
291 | else |
292 | reg &= ~mask; |
293 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
294 | break; |
295 | case CH2_BLOCK: |
296 | mask = CH2_PD; |
297 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
298 | |
299 | if (enable) |
300 | reg |= mask; |
301 | else |
302 | reg &= ~mask; |
303 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
304 | break; |
305 | case CH3_BLOCK: |
306 | mask = CH3_PD; |
307 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
308 | |
309 | if (enable) |
310 | reg |= mask; |
311 | else |
312 | reg &= ~mask; |
313 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
314 | break; |
315 | case ANALOG_TOTAL: |
316 | /* |
317 | * There is no bit named DP_PHY_PD, so We used DP_INC_BG |
318 | * to power off everything instead of DP_PHY_PD in |
319 | * Rockchip |
320 | */ |
321 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
322 | mask = DP_INC_BG; |
323 | else |
324 | mask = DP_PHY_PD; |
325 | |
326 | reg = readl(addr: dp->reg_base + phy_pd_addr); |
327 | if (enable) |
328 | reg |= mask; |
329 | else |
330 | reg &= ~mask; |
331 | |
332 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
333 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
334 | usleep_range(min: 10, max: 15); |
335 | break; |
336 | case POWER_ALL: |
337 | if (enable) { |
338 | reg = DP_ALL_PD; |
339 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
340 | } else { |
341 | reg = DP_ALL_PD; |
342 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
343 | usleep_range(min: 10, max: 15); |
344 | reg &= ~DP_INC_BG; |
345 | writel(val: reg, addr: dp->reg_base + phy_pd_addr); |
346 | usleep_range(min: 10, max: 15); |
347 | |
348 | writel(val: 0x00, addr: dp->reg_base + phy_pd_addr); |
349 | } |
350 | break; |
351 | default: |
352 | break; |
353 | } |
354 | } |
355 | |
356 | int analogix_dp_init_analog_func(struct analogix_dp_device *dp) |
357 | { |
358 | u32 reg; |
359 | int timeout_loop = 0; |
360 | |
361 | analogix_dp_set_analog_power_down(dp, block: POWER_ALL, enable: 0); |
362 | |
363 | reg = PLL_LOCK_CHG; |
364 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); |
365 | |
366 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_DEBUG_CTL); |
367 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); |
368 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_DEBUG_CTL); |
369 | |
370 | /* Power up PLL */ |
371 | if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
372 | analogix_dp_set_pll_power_down(dp, enable: 0); |
373 | |
374 | while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
375 | timeout_loop++; |
376 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { |
377 | dev_err(dp->dev, "failed to get pll lock status\n" ); |
378 | return -ETIMEDOUT; |
379 | } |
380 | usleep_range(min: 10, max: 20); |
381 | } |
382 | } |
383 | |
384 | /* Enable Serdes FIFO function and Link symbol clock domain module */ |
385 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
386 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N |
387 | | AUX_FUNC_EN_N); |
388 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
389 | return 0; |
390 | } |
391 | |
392 | void analogix_dp_clear_hotplug_interrupts(struct analogix_dp_device *dp) |
393 | { |
394 | u32 reg; |
395 | |
396 | if (dp->hpd_gpiod) |
397 | return; |
398 | |
399 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; |
400 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); |
401 | |
402 | reg = INT_HPD; |
403 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
404 | } |
405 | |
406 | void analogix_dp_init_hpd(struct analogix_dp_device *dp) |
407 | { |
408 | u32 reg; |
409 | |
410 | if (dp->hpd_gpiod) |
411 | return; |
412 | |
413 | analogix_dp_clear_hotplug_interrupts(dp); |
414 | |
415 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
416 | reg &= ~(F_HPD | HPD_CTRL); |
417 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
418 | } |
419 | |
420 | void analogix_dp_force_hpd(struct analogix_dp_device *dp) |
421 | { |
422 | u32 reg; |
423 | |
424 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
425 | reg = (F_HPD | HPD_CTRL); |
426 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
427 | } |
428 | |
429 | enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp) |
430 | { |
431 | u32 reg; |
432 | |
433 | if (dp->hpd_gpiod) { |
434 | reg = gpiod_get_value(desc: dp->hpd_gpiod); |
435 | if (reg) |
436 | return DP_IRQ_TYPE_HP_CABLE_IN; |
437 | else |
438 | return DP_IRQ_TYPE_HP_CABLE_OUT; |
439 | } else { |
440 | /* Parse hotplug interrupt status register */ |
441 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_4); |
442 | |
443 | if (reg & PLUG) |
444 | return DP_IRQ_TYPE_HP_CABLE_IN; |
445 | |
446 | if (reg & HPD_LOST) |
447 | return DP_IRQ_TYPE_HP_CABLE_OUT; |
448 | |
449 | if (reg & HOTPLUG_CHG) |
450 | return DP_IRQ_TYPE_HP_CHANGE; |
451 | |
452 | return DP_IRQ_TYPE_UNKNOWN; |
453 | } |
454 | } |
455 | |
456 | void analogix_dp_reset_aux(struct analogix_dp_device *dp) |
457 | { |
458 | u32 reg; |
459 | |
460 | /* Disable AUX channel module */ |
461 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
462 | reg |= AUX_FUNC_EN_N; |
463 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
464 | } |
465 | |
466 | void analogix_dp_init_aux(struct analogix_dp_device *dp) |
467 | { |
468 | u32 reg; |
469 | |
470 | /* Clear inerrupts related to AUX channel */ |
471 | reg = RPLY_RECEIV | AUX_ERR; |
472 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
473 | |
474 | analogix_dp_set_analog_power_down(dp, block: AUX_BLOCK, enable: true); |
475 | usleep_range(min: 10, max: 11); |
476 | analogix_dp_set_analog_power_down(dp, block: AUX_BLOCK, enable: false); |
477 | |
478 | analogix_dp_reset_aux(dp); |
479 | |
480 | /* AUX_BIT_PERIOD_EXPECTED_DELAY doesn't apply to Rockchip IP */ |
481 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) |
482 | reg = 0; |
483 | else |
484 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3); |
485 | |
486 | /* Disable AUX transaction H/W retry */ |
487 | reg |= AUX_HW_RETRY_COUNT_SEL(0) | |
488 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; |
489 | |
490 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_HW_RETRY_CTL); |
491 | |
492 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ |
493 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); |
494 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_CH_DEFER_CTL); |
495 | |
496 | /* Enable AUX channel module */ |
497 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
498 | reg &= ~AUX_FUNC_EN_N; |
499 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_2); |
500 | } |
501 | |
502 | int analogix_dp_get_plug_in_status(struct analogix_dp_device *dp) |
503 | { |
504 | u32 reg; |
505 | |
506 | if (dp->hpd_gpiod) { |
507 | if (gpiod_get_value(desc: dp->hpd_gpiod)) |
508 | return 0; |
509 | } else { |
510 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
511 | if (reg & HPD_STATUS) |
512 | return 0; |
513 | } |
514 | |
515 | return -EINVAL; |
516 | } |
517 | |
518 | void analogix_dp_enable_sw_function(struct analogix_dp_device *dp) |
519 | { |
520 | u32 reg; |
521 | |
522 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_1); |
523 | reg &= ~SW_FUNC_EN_N; |
524 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_1); |
525 | } |
526 | |
527 | void analogix_dp_set_link_bandwidth(struct analogix_dp_device *dp, u32 bwtype) |
528 | { |
529 | u32 reg; |
530 | |
531 | reg = bwtype; |
532 | if ((bwtype == DP_LINK_BW_2_7) || (bwtype == DP_LINK_BW_1_62)) |
533 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LINK_BW_SET); |
534 | } |
535 | |
536 | void analogix_dp_get_link_bandwidth(struct analogix_dp_device *dp, u32 *bwtype) |
537 | { |
538 | u32 reg; |
539 | |
540 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LINK_BW_SET); |
541 | *bwtype = reg; |
542 | } |
543 | |
544 | void analogix_dp_set_lane_count(struct analogix_dp_device *dp, u32 count) |
545 | { |
546 | u32 reg; |
547 | |
548 | reg = count; |
549 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); |
550 | } |
551 | |
552 | void analogix_dp_get_lane_count(struct analogix_dp_device *dp, u32 *count) |
553 | { |
554 | u32 reg; |
555 | |
556 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LANE_COUNT_SET); |
557 | *count = reg; |
558 | } |
559 | |
560 | void analogix_dp_enable_enhanced_mode(struct analogix_dp_device *dp, |
561 | bool enable) |
562 | { |
563 | u32 reg; |
564 | |
565 | if (enable) { |
566 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
567 | reg |= ENHANCED; |
568 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
569 | } else { |
570 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
571 | reg &= ~ENHANCED; |
572 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
573 | } |
574 | } |
575 | |
576 | void analogix_dp_set_training_pattern(struct analogix_dp_device *dp, |
577 | enum pattern_set pattern) |
578 | { |
579 | u32 reg; |
580 | |
581 | switch (pattern) { |
582 | case PRBS7: |
583 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; |
584 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
585 | break; |
586 | case D10_2: |
587 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; |
588 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
589 | break; |
590 | case TRAINING_PTN1: |
591 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; |
592 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
593 | break; |
594 | case TRAINING_PTN2: |
595 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; |
596 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
597 | break; |
598 | case DP_NONE: |
599 | reg = SCRAMBLING_ENABLE | |
600 | LINK_QUAL_PATTERN_SET_DISABLE | |
601 | SW_TRAINING_PATTERN_SET_NORMAL; |
602 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
603 | break; |
604 | default: |
605 | break; |
606 | } |
607 | } |
608 | |
609 | void analogix_dp_set_lane0_pre_emphasis(struct analogix_dp_device *dp, |
610 | u32 level) |
611 | { |
612 | u32 reg; |
613 | |
614 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); |
615 | reg &= ~PRE_EMPHASIS_SET_MASK; |
616 | reg |= level << PRE_EMPHASIS_SET_SHIFT; |
617 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); |
618 | } |
619 | |
620 | void analogix_dp_set_lane1_pre_emphasis(struct analogix_dp_device *dp, |
621 | u32 level) |
622 | { |
623 | u32 reg; |
624 | |
625 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); |
626 | reg &= ~PRE_EMPHASIS_SET_MASK; |
627 | reg |= level << PRE_EMPHASIS_SET_SHIFT; |
628 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); |
629 | } |
630 | |
631 | void analogix_dp_set_lane2_pre_emphasis(struct analogix_dp_device *dp, |
632 | u32 level) |
633 | { |
634 | u32 reg; |
635 | |
636 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); |
637 | reg &= ~PRE_EMPHASIS_SET_MASK; |
638 | reg |= level << PRE_EMPHASIS_SET_SHIFT; |
639 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); |
640 | } |
641 | |
642 | void analogix_dp_set_lane3_pre_emphasis(struct analogix_dp_device *dp, |
643 | u32 level) |
644 | { |
645 | u32 reg; |
646 | |
647 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); |
648 | reg &= ~PRE_EMPHASIS_SET_MASK; |
649 | reg |= level << PRE_EMPHASIS_SET_SHIFT; |
650 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); |
651 | } |
652 | |
653 | void analogix_dp_set_lane0_link_training(struct analogix_dp_device *dp, |
654 | u32 training_lane) |
655 | { |
656 | u32 reg; |
657 | |
658 | reg = training_lane; |
659 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); |
660 | } |
661 | |
662 | void analogix_dp_set_lane1_link_training(struct analogix_dp_device *dp, |
663 | u32 training_lane) |
664 | { |
665 | u32 reg; |
666 | |
667 | reg = training_lane; |
668 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); |
669 | } |
670 | |
671 | void analogix_dp_set_lane2_link_training(struct analogix_dp_device *dp, |
672 | u32 training_lane) |
673 | { |
674 | u32 reg; |
675 | |
676 | reg = training_lane; |
677 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); |
678 | } |
679 | |
680 | void analogix_dp_set_lane3_link_training(struct analogix_dp_device *dp, |
681 | u32 training_lane) |
682 | { |
683 | u32 reg; |
684 | |
685 | reg = training_lane; |
686 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); |
687 | } |
688 | |
689 | u32 analogix_dp_get_lane0_link_training(struct analogix_dp_device *dp) |
690 | { |
691 | return readl(addr: dp->reg_base + ANALOGIX_DP_LN0_LINK_TRAINING_CTL); |
692 | } |
693 | |
694 | u32 analogix_dp_get_lane1_link_training(struct analogix_dp_device *dp) |
695 | { |
696 | return readl(addr: dp->reg_base + ANALOGIX_DP_LN1_LINK_TRAINING_CTL); |
697 | } |
698 | |
699 | u32 analogix_dp_get_lane2_link_training(struct analogix_dp_device *dp) |
700 | { |
701 | return readl(addr: dp->reg_base + ANALOGIX_DP_LN2_LINK_TRAINING_CTL); |
702 | } |
703 | |
704 | u32 analogix_dp_get_lane3_link_training(struct analogix_dp_device *dp) |
705 | { |
706 | return readl(addr: dp->reg_base + ANALOGIX_DP_LN3_LINK_TRAINING_CTL); |
707 | } |
708 | |
709 | void analogix_dp_reset_macro(struct analogix_dp_device *dp) |
710 | { |
711 | u32 reg; |
712 | |
713 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_PHY_TEST); |
714 | reg |= MACRO_RST; |
715 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_PHY_TEST); |
716 | |
717 | /* 10 us is the minimum reset time. */ |
718 | usleep_range(min: 10, max: 20); |
719 | |
720 | reg &= ~MACRO_RST; |
721 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_PHY_TEST); |
722 | } |
723 | |
724 | void analogix_dp_init_video(struct analogix_dp_device *dp) |
725 | { |
726 | u32 reg; |
727 | |
728 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; |
729 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_COMMON_INT_STA_1); |
730 | |
731 | reg = 0x0; |
732 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_1); |
733 | |
734 | reg = CHA_CRI(4) | CHA_CTRL; |
735 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_2); |
736 | |
737 | reg = 0x0; |
738 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
739 | |
740 | reg = VID_HRES_TH(2) | VID_VRES_TH(0); |
741 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_8); |
742 | } |
743 | |
744 | void analogix_dp_set_video_color_format(struct analogix_dp_device *dp) |
745 | { |
746 | u32 reg; |
747 | |
748 | /* Configure the input color depth, color space, dynamic range */ |
749 | reg = (dp->video_info.dynamic_range << IN_D_RANGE_SHIFT) | |
750 | (dp->video_info.color_depth << IN_BPC_SHIFT) | |
751 | (dp->video_info.color_space << IN_COLOR_F_SHIFT); |
752 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_2); |
753 | |
754 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ |
755 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); |
756 | reg &= ~IN_YC_COEFFI_MASK; |
757 | if (dp->video_info.ycbcr_coeff) |
758 | reg |= IN_YC_COEFFI_ITU709; |
759 | else |
760 | reg |= IN_YC_COEFFI_ITU601; |
761 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); |
762 | } |
763 | |
764 | int analogix_dp_is_slave_video_stream_clock_on(struct analogix_dp_device *dp) |
765 | { |
766 | u32 reg; |
767 | |
768 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_1); |
769 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_1); |
770 | |
771 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_1); |
772 | |
773 | if (!(reg & DET_STA)) { |
774 | dev_dbg(dp->dev, "Input stream clock not detected.\n" ); |
775 | return -EINVAL; |
776 | } |
777 | |
778 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_2); |
779 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_2); |
780 | |
781 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_2); |
782 | dev_dbg(dp->dev, "wait SYS_CTL_2.\n" ); |
783 | |
784 | if (reg & CHA_STA) { |
785 | dev_dbg(dp->dev, "Input stream clk is changing\n" ); |
786 | return -EINVAL; |
787 | } |
788 | |
789 | return 0; |
790 | } |
791 | |
792 | void analogix_dp_set_video_cr_mn(struct analogix_dp_device *dp, |
793 | enum clock_recovery_m_value_type type, |
794 | u32 m_value, u32 n_value) |
795 | { |
796 | u32 reg; |
797 | |
798 | if (type == REGISTER_M) { |
799 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
800 | reg |= FIX_M_VID; |
801 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
802 | reg = m_value & 0xff; |
803 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_M_VID_0); |
804 | reg = (m_value >> 8) & 0xff; |
805 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_M_VID_1); |
806 | reg = (m_value >> 16) & 0xff; |
807 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_M_VID_2); |
808 | |
809 | reg = n_value & 0xff; |
810 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_N_VID_0); |
811 | reg = (n_value >> 8) & 0xff; |
812 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_N_VID_1); |
813 | reg = (n_value >> 16) & 0xff; |
814 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_N_VID_2); |
815 | } else { |
816 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
817 | reg &= ~FIX_M_VID; |
818 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_4); |
819 | |
820 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_N_VID_0); |
821 | writel(val: 0x80, addr: dp->reg_base + ANALOGIX_DP_N_VID_1); |
822 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_N_VID_2); |
823 | } |
824 | } |
825 | |
826 | void analogix_dp_set_video_timing_mode(struct analogix_dp_device *dp, u32 type) |
827 | { |
828 | u32 reg; |
829 | |
830 | if (type == VIDEO_TIMING_FROM_CAPTURE) { |
831 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
832 | reg &= ~FORMAT_SEL; |
833 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
834 | } else { |
835 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
836 | reg |= FORMAT_SEL; |
837 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
838 | } |
839 | } |
840 | |
841 | void analogix_dp_enable_video_master(struct analogix_dp_device *dp, bool enable) |
842 | { |
843 | u32 reg; |
844 | |
845 | if (enable) { |
846 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
847 | reg &= ~VIDEO_MODE_MASK; |
848 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; |
849 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
850 | } else { |
851 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
852 | reg &= ~VIDEO_MODE_MASK; |
853 | reg |= VIDEO_MODE_SLAVE_MODE; |
854 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
855 | } |
856 | } |
857 | |
858 | void analogix_dp_start_video(struct analogix_dp_device *dp) |
859 | { |
860 | u32 reg; |
861 | |
862 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
863 | reg |= VIDEO_EN; |
864 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1); |
865 | } |
866 | |
867 | int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp) |
868 | { |
869 | u32 reg; |
870 | |
871 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
872 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
873 | |
874 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_SYS_CTL_3); |
875 | if (!(reg & STRM_VALID)) { |
876 | dev_dbg(dp->dev, "Input video stream is not detected.\n" ); |
877 | return -EINVAL; |
878 | } |
879 | |
880 | return 0; |
881 | } |
882 | |
883 | void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp) |
884 | { |
885 | u32 reg; |
886 | |
887 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_1); |
888 | if (dp->plat_data && is_rockchip(type: dp->plat_data->dev_type)) { |
889 | reg &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N); |
890 | } else { |
891 | reg &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N); |
892 | reg |= MASTER_VID_FUNC_EN_N; |
893 | } |
894 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_FUNC_EN_1); |
895 | |
896 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
897 | reg &= ~INTERACE_SCAN_CFG; |
898 | reg |= (dp->video_info.interlaced << 2); |
899 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
900 | |
901 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
902 | reg &= ~VSYNC_POLARITY_CFG; |
903 | reg |= (dp->video_info.v_sync_polarity << 1); |
904 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
905 | |
906 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
907 | reg &= ~HSYNC_POLARITY_CFG; |
908 | reg |= (dp->video_info.h_sync_polarity << 0); |
909 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_10); |
910 | |
911 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; |
912 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_SOC_GENERAL_CTL); |
913 | } |
914 | |
915 | void analogix_dp_enable_scrambling(struct analogix_dp_device *dp) |
916 | { |
917 | u32 reg; |
918 | |
919 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
920 | reg &= ~SCRAMBLING_DISABLE; |
921 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
922 | } |
923 | |
924 | void analogix_dp_disable_scrambling(struct analogix_dp_device *dp) |
925 | { |
926 | u32 reg; |
927 | |
928 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
929 | reg |= SCRAMBLING_DISABLE; |
930 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET); |
931 | } |
932 | |
933 | void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp) |
934 | { |
935 | writel(PSR_VID_CRC_ENABLE, addr: dp->reg_base + ANALOGIX_DP_CRC_CON); |
936 | } |
937 | |
938 | static ssize_t analogix_dp_get_psr_status(struct analogix_dp_device *dp) |
939 | { |
940 | ssize_t val; |
941 | u8 status; |
942 | |
943 | val = drm_dp_dpcd_readb(aux: &dp->aux, DP_PSR_STATUS, valuep: &status); |
944 | if (val < 0) { |
945 | dev_err(dp->dev, "PSR_STATUS read failed ret=%zd" , val); |
946 | return val; |
947 | } |
948 | return status; |
949 | } |
950 | |
951 | int analogix_dp_send_psr_spd(struct analogix_dp_device *dp, |
952 | struct dp_sdp *vsc, bool blocking) |
953 | { |
954 | unsigned int val; |
955 | int ret; |
956 | ssize_t psr_status; |
957 | |
958 | /* don't send info frame */ |
959 | val = readl(addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
960 | val &= ~IF_EN; |
961 | writel(val, addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
962 | |
963 | /* configure single frame update mode */ |
964 | writel(PSR_FRAME_UP_TYPE_BURST | PSR_CRC_SEL_HARDWARE, |
965 | addr: dp->reg_base + ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL); |
966 | |
967 | /* configure VSC HB0~HB3 */ |
968 | writel(val: vsc->sdp_header.HB0, addr: dp->reg_base + ANALOGIX_DP_SPD_HB0); |
969 | writel(val: vsc->sdp_header.HB1, addr: dp->reg_base + ANALOGIX_DP_SPD_HB1); |
970 | writel(val: vsc->sdp_header.HB2, addr: dp->reg_base + ANALOGIX_DP_SPD_HB2); |
971 | writel(val: vsc->sdp_header.HB3, addr: dp->reg_base + ANALOGIX_DP_SPD_HB3); |
972 | |
973 | /* configure reused VSC PB0~PB3, magic number from vendor */ |
974 | writel(val: 0x00, addr: dp->reg_base + ANALOGIX_DP_SPD_PB0); |
975 | writel(val: 0x16, addr: dp->reg_base + ANALOGIX_DP_SPD_PB1); |
976 | writel(val: 0xCE, addr: dp->reg_base + ANALOGIX_DP_SPD_PB2); |
977 | writel(val: 0x5D, addr: dp->reg_base + ANALOGIX_DP_SPD_PB3); |
978 | |
979 | /* configure DB0 / DB1 values */ |
980 | writel(val: vsc->db[0], addr: dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB0); |
981 | writel(val: vsc->db[1], addr: dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB1); |
982 | |
983 | /* set reuse spd inforframe */ |
984 | val = readl(addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); |
985 | val |= REUSE_SPD_EN; |
986 | writel(val, addr: dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3); |
987 | |
988 | /* mark info frame update */ |
989 | val = readl(addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
990 | val = (val | IF_UP) & ~IF_EN; |
991 | writel(val, addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
992 | |
993 | /* send info frame */ |
994 | val = readl(addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
995 | val |= IF_EN; |
996 | writel(val, addr: dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL); |
997 | |
998 | if (!blocking) |
999 | return 0; |
1000 | |
1001 | /* |
1002 | * db[1]!=0: entering PSR, wait for fully active remote frame buffer. |
1003 | * db[1]==0: exiting PSR, wait for either |
1004 | * (a) ACTIVE_RESYNC - the sink "must display the |
1005 | * incoming active frames from the Source device with no visible |
1006 | * glitches and/or artifacts", even though timings may still be |
1007 | * re-synchronizing; or |
1008 | * (b) INACTIVE - the transition is fully complete. |
1009 | */ |
1010 | ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status, |
1011 | psr_status >= 0 && |
1012 | ((vsc->db[1] && psr_status == DP_PSR_SINK_ACTIVE_RFB) || |
1013 | (!vsc->db[1] && (psr_status == DP_PSR_SINK_ACTIVE_RESYNC || |
1014 | psr_status == DP_PSR_SINK_INACTIVE))), |
1015 | 1500, DP_TIMEOUT_PSR_LOOP_MS * 1000); |
1016 | if (ret) { |
1017 | dev_warn(dp->dev, "Failed to apply PSR %d\n" , ret); |
1018 | return ret; |
1019 | } |
1020 | return 0; |
1021 | } |
1022 | |
1023 | ssize_t analogix_dp_transfer(struct analogix_dp_device *dp, |
1024 | struct drm_dp_aux_msg *msg) |
1025 | { |
1026 | u32 reg; |
1027 | u32 status_reg; |
1028 | u8 *buffer = msg->buffer; |
1029 | unsigned int i; |
1030 | int num_transferred = 0; |
1031 | int ret; |
1032 | |
1033 | /* Buffer size of AUX CH is 16 bytes */ |
1034 | if (WARN_ON(msg->size > 16)) |
1035 | return -E2BIG; |
1036 | |
1037 | /* Clear AUX CH data buffer */ |
1038 | reg = BUF_CLR; |
1039 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_BUFFER_DATA_CTL); |
1040 | |
1041 | switch (msg->request & ~DP_AUX_I2C_MOT) { |
1042 | case DP_AUX_I2C_WRITE: |
1043 | reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_I2C_TRANSACTION; |
1044 | if (msg->request & DP_AUX_I2C_MOT) |
1045 | reg |= AUX_TX_COMM_MOT; |
1046 | break; |
1047 | |
1048 | case DP_AUX_I2C_READ: |
1049 | reg = AUX_TX_COMM_READ | AUX_TX_COMM_I2C_TRANSACTION; |
1050 | if (msg->request & DP_AUX_I2C_MOT) |
1051 | reg |= AUX_TX_COMM_MOT; |
1052 | break; |
1053 | |
1054 | case DP_AUX_NATIVE_WRITE: |
1055 | reg = AUX_TX_COMM_WRITE | AUX_TX_COMM_DP_TRANSACTION; |
1056 | break; |
1057 | |
1058 | case DP_AUX_NATIVE_READ: |
1059 | reg = AUX_TX_COMM_READ | AUX_TX_COMM_DP_TRANSACTION; |
1060 | break; |
1061 | |
1062 | default: |
1063 | return -EINVAL; |
1064 | } |
1065 | |
1066 | reg |= AUX_LENGTH(msg->size); |
1067 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_1); |
1068 | |
1069 | /* Select DPCD device address */ |
1070 | reg = AUX_ADDR_7_0(msg->address); |
1071 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_ADDR_7_0); |
1072 | reg = AUX_ADDR_15_8(msg->address); |
1073 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_ADDR_15_8); |
1074 | reg = AUX_ADDR_19_16(msg->address); |
1075 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_ADDR_19_16); |
1076 | |
1077 | if (!(msg->request & DP_AUX_I2C_READ)) { |
1078 | for (i = 0; i < msg->size; i++) { |
1079 | reg = buffer[i]; |
1080 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + |
1081 | 4 * i); |
1082 | num_transferred++; |
1083 | } |
1084 | } |
1085 | |
1086 | /* Enable AUX CH operation */ |
1087 | reg = AUX_EN; |
1088 | |
1089 | /* Zero-sized messages specify address-only transactions. */ |
1090 | if (msg->size < 1) |
1091 | reg |= ADDR_ONLY; |
1092 | |
1093 | writel(val: reg, addr: dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2); |
1094 | |
1095 | ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_AUX_CH_CTL_2, |
1096 | reg, !(reg & AUX_EN), 25, 500 * 1000); |
1097 | if (ret) { |
1098 | dev_err(dp->dev, "AUX CH enable timeout!\n" ); |
1099 | goto aux_error; |
1100 | } |
1101 | |
1102 | /* TODO: Wait for an interrupt instead of looping? */ |
1103 | /* Is AUX CH command reply received? */ |
1104 | ret = readx_poll_timeout(readl, dp->reg_base + ANALOGIX_DP_INT_STA, |
1105 | reg, reg & RPLY_RECEIV, 10, 20 * 1000); |
1106 | if (ret) { |
1107 | dev_err(dp->dev, "AUX CH cmd reply timeout!\n" ); |
1108 | goto aux_error; |
1109 | } |
1110 | |
1111 | /* Clear interrupt source for AUX CH command reply */ |
1112 | writel(RPLY_RECEIV, addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
1113 | |
1114 | /* Clear interrupt source for AUX CH access error */ |
1115 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
1116 | status_reg = readl(addr: dp->reg_base + ANALOGIX_DP_AUX_CH_STA); |
1117 | if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) { |
1118 | writel(AUX_ERR, addr: dp->reg_base + ANALOGIX_DP_INT_STA); |
1119 | |
1120 | dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n" , |
1121 | status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR)); |
1122 | goto aux_error; |
1123 | } |
1124 | |
1125 | if (msg->request & DP_AUX_I2C_READ) { |
1126 | for (i = 0; i < msg->size; i++) { |
1127 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_BUF_DATA_0 + |
1128 | 4 * i); |
1129 | buffer[i] = (unsigned char)reg; |
1130 | num_transferred++; |
1131 | } |
1132 | } |
1133 | |
1134 | /* Check if Rx sends defer */ |
1135 | reg = readl(addr: dp->reg_base + ANALOGIX_DP_AUX_RX_COMM); |
1136 | if (reg == AUX_RX_COMM_AUX_DEFER) |
1137 | msg->reply = DP_AUX_NATIVE_REPLY_DEFER; |
1138 | else if (reg == AUX_RX_COMM_I2C_DEFER) |
1139 | msg->reply = DP_AUX_I2C_REPLY_DEFER; |
1140 | else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE || |
1141 | (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ) |
1142 | msg->reply = DP_AUX_I2C_REPLY_ACK; |
1143 | else if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE || |
1144 | (msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ) |
1145 | msg->reply = DP_AUX_NATIVE_REPLY_ACK; |
1146 | |
1147 | return num_transferred > 0 ? num_transferred : -EBUSY; |
1148 | |
1149 | aux_error: |
1150 | /* if aux err happen, reset aux */ |
1151 | analogix_dp_init_aux(dp); |
1152 | |
1153 | return -EREMOTEIO; |
1154 | } |
1155 | |