diff options
Diffstat (limited to 'drivers/video/exynos/exynos_dp_reg.c')
-rw-r--r-- | drivers/video/exynos/exynos_dp_reg.c | 1173 |
1 files changed, 1173 insertions, 0 deletions
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c new file mode 100644 index 000000000000..6548afa0e3d2 --- /dev/null +++ b/drivers/video/exynos/exynos_dp_reg.c | |||
@@ -0,0 +1,1173 @@ | |||
1 | /* | ||
2 | * Samsung DP (Display port) register interface driver. | ||
3 | * | ||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. | ||
5 | * Author: Jingoo Han <jg1.han@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/delay.h> | ||
16 | |||
17 | #include <video/exynos_dp.h> | ||
18 | |||
19 | #include <plat/cpu.h> | ||
20 | |||
21 | #include "exynos_dp_core.h" | ||
22 | #include "exynos_dp_reg.h" | ||
23 | |||
24 | #define COMMON_INT_MASK_1 (0) | ||
25 | #define COMMON_INT_MASK_2 (0) | ||
26 | #define COMMON_INT_MASK_3 (0) | ||
27 | #define COMMON_INT_MASK_4 (0) | ||
28 | #define INT_STA_MASK (0) | ||
29 | |||
30 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) | ||
31 | { | ||
32 | u32 reg; | ||
33 | |||
34 | if (enable) { | ||
35 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
36 | reg |= HDCP_VIDEO_MUTE; | ||
37 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
38 | } else { | ||
39 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
40 | reg &= ~HDCP_VIDEO_MUTE; | ||
41 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | void exynos_dp_stop_video(struct exynos_dp_device *dp) | ||
46 | { | ||
47 | u32 reg; | ||
48 | |||
49 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
50 | reg &= ~VIDEO_EN; | ||
51 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
52 | } | ||
53 | |||
54 | void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable) | ||
55 | { | ||
56 | u32 reg; | ||
57 | |||
58 | if (enable) | ||
59 | reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 | | ||
60 | LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3; | ||
61 | else | ||
62 | reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 | | ||
63 | LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0; | ||
64 | |||
65 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP); | ||
66 | } | ||
67 | |||
68 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | ||
69 | { | ||
70 | /* Set interrupt pin assertion polarity as high */ | ||
71 | writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL); | ||
72 | |||
73 | /* Clear pending regisers */ | ||
74 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
75 | writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2); | ||
76 | writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3); | ||
77 | writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
78 | writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA); | ||
79 | |||
80 | /* 0:mask,1: unmask */ | ||
81 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
82 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
83 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
84 | writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
85 | writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
86 | } | ||
87 | |||
88 | void exynos_dp_reset(struct exynos_dp_device *dp) | ||
89 | { | ||
90 | u32 reg; | ||
91 | |||
92 | writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET); | ||
93 | |||
94 | exynos_dp_stop_video(dp); | ||
95 | exynos_dp_enable_video_mute(dp, 0); | ||
96 | |||
97 | reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | | ||
98 | AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | | ||
99 | HDCP_FUNC_EN_N | SW_FUNC_EN_N; | ||
100 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
101 | |||
102 | reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N | | ||
103 | SERDES_FIFO_FUNC_EN_N | | ||
104 | LS_CLK_DOMAIN_FUNC_EN_N; | ||
105 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
106 | |||
107 | udelay(20); | ||
108 | |||
109 | exynos_dp_lane_swap(dp, 0); | ||
110 | |||
111 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
112 | writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
113 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
114 | writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
115 | |||
116 | writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL); | ||
117 | writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL); | ||
118 | |||
119 | writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L); | ||
120 | writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H); | ||
121 | |||
122 | writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL); | ||
123 | |||
124 | writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
125 | |||
126 | writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD); | ||
127 | writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN); | ||
128 | |||
129 | writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH); | ||
130 | writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH); | ||
131 | |||
132 | writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
133 | |||
134 | exynos_dp_init_interrupt(dp); | ||
135 | } | ||
136 | |||
137 | void exynos_dp_config_interrupt(struct exynos_dp_device *dp) | ||
138 | { | ||
139 | u32 reg; | ||
140 | |||
141 | /* 0: mask, 1: unmask */ | ||
142 | reg = COMMON_INT_MASK_1; | ||
143 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1); | ||
144 | |||
145 | reg = COMMON_INT_MASK_2; | ||
146 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2); | ||
147 | |||
148 | reg = COMMON_INT_MASK_3; | ||
149 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3); | ||
150 | |||
151 | reg = COMMON_INT_MASK_4; | ||
152 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4); | ||
153 | |||
154 | reg = INT_STA_MASK; | ||
155 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK); | ||
156 | } | ||
157 | |||
158 | u32 exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp) | ||
159 | { | ||
160 | u32 reg; | ||
161 | |||
162 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
163 | if (reg & PLL_LOCK) | ||
164 | return PLL_LOCKED; | ||
165 | else | ||
166 | return PLL_UNLOCKED; | ||
167 | } | ||
168 | |||
169 | void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable) | ||
170 | { | ||
171 | u32 reg; | ||
172 | |||
173 | if (enable) { | ||
174 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
175 | reg |= DP_PLL_PD; | ||
176 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
177 | } else { | ||
178 | reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
179 | reg &= ~DP_PLL_PD; | ||
180 | writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | ||
185 | enum analog_power_block block, | ||
186 | bool enable) | ||
187 | { | ||
188 | u32 reg; | ||
189 | |||
190 | switch (block) { | ||
191 | case AUX_BLOCK: | ||
192 | if (enable) { | ||
193 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
194 | reg |= AUX_PD; | ||
195 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
196 | } else { | ||
197 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
198 | reg &= ~AUX_PD; | ||
199 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
200 | } | ||
201 | break; | ||
202 | case CH0_BLOCK: | ||
203 | if (enable) { | ||
204 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
205 | reg |= CH0_PD; | ||
206 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
207 | } else { | ||
208 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
209 | reg &= ~CH0_PD; | ||
210 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
211 | } | ||
212 | break; | ||
213 | case CH1_BLOCK: | ||
214 | if (enable) { | ||
215 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
216 | reg |= CH1_PD; | ||
217 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
218 | } else { | ||
219 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
220 | reg &= ~CH1_PD; | ||
221 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
222 | } | ||
223 | break; | ||
224 | case CH2_BLOCK: | ||
225 | if (enable) { | ||
226 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
227 | reg |= CH2_PD; | ||
228 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
229 | } else { | ||
230 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
231 | reg &= ~CH2_PD; | ||
232 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
233 | } | ||
234 | break; | ||
235 | case CH3_BLOCK: | ||
236 | if (enable) { | ||
237 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
238 | reg |= CH3_PD; | ||
239 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
240 | } else { | ||
241 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
242 | reg &= ~CH3_PD; | ||
243 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
244 | } | ||
245 | break; | ||
246 | case ANALOG_TOTAL: | ||
247 | if (enable) { | ||
248 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
249 | reg |= DP_PHY_PD; | ||
250 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
251 | } else { | ||
252 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD); | ||
253 | reg &= ~DP_PHY_PD; | ||
254 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
255 | } | ||
256 | break; | ||
257 | case POWER_ALL: | ||
258 | if (enable) { | ||
259 | reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD | | ||
260 | CH1_PD | CH0_PD; | ||
261 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
262 | } else { | ||
263 | writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD); | ||
264 | } | ||
265 | break; | ||
266 | default: | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | ||
272 | { | ||
273 | u32 reg; | ||
274 | |||
275 | exynos_dp_set_analog_power_down(dp, POWER_ALL, 0); | ||
276 | |||
277 | reg = PLL_LOCK_CHG; | ||
278 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
279 | |||
280 | reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
281 | reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); | ||
282 | writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL); | ||
283 | |||
284 | /* Power up PLL */ | ||
285 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) | ||
286 | exynos_dp_set_pll_power_down(dp, 0); | ||
287 | |||
288 | /* Enable Serdes FIFO function and Link symbol clock domain module */ | ||
289 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
290 | reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N | ||
291 | | AUX_FUNC_EN_N); | ||
292 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
293 | } | ||
294 | |||
295 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | ||
296 | { | ||
297 | u32 reg; | ||
298 | |||
299 | reg = HOTPLUG_CHG | HPD_LOST | PLUG; | ||
300 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
301 | |||
302 | reg = INT_HPD; | ||
303 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
304 | |||
305 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
306 | reg &= ~(F_HPD | HPD_CTRL); | ||
307 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
308 | } | ||
309 | |||
310 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | ||
311 | { | ||
312 | u32 reg; | ||
313 | |||
314 | /* Disable AUX channel module */ | ||
315 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
316 | reg |= AUX_FUNC_EN_N; | ||
317 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
318 | } | ||
319 | |||
320 | void exynos_dp_init_aux(struct exynos_dp_device *dp) | ||
321 | { | ||
322 | u32 reg; | ||
323 | |||
324 | /* Clear inerrupts related to AUX channel */ | ||
325 | reg = RPLY_RECEIV | AUX_ERR; | ||
326 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | ||
327 | |||
328 | exynos_dp_reset_aux(dp); | ||
329 | |||
330 | /* Disable AUX transaction H/W retry */ | ||
331 | reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)| | ||
332 | AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; | ||
333 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ; | ||
334 | |||
335 | /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */ | ||
336 | reg = DEFER_CTRL_EN | DEFER_COUNT(1); | ||
337 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL); | ||
338 | |||
339 | /* Enable AUX channel module */ | ||
340 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
341 | reg &= ~AUX_FUNC_EN_N; | ||
342 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | ||
343 | } | ||
344 | |||
345 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp) | ||
346 | { | ||
347 | u32 reg; | ||
348 | |||
349 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
350 | if (reg & HPD_STATUS) | ||
351 | return 0; | ||
352 | |||
353 | return -EINVAL; | ||
354 | } | ||
355 | |||
356 | void exynos_dp_enable_sw_function(struct exynos_dp_device *dp) | ||
357 | { | ||
358 | u32 reg; | ||
359 | |||
360 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
361 | reg &= ~SW_FUNC_EN_N; | ||
362 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
363 | } | ||
364 | |||
365 | int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp) | ||
366 | { | ||
367 | int reg; | ||
368 | int retval = 0; | ||
369 | |||
370 | /* Enable AUX CH operation */ | ||
371 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
372 | reg |= AUX_EN; | ||
373 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
374 | |||
375 | /* Is AUX CH command reply received? */ | ||
376 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
377 | while (!(reg & RPLY_RECEIV)) | ||
378 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
379 | |||
380 | /* Clear interrupt source for AUX CH command reply */ | ||
381 | writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA); | ||
382 | |||
383 | /* Clear interrupt source for AUX CH access error */ | ||
384 | reg = readl(dp->reg_base + EXYNOS_DP_INT_STA); | ||
385 | if (reg & AUX_ERR) { | ||
386 | writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA); | ||
387 | return -EREMOTEIO; | ||
388 | } | ||
389 | |||
390 | /* Check AUX CH error access status */ | ||
391 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA); | ||
392 | if ((reg & AUX_STATUS_MASK) != 0) { | ||
393 | dev_err(dp->dev, "AUX CH error happens: %d\n\n", | ||
394 | reg & AUX_STATUS_MASK); | ||
395 | return -EREMOTEIO; | ||
396 | } | ||
397 | |||
398 | return retval; | ||
399 | } | ||
400 | |||
401 | int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp, | ||
402 | unsigned int reg_addr, | ||
403 | unsigned char data) | ||
404 | { | ||
405 | u32 reg; | ||
406 | int i; | ||
407 | int retval; | ||
408 | |||
409 | for (i = 0; i < 3; i++) { | ||
410 | /* Clear AUX CH data buffer */ | ||
411 | reg = BUF_CLR; | ||
412 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
413 | |||
414 | /* Select DPCD device address */ | ||
415 | reg = AUX_ADDR_7_0(reg_addr); | ||
416 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
417 | reg = AUX_ADDR_15_8(reg_addr); | ||
418 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
419 | reg = AUX_ADDR_19_16(reg_addr); | ||
420 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
421 | |||
422 | /* Write data buffer */ | ||
423 | reg = (unsigned int)data; | ||
424 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
425 | |||
426 | /* | ||
427 | * Set DisplayPort transaction and write 1 byte | ||
428 | * If bit 3 is 1, DisplayPort transaction. | ||
429 | * If Bit 3 is 0, I2C transaction. | ||
430 | */ | ||
431 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
432 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
433 | |||
434 | /* Start AUX transaction */ | ||
435 | retval = exynos_dp_start_aux_transaction(dp); | ||
436 | if (retval == 0) | ||
437 | break; | ||
438 | else | ||
439 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
440 | } | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | ||
446 | unsigned int reg_addr, | ||
447 | unsigned char *data) | ||
448 | { | ||
449 | u32 reg; | ||
450 | int i; | ||
451 | int retval; | ||
452 | |||
453 | for (i = 0; i < 10; i++) { | ||
454 | /* Clear AUX CH data buffer */ | ||
455 | reg = BUF_CLR; | ||
456 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
457 | |||
458 | /* Select DPCD device address */ | ||
459 | reg = AUX_ADDR_7_0(reg_addr); | ||
460 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
461 | reg = AUX_ADDR_15_8(reg_addr); | ||
462 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
463 | reg = AUX_ADDR_19_16(reg_addr); | ||
464 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
465 | |||
466 | /* | ||
467 | * Set DisplayPort transaction and read 1 byte | ||
468 | * If bit 3 is 1, DisplayPort transaction. | ||
469 | * If Bit 3 is 0, I2C transaction. | ||
470 | */ | ||
471 | reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
472 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
473 | |||
474 | /* Start AUX transaction */ | ||
475 | retval = exynos_dp_start_aux_transaction(dp); | ||
476 | if (retval == 0) | ||
477 | break; | ||
478 | else | ||
479 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
480 | } | ||
481 | |||
482 | /* Read data buffer */ | ||
483 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
484 | *data = (unsigned char)(reg & 0xff); | ||
485 | |||
486 | return retval; | ||
487 | } | ||
488 | |||
489 | int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | ||
490 | unsigned int reg_addr, | ||
491 | unsigned int count, | ||
492 | unsigned char data[]) | ||
493 | { | ||
494 | u32 reg; | ||
495 | unsigned int start_offset; | ||
496 | unsigned int cur_data_count; | ||
497 | unsigned int cur_data_idx; | ||
498 | int i; | ||
499 | int retval = 0; | ||
500 | |||
501 | /* Clear AUX CH data buffer */ | ||
502 | reg = BUF_CLR; | ||
503 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
504 | |||
505 | start_offset = 0; | ||
506 | while (start_offset < count) { | ||
507 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
508 | if ((count - start_offset) > 16) | ||
509 | cur_data_count = 16; | ||
510 | else | ||
511 | cur_data_count = count - start_offset; | ||
512 | |||
513 | for (i = 0; i < 10; i++) { | ||
514 | /* Select DPCD device address */ | ||
515 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
516 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
517 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
518 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
519 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
520 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
521 | |||
522 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
523 | cur_data_idx++) { | ||
524 | reg = data[start_offset + cur_data_idx]; | ||
525 | writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
526 | + 4 * cur_data_idx); | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * Set DisplayPort transaction and write | ||
531 | * If bit 3 is 1, DisplayPort transaction. | ||
532 | * If Bit 3 is 0, I2C transaction. | ||
533 | */ | ||
534 | reg = AUX_LENGTH(cur_data_count) | | ||
535 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; | ||
536 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
537 | |||
538 | /* Start AUX transaction */ | ||
539 | retval = exynos_dp_start_aux_transaction(dp); | ||
540 | if (retval == 0) | ||
541 | break; | ||
542 | else | ||
543 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
544 | } | ||
545 | |||
546 | start_offset += cur_data_count; | ||
547 | } | ||
548 | |||
549 | return retval; | ||
550 | } | ||
551 | |||
552 | int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | ||
553 | unsigned int reg_addr, | ||
554 | unsigned int count, | ||
555 | unsigned char data[]) | ||
556 | { | ||
557 | u32 reg; | ||
558 | unsigned int start_offset; | ||
559 | unsigned int cur_data_count; | ||
560 | unsigned int cur_data_idx; | ||
561 | int i; | ||
562 | int retval = 0; | ||
563 | |||
564 | /* Clear AUX CH data buffer */ | ||
565 | reg = BUF_CLR; | ||
566 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
567 | |||
568 | start_offset = 0; | ||
569 | while (start_offset < count) { | ||
570 | /* Buffer size of AUX CH is 16 * 4bytes */ | ||
571 | if ((count - start_offset) > 16) | ||
572 | cur_data_count = 16; | ||
573 | else | ||
574 | cur_data_count = count - start_offset; | ||
575 | |||
576 | /* AUX CH Request Transaction process */ | ||
577 | for (i = 0; i < 10; i++) { | ||
578 | /* Select DPCD device address */ | ||
579 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | ||
580 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
581 | reg = AUX_ADDR_15_8(reg_addr + start_offset); | ||
582 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
583 | reg = AUX_ADDR_19_16(reg_addr + start_offset); | ||
584 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
585 | |||
586 | /* | ||
587 | * Set DisplayPort transaction and read | ||
588 | * If bit 3 is 1, DisplayPort transaction. | ||
589 | * If Bit 3 is 0, I2C transaction. | ||
590 | */ | ||
591 | reg = AUX_LENGTH(cur_data_count) | | ||
592 | AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; | ||
593 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
594 | |||
595 | /* Start AUX transaction */ | ||
596 | retval = exynos_dp_start_aux_transaction(dp); | ||
597 | if (retval == 0) | ||
598 | break; | ||
599 | else | ||
600 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
601 | } | ||
602 | |||
603 | for (cur_data_idx = 0; cur_data_idx < cur_data_count; | ||
604 | cur_data_idx++) { | ||
605 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
606 | + 4 * cur_data_idx); | ||
607 | data[start_offset + cur_data_idx] = | ||
608 | (unsigned char)reg; | ||
609 | } | ||
610 | |||
611 | start_offset += cur_data_count; | ||
612 | } | ||
613 | |||
614 | return retval; | ||
615 | } | ||
616 | |||
617 | int exynos_dp_select_i2c_device(struct exynos_dp_device *dp, | ||
618 | unsigned int device_addr, | ||
619 | unsigned int reg_addr) | ||
620 | { | ||
621 | u32 reg; | ||
622 | int retval; | ||
623 | |||
624 | /* Set EDID device address */ | ||
625 | reg = device_addr; | ||
626 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | ||
627 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8); | ||
628 | writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16); | ||
629 | |||
630 | /* Set offset from base address of EDID device */ | ||
631 | writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
632 | |||
633 | /* | ||
634 | * Set I2C transaction and write address | ||
635 | * If bit 3 is 1, DisplayPort transaction. | ||
636 | * If Bit 3 is 0, I2C transaction. | ||
637 | */ | ||
638 | reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | | ||
639 | AUX_TX_COMM_WRITE; | ||
640 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
641 | |||
642 | /* Start AUX transaction */ | ||
643 | retval = exynos_dp_start_aux_transaction(dp); | ||
644 | if (retval != 0) | ||
645 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
646 | |||
647 | return retval; | ||
648 | } | ||
649 | |||
650 | int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | ||
651 | unsigned int device_addr, | ||
652 | unsigned int reg_addr, | ||
653 | unsigned int *data) | ||
654 | { | ||
655 | u32 reg; | ||
656 | int i; | ||
657 | int retval; | ||
658 | |||
659 | for (i = 0; i < 10; i++) { | ||
660 | /* Clear AUX CH data buffer */ | ||
661 | reg = BUF_CLR; | ||
662 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
663 | |||
664 | /* Select EDID device */ | ||
665 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); | ||
666 | if (retval != 0) { | ||
667 | dev_err(dp->dev, "Select EDID device fail!\n"); | ||
668 | continue; | ||
669 | } | ||
670 | |||
671 | /* | ||
672 | * Set I2C transaction and read data | ||
673 | * If bit 3 is 1, DisplayPort transaction. | ||
674 | * If Bit 3 is 0, I2C transaction. | ||
675 | */ | ||
676 | reg = AUX_TX_COMM_I2C_TRANSACTION | | ||
677 | AUX_TX_COMM_READ; | ||
678 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1); | ||
679 | |||
680 | /* Start AUX transaction */ | ||
681 | retval = exynos_dp_start_aux_transaction(dp); | ||
682 | if (retval == 0) | ||
683 | break; | ||
684 | else | ||
685 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
686 | } | ||
687 | |||
688 | /* Read data */ | ||
689 | if (retval == 0) | ||
690 | *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0); | ||
691 | |||
692 | return retval; | ||
693 | } | ||
694 | |||
695 | int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | ||
696 | unsigned int device_addr, | ||
697 | unsigned int reg_addr, | ||
698 | unsigned int count, | ||
699 | unsigned char edid[]) | ||
700 | { | ||
701 | u32 reg; | ||
702 | unsigned int i, j; | ||
703 | unsigned int cur_data_idx; | ||
704 | unsigned int defer = 0; | ||
705 | int retval = 0; | ||
706 | |||
707 | for (i = 0; i < count; i += 16) { | ||
708 | for (j = 0; j < 100; j++) { | ||
709 | /* Clear AUX CH data buffer */ | ||
710 | reg = BUF_CLR; | ||
711 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | ||
712 | |||
713 | /* Set normal AUX CH command */ | ||
714 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
715 | reg &= ~ADDR_ONLY; | ||
716 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2); | ||
717 | |||
718 | /* | ||
719 | * If Rx sends defer, Tx sends only reads | ||
720 | * request without sending addres | ||
721 | */ | ||
722 | if (!defer) | ||
723 | retval = exynos_dp_select_i2c_device(dp, | ||
724 | device_addr, reg_addr + i); | ||
725 | else | ||
726 | defer = 0; | ||
727 | |||
728 | if (retval == 0) { | ||
729 | /* | ||
730 | * Set I2C transaction and write data | ||
731 | * If bit 3 is 1, DisplayPort transaction. | ||
732 | * If Bit 3 is 0, I2C transaction. | ||
733 | */ | ||
734 | reg = AUX_LENGTH(16) | | ||
735 | AUX_TX_COMM_I2C_TRANSACTION | | ||
736 | AUX_TX_COMM_READ; | ||
737 | writel(reg, dp->reg_base + | ||
738 | EXYNOS_DP_AUX_CH_CTL_1); | ||
739 | |||
740 | /* Start AUX transaction */ | ||
741 | retval = exynos_dp_start_aux_transaction(dp); | ||
742 | if (retval == 0) | ||
743 | break; | ||
744 | else | ||
745 | dev_err(dp->dev, "Aux Transaction fail!\n"); | ||
746 | } | ||
747 | /* Check if Rx sends defer */ | ||
748 | reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM); | ||
749 | if (reg == AUX_RX_COMM_AUX_DEFER || | ||
750 | reg == AUX_RX_COMM_I2C_DEFER) { | ||
751 | dev_err(dp->dev, "Defer: %d\n\n", reg); | ||
752 | defer = 1; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { | ||
757 | reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0 | ||
758 | + 4 * cur_data_idx); | ||
759 | edid[i + cur_data_idx] = (unsigned char)reg; | ||
760 | } | ||
761 | } | ||
762 | |||
763 | return retval; | ||
764 | } | ||
765 | |||
766 | void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype) | ||
767 | { | ||
768 | u32 reg; | ||
769 | |||
770 | reg = bwtype; | ||
771 | if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS)) | ||
772 | writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
773 | } | ||
774 | |||
775 | void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype) | ||
776 | { | ||
777 | u32 reg; | ||
778 | |||
779 | reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET); | ||
780 | *bwtype = reg; | ||
781 | } | ||
782 | |||
783 | void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count) | ||
784 | { | ||
785 | u32 reg; | ||
786 | |||
787 | reg = count; | ||
788 | writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
789 | } | ||
790 | |||
791 | void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count) | ||
792 | { | ||
793 | u32 reg; | ||
794 | |||
795 | reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET); | ||
796 | *count = reg; | ||
797 | } | ||
798 | |||
799 | void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable) | ||
800 | { | ||
801 | u32 reg; | ||
802 | |||
803 | if (enable) { | ||
804 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
805 | reg |= ENHANCED; | ||
806 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
807 | } else { | ||
808 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
809 | reg &= ~ENHANCED; | ||
810 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | void exynos_dp_set_training_pattern(struct exynos_dp_device *dp, | ||
815 | enum pattern_set pattern) | ||
816 | { | ||
817 | u32 reg; | ||
818 | |||
819 | switch (pattern) { | ||
820 | case PRBS7: | ||
821 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; | ||
822 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
823 | break; | ||
824 | case D10_2: | ||
825 | reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; | ||
826 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
827 | break; | ||
828 | case TRAINING_PTN1: | ||
829 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; | ||
830 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
831 | break; | ||
832 | case TRAINING_PTN2: | ||
833 | reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; | ||
834 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
835 | break; | ||
836 | case DP_NONE: | ||
837 | reg = SCRAMBLING_ENABLE | | ||
838 | LINK_QUAL_PATTERN_SET_DISABLE | | ||
839 | SW_TRAINING_PATTERN_SET_NORMAL; | ||
840 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
841 | break; | ||
842 | default: | ||
843 | break; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
848 | { | ||
849 | u32 reg; | ||
850 | |||
851 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
852 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
853 | } | ||
854 | |||
855 | void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
856 | { | ||
857 | u32 reg; | ||
858 | |||
859 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
860 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
861 | } | ||
862 | |||
863 | void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
864 | { | ||
865 | u32 reg; | ||
866 | |||
867 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
868 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
869 | } | ||
870 | |||
871 | void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level) | ||
872 | { | ||
873 | u32 reg; | ||
874 | |||
875 | reg = level << PRE_EMPHASIS_SET_SHIFT; | ||
876 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
877 | } | ||
878 | |||
879 | void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp, | ||
880 | u32 training_lane) | ||
881 | { | ||
882 | u32 reg; | ||
883 | |||
884 | reg = training_lane; | ||
885 | writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
886 | } | ||
887 | |||
888 | void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp, | ||
889 | u32 training_lane) | ||
890 | { | ||
891 | u32 reg; | ||
892 | |||
893 | reg = training_lane; | ||
894 | writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
895 | } | ||
896 | |||
897 | void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp, | ||
898 | u32 training_lane) | ||
899 | { | ||
900 | u32 reg; | ||
901 | |||
902 | reg = training_lane; | ||
903 | writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
904 | } | ||
905 | |||
906 | void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp, | ||
907 | u32 training_lane) | ||
908 | { | ||
909 | u32 reg; | ||
910 | |||
911 | reg = training_lane; | ||
912 | writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
913 | } | ||
914 | |||
915 | u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp) | ||
916 | { | ||
917 | u32 reg; | ||
918 | |||
919 | reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL); | ||
920 | return reg; | ||
921 | } | ||
922 | |||
923 | u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp) | ||
924 | { | ||
925 | u32 reg; | ||
926 | |||
927 | reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL); | ||
928 | return reg; | ||
929 | } | ||
930 | |||
931 | u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp) | ||
932 | { | ||
933 | u32 reg; | ||
934 | |||
935 | reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL); | ||
936 | return reg; | ||
937 | } | ||
938 | |||
939 | u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp) | ||
940 | { | ||
941 | u32 reg; | ||
942 | |||
943 | reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL); | ||
944 | return reg; | ||
945 | } | ||
946 | |||
947 | void exynos_dp_reset_macro(struct exynos_dp_device *dp) | ||
948 | { | ||
949 | u32 reg; | ||
950 | |||
951 | reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
952 | reg |= MACRO_RST; | ||
953 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
954 | |||
955 | /* 10 us is the minimum reset time. */ | ||
956 | udelay(10); | ||
957 | |||
958 | reg &= ~MACRO_RST; | ||
959 | writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST); | ||
960 | } | ||
961 | |||
962 | int exynos_dp_init_video(struct exynos_dp_device *dp) | ||
963 | { | ||
964 | u32 reg; | ||
965 | |||
966 | reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; | ||
967 | writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | ||
968 | |||
969 | reg = 0x0; | ||
970 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
971 | |||
972 | reg = CHA_CRI(4) | CHA_CTRL; | ||
973 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
974 | |||
975 | reg = 0x0; | ||
976 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
977 | |||
978 | reg = VID_HRES_TH(2) | VID_VRES_TH(0); | ||
979 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | ||
985 | u32 color_depth, | ||
986 | u32 color_space, | ||
987 | u32 dynamic_range, | ||
988 | u32 ycbcr_coeff) | ||
989 | { | ||
990 | u32 reg; | ||
991 | |||
992 | /* Configure the input color depth, color space, dynamic range */ | ||
993 | reg = (dynamic_range << IN_D_RANGE_SHIFT) | | ||
994 | (color_depth << IN_BPC_SHIFT) | | ||
995 | (color_space << IN_COLOR_F_SHIFT); | ||
996 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); | ||
997 | |||
998 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | ||
999 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1000 | reg &= ~IN_YC_COEFFI_MASK; | ||
1001 | if (ycbcr_coeff) | ||
1002 | reg |= IN_YC_COEFFI_ITU709; | ||
1003 | else | ||
1004 | reg |= IN_YC_COEFFI_ITU601; | ||
1005 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | ||
1006 | } | ||
1007 | |||
1008 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp) | ||
1009 | { | ||
1010 | u32 reg; | ||
1011 | |||
1012 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1013 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1014 | |||
1015 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1); | ||
1016 | |||
1017 | if (!(reg & DET_STA)) { | ||
1018 | dev_dbg(dp->dev, "Input stream clock not detected.\n"); | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | |||
1022 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1023 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1024 | |||
1025 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2); | ||
1026 | dev_dbg(dp->dev, "wait SYS_CTL_2.\n"); | ||
1027 | |||
1028 | if (reg & CHA_STA) { | ||
1029 | dev_dbg(dp->dev, "Input stream clk is changing\n"); | ||
1030 | return -EINVAL; | ||
1031 | } | ||
1032 | |||
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | ||
1037 | enum clock_recovery_m_value_type type, | ||
1038 | u32 m_value, | ||
1039 | u32 n_value) | ||
1040 | { | ||
1041 | u32 reg; | ||
1042 | |||
1043 | if (type == REGISTER_M) { | ||
1044 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1045 | reg |= FIX_M_VID; | ||
1046 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1047 | reg = m_value & 0xff; | ||
1048 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0); | ||
1049 | reg = (m_value >> 8) & 0xff; | ||
1050 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1); | ||
1051 | reg = (m_value >> 16) & 0xff; | ||
1052 | writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2); | ||
1053 | |||
1054 | reg = n_value & 0xff; | ||
1055 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1056 | reg = (n_value >> 8) & 0xff; | ||
1057 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1058 | reg = (n_value >> 16) & 0xff; | ||
1059 | writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1060 | } else { | ||
1061 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1062 | reg &= ~FIX_M_VID; | ||
1063 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4); | ||
1064 | |||
1065 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0); | ||
1066 | writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1); | ||
1067 | writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2); | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type) | ||
1072 | { | ||
1073 | u32 reg; | ||
1074 | |||
1075 | if (type == VIDEO_TIMING_FROM_CAPTURE) { | ||
1076 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1077 | reg &= ~FORMAT_SEL; | ||
1078 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1079 | } else { | ||
1080 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1081 | reg |= FORMAT_SEL; | ||
1082 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable) | ||
1087 | { | ||
1088 | u32 reg; | ||
1089 | |||
1090 | if (enable) { | ||
1091 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1092 | reg &= ~VIDEO_MODE_MASK; | ||
1093 | reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; | ||
1094 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1095 | } else { | ||
1096 | reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1097 | reg &= ~VIDEO_MODE_MASK; | ||
1098 | reg |= VIDEO_MODE_SLAVE_MODE; | ||
1099 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | void exynos_dp_start_video(struct exynos_dp_device *dp) | ||
1104 | { | ||
1105 | u32 reg; | ||
1106 | |||
1107 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1108 | reg |= VIDEO_EN; | ||
1109 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1); | ||
1110 | } | ||
1111 | |||
1112 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) | ||
1113 | { | ||
1114 | u32 reg; | ||
1115 | |||
1116 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1117 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1118 | |||
1119 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | ||
1120 | if (!(reg & STRM_VALID)) { | ||
1121 | dev_dbg(dp->dev, "Input video stream is not detected.\n"); | ||
1122 | return -EINVAL; | ||
1123 | } | ||
1124 | |||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | ||
1129 | struct video_info *video_info) | ||
1130 | { | ||
1131 | u32 reg; | ||
1132 | |||
1133 | reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1134 | reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); | ||
1135 | reg |= MASTER_VID_FUNC_EN_N; | ||
1136 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1); | ||
1137 | |||
1138 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1139 | reg &= ~INTERACE_SCAN_CFG; | ||
1140 | reg |= (video_info->interlaced << 2); | ||
1141 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1142 | |||
1143 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1144 | reg &= ~VSYNC_POLARITY_CFG; | ||
1145 | reg |= (video_info->v_sync_polarity << 1); | ||
1146 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1147 | |||
1148 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1149 | reg &= ~HSYNC_POLARITY_CFG; | ||
1150 | reg |= (video_info->h_sync_polarity << 0); | ||
1151 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | ||
1152 | |||
1153 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | ||
1154 | writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL); | ||
1155 | } | ||
1156 | |||
1157 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp) | ||
1158 | { | ||
1159 | u32 reg; | ||
1160 | |||
1161 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1162 | reg &= ~SCRAMBLING_DISABLE; | ||
1163 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1164 | } | ||
1165 | |||
1166 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp) | ||
1167 | { | ||
1168 | u32 reg; | ||
1169 | |||
1170 | reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1171 | reg |= SCRAMBLING_DISABLE; | ||
1172 | writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET); | ||
1173 | } | ||