]>
Commit | Line | Data |
---|---|---|
d2a6982f DL |
1 | /* |
2 | * Copyright (C) 2012 Samsung Electronics | |
3 | * | |
4 | * Author: Donghwa Lee <dh09.lee@samsung.com> | |
5 | * | |
3765b3e7 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
d2a6982f DL |
7 | */ |
8 | ||
9 | #include <config.h> | |
10 | #include <common.h> | |
11 | #include <linux/err.h> | |
12 | #include <asm/arch/cpu.h> | |
13 | #include <asm/arch/dp_info.h> | |
14 | #include <asm/arch/dp.h> | |
9947d13e | 15 | #include <fdtdec.h> |
b08c8c48 | 16 | #include <linux/libfdt.h> |
8c9b8dc0 | 17 | #include "exynos_dp_lowlevel.h" |
9947d13e AK |
18 | |
19 | /* Declare global data pointer */ | |
20 | DECLARE_GLOBAL_DATA_PTR; | |
d2a6982f | 21 | |
8c9b8dc0 SG |
22 | static void exynos_dp_enable_video_input(struct exynos_dp *dp_regs, |
23 | unsigned int enable) | |
d2a6982f DL |
24 | { |
25 | unsigned int reg; | |
d2a6982f DL |
26 | |
27 | reg = readl(&dp_regs->video_ctl1); | |
28 | reg &= ~VIDEO_EN_MASK; | |
29 | ||
a418f7e8 | 30 | /* enable video input */ |
d2a6982f DL |
31 | if (enable) |
32 | reg |= VIDEO_EN_MASK; | |
33 | ||
34 | writel(reg, &dp_regs->video_ctl1); | |
35 | ||
36 | return; | |
37 | } | |
38 | ||
8c9b8dc0 | 39 | void exynos_dp_enable_video_bist(struct exynos_dp *dp_regs, unsigned int enable) |
d2a6982f | 40 | { |
a418f7e8 | 41 | /* enable video bist */ |
d2a6982f | 42 | unsigned int reg; |
d2a6982f DL |
43 | |
44 | reg = readl(&dp_regs->video_ctl4); | |
45 | reg &= ~VIDEO_BIST_MASK; | |
46 | ||
a418f7e8 | 47 | /* enable video bist */ |
d2a6982f DL |
48 | if (enable) |
49 | reg |= VIDEO_BIST_MASK; | |
50 | ||
51 | writel(reg, &dp_regs->video_ctl4); | |
52 | ||
53 | return; | |
54 | } | |
55 | ||
8c9b8dc0 | 56 | void exynos_dp_enable_video_mute(struct exynos_dp *dp_regs, unsigned int enable) |
d2a6982f DL |
57 | { |
58 | unsigned int reg; | |
d2a6982f DL |
59 | |
60 | reg = readl(&dp_regs->video_ctl1); | |
61 | reg &= ~(VIDEO_MUTE_MASK); | |
62 | if (enable) | |
63 | reg |= VIDEO_MUTE_MASK; | |
64 | ||
65 | writel(reg, &dp_regs->video_ctl1); | |
66 | ||
67 | return; | |
68 | } | |
69 | ||
70 | ||
8c9b8dc0 | 71 | static void exynos_dp_init_analog_param(struct exynos_dp *dp_regs) |
d2a6982f DL |
72 | { |
73 | unsigned int reg; | |
d2a6982f DL |
74 | |
75 | /* | |
76 | * Set termination | |
77 | * Normal bandgap, Normal swing, Tx terminal registor 61 ohm | |
78 | * 24M Phy clock, TX digital logic power is 100:1.0625V | |
79 | */ | |
80 | reg = SEL_BG_NEW_BANDGAP | TX_TERMINAL_CTRL_61_OHM | | |
81 | SWING_A_30PER_G_NORMAL; | |
82 | writel(reg, &dp_regs->analog_ctl1); | |
83 | ||
84 | reg = SEL_24M | TX_DVDD_BIT_1_0625V; | |
85 | writel(reg, &dp_regs->analog_ctl2); | |
86 | ||
87 | /* | |
88 | * Set power source for internal clk driver to 1.0625v. | |
89 | * Select current reference of TX driver current to 00:Ipp/2+Ic/2. | |
90 | * Set VCO range of PLL +- 0uA | |
91 | */ | |
92 | reg = DRIVE_DVDD_BIT_1_0625V | SEL_CURRENT_DEFAULT | VCO_BIT_000_MICRO; | |
93 | writel(reg, &dp_regs->analog_ctl3); | |
94 | ||
95 | /* | |
96 | * Set AUX TX terminal resistor to 102 ohm | |
97 | * Set AUX channel amplitude control | |
a418f7e8 | 98 | */ |
d2a6982f DL |
99 | reg = PD_RING_OSC | AUX_TERMINAL_CTRL_52_OHM | TX_CUR1_2X | TX_CUR_4_MA; |
100 | writel(reg, &dp_regs->pll_filter_ctl1); | |
101 | ||
102 | /* | |
103 | * PLL loop filter bandwidth | |
104 | * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz | |
105 | * PLL digital power select: 1.2500V | |
106 | */ | |
107 | reg = CH3_AMP_0_MV | CH2_AMP_0_MV | CH1_AMP_0_MV | CH0_AMP_0_MV; | |
108 | ||
109 | writel(reg, &dp_regs->amp_tuning_ctl); | |
110 | ||
111 | /* | |
112 | * PLL loop filter bandwidth | |
113 | * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz | |
114 | * PLL digital power select: 1.1250V | |
115 | */ | |
116 | reg = DP_PLL_LOOP_BIT_DEFAULT | DP_PLL_REF_BIT_1_1250V; | |
117 | writel(reg, &dp_regs->pll_ctl); | |
118 | } | |
119 | ||
8c9b8dc0 | 120 | static void exynos_dp_init_interrupt(struct exynos_dp *dp_regs) |
d2a6982f | 121 | { |
d2a6982f DL |
122 | /* Set interrupt registers to initial states */ |
123 | ||
124 | /* | |
125 | * Disable interrupt | |
126 | * INT pin assertion polarity. It must be configured | |
127 | * correctly according to ICU setting. | |
128 | * 1 = assert high, 0 = assert low | |
129 | */ | |
130 | writel(INT_POL, &dp_regs->int_ctl); | |
131 | ||
a418f7e8 | 132 | /* Clear pending registers */ |
d2a6982f DL |
133 | writel(0xff, &dp_regs->common_int_sta1); |
134 | writel(0xff, &dp_regs->common_int_sta2); | |
135 | writel(0xff, &dp_regs->common_int_sta3); | |
136 | writel(0xff, &dp_regs->common_int_sta4); | |
137 | writel(0xff, &dp_regs->int_sta); | |
138 | ||
139 | /* 0:mask,1: unmask */ | |
140 | writel(0x00, &dp_regs->int_sta_mask1); | |
141 | writel(0x00, &dp_regs->int_sta_mask2); | |
142 | writel(0x00, &dp_regs->int_sta_mask3); | |
143 | writel(0x00, &dp_regs->int_sta_mask4); | |
144 | writel(0x00, &dp_regs->int_sta_mask); | |
145 | } | |
146 | ||
8c9b8dc0 | 147 | void exynos_dp_reset(struct exynos_dp *dp_regs) |
d2a6982f DL |
148 | { |
149 | unsigned int reg_func_1; | |
d2a6982f | 150 | |
a418f7e8 | 151 | /* dp tx sw reset */ |
d2a6982f DL |
152 | writel(RESET_DP_TX, &dp_regs->tx_sw_reset); |
153 | ||
8c9b8dc0 SG |
154 | exynos_dp_enable_video_input(dp_regs, DP_DISABLE); |
155 | exynos_dp_enable_video_bist(dp_regs, DP_DISABLE); | |
156 | exynos_dp_enable_video_mute(dp_regs, DP_DISABLE); | |
d2a6982f DL |
157 | |
158 | /* software reset */ | |
159 | reg_func_1 = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | | |
160 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | | |
161 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; | |
162 | ||
163 | writel(reg_func_1, &dp_regs->func_en1); | |
164 | writel(reg_func_1, &dp_regs->func_en2); | |
165 | ||
166 | mdelay(1); | |
167 | ||
8c9b8dc0 SG |
168 | exynos_dp_init_analog_param(dp_regs); |
169 | exynos_dp_init_interrupt(dp_regs); | |
d2a6982f DL |
170 | |
171 | return; | |
172 | } | |
173 | ||
8c9b8dc0 | 174 | void exynos_dp_enable_sw_func(struct exynos_dp *dp_regs, unsigned int enable) |
d2a6982f DL |
175 | { |
176 | unsigned int reg; | |
d2a6982f DL |
177 | |
178 | reg = readl(&dp_regs->func_en1); | |
179 | reg &= ~(SW_FUNC_EN_N); | |
180 | ||
181 | if (!enable) | |
182 | reg |= SW_FUNC_EN_N; | |
183 | ||
184 | writel(reg, &dp_regs->func_en1); | |
185 | ||
186 | return; | |
187 | } | |
188 | ||
8c9b8dc0 SG |
189 | unsigned int exynos_dp_set_analog_power_down(struct exynos_dp *dp_regs, |
190 | unsigned int block, u32 enable) | |
d2a6982f DL |
191 | { |
192 | unsigned int reg; | |
d2a6982f DL |
193 | |
194 | reg = readl(&dp_regs->phy_pd); | |
195 | switch (block) { | |
196 | case AUX_BLOCK: | |
197 | reg &= ~(AUX_PD); | |
198 | if (enable) | |
199 | reg |= AUX_PD; | |
200 | break; | |
201 | case CH0_BLOCK: | |
202 | reg &= ~(CH0_PD); | |
203 | if (enable) | |
204 | reg |= CH0_PD; | |
205 | break; | |
206 | case CH1_BLOCK: | |
207 | reg &= ~(CH1_PD); | |
208 | if (enable) | |
209 | reg |= CH1_PD; | |
210 | break; | |
211 | case CH2_BLOCK: | |
212 | reg &= ~(CH2_PD); | |
213 | if (enable) | |
214 | reg |= CH2_PD; | |
215 | break; | |
216 | case CH3_BLOCK: | |
217 | reg &= ~(CH3_PD); | |
218 | if (enable) | |
219 | reg |= CH3_PD; | |
220 | break; | |
221 | case ANALOG_TOTAL: | |
222 | reg &= ~PHY_PD; | |
223 | if (enable) | |
224 | reg |= PHY_PD; | |
225 | break; | |
226 | case POWER_ALL: | |
227 | reg &= ~(PHY_PD | AUX_PD | CH0_PD | CH1_PD | CH2_PD | | |
228 | CH3_PD); | |
229 | if (enable) | |
230 | reg |= (PHY_PD | AUX_PD | CH0_PD | CH1_PD | | |
231 | CH2_PD | CH3_PD); | |
232 | break; | |
233 | default: | |
234 | printf("DP undefined block number : %d\n", block); | |
235 | return -1; | |
236 | } | |
237 | ||
238 | writel(reg, &dp_regs->phy_pd); | |
239 | ||
240 | return 0; | |
241 | } | |
242 | ||
8c9b8dc0 | 243 | unsigned int exynos_dp_get_pll_lock_status(struct exynos_dp *dp_regs) |
d2a6982f DL |
244 | { |
245 | unsigned int reg; | |
d2a6982f DL |
246 | |
247 | reg = readl(&dp_regs->debug_ctl); | |
248 | ||
249 | if (reg & PLL_LOCK) | |
250 | return PLL_LOCKED; | |
251 | else | |
252 | return PLL_UNLOCKED; | |
253 | } | |
254 | ||
8c9b8dc0 SG |
255 | static void exynos_dp_set_pll_power(struct exynos_dp *dp_regs, |
256 | unsigned int enable) | |
d2a6982f DL |
257 | { |
258 | unsigned int reg; | |
d2a6982f DL |
259 | |
260 | reg = readl(&dp_regs->pll_ctl); | |
261 | reg &= ~(DP_PLL_PD); | |
262 | ||
263 | if (!enable) | |
264 | reg |= DP_PLL_PD; | |
265 | ||
266 | writel(reg, &dp_regs->pll_ctl); | |
267 | } | |
268 | ||
8c9b8dc0 | 269 | int exynos_dp_init_analog_func(struct exynos_dp *dp_regs) |
d2a6982f DL |
270 | { |
271 | int ret = EXYNOS_DP_SUCCESS; | |
272 | unsigned int retry_cnt = 10; | |
273 | unsigned int reg; | |
d2a6982f | 274 | |
a418f7e8 | 275 | /* Power On All Analog block */ |
8c9b8dc0 | 276 | exynos_dp_set_analog_power_down(dp_regs, POWER_ALL, DP_DISABLE); |
d2a6982f DL |
277 | |
278 | reg = PLL_LOCK_CHG; | |
279 | writel(reg, &dp_regs->common_int_sta1); | |
280 | ||
281 | reg = readl(&dp_regs->debug_ctl); | |
282 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); | |
283 | writel(reg, &dp_regs->debug_ctl); | |
284 | ||
a418f7e8 | 285 | /* Assert DP PLL Reset */ |
d2a6982f DL |
286 | reg = readl(&dp_regs->pll_ctl); |
287 | reg |= DP_PLL_RESET; | |
288 | writel(reg, &dp_regs->pll_ctl); | |
289 | ||
290 | mdelay(1); | |
291 | ||
a418f7e8 | 292 | /* Deassert DP PLL Reset */ |
d2a6982f DL |
293 | reg = readl(&dp_regs->pll_ctl); |
294 | reg &= ~(DP_PLL_RESET); | |
295 | writel(reg, &dp_regs->pll_ctl); | |
296 | ||
8c9b8dc0 | 297 | exynos_dp_set_pll_power(dp_regs, DP_ENABLE); |
d2a6982f | 298 | |
8c9b8dc0 | 299 | while (exynos_dp_get_pll_lock_status(dp_regs) == PLL_UNLOCKED) { |
d2a6982f DL |
300 | mdelay(1); |
301 | retry_cnt--; | |
302 | if (retry_cnt == 0) { | |
303 | printf("DP dp's pll lock failed : retry : %d\n", | |
304 | retry_cnt); | |
305 | return -EINVAL; | |
306 | } | |
307 | } | |
308 | ||
309 | debug("dp's pll lock success(%d)\n", retry_cnt); | |
310 | ||
311 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | |
312 | reg = readl(&dp_regs->func_en2); | |
313 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | |
314 | | AUX_FUNC_EN_N); | |
315 | writel(reg, &dp_regs->func_en2); | |
316 | ||
317 | return ret; | |
318 | } | |
319 | ||
8c9b8dc0 | 320 | void exynos_dp_init_hpd(struct exynos_dp *dp_regs) |
d2a6982f DL |
321 | { |
322 | unsigned int reg; | |
d2a6982f | 323 | |
a418f7e8 | 324 | /* Clear interrupts related to Hot Plug Detect */ |
d2a6982f DL |
325 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; |
326 | writel(reg, &dp_regs->common_int_sta4); | |
327 | ||
328 | reg = INT_HPD; | |
329 | writel(reg, &dp_regs->int_sta); | |
330 | ||
331 | reg = readl(&dp_regs->sys_ctl3); | |
332 | reg &= ~(F_HPD | HPD_CTRL); | |
333 | writel(reg, &dp_regs->sys_ctl3); | |
334 | ||
335 | return; | |
336 | } | |
337 | ||
8c9b8dc0 | 338 | static inline void exynos_dp_reset_aux(struct exynos_dp *dp_regs) |
d2a6982f DL |
339 | { |
340 | unsigned int reg; | |
d2a6982f DL |
341 | |
342 | /* Disable AUX channel module */ | |
343 | reg = readl(&dp_regs->func_en2); | |
344 | reg |= AUX_FUNC_EN_N; | |
345 | writel(reg, &dp_regs->func_en2); | |
346 | ||
347 | return; | |
348 | } | |
349 | ||
8c9b8dc0 | 350 | void exynos_dp_init_aux(struct exynos_dp *dp_regs) |
d2a6982f DL |
351 | { |
352 | unsigned int reg; | |
d2a6982f | 353 | |
a418f7e8 | 354 | /* Clear interrupts related to AUX channel */ |
d2a6982f DL |
355 | reg = RPLY_RECEIV | AUX_ERR; |
356 | writel(reg, &dp_regs->int_sta); | |
357 | ||
8c9b8dc0 | 358 | exynos_dp_reset_aux(dp_regs); |
d2a6982f DL |
359 | |
360 | /* Disable AUX transaction H/W retry */ | |
361 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(3)| | |
362 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | |
363 | writel(reg, &dp_regs->aux_hw_retry_ctl); | |
364 | ||
a418f7e8 | 365 | /* Receive AUX Channel DEFER commands equal to DEFER_COUNT*64 */ |
d2a6982f DL |
366 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); |
367 | writel(reg, &dp_regs->aux_ch_defer_ctl); | |
368 | ||
369 | /* Enable AUX channel module */ | |
370 | reg = readl(&dp_regs->func_en2); | |
371 | reg &= ~AUX_FUNC_EN_N; | |
372 | writel(reg, &dp_regs->func_en2); | |
373 | ||
374 | return; | |
375 | } | |
376 | ||
8c9b8dc0 | 377 | void exynos_dp_config_interrupt(struct exynos_dp *dp_regs) |
d2a6982f DL |
378 | { |
379 | unsigned int reg; | |
d2a6982f DL |
380 | |
381 | /* 0: mask, 1: unmask */ | |
382 | reg = COMMON_INT_MASK_1; | |
383 | writel(reg, &dp_regs->common_int_mask1); | |
384 | ||
385 | reg = COMMON_INT_MASK_2; | |
386 | writel(reg, &dp_regs->common_int_mask2); | |
387 | ||
388 | reg = COMMON_INT_MASK_3; | |
389 | writel(reg, &dp_regs->common_int_mask3); | |
390 | ||
391 | reg = COMMON_INT_MASK_4; | |
392 | writel(reg, &dp_regs->common_int_mask4); | |
393 | ||
394 | reg = INT_STA_MASK; | |
395 | writel(reg, &dp_regs->int_sta_mask); | |
396 | ||
397 | return; | |
398 | } | |
399 | ||
8c9b8dc0 | 400 | unsigned int exynos_dp_get_plug_in_status(struct exynos_dp *dp_regs) |
d2a6982f DL |
401 | { |
402 | unsigned int reg; | |
d2a6982f DL |
403 | |
404 | reg = readl(&dp_regs->sys_ctl3); | |
405 | if (reg & HPD_STATUS) | |
406 | return 0; | |
407 | ||
408 | return -1; | |
409 | } | |
410 | ||
8c9b8dc0 | 411 | unsigned int exynos_dp_detect_hpd(struct exynos_dp *dp_regs) |
d2a6982f DL |
412 | { |
413 | int timeout_loop = DP_TIMEOUT_LOOP_COUNT; | |
414 | ||
415 | mdelay(2); | |
416 | ||
8c9b8dc0 | 417 | while (exynos_dp_get_plug_in_status(dp_regs) != 0) { |
d2a6982f DL |
418 | if (timeout_loop == 0) |
419 | return -EINVAL; | |
420 | mdelay(10); | |
421 | timeout_loop--; | |
422 | } | |
423 | ||
424 | return EXYNOS_DP_SUCCESS; | |
425 | } | |
426 | ||
8c9b8dc0 | 427 | unsigned int exynos_dp_start_aux_transaction(struct exynos_dp *dp_regs) |
d2a6982f DL |
428 | { |
429 | unsigned int reg; | |
430 | unsigned int ret = 0; | |
431 | unsigned int retry_cnt; | |
d2a6982f DL |
432 | |
433 | /* Enable AUX CH operation */ | |
434 | reg = readl(&dp_regs->aux_ch_ctl2); | |
435 | reg |= AUX_EN; | |
436 | writel(reg, &dp_regs->aux_ch_ctl2); | |
437 | ||
438 | retry_cnt = 10; | |
439 | while (retry_cnt) { | |
440 | reg = readl(&dp_regs->int_sta); | |
441 | if (!(reg & RPLY_RECEIV)) { | |
442 | if (retry_cnt == 0) { | |
443 | printf("DP Reply Timeout!!\n"); | |
444 | ret = -EAGAIN; | |
445 | return ret; | |
446 | } | |
447 | mdelay(1); | |
448 | retry_cnt--; | |
449 | } else | |
450 | break; | |
451 | } | |
452 | ||
453 | /* Clear interrupt source for AUX CH command reply */ | |
454 | writel(reg, &dp_regs->int_sta); | |
455 | ||
456 | /* Clear interrupt source for AUX CH access error */ | |
457 | reg = readl(&dp_regs->int_sta); | |
458 | if (reg & AUX_ERR) { | |
459 | printf("DP Aux Access Error\n"); | |
460 | writel(AUX_ERR, &dp_regs->int_sta); | |
461 | ret = -EAGAIN; | |
462 | return ret; | |
463 | } | |
464 | ||
465 | /* Check AUX CH error access status */ | |
466 | reg = readl(&dp_regs->aux_ch_sta); | |
467 | if ((reg & AUX_STATUS_MASK) != 0) { | |
468 | debug("DP AUX CH error happens: %x\n", reg & AUX_STATUS_MASK); | |
469 | ret = -EAGAIN; | |
470 | return ret; | |
471 | } | |
472 | ||
473 | return EXYNOS_DP_SUCCESS; | |
474 | } | |
475 | ||
8c9b8dc0 SG |
476 | unsigned int exynos_dp_write_byte_to_dpcd(struct exynos_dp *dp_regs, |
477 | unsigned int reg_addr, | |
478 | unsigned char data) | |
d2a6982f DL |
479 | { |
480 | unsigned int reg, ret; | |
d2a6982f DL |
481 | |
482 | /* Clear AUX CH data buffer */ | |
483 | reg = BUF_CLR; | |
484 | writel(reg, &dp_regs->buffer_data_ctl); | |
485 | ||
486 | /* Select DPCD device address */ | |
487 | reg = AUX_ADDR_7_0(reg_addr); | |
488 | writel(reg, &dp_regs->aux_addr_7_0); | |
489 | reg = AUX_ADDR_15_8(reg_addr); | |
490 | writel(reg, &dp_regs->aux_addr_15_8); | |
491 | reg = AUX_ADDR_19_16(reg_addr); | |
492 | writel(reg, &dp_regs->aux_addr_19_16); | |
493 | ||
494 | /* Write data buffer */ | |
495 | reg = (unsigned int)data; | |
496 | writel(reg, &dp_regs->buf_data0); | |
497 | ||
498 | /* | |
499 | * Set DisplayPort transaction and write 1 byte | |
500 | * If bit 3 is 1, DisplayPort transaction. | |
501 | * If Bit 3 is 0, I2C transaction. | |
502 | */ | |
503 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | |
504 | writel(reg, &dp_regs->aux_ch_ctl1); | |
505 | ||
506 | /* Start AUX transaction */ | |
8c9b8dc0 | 507 | ret = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
508 | if (ret != EXYNOS_DP_SUCCESS) { |
509 | printf("DP Aux transaction failed\n"); | |
510 | return ret; | |
511 | } | |
512 | ||
513 | return ret; | |
514 | } | |
515 | ||
8c9b8dc0 SG |
516 | unsigned int exynos_dp_read_byte_from_dpcd(struct exynos_dp *dp_regs, |
517 | unsigned int reg_addr, | |
518 | unsigned char *data) | |
d2a6982f DL |
519 | { |
520 | unsigned int reg; | |
521 | int retval; | |
d2a6982f DL |
522 | |
523 | /* Clear AUX CH data buffer */ | |
524 | reg = BUF_CLR; | |
525 | writel(reg, &dp_regs->buffer_data_ctl); | |
526 | ||
527 | /* Select DPCD device address */ | |
528 | reg = AUX_ADDR_7_0(reg_addr); | |
529 | writel(reg, &dp_regs->aux_addr_7_0); | |
530 | reg = AUX_ADDR_15_8(reg_addr); | |
531 | writel(reg, &dp_regs->aux_addr_15_8); | |
532 | reg = AUX_ADDR_19_16(reg_addr); | |
533 | writel(reg, &dp_regs->aux_addr_19_16); | |
534 | ||
535 | /* | |
536 | * Set DisplayPort transaction and read 1 byte | |
537 | * If bit 3 is 1, DisplayPort transaction. | |
538 | * If Bit 3 is 0, I2C transaction. | |
539 | */ | |
540 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | |
541 | writel(reg, &dp_regs->aux_ch_ctl1); | |
542 | ||
543 | /* Start AUX transaction */ | |
8c9b8dc0 | 544 | retval = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
545 | if (!retval) |
546 | debug("DP Aux Transaction fail!\n"); | |
547 | ||
548 | /* Read data buffer */ | |
549 | reg = readl(&dp_regs->buf_data0); | |
550 | *data = (unsigned char)(reg & 0xff); | |
551 | ||
552 | return retval; | |
553 | } | |
554 | ||
8c9b8dc0 SG |
555 | unsigned int exynos_dp_write_bytes_to_dpcd(struct exynos_dp *dp_regs, |
556 | unsigned int reg_addr, | |
557 | unsigned int count, | |
558 | unsigned char data[]) | |
d2a6982f DL |
559 | { |
560 | unsigned int reg; | |
561 | unsigned int start_offset; | |
562 | unsigned int cur_data_count; | |
563 | unsigned int cur_data_idx; | |
564 | unsigned int retry_cnt; | |
565 | unsigned int ret = 0; | |
d2a6982f DL |
566 | |
567 | /* Clear AUX CH data buffer */ | |
568 | reg = BUF_CLR; | |
569 | writel(reg, &dp_regs->buffer_data_ctl); | |
570 | ||
571 | start_offset = 0; | |
572 | while (start_offset < count) { | |
573 | /* Buffer size of AUX CH is 16 * 4bytes */ | |
574 | if ((count - start_offset) > 16) | |
575 | cur_data_count = 16; | |
576 | else | |
577 | cur_data_count = count - start_offset; | |
578 | ||
579 | retry_cnt = 5; | |
580 | while (retry_cnt) { | |
581 | /* Select DPCD device address */ | |
582 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | |
583 | writel(reg, &dp_regs->aux_addr_7_0); | |
584 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | |
585 | writel(reg, &dp_regs->aux_addr_15_8); | |
586 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | |
587 | writel(reg, &dp_regs->aux_addr_19_16); | |
588 | ||
589 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | |
590 | cur_data_idx++) { | |
591 | reg = data[start_offset + cur_data_idx]; | |
592 | writel(reg, (unsigned int)&dp_regs->buf_data0 + | |
593 | (4 * cur_data_idx)); | |
594 | } | |
595 | /* | |
596 | * Set DisplayPort transaction and write | |
597 | * If bit 3 is 1, DisplayPort transaction. | |
598 | * If Bit 3 is 0, I2C transaction. | |
599 | */ | |
600 | reg = AUX_LENGTH(cur_data_count) | | |
601 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | |
602 | writel(reg, &dp_regs->aux_ch_ctl1); | |
603 | ||
604 | /* Start AUX transaction */ | |
8c9b8dc0 | 605 | ret = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
606 | if (ret != EXYNOS_DP_SUCCESS) { |
607 | if (retry_cnt == 0) { | |
608 | printf("DP Aux Transaction failed\n"); | |
609 | return ret; | |
610 | } | |
611 | retry_cnt--; | |
612 | } else | |
613 | break; | |
614 | } | |
615 | start_offset += cur_data_count; | |
616 | } | |
617 | ||
618 | return ret; | |
619 | } | |
620 | ||
8c9b8dc0 SG |
621 | unsigned int exynos_dp_read_bytes_from_dpcd(struct exynos_dp *dp_regs, |
622 | unsigned int reg_addr, | |
623 | unsigned int count, | |
624 | unsigned char data[]) | |
d2a6982f DL |
625 | { |
626 | unsigned int reg; | |
627 | unsigned int start_offset; | |
628 | unsigned int cur_data_count; | |
629 | unsigned int cur_data_idx; | |
630 | unsigned int retry_cnt; | |
631 | unsigned int ret = 0; | |
d2a6982f DL |
632 | |
633 | /* Clear AUX CH data buffer */ | |
634 | reg = BUF_CLR; | |
635 | writel(reg, &dp_regs->buffer_data_ctl); | |
636 | ||
637 | start_offset = 0; | |
638 | while (start_offset < count) { | |
639 | /* Buffer size of AUX CH is 16 * 4bytes */ | |
640 | if ((count - start_offset) > 16) | |
641 | cur_data_count = 16; | |
642 | else | |
643 | cur_data_count = count - start_offset; | |
644 | ||
645 | retry_cnt = 5; | |
646 | while (retry_cnt) { | |
647 | /* Select DPCD device address */ | |
648 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | |
649 | writel(reg, &dp_regs->aux_addr_7_0); | |
650 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | |
651 | writel(reg, &dp_regs->aux_addr_15_8); | |
652 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | |
653 | writel(reg, &dp_regs->aux_addr_19_16); | |
654 | /* | |
655 | * Set DisplayPort transaction and read | |
656 | * If bit 3 is 1, DisplayPort transaction. | |
657 | * If Bit 3 is 0, I2C transaction. | |
658 | */ | |
659 | reg = AUX_LENGTH(cur_data_count) | | |
660 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | |
661 | writel(reg, &dp_regs->aux_ch_ctl1); | |
662 | ||
663 | /* Start AUX transaction */ | |
8c9b8dc0 | 664 | ret = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
665 | if (ret != EXYNOS_DP_SUCCESS) { |
666 | if (retry_cnt == 0) { | |
667 | printf("DP Aux Transaction failed\n"); | |
668 | return ret; | |
669 | } | |
670 | retry_cnt--; | |
671 | } else | |
672 | break; | |
673 | } | |
674 | ||
675 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | |
676 | cur_data_idx++) { | |
677 | reg = readl((unsigned int)&dp_regs->buf_data0 + | |
678 | 4 * cur_data_idx); | |
679 | data[start_offset + cur_data_idx] = (unsigned char)reg; | |
680 | } | |
681 | ||
682 | start_offset += cur_data_count; | |
683 | } | |
684 | ||
685 | return ret; | |
686 | } | |
687 | ||
8c9b8dc0 SG |
688 | int exynos_dp_select_i2c_device(struct exynos_dp *dp_regs, |
689 | unsigned int device_addr, unsigned int reg_addr) | |
d2a6982f DL |
690 | { |
691 | unsigned int reg; | |
692 | int retval; | |
d2a6982f DL |
693 | |
694 | /* Set EDID device address */ | |
695 | reg = device_addr; | |
696 | writel(reg, &dp_regs->aux_addr_7_0); | |
697 | writel(0x0, &dp_regs->aux_addr_15_8); | |
698 | writel(0x0, &dp_regs->aux_addr_19_16); | |
699 | ||
700 | /* Set offset from base address of EDID device */ | |
701 | writel(reg_addr, &dp_regs->buf_data0); | |
702 | ||
703 | /* | |
704 | * Set I2C transaction and write address | |
705 | * If bit 3 is 1, DisplayPort transaction. | |
706 | * If Bit 3 is 0, I2C transaction. | |
707 | */ | |
708 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | |
709 | AUX_TX_COMM_WRITE; | |
710 | writel(reg, &dp_regs->aux_ch_ctl1); | |
711 | ||
712 | /* Start AUX transaction */ | |
8c9b8dc0 | 713 | retval = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
714 | if (retval != 0) |
715 | printf("%s: DP Aux Transaction fail!\n", __func__); | |
716 | ||
717 | return retval; | |
718 | } | |
719 | ||
8c9b8dc0 SG |
720 | int exynos_dp_read_byte_from_i2c(struct exynos_dp *dp_regs, |
721 | unsigned int device_addr, | |
722 | unsigned int reg_addr, unsigned int *data) | |
d2a6982f DL |
723 | { |
724 | unsigned int reg; | |
725 | int i; | |
726 | int retval; | |
d2a6982f DL |
727 | |
728 | for (i = 0; i < 10; i++) { | |
729 | /* Clear AUX CH data buffer */ | |
730 | reg = BUF_CLR; | |
731 | writel(reg, &dp_regs->buffer_data_ctl); | |
732 | ||
733 | /* Select EDID device */ | |
8c9b8dc0 SG |
734 | retval = exynos_dp_select_i2c_device(dp_regs, device_addr, |
735 | reg_addr); | |
d2a6982f DL |
736 | if (retval != 0) { |
737 | printf("DP Select EDID device fail. retry !\n"); | |
738 | continue; | |
739 | } | |
740 | ||
741 | /* | |
742 | * Set I2C transaction and read data | |
743 | * If bit 3 is 1, DisplayPort transaction. | |
744 | * If Bit 3 is 0, I2C transaction. | |
745 | */ | |
746 | reg = AUX_TX_COMM_I2C_TRANSACTION | | |
747 | AUX_TX_COMM_READ; | |
748 | writel(reg, &dp_regs->aux_ch_ctl1); | |
749 | ||
750 | /* Start AUX transaction */ | |
8c9b8dc0 | 751 | retval = exynos_dp_start_aux_transaction(dp_regs); |
d2a6982f DL |
752 | if (retval != EXYNOS_DP_SUCCESS) |
753 | printf("%s: DP Aux Transaction fail!\n", __func__); | |
754 | } | |
755 | ||
756 | /* Read data */ | |
757 | if (retval == 0) | |
758 | *data = readl(&dp_regs->buf_data0); | |
759 | ||
760 | return retval; | |
761 | } | |
762 | ||
8c9b8dc0 SG |
763 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp *dp_regs, |
764 | unsigned int device_addr, | |
765 | unsigned int reg_addr, unsigned int count, | |
766 | unsigned char edid[]) | |
d2a6982f DL |
767 | { |
768 | unsigned int reg; | |
769 | unsigned int i, j; | |
770 | unsigned int cur_data_idx; | |
771 | unsigned int defer = 0; | |
772 | int retval = 0; | |
d2a6982f DL |
773 | |
774 | for (i = 0; i < count; i += 16) { /* use 16 burst */ | |
775 | for (j = 0; j < 100; j++) { | |
776 | /* Clear AUX CH data buffer */ | |
777 | reg = BUF_CLR; | |
778 | writel(reg, &dp_regs->buffer_data_ctl); | |
779 | ||
780 | /* Set normal AUX CH command */ | |
781 | reg = readl(&dp_regs->aux_ch_ctl2); | |
782 | reg &= ~ADDR_ONLY; | |
783 | writel(reg, &dp_regs->aux_ch_ctl2); | |
784 | ||
785 | /* | |
786 | * If Rx sends defer, Tx sends only reads | |
787 | * request without sending addres | |
788 | */ | |
789 | if (!defer) | |
8c9b8dc0 SG |
790 | retval = exynos_dp_select_i2c_device( |
791 | dp_regs, device_addr, reg_addr + i); | |
d2a6982f DL |
792 | else |
793 | defer = 0; | |
794 | ||
795 | if (retval == EXYNOS_DP_SUCCESS) { | |
796 | /* | |
797 | * Set I2C transaction and write data | |
798 | * If bit 3 is 1, DisplayPort transaction. | |
799 | * If Bit 3 is 0, I2C transaction. | |
800 | */ | |
801 | reg = AUX_LENGTH(16) | | |
802 | AUX_TX_COMM_I2C_TRANSACTION | | |
803 | AUX_TX_COMM_READ; | |
804 | writel(reg, &dp_regs->aux_ch_ctl1); | |
805 | ||
806 | /* Start AUX transaction */ | |
8c9b8dc0 SG |
807 | retval = exynos_dp_start_aux_transaction( |
808 | dp_regs); | |
d2a6982f DL |
809 | if (retval == 0) |
810 | break; | |
811 | else | |
812 | printf("DP Aux Transaction fail!\n"); | |
813 | } | |
814 | /* Check if Rx sends defer */ | |
815 | reg = readl(&dp_regs->aux_rx_comm); | |
816 | if (reg == AUX_RX_COMM_AUX_DEFER || | |
817 | reg == AUX_RX_COMM_I2C_DEFER) { | |
129c942f | 818 | printf("DP Defer: %d\n", reg); |
d2a6982f DL |
819 | defer = 1; |
820 | } | |
821 | } | |
822 | ||
823 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | |
824 | reg = readl((unsigned int)&dp_regs->buf_data0 | |
825 | + 4 * cur_data_idx); | |
826 | edid[i + cur_data_idx] = (unsigned char)reg; | |
827 | } | |
828 | } | |
829 | ||
830 | return retval; | |
831 | } | |
832 | ||
8c9b8dc0 | 833 | void exynos_dp_reset_macro(struct exynos_dp *dp_regs) |
d2a6982f DL |
834 | { |
835 | unsigned int reg; | |
d2a6982f DL |
836 | |
837 | reg = readl(&dp_regs->phy_test); | |
838 | reg |= MACRO_RST; | |
839 | writel(reg, &dp_regs->phy_test); | |
840 | ||
841 | /* 10 us is the minimum Macro reset time. */ | |
842 | mdelay(1); | |
843 | ||
844 | reg &= ~MACRO_RST; | |
845 | writel(reg, &dp_regs->phy_test); | |
846 | } | |
847 | ||
8c9b8dc0 SG |
848 | void exynos_dp_set_link_bandwidth(struct exynos_dp *dp_regs, |
849 | unsigned char bwtype) | |
d2a6982f DL |
850 | { |
851 | unsigned int reg; | |
d2a6982f DL |
852 | |
853 | reg = (unsigned int)bwtype; | |
854 | ||
855 | /* Set bandwidth to 2.7G or 1.62G */ | |
856 | if ((bwtype == DP_LANE_BW_1_62) || (bwtype == DP_LANE_BW_2_70)) | |
857 | writel(reg, &dp_regs->link_bw_set); | |
858 | } | |
859 | ||
8c9b8dc0 | 860 | unsigned char exynos_dp_get_link_bandwidth(struct exynos_dp *dp_regs) |
d2a6982f DL |
861 | { |
862 | unsigned char ret; | |
863 | unsigned int reg; | |
d2a6982f DL |
864 | |
865 | reg = readl(&dp_regs->link_bw_set); | |
866 | ret = (unsigned char)reg; | |
867 | ||
868 | return ret; | |
869 | } | |
870 | ||
8c9b8dc0 | 871 | void exynos_dp_set_lane_count(struct exynos_dp *dp_regs, unsigned char count) |
d2a6982f DL |
872 | { |
873 | unsigned int reg; | |
d2a6982f DL |
874 | |
875 | reg = (unsigned int)count; | |
876 | ||
877 | if ((count == DP_LANE_CNT_1) || (count == DP_LANE_CNT_2) || | |
878 | (count == DP_LANE_CNT_4)) | |
879 | writel(reg, &dp_regs->lane_count_set); | |
880 | } | |
881 | ||
8c9b8dc0 | 882 | unsigned int exynos_dp_get_lane_count(struct exynos_dp *dp_regs) |
d2a6982f | 883 | { |
720873bf | 884 | return readl(&dp_regs->lane_count_set); |
d2a6982f DL |
885 | } |
886 | ||
8c9b8dc0 SG |
887 | unsigned char exynos_dp_get_lanex_pre_emphasis(struct exynos_dp *dp_regs, |
888 | unsigned char lanecnt) | |
d2a6982f | 889 | { |
d2a6982f DL |
890 | unsigned int reg_list[DP_LANE_CNT_4] = { |
891 | (unsigned int)&dp_regs->ln0_link_training_ctl, | |
892 | (unsigned int)&dp_regs->ln1_link_training_ctl, | |
893 | (unsigned int)&dp_regs->ln2_link_training_ctl, | |
894 | (unsigned int)&dp_regs->ln3_link_training_ctl, | |
895 | }; | |
896 | ||
897 | return readl(reg_list[lanecnt]); | |
898 | } | |
899 | ||
8c9b8dc0 SG |
900 | void exynos_dp_set_lanex_pre_emphasis(struct exynos_dp *dp_regs, |
901 | unsigned char request_val, | |
902 | unsigned char lanecnt) | |
d2a6982f | 903 | { |
d2a6982f DL |
904 | unsigned int reg_list[DP_LANE_CNT_4] = { |
905 | (unsigned int)&dp_regs->ln0_link_training_ctl, | |
906 | (unsigned int)&dp_regs->ln1_link_training_ctl, | |
907 | (unsigned int)&dp_regs->ln2_link_training_ctl, | |
908 | (unsigned int)&dp_regs->ln3_link_training_ctl, | |
909 | }; | |
910 | ||
911 | writel(request_val, reg_list[lanecnt]); | |
912 | } | |
913 | ||
8c9b8dc0 SG |
914 | void exynos_dp_set_lane_pre_emphasis(struct exynos_dp *dp_regs, |
915 | unsigned int level, unsigned char lanecnt) | |
d2a6982f DL |
916 | { |
917 | unsigned char i; | |
918 | unsigned int reg; | |
d2a6982f DL |
919 | unsigned int reg_list[DP_LANE_CNT_4] = { |
920 | (unsigned int)&dp_regs->ln0_link_training_ctl, | |
921 | (unsigned int)&dp_regs->ln1_link_training_ctl, | |
922 | (unsigned int)&dp_regs->ln2_link_training_ctl, | |
923 | (unsigned int)&dp_regs->ln3_link_training_ctl, | |
924 | }; | |
925 | unsigned int reg_shift[DP_LANE_CNT_4] = { | |
926 | PRE_EMPHASIS_SET_0_SHIFT, | |
927 | PRE_EMPHASIS_SET_1_SHIFT, | |
928 | PRE_EMPHASIS_SET_2_SHIFT, | |
929 | PRE_EMPHASIS_SET_3_SHIFT | |
930 | }; | |
931 | ||
932 | for (i = 0; i < lanecnt; i++) { | |
933 | reg = level << reg_shift[i]; | |
934 | writel(reg, reg_list[i]); | |
935 | } | |
936 | } | |
937 | ||
8c9b8dc0 SG |
938 | void exynos_dp_set_training_pattern(struct exynos_dp *dp_regs, |
939 | unsigned int pattern) | |
d2a6982f DL |
940 | { |
941 | unsigned int reg = 0; | |
d2a6982f DL |
942 | |
943 | switch (pattern) { | |
944 | case PRBS7: | |
945 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; | |
946 | break; | |
947 | case D10_2: | |
948 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; | |
949 | break; | |
950 | case TRAINING_PTN1: | |
951 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; | |
952 | break; | |
953 | case TRAINING_PTN2: | |
954 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; | |
955 | break; | |
956 | case DP_NONE: | |
957 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_DISABLE | | |
958 | SW_TRAINING_PATTERN_SET_NORMAL; | |
959 | break; | |
960 | default: | |
961 | break; | |
962 | } | |
963 | ||
964 | writel(reg, &dp_regs->training_ptn_set); | |
965 | } | |
966 | ||
8c9b8dc0 SG |
967 | void exynos_dp_enable_enhanced_mode(struct exynos_dp *dp_regs, |
968 | unsigned char enable) | |
d2a6982f DL |
969 | { |
970 | unsigned int reg; | |
d2a6982f DL |
971 | |
972 | reg = readl(&dp_regs->sys_ctl4); | |
973 | reg &= ~ENHANCED; | |
974 | ||
975 | if (enable) | |
976 | reg |= ENHANCED; | |
977 | ||
978 | writel(reg, &dp_regs->sys_ctl4); | |
979 | } | |
980 | ||
8c9b8dc0 | 981 | void exynos_dp_enable_scrambling(struct exynos_dp *dp_regs, unsigned int enable) |
d2a6982f DL |
982 | { |
983 | unsigned int reg; | |
d2a6982f DL |
984 | |
985 | reg = readl(&dp_regs->training_ptn_set); | |
986 | reg &= ~(SCRAMBLING_DISABLE); | |
987 | ||
988 | if (!enable) | |
989 | reg |= SCRAMBLING_DISABLE; | |
990 | ||
991 | writel(reg, &dp_regs->training_ptn_set); | |
992 | } | |
993 | ||
8c9b8dc0 | 994 | int exynos_dp_init_video(struct exynos_dp *dp_regs) |
d2a6982f DL |
995 | { |
996 | unsigned int reg; | |
d2a6982f DL |
997 | |
998 | /* Clear VID_CLK_CHG[1] and VID_FORMAT_CHG[3] and VSYNC_DET[7] */ | |
999 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; | |
1000 | writel(reg, &dp_regs->common_int_sta1); | |
1001 | ||
1002 | /* I_STRM__CLK detect : DE_CTL : Auto detect */ | |
1003 | reg &= ~DET_CTRL; | |
1004 | writel(reg, &dp_regs->sys_ctl1); | |
1005 | ||
1006 | return 0; | |
1007 | } | |
1008 | ||
8c9b8dc0 SG |
1009 | void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, |
1010 | struct edp_video_info *video_info) | |
d2a6982f DL |
1011 | { |
1012 | unsigned int reg; | |
d2a6982f DL |
1013 | |
1014 | /* Video Slave mode setting */ | |
1015 | reg = readl(&dp_regs->func_en1); | |
1016 | reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); | |
1017 | reg |= MASTER_VID_FUNC_EN_N; | |
1018 | writel(reg, &dp_regs->func_en1); | |
1019 | ||
1020 | /* Configure Interlaced for slave mode video */ | |
1021 | reg = readl(&dp_regs->video_ctl10); | |
1022 | reg &= ~INTERACE_SCAN_CFG; | |
1023 | reg |= (video_info->interlaced << INTERACE_SCAN_CFG_SHIFT); | |
1024 | writel(reg, &dp_regs->video_ctl10); | |
1025 | ||
1026 | /* Configure V sync polarity for slave mode video */ | |
1027 | reg = readl(&dp_regs->video_ctl10); | |
1028 | reg &= ~VSYNC_POLARITY_CFG; | |
1029 | reg |= (video_info->v_sync_polarity << V_S_POLARITY_CFG_SHIFT); | |
1030 | writel(reg, &dp_regs->video_ctl10); | |
1031 | ||
1032 | /* Configure H sync polarity for slave mode video */ | |
1033 | reg = readl(&dp_regs->video_ctl10); | |
1034 | reg &= ~HSYNC_POLARITY_CFG; | |
1035 | reg |= (video_info->h_sync_polarity << H_S_POLARITY_CFG_SHIFT); | |
1036 | writel(reg, &dp_regs->video_ctl10); | |
1037 | ||
a418f7e8 | 1038 | /* Set video mode to slave mode */ |
d2a6982f DL |
1039 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; |
1040 | writel(reg, &dp_regs->soc_general_ctl); | |
1041 | } | |
1042 | ||
8c9b8dc0 SG |
1043 | void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, |
1044 | struct edp_video_info *video_info) | |
d2a6982f DL |
1045 | { |
1046 | unsigned int reg; | |
d2a6982f DL |
1047 | |
1048 | /* Configure the input color depth, color space, dynamic range */ | |
1049 | reg = (video_info->dynamic_range << IN_D_RANGE_SHIFT) | | |
1050 | (video_info->color_depth << IN_BPC_SHIFT) | | |
1051 | (video_info->color_space << IN_COLOR_F_SHIFT); | |
1052 | writel(reg, &dp_regs->video_ctl2); | |
1053 | ||
1054 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | |
1055 | reg = readl(&dp_regs->video_ctl3); | |
1056 | reg &= ~IN_YC_COEFFI_MASK; | |
1057 | if (video_info->ycbcr_coeff) | |
1058 | reg |= IN_YC_COEFFI_ITU709; | |
1059 | else | |
1060 | reg |= IN_YC_COEFFI_ITU601; | |
1061 | writel(reg, &dp_regs->video_ctl3); | |
1062 | } | |
1063 | ||
8c9b8dc0 | 1064 | int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, |
8b449a66 | 1065 | struct exynos_dp_priv *priv) |
d2a6982f DL |
1066 | { |
1067 | unsigned int reg; | |
1068 | unsigned int bist_type = 0; | |
8b449a66 | 1069 | struct edp_video_info video_info = priv->video_info; |
d2a6982f DL |
1070 | |
1071 | /* For master mode, you don't need to set the video format */ | |
1072 | if (video_info.master_mode == 0) { | |
8b449a66 SG |
1073 | writel(TOTAL_LINE_CFG_L(priv->disp_info.v_total), |
1074 | &dp_regs->total_ln_cfg_l); | |
1075 | writel(TOTAL_LINE_CFG_H(priv->disp_info.v_total), | |
1076 | &dp_regs->total_ln_cfg_h); | |
1077 | writel(ACTIVE_LINE_CFG_L(priv->disp_info.v_res), | |
1078 | &dp_regs->active_ln_cfg_l); | |
1079 | writel(ACTIVE_LINE_CFG_H(priv->disp_info.v_res), | |
1080 | &dp_regs->active_ln_cfg_h); | |
1081 | writel(priv->disp_info.v_sync_width, &dp_regs->vsw_cfg); | |
1082 | writel(priv->disp_info.v_back_porch, &dp_regs->vbp_cfg); | |
1083 | writel(priv->disp_info.v_front_porch, &dp_regs->vfp_cfg); | |
1084 | ||
1085 | writel(TOTAL_PIXEL_CFG_L(priv->disp_info.h_total), | |
1086 | &dp_regs->total_pix_cfg_l); | |
1087 | writel(TOTAL_PIXEL_CFG_H(priv->disp_info.h_total), | |
1088 | &dp_regs->total_pix_cfg_h); | |
1089 | writel(ACTIVE_PIXEL_CFG_L(priv->disp_info.h_res), | |
1090 | &dp_regs->active_pix_cfg_l); | |
1091 | writel(ACTIVE_PIXEL_CFG_H(priv->disp_info.h_res), | |
1092 | &dp_regs->active_pix_cfg_h); | |
1093 | writel(H_F_PORCH_CFG_L(priv->disp_info.h_front_porch), | |
1094 | &dp_regs->hfp_cfg_l); | |
1095 | writel(H_F_PORCH_CFG_H(priv->disp_info.h_front_porch), | |
1096 | &dp_regs->hfp_cfg_h); | |
1097 | writel(H_SYNC_PORCH_CFG_L(priv->disp_info.h_sync_width), | |
1098 | &dp_regs->hsw_cfg_l); | |
1099 | writel(H_SYNC_PORCH_CFG_H(priv->disp_info.h_sync_width), | |
1100 | &dp_regs->hsw_cfg_h); | |
1101 | writel(H_B_PORCH_CFG_L(priv->disp_info.h_back_porch), | |
1102 | &dp_regs->hbp_cfg_l); | |
1103 | writel(H_B_PORCH_CFG_H(priv->disp_info.h_back_porch), | |
1104 | &dp_regs->hbp_cfg_h); | |
d2a6982f DL |
1105 | |
1106 | /* | |
1107 | * Set SLAVE_I_SCAN_CFG[2], VSYNC_P_CFG[1], | |
1108 | * HSYNC_P_CFG[0] properly | |
1109 | */ | |
1110 | reg = (video_info.interlaced << INTERACE_SCAN_CFG_SHIFT | | |
1111 | video_info.v_sync_polarity << V_S_POLARITY_CFG_SHIFT | | |
1112 | video_info.h_sync_polarity << H_S_POLARITY_CFG_SHIFT); | |
1113 | writel(reg, &dp_regs->video_ctl10); | |
1114 | } | |
1115 | ||
1116 | /* BIST color bar width set--set to each bar is 32 pixel width */ | |
1117 | switch (video_info.bist_pattern) { | |
1118 | case COLORBAR_32: | |
1119 | bist_type = BIST_WIDTH_BAR_32_PIXEL | | |
1120 | BIST_TYPE_COLOR_BAR; | |
1121 | break; | |
1122 | case COLORBAR_64: | |
1123 | bist_type = BIST_WIDTH_BAR_64_PIXEL | | |
1124 | BIST_TYPE_COLOR_BAR; | |
1125 | break; | |
1126 | case WHITE_GRAY_BALCKBAR_32: | |
1127 | bist_type = BIST_WIDTH_BAR_32_PIXEL | | |
1128 | BIST_TYPE_WHITE_GRAY_BLACK_BAR; | |
1129 | break; | |
1130 | case WHITE_GRAY_BALCKBAR_64: | |
1131 | bist_type = BIST_WIDTH_BAR_64_PIXEL | | |
1132 | BIST_TYPE_WHITE_GRAY_BLACK_BAR; | |
1133 | break; | |
1134 | case MOBILE_WHITEBAR_32: | |
1135 | bist_type = BIST_WIDTH_BAR_32_PIXEL | | |
1136 | BIST_TYPE_MOBILE_WHITE_BAR; | |
1137 | break; | |
1138 | case MOBILE_WHITEBAR_64: | |
1139 | bist_type = BIST_WIDTH_BAR_64_PIXEL | | |
1140 | BIST_TYPE_MOBILE_WHITE_BAR; | |
1141 | break; | |
1142 | default: | |
1143 | return -1; | |
1144 | } | |
1145 | ||
1146 | reg = bist_type; | |
1147 | writel(reg, &dp_regs->video_ctl4); | |
1148 | ||
1149 | return 0; | |
1150 | } | |
1151 | ||
8c9b8dc0 | 1152 | unsigned int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp *dp_regs) |
d2a6982f DL |
1153 | { |
1154 | unsigned int reg; | |
d2a6982f DL |
1155 | |
1156 | /* Update Video stream clk detect status */ | |
1157 | reg = readl(&dp_regs->sys_ctl1); | |
1158 | writel(reg, &dp_regs->sys_ctl1); | |
1159 | ||
1160 | reg = readl(&dp_regs->sys_ctl1); | |
1161 | ||
1162 | if (!(reg & DET_STA)) { | |
1163 | debug("DP Input stream clock not detected.\n"); | |
1164 | return -EIO; | |
1165 | } | |
1166 | ||
1167 | return EXYNOS_DP_SUCCESS; | |
1168 | } | |
1169 | ||
8c9b8dc0 SG |
1170 | void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, |
1171 | unsigned int m_value, unsigned int n_value) | |
d2a6982f DL |
1172 | { |
1173 | unsigned int reg; | |
d2a6982f DL |
1174 | |
1175 | if (type == REGISTER_M) { | |
1176 | reg = readl(&dp_regs->sys_ctl4); | |
1177 | reg |= FIX_M_VID; | |
1178 | writel(reg, &dp_regs->sys_ctl4); | |
1179 | reg = M_VID0_CFG(m_value); | |
1180 | writel(reg, &dp_regs->m_vid0); | |
1181 | reg = M_VID1_CFG(m_value); | |
1182 | writel(reg, &dp_regs->m_vid1); | |
1183 | reg = M_VID2_CFG(m_value); | |
1184 | writel(reg, &dp_regs->m_vid2); | |
1185 | ||
1186 | reg = N_VID0_CFG(n_value); | |
1187 | writel(reg, &dp_regs->n_vid0); | |
1188 | reg = N_VID1_CFG(n_value); | |
1189 | writel(reg, &dp_regs->n_vid1); | |
1190 | reg = N_VID2_CFG(n_value); | |
1191 | writel(reg, &dp_regs->n_vid2); | |
1192 | } else { | |
1193 | reg = readl(&dp_regs->sys_ctl4); | |
1194 | reg &= ~FIX_M_VID; | |
1195 | writel(reg, &dp_regs->sys_ctl4); | |
1196 | } | |
1197 | } | |
1198 | ||
8c9b8dc0 SG |
1199 | void exynos_dp_set_video_timing_mode(struct exynos_dp *dp_regs, |
1200 | unsigned int type) | |
d2a6982f DL |
1201 | { |
1202 | unsigned int reg; | |
d2a6982f DL |
1203 | |
1204 | reg = readl(&dp_regs->video_ctl10); | |
1205 | reg &= ~FORMAT_SEL; | |
1206 | ||
1207 | if (type != VIDEO_TIMING_FROM_CAPTURE) | |
1208 | reg |= FORMAT_SEL; | |
1209 | ||
1210 | writel(reg, &dp_regs->video_ctl10); | |
1211 | } | |
1212 | ||
8c9b8dc0 SG |
1213 | void exynos_dp_enable_video_master(struct exynos_dp *dp_regs, |
1214 | unsigned int enable) | |
d2a6982f DL |
1215 | { |
1216 | unsigned int reg; | |
d2a6982f DL |
1217 | |
1218 | reg = readl(&dp_regs->soc_general_ctl); | |
1219 | if (enable) { | |
1220 | reg &= ~VIDEO_MODE_MASK; | |
1221 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; | |
1222 | } else { | |
1223 | reg &= ~VIDEO_MODE_MASK; | |
1224 | reg |= VIDEO_MODE_SLAVE_MODE; | |
1225 | } | |
1226 | ||
1227 | writel(reg, &dp_regs->soc_general_ctl); | |
1228 | } | |
1229 | ||
8c9b8dc0 | 1230 | void exynos_dp_start_video(struct exynos_dp *dp_regs) |
d2a6982f DL |
1231 | { |
1232 | unsigned int reg; | |
d2a6982f DL |
1233 | |
1234 | /* Enable Video input and disable Mute */ | |
1235 | reg = readl(&dp_regs->video_ctl1); | |
1236 | reg |= VIDEO_EN; | |
1237 | writel(reg, &dp_regs->video_ctl1); | |
1238 | } | |
1239 | ||
8c9b8dc0 | 1240 | unsigned int exynos_dp_is_video_stream_on(struct exynos_dp *dp_regs) |
d2a6982f DL |
1241 | { |
1242 | unsigned int reg; | |
d2a6982f DL |
1243 | |
1244 | /* Update STRM_VALID */ | |
1245 | reg = readl(&dp_regs->sys_ctl3); | |
1246 | writel(reg, &dp_regs->sys_ctl3); | |
1247 | ||
1248 | reg = readl(&dp_regs->sys_ctl3); | |
1249 | if (!(reg & STRM_VALID)) | |
1250 | return -EIO; | |
1251 | ||
1252 | return EXYNOS_DP_SUCCESS; | |
1253 | } |