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