blob: a4c1dec763bd9703ee57668161b76abfdfd0f09d [file] [log] [blame]
Jingoo Hane9474be2012-02-03 18:01:55 +09001/*
2 * Samsung SoC DP (Display Port) 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/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/err.h>
17#include <linux/clk.h>
18#include <linux/io.h>
19#include <linux/interrupt.h>
20#include <linux/delay.h>
Ajay Kumarc4e235c2012-10-13 05:48:00 +090021#include <linux/of.h>
Jingoo Hane9474be2012-02-03 18:01:55 +090022
23#include <video/exynos_dp.h>
24
Jingoo Hane9474be2012-02-03 18:01:55 +090025#include "exynos_dp_core.h"
26
27static int exynos_dp_init_dp(struct exynos_dp_device *dp)
28{
29 exynos_dp_reset(dp);
30
Jingoo Han24db03a2012-05-25 16:21:08 +090031 exynos_dp_swreset(dp);
32
Jingoo Han75435c72012-08-23 19:55:13 +090033 exynos_dp_init_analog_param(dp);
34 exynos_dp_init_interrupt(dp);
35
Jingoo Hane9474be2012-02-03 18:01:55 +090036 /* SW defined function Normal operation */
37 exynos_dp_enable_sw_function(dp);
38
39 exynos_dp_config_interrupt(dp);
40 exynos_dp_init_analog_func(dp);
41
42 exynos_dp_init_hpd(dp);
43 exynos_dp_init_aux(dp);
44
45 return 0;
46}
47
48static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
49{
50 int timeout_loop = 0;
51
52 exynos_dp_init_hpd(dp);
53
Jingoo Hana2c81bc2012-07-18 18:50:59 +090054 usleep_range(200, 210);
Jingoo Hane9474be2012-02-03 18:01:55 +090055
56 while (exynos_dp_get_plug_in_status(dp) != 0) {
57 timeout_loop++;
58 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
59 dev_err(dp->dev, "failed to get hpd plug status\n");
60 return -ETIMEDOUT;
61 }
Jingoo Hana2c81bc2012-07-18 18:50:59 +090062 usleep_range(10, 11);
Jingoo Hane9474be2012-02-03 18:01:55 +090063 }
64
65 return 0;
66}
67
68static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
69{
70 int i;
71 unsigned char sum = 0;
72
73 for (i = 0; i < EDID_BLOCK_LENGTH; i++)
74 sum = sum + edid_data[i];
75
76 return sum;
77}
78
79static int exynos_dp_read_edid(struct exynos_dp_device *dp)
80{
81 unsigned char edid[EDID_BLOCK_LENGTH * 2];
82 unsigned int extend_block = 0;
83 unsigned char sum;
84 unsigned char test_vector;
85 int retval;
86
87 /*
88 * EDID device address is 0x50.
89 * However, if necessary, you must have set upper address
90 * into E-EDID in I2C device, 0x30.
91 */
92
93 /* Read Extension Flag, Number of 128-byte EDID extension blocks */
Sean Paul99f54152012-11-01 02:13:00 +000094 retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
Jingoo Hane9474be2012-02-03 18:01:55 +090095 EDID_EXTENSION_FLAG,
96 &extend_block);
Sean Paul99f54152012-11-01 02:13:00 +000097 if (retval)
98 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +090099
100 if (extend_block > 0) {
101 dev_dbg(dp->dev, "EDID data includes a single extension!\n");
102
103 /* Read EDID data */
104 retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
105 EDID_HEADER_PATTERN,
106 EDID_BLOCK_LENGTH,
107 &edid[EDID_HEADER_PATTERN]);
108 if (retval != 0) {
109 dev_err(dp->dev, "EDID Read failed!\n");
110 return -EIO;
111 }
112 sum = exynos_dp_calc_edid_check_sum(edid);
113 if (sum != 0) {
114 dev_err(dp->dev, "EDID bad checksum!\n");
115 return -EIO;
116 }
117
118 /* Read additional EDID data */
119 retval = exynos_dp_read_bytes_from_i2c(dp,
120 I2C_EDID_DEVICE_ADDR,
121 EDID_BLOCK_LENGTH,
122 EDID_BLOCK_LENGTH,
123 &edid[EDID_BLOCK_LENGTH]);
124 if (retval != 0) {
125 dev_err(dp->dev, "EDID Read failed!\n");
126 return -EIO;
127 }
128 sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
129 if (sum != 0) {
130 dev_err(dp->dev, "EDID bad checksum!\n");
131 return -EIO;
132 }
133
134 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
135 &test_vector);
136 if (test_vector & DPCD_TEST_EDID_READ) {
137 exynos_dp_write_byte_to_dpcd(dp,
138 DPCD_ADDR_TEST_EDID_CHECKSUM,
139 edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
140 exynos_dp_write_byte_to_dpcd(dp,
141 DPCD_ADDR_TEST_RESPONSE,
142 DPCD_TEST_EDID_CHECKSUM_WRITE);
143 }
144 } else {
145 dev_info(dp->dev, "EDID data does not include any extensions.\n");
146
147 /* Read EDID data */
148 retval = exynos_dp_read_bytes_from_i2c(dp,
149 I2C_EDID_DEVICE_ADDR,
150 EDID_HEADER_PATTERN,
151 EDID_BLOCK_LENGTH,
152 &edid[EDID_HEADER_PATTERN]);
153 if (retval != 0) {
154 dev_err(dp->dev, "EDID Read failed!\n");
155 return -EIO;
156 }
157 sum = exynos_dp_calc_edid_check_sum(edid);
158 if (sum != 0) {
159 dev_err(dp->dev, "EDID bad checksum!\n");
160 return -EIO;
161 }
162
163 exynos_dp_read_byte_from_dpcd(dp,
164 DPCD_ADDR_TEST_REQUEST,
165 &test_vector);
166 if (test_vector & DPCD_TEST_EDID_READ) {
167 exynos_dp_write_byte_to_dpcd(dp,
168 DPCD_ADDR_TEST_EDID_CHECKSUM,
169 edid[EDID_CHECKSUM]);
170 exynos_dp_write_byte_to_dpcd(dp,
171 DPCD_ADDR_TEST_RESPONSE,
172 DPCD_TEST_EDID_CHECKSUM_WRITE);
173 }
174 }
175
176 dev_err(dp->dev, "EDID Read success!\n");
177 return 0;
178}
179
180static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
181{
182 u8 buf[12];
183 int i;
184 int retval;
185
186 /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
Sean Paul99f54152012-11-01 02:13:00 +0000187 retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
188 12, buf);
189 if (retval)
190 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900191
192 /* Read EDID */
193 for (i = 0; i < 3; i++) {
194 retval = exynos_dp_read_edid(dp);
Sean Paul99f54152012-11-01 02:13:00 +0000195 if (!retval)
Jingoo Hane9474be2012-02-03 18:01:55 +0900196 break;
197 }
198
199 return retval;
200}
201
202static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
203 bool enable)
204{
205 u8 data;
206
207 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
208
209 if (enable)
210 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
211 DPCD_ENHANCED_FRAME_EN |
212 DPCD_LANE_COUNT_SET(data));
213 else
214 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
215 DPCD_LANE_COUNT_SET(data));
216}
217
218static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
219{
220 u8 data;
221 int retval;
222
223 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
224 retval = DPCD_ENHANCED_FRAME_CAP(data);
225
226 return retval;
227}
228
229static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
230{
231 u8 data;
232
233 data = exynos_dp_is_enhanced_mode_available(dp);
234 exynos_dp_enable_rx_to_enhanced_mode(dp, data);
235 exynos_dp_enable_enhanced_mode(dp, data);
236}
237
238static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
239{
240 exynos_dp_set_training_pattern(dp, DP_NONE);
241
242 exynos_dp_write_byte_to_dpcd(dp,
243 DPCD_ADDR_TRAINING_PATTERN_SET,
244 DPCD_TRAINING_PATTERN_DISABLED);
245}
246
247static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
248 int pre_emphasis, int lane)
249{
250 switch (lane) {
251 case 0:
252 exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
253 break;
254 case 1:
255 exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
256 break;
257
258 case 2:
259 exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
260 break;
261
262 case 3:
263 exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
264 break;
265 }
266}
267
Sean Paulace2d7f2012-10-31 23:21:00 +0000268static int exynos_dp_link_start(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900269{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900270 u8 buf[4];
Sean Paul49ce41f2012-10-31 23:21:00 +0000271 int lane, lane_count, pll_tries, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900272
273 lane_count = dp->link_train.lane_count;
274
275 dp->link_train.lt_state = CLOCK_RECOVERY;
276 dp->link_train.eq_loop = 0;
277
278 for (lane = 0; lane < lane_count; lane++)
279 dp->link_train.cr_loop[lane] = 0;
280
281 /* Set sink to D0 (Sink Not Ready) mode. */
Sean Paulace2d7f2012-10-31 23:21:00 +0000282 retval = exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
Sean Paulfadec4b2012-10-31 23:21:00 +0000283 DPCD_SET_POWER_STATE_D0);
Sean Paulace2d7f2012-10-31 23:21:00 +0000284 if (retval)
285 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900286
287 /* Set link rate and count as you want to establish*/
288 exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
289 exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
290
291 /* Setup RX configuration */
292 buf[0] = dp->link_train.link_rate;
293 buf[1] = dp->link_train.lane_count;
Sean Paulace2d7f2012-10-31 23:21:00 +0000294 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900295 2, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000296 if (retval)
297 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900298
299 /* Set TX pre-emphasis to minimum */
300 for (lane = 0; lane < lane_count; lane++)
301 exynos_dp_set_lane_lane_pre_emphasis(dp,
302 PRE_EMPHASIS_LEVEL_0, lane);
303
Sean Paul49ce41f2012-10-31 23:21:00 +0000304 /* Wait for PLL lock */
305 pll_tries = 0;
306 while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
307 if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
308 dev_err(dp->dev, "Wait for PLL lock timed out\n");
309 return -ETIMEDOUT;
310 }
311
312 pll_tries++;
313 usleep_range(90, 120);
314 }
315
Jingoo Hane9474be2012-02-03 18:01:55 +0900316 /* Set training pattern 1 */
317 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
318
319 /* Set RX training pattern */
Sean Paulfadec4b2012-10-31 23:21:00 +0000320 retval = exynos_dp_write_byte_to_dpcd(dp,
321 DPCD_ADDR_TRAINING_PATTERN_SET,
322 DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
323 if (retval)
324 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900325
326 for (lane = 0; lane < lane_count; lane++)
327 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
328 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
Sean Paulfadec4b2012-10-31 23:21:00 +0000329
330 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
331 lane_count, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000332
333 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900334}
335
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900336static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
Jingoo Hane9474be2012-02-03 18:01:55 +0900337{
338 int shift = (lane & 1) * 4;
339 u8 link_value = link_status[lane>>1];
340
341 return (link_value >> shift) & 0xf;
342}
343
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900344static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900345{
346 int lane;
347 u8 lane_status;
348
349 for (lane = 0; lane < lane_count; lane++) {
350 lane_status = exynos_dp_get_lane_status(link_status, lane);
351 if ((lane_status & DPCD_LANE_CR_DONE) == 0)
352 return -EINVAL;
353 }
354 return 0;
355}
356
Sean Paulfadec4b2012-10-31 23:21:00 +0000357static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
358 int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900359{
360 int lane;
Jingoo Hane9474be2012-02-03 18:01:55 +0900361 u8 lane_status;
362
Sean Paulfadec4b2012-10-31 23:21:00 +0000363 if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900364 return -EINVAL;
365
366 for (lane = 0; lane < lane_count; lane++) {
Sean Paulfadec4b2012-10-31 23:21:00 +0000367 lane_status = exynos_dp_get_lane_status(link_status, lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900368 lane_status &= DPCD_CHANNEL_EQ_BITS;
369 if (lane_status != DPCD_CHANNEL_EQ_BITS)
370 return -EINVAL;
371 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900372
Jingoo Hane9474be2012-02-03 18:01:55 +0900373 return 0;
374}
375
376static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
377 int lane)
378{
379 int shift = (lane & 1) * 4;
380 u8 link_value = adjust_request[lane>>1];
381
382 return (link_value >> shift) & 0x3;
383}
384
385static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
386 u8 adjust_request[2],
387 int lane)
388{
389 int shift = (lane & 1) * 4;
390 u8 link_value = adjust_request[lane>>1];
391
392 return ((link_value >> shift) & 0xc) >> 2;
393}
394
395static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
396 u8 training_lane_set, int lane)
397{
398 switch (lane) {
399 case 0:
400 exynos_dp_set_lane0_link_training(dp, training_lane_set);
401 break;
402 case 1:
403 exynos_dp_set_lane1_link_training(dp, training_lane_set);
404 break;
405
406 case 2:
407 exynos_dp_set_lane2_link_training(dp, training_lane_set);
408 break;
409
410 case 3:
411 exynos_dp_set_lane3_link_training(dp, training_lane_set);
412 break;
413 }
414}
415
416static unsigned int exynos_dp_get_lane_link_training(
417 struct exynos_dp_device *dp,
418 int lane)
419{
420 u32 reg;
421
422 switch (lane) {
423 case 0:
424 reg = exynos_dp_get_lane0_link_training(dp);
425 break;
426 case 1:
427 reg = exynos_dp_get_lane1_link_training(dp);
428 break;
429 case 2:
430 reg = exynos_dp_get_lane2_link_training(dp);
431 break;
432 case 3:
433 reg = exynos_dp_get_lane3_link_training(dp);
434 break;
Jingoo Han64c43df2012-06-20 10:25:48 +0900435 default:
436 WARN_ON(1);
437 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900438 }
439
440 return reg;
441}
442
443static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
444{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900445 exynos_dp_training_pattern_dis(dp);
446 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900447
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900448 dp->link_train.lt_state = FAILED;
Jingoo Hane9474be2012-02-03 18:01:55 +0900449}
450
Sean Paulfadec4b2012-10-31 23:21:00 +0000451static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
452 u8 adjust_request[2])
453{
454 int lane, lane_count;
455 u8 voltage_swing, pre_emphasis, training_lane;
456
457 lane_count = dp->link_train.lane_count;
458 for (lane = 0; lane < lane_count; lane++) {
459 voltage_swing = exynos_dp_get_adjust_request_voltage(
460 adjust_request, lane);
461 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
462 adjust_request, lane);
463 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
464 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
465
466 if (voltage_swing == VOLTAGE_LEVEL_3)
467 training_lane |= DPCD_MAX_SWING_REACHED;
468 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
469 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
470
471 dp->link_train.training_lane[lane] = training_lane;
472 }
473}
474
Jingoo Hane9474be2012-02-03 18:01:55 +0900475static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
476{
Sean Paulace2d7f2012-10-31 23:21:00 +0000477 int lane, lane_count, retval;
Sean Paulfadec4b2012-10-31 23:21:00 +0000478 u8 voltage_swing, pre_emphasis, training_lane;
479 u8 link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900480
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900481 usleep_range(100, 101);
Jingoo Hane9474be2012-02-03 18:01:55 +0900482
Jingoo Hane9474be2012-02-03 18:01:55 +0900483 lane_count = dp->link_train.lane_count;
484
Sean Paulfadec4b2012-10-31 23:21:00 +0000485 retval = exynos_dp_read_bytes_from_dpcd(dp,
486 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
487 if (retval)
488 return retval;
489
490 retval = exynos_dp_read_bytes_from_dpcd(dp,
491 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
Sean Paulace2d7f2012-10-31 23:21:00 +0000492 if (retval)
493 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900494
Jingoo Hane9474be2012-02-03 18:01:55 +0900495 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
496 /* set training pattern 2 for EQ */
497 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
498
Sean Paulace2d7f2012-10-31 23:21:00 +0000499 retval = exynos_dp_write_byte_to_dpcd(dp,
Sean Paulfadec4b2012-10-31 23:21:00 +0000500 DPCD_ADDR_TRAINING_PATTERN_SET,
501 DPCD_SCRAMBLING_DISABLED |
502 DPCD_TRAINING_PATTERN_2);
Sean Paulace2d7f2012-10-31 23:21:00 +0000503 if (retval)
504 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900505
506 dev_info(dp->dev, "Link Training Clock Recovery success\n");
507 dp->link_train.lt_state = EQUALIZER_TRAINING;
508 } else {
509 for (lane = 0; lane < lane_count; lane++) {
510 training_lane = exynos_dp_get_lane_link_training(
511 dp, lane);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900512 voltage_swing = exynos_dp_get_adjust_request_voltage(
513 adjust_request, lane);
514 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
515 adjust_request, lane);
516
Sean Paulfadec4b2012-10-31 23:21:00 +0000517 if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
518 voltage_swing &&
519 DPCD_PRE_EMPHASIS_GET(training_lane) ==
520 pre_emphasis)
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900521 dp->link_train.cr_loop[lane]++;
Sean Paulfadec4b2012-10-31 23:21:00 +0000522
523 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
524 voltage_swing == VOLTAGE_LEVEL_3 ||
525 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
526 dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
527 dp->link_train.cr_loop[lane],
528 voltage_swing, pre_emphasis);
529 exynos_dp_reduce_link_rate(dp);
530 return -EIO;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900531 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900532 }
533 }
534
Sean Paulfadec4b2012-10-31 23:21:00 +0000535 exynos_dp_get_adjust_training_lane(dp, adjust_request);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900536
Sean Paulfadec4b2012-10-31 23:21:00 +0000537 for (lane = 0; lane < lane_count; lane++)
538 exynos_dp_set_lane_link_training(dp,
539 dp->link_train.training_lane[lane], lane);
540
541 retval = exynos_dp_write_bytes_to_dpcd(dp,
542 DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
543 dp->link_train.training_lane);
544 if (retval)
545 return retval;
546
547 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900548}
549
550static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
551{
Sean Paulace2d7f2012-10-31 23:21:00 +0000552 int lane, lane_count, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900553 u32 reg;
Sean Paulfadec4b2012-10-31 23:21:00 +0000554 u8 link_align, link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900555
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900556 usleep_range(400, 401);
Jingoo Hane9474be2012-02-03 18:01:55 +0900557
Jingoo Hane9474be2012-02-03 18:01:55 +0900558 lane_count = dp->link_train.lane_count;
559
Sean Paulfadec4b2012-10-31 23:21:00 +0000560 retval = exynos_dp_read_bytes_from_dpcd(dp,
561 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
Sean Paulace2d7f2012-10-31 23:21:00 +0000562 if (retval)
563 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900564
Sean Paulfadec4b2012-10-31 23:21:00 +0000565 if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
566 exynos_dp_reduce_link_rate(dp);
567 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900568 }
569
Sean Paulfadec4b2012-10-31 23:21:00 +0000570 retval = exynos_dp_read_bytes_from_dpcd(dp,
571 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
572 if (retval)
573 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900574
Sean Paulfadec4b2012-10-31 23:21:00 +0000575 retval = exynos_dp_read_byte_from_dpcd(dp,
576 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
577 if (retval)
578 return retval;
579
580 exynos_dp_get_adjust_training_lane(dp, adjust_request);
581
582 if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
583 /* traing pattern Set to Normal */
584 exynos_dp_training_pattern_dis(dp);
585
586 dev_info(dp->dev, "Link Training success!\n");
587
588 exynos_dp_get_link_bandwidth(dp, &reg);
589 dp->link_train.link_rate = reg;
590 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
591 dp->link_train.link_rate);
592
593 exynos_dp_get_lane_count(dp, &reg);
594 dp->link_train.lane_count = reg;
595 dev_dbg(dp->dev, "final lane count = %.2x\n",
596 dp->link_train.lane_count);
597
598 /* set enhanced mode if available */
599 exynos_dp_set_enhanced_mode(dp);
600 dp->link_train.lt_state = FINISHED;
601
602 return 0;
603 }
604
605 /* not all locked */
606 dp->link_train.eq_loop++;
607
608 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
609 dev_err(dp->dev, "EQ Max loop\n");
610 exynos_dp_reduce_link_rate(dp);
611 return -EIO;
612 }
613
614 for (lane = 0; lane < lane_count; lane++)
615 exynos_dp_set_lane_link_training(dp,
616 dp->link_train.training_lane[lane], lane);
617
618 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
619 lane_count, dp->link_train.training_lane);
620
621 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900622}
623
624static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900625 u8 *bandwidth)
Jingoo Hane9474be2012-02-03 18:01:55 +0900626{
627 u8 data;
628
629 /*
630 * For DP rev.1.1, Maximum link rate of Main Link lanes
631 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
632 */
633 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
634 *bandwidth = data;
635}
636
637static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900638 u8 *lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900639{
640 u8 data;
641
642 /*
643 * For DP rev.1.1, Maximum number of Main Link lanes
644 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
645 */
646 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
647 *lane_count = DPCD_MAX_LANE_COUNT(data);
648}
649
650static void exynos_dp_init_training(struct exynos_dp_device *dp,
651 enum link_lane_count_type max_lane,
652 enum link_rate_type max_rate)
653{
654 /*
655 * MACRO_RST must be applied after the PLL_LOCK to avoid
656 * the DP inter pair skew issue for at least 10 us
657 */
658 exynos_dp_reset_macro(dp);
659
660 /* Initialize by reading RX's DPCD */
661 exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
662 exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
663
664 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
665 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
666 dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
667 dp->link_train.link_rate);
668 dp->link_train.link_rate = LINK_RATE_1_62GBPS;
669 }
670
671 if (dp->link_train.lane_count == 0) {
672 dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
673 dp->link_train.lane_count);
674 dp->link_train.lane_count = (u8)LANE_COUNT1;
675 }
676
677 /* Setup TX lane count & rate */
678 if (dp->link_train.lane_count > max_lane)
679 dp->link_train.lane_count = max_lane;
680 if (dp->link_train.link_rate > max_rate)
681 dp->link_train.link_rate = max_rate;
682
683 /* All DP analog module power up */
684 exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
685}
686
687static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
688{
Sean Paulace2d7f2012-10-31 23:21:00 +0000689 int retval = 0, training_finished = 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900690
691 dp->link_train.lt_state = START;
692
693 /* Process here */
Sean Paulace2d7f2012-10-31 23:21:00 +0000694 while (!retval && !training_finished) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900695 switch (dp->link_train.lt_state) {
696 case START:
Sean Paulace2d7f2012-10-31 23:21:00 +0000697 retval = exynos_dp_link_start(dp);
698 if (retval)
699 dev_err(dp->dev, "LT link start failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900700 break;
701 case CLOCK_RECOVERY:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900702 retval = exynos_dp_process_clock_recovery(dp);
703 if (retval)
704 dev_err(dp->dev, "LT CR failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900705 break;
706 case EQUALIZER_TRAINING:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900707 retval = exynos_dp_process_equalizer_training(dp);
708 if (retval)
709 dev_err(dp->dev, "LT EQ failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900710 break;
711 case FINISHED:
712 training_finished = 1;
713 break;
714 case FAILED:
715 return -EREMOTEIO;
716 }
717 }
Sean Paulace2d7f2012-10-31 23:21:00 +0000718 if (retval)
719 dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
Jingoo Hane9474be2012-02-03 18:01:55 +0900720
721 return retval;
722}
723
724static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
725 u32 count,
726 u32 bwtype)
727{
728 int i;
729 int retval;
730
731 for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
732 exynos_dp_init_training(dp, count, bwtype);
733 retval = exynos_dp_sw_link_training(dp);
734 if (retval == 0)
735 break;
736
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900737 usleep_range(100, 110);
Jingoo Hane9474be2012-02-03 18:01:55 +0900738 }
739
740 return retval;
741}
742
743static int exynos_dp_config_video(struct exynos_dp_device *dp,
744 struct video_info *video_info)
745{
746 int retval = 0;
747 int timeout_loop = 0;
748 int done_count = 0;
749
750 exynos_dp_config_video_slave_mode(dp, video_info);
751
752 exynos_dp_set_video_color_format(dp, video_info->color_depth,
753 video_info->color_space,
754 video_info->dynamic_range,
755 video_info->ycbcr_coeff);
756
757 if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
758 dev_err(dp->dev, "PLL is not locked yet.\n");
759 return -EINVAL;
760 }
761
762 for (;;) {
763 timeout_loop++;
764 if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
765 break;
766 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
767 dev_err(dp->dev, "Timeout of video streamclk ok\n");
768 return -ETIMEDOUT;
769 }
770
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900771 usleep_range(1, 2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900772 }
773
774 /* Set to use the register calculated M/N video */
775 exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
776
777 /* For video bist, Video timing must be generated by register */
778 exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
779
780 /* Disable video mute */
781 exynos_dp_enable_video_mute(dp, 0);
782
783 /* Configure video slave mode */
784 exynos_dp_enable_video_master(dp, 0);
785
786 /* Enable video */
787 exynos_dp_start_video(dp);
788
789 timeout_loop = 0;
790
791 for (;;) {
792 timeout_loop++;
793 if (exynos_dp_is_video_stream_on(dp) == 0) {
794 done_count++;
795 if (done_count > 10)
796 break;
797 } else if (done_count) {
798 done_count = 0;
799 }
800 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
801 dev_err(dp->dev, "Timeout of video streamclk ok\n");
802 return -ETIMEDOUT;
803 }
804
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900805 usleep_range(1000, 1001);
Jingoo Hane9474be2012-02-03 18:01:55 +0900806 }
807
808 if (retval != 0)
809 dev_err(dp->dev, "Video stream is not detected!\n");
810
811 return retval;
812}
813
814static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
815{
816 u8 data;
817
818 if (enable) {
819 exynos_dp_enable_scrambling(dp);
820
821 exynos_dp_read_byte_from_dpcd(dp,
822 DPCD_ADDR_TRAINING_PATTERN_SET,
823 &data);
824 exynos_dp_write_byte_to_dpcd(dp,
825 DPCD_ADDR_TRAINING_PATTERN_SET,
826 (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
827 } else {
828 exynos_dp_disable_scrambling(dp);
829
830 exynos_dp_read_byte_from_dpcd(dp,
831 DPCD_ADDR_TRAINING_PATTERN_SET,
832 &data);
833 exynos_dp_write_byte_to_dpcd(dp,
834 DPCD_ADDR_TRAINING_PATTERN_SET,
835 (u8)(data | DPCD_SCRAMBLING_DISABLED));
836 }
837}
838
839static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
840{
841 struct exynos_dp_device *dp = arg;
842
843 dev_err(dp->dev, "exynos_dp_irq_handler\n");
844 return IRQ_HANDLED;
845}
846
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900847#ifdef CONFIG_OF
848static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
849{
850 struct device_node *dp_node = dev->of_node;
851 struct exynos_dp_platdata *pd;
852 struct video_info *dp_video_config;
853
854 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
855 if (!pd) {
856 dev_err(dev, "memory allocation for pdata failed\n");
857 return ERR_PTR(-ENOMEM);
858 }
859 dp_video_config = devm_kzalloc(dev,
860 sizeof(*dp_video_config), GFP_KERNEL);
861
862 if (!dp_video_config) {
863 dev_err(dev, "memory allocation for video config failed\n");
864 return ERR_PTR(-ENOMEM);
865 }
866 pd->video_info = dp_video_config;
867
868 dp_video_config->h_sync_polarity =
869 of_property_read_bool(dp_node, "hsync-active-high");
870
871 dp_video_config->v_sync_polarity =
872 of_property_read_bool(dp_node, "vsync-active-high");
873
874 dp_video_config->interlaced =
875 of_property_read_bool(dp_node, "interlaced");
876
877 if (of_property_read_u32(dp_node, "samsung,color-space",
878 &dp_video_config->color_space)) {
879 dev_err(dev, "failed to get color-space\n");
880 return ERR_PTR(-EINVAL);
881 }
882
883 if (of_property_read_u32(dp_node, "samsung,dynamic-range",
884 &dp_video_config->dynamic_range)) {
885 dev_err(dev, "failed to get dynamic-range\n");
886 return ERR_PTR(-EINVAL);
887 }
888
889 if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
890 &dp_video_config->ycbcr_coeff)) {
891 dev_err(dev, "failed to get ycbcr-coeff\n");
892 return ERR_PTR(-EINVAL);
893 }
894
895 if (of_property_read_u32(dp_node, "samsung,color-depth",
896 &dp_video_config->color_depth)) {
897 dev_err(dev, "failed to get color-depth\n");
898 return ERR_PTR(-EINVAL);
899 }
900
901 if (of_property_read_u32(dp_node, "samsung,link-rate",
902 &dp_video_config->link_rate)) {
903 dev_err(dev, "failed to get link-rate\n");
904 return ERR_PTR(-EINVAL);
905 }
906
907 if (of_property_read_u32(dp_node, "samsung,lane-count",
908 &dp_video_config->lane_count)) {
909 dev_err(dev, "failed to get lane-count\n");
910 return ERR_PTR(-EINVAL);
911 }
912
913 return pd;
914}
915
916static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
917{
918 struct device_node *dp_phy_node;
919 u32 phy_base;
920
921 dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy");
922 if (!dp_phy_node) {
923 dev_err(dp->dev, "could not find dptx-phy node\n");
924 return -ENODEV;
925 }
926
927 if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
928 dev_err(dp->dev, "faild to get reg for dptx-phy\n");
929 return -EINVAL;
930 }
931
932 if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
933 &dp->enable_mask)) {
934 dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
935 return -EINVAL;
936 }
937
938 dp->phy_addr = ioremap(phy_base, SZ_4);
939 if (!dp->phy_addr) {
940 dev_err(dp->dev, "failed to ioremap dp-phy\n");
941 return -ENOMEM;
942 }
943
944 return 0;
945}
946
947static void exynos_dp_phy_init(struct exynos_dp_device *dp)
948{
949 u32 reg;
950
951 reg = __raw_readl(dp->phy_addr);
952 reg |= dp->enable_mask;
953 __raw_writel(reg, dp->phy_addr);
954}
955
956static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
957{
958 u32 reg;
959
960 reg = __raw_readl(dp->phy_addr);
961 reg &= ~(dp->enable_mask);
962 __raw_writel(reg, dp->phy_addr);
963}
964#else
965static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
966{
967 return NULL;
968}
969
970static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
971{
972 return -EINVAL;
973}
974
975static void exynos_dp_phy_init(struct exynos_dp_device *dp)
976{
977 return;
978}
979
980static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
981{
982 return;
983}
984#endif /* CONFIG_OF */
985
Jingoo Hane9474be2012-02-03 18:01:55 +0900986static int __devinit exynos_dp_probe(struct platform_device *pdev)
987{
988 struct resource *res;
989 struct exynos_dp_device *dp;
990 struct exynos_dp_platdata *pdata;
991
992 int ret = 0;
993
Jingoo Han4d10ecf82012-05-25 16:20:45 +0900994 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
995 GFP_KERNEL);
Jingoo Hane9474be2012-02-03 18:01:55 +0900996 if (!dp) {
997 dev_err(&pdev->dev, "no memory for device data\n");
998 return -ENOMEM;
999 }
1000
1001 dp->dev = &pdev->dev;
1002
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001003 if (pdev->dev.of_node) {
1004 pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
1005 if (IS_ERR(pdata))
1006 return PTR_ERR(pdata);
1007
1008 ret = exynos_dp_dt_parse_phydata(dp);
1009 if (ret)
1010 return ret;
1011 } else {
1012 pdata = pdev->dev.platform_data;
1013 if (!pdata) {
1014 dev_err(&pdev->dev, "no platform data\n");
1015 return -EINVAL;
1016 }
1017 }
1018
Damien Cassoud913f362012-08-01 18:20:39 +02001019 dp->clock = devm_clk_get(&pdev->dev, "dp");
Jingoo Hane9474be2012-02-03 18:01:55 +09001020 if (IS_ERR(dp->clock)) {
1021 dev_err(&pdev->dev, "failed to get clock\n");
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001022 return PTR_ERR(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001023 }
1024
Jingoo Han37414fb2012-10-04 15:45:14 +09001025 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001026
1027 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Hane9474be2012-02-03 18:01:55 +09001028
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001029 dp->reg_base = devm_request_and_ioremap(&pdev->dev, res);
Jingoo Hane9474be2012-02-03 18:01:55 +09001030 if (!dp->reg_base) {
1031 dev_err(&pdev->dev, "failed to ioremap\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001032 return -ENOMEM;
Jingoo Hane9474be2012-02-03 18:01:55 +09001033 }
1034
1035 dp->irq = platform_get_irq(pdev, 0);
1036 if (!dp->irq) {
1037 dev_err(&pdev->dev, "failed to get irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001038 return -ENODEV;
Jingoo Hane9474be2012-02-03 18:01:55 +09001039 }
1040
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001041 ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
1042 "exynos-dp", dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001043 if (ret) {
1044 dev_err(&pdev->dev, "failed to request irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001045 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001046 }
1047
1048 dp->video_info = pdata->video_info;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001049
1050 if (pdev->dev.of_node) {
1051 if (dp->phy_addr)
1052 exynos_dp_phy_init(dp);
1053 } else {
1054 if (pdata->phy_init)
1055 pdata->phy_init();
1056 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001057
1058 exynos_dp_init_dp(dp);
1059
1060 ret = exynos_dp_detect_hpd(dp);
1061 if (ret) {
1062 dev_err(&pdev->dev, "unable to detect hpd\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001063 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001064 }
1065
1066 exynos_dp_handle_edid(dp);
1067
1068 ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
1069 dp->video_info->link_rate);
1070 if (ret) {
1071 dev_err(&pdev->dev, "unable to do link train\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001072 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001073 }
1074
1075 exynos_dp_enable_scramble(dp, 1);
1076 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
1077 exynos_dp_enable_enhanced_mode(dp, 1);
1078
1079 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
1080 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
1081
1082 exynos_dp_init_video(dp);
1083 ret = exynos_dp_config_video(dp, dp->video_info);
1084 if (ret) {
1085 dev_err(&pdev->dev, "unable to config video\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001086 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001087 }
1088
1089 platform_set_drvdata(pdev, dp);
1090
1091 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +09001092}
1093
1094static int __devexit exynos_dp_remove(struct platform_device *pdev)
1095{
1096 struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
1097 struct exynos_dp_device *dp = platform_get_drvdata(pdev);
1098
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001099 if (pdev->dev.of_node) {
1100 if (dp->phy_addr)
1101 exynos_dp_phy_exit(dp);
1102 } else {
1103 if (pdata->phy_exit)
1104 pdata->phy_exit();
1105 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001106
Jingoo Han37414fb2012-10-04 15:45:14 +09001107 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001108
Jingoo Hane9474be2012-02-03 18:01:55 +09001109 return 0;
1110}
1111
1112#ifdef CONFIG_PM_SLEEP
1113static int exynos_dp_suspend(struct device *dev)
1114{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001115 struct exynos_dp_platdata *pdata = dev->platform_data;
1116 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001117
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001118 if (dev->of_node) {
1119 if (dp->phy_addr)
1120 exynos_dp_phy_exit(dp);
1121 } else {
1122 if (pdata->phy_exit)
1123 pdata->phy_exit();
1124 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001125
Jingoo Han37414fb2012-10-04 15:45:14 +09001126 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001127
1128 return 0;
1129}
1130
1131static int exynos_dp_resume(struct device *dev)
1132{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001133 struct exynos_dp_platdata *pdata = dev->platform_data;
1134 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001135
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001136 if (dev->of_node) {
1137 if (dp->phy_addr)
1138 exynos_dp_phy_init(dp);
1139 } else {
1140 if (pdata->phy_init)
1141 pdata->phy_init();
1142 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001143
Jingoo Han37414fb2012-10-04 15:45:14 +09001144 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001145
1146 exynos_dp_init_dp(dp);
1147
1148 exynos_dp_detect_hpd(dp);
1149 exynos_dp_handle_edid(dp);
1150
1151 exynos_dp_set_link_train(dp, dp->video_info->lane_count,
1152 dp->video_info->link_rate);
1153
1154 exynos_dp_enable_scramble(dp, 1);
1155 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
1156 exynos_dp_enable_enhanced_mode(dp, 1);
1157
1158 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
1159 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
1160
1161 exynos_dp_init_video(dp);
1162 exynos_dp_config_video(dp, dp->video_info);
1163
1164 return 0;
1165}
1166#endif
1167
1168static const struct dev_pm_ops exynos_dp_pm_ops = {
1169 SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
1170};
1171
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001172static const struct of_device_id exynos_dp_match[] = {
1173 { .compatible = "samsung,exynos5-dp" },
1174 {},
1175};
1176MODULE_DEVICE_TABLE(of, exynos_dp_match);
1177
Jingoo Hane9474be2012-02-03 18:01:55 +09001178static struct platform_driver exynos_dp_driver = {
1179 .probe = exynos_dp_probe,
1180 .remove = __devexit_p(exynos_dp_remove),
1181 .driver = {
1182 .name = "exynos-dp",
1183 .owner = THIS_MODULE,
1184 .pm = &exynos_dp_pm_ops,
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001185 .of_match_table = of_match_ptr(exynos_dp_match),
Jingoo Hane9474be2012-02-03 18:01:55 +09001186 },
1187};
1188
1189module_platform_driver(exynos_dp_driver);
1190
1191MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1192MODULE_DESCRIPTION("Samsung SoC DP Driver");
1193MODULE_LICENSE("GPL");