blob: 9a9ecc16269aa18454c1c58835526f3ba679a296 [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 */
94 exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
95 EDID_EXTENSION_FLAG,
96 &extend_block);
97
98 if (extend_block > 0) {
99 dev_dbg(dp->dev, "EDID data includes a single extension!\n");
100
101 /* Read EDID data */
102 retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
103 EDID_HEADER_PATTERN,
104 EDID_BLOCK_LENGTH,
105 &edid[EDID_HEADER_PATTERN]);
106 if (retval != 0) {
107 dev_err(dp->dev, "EDID Read failed!\n");
108 return -EIO;
109 }
110 sum = exynos_dp_calc_edid_check_sum(edid);
111 if (sum != 0) {
112 dev_err(dp->dev, "EDID bad checksum!\n");
113 return -EIO;
114 }
115
116 /* Read additional EDID data */
117 retval = exynos_dp_read_bytes_from_i2c(dp,
118 I2C_EDID_DEVICE_ADDR,
119 EDID_BLOCK_LENGTH,
120 EDID_BLOCK_LENGTH,
121 &edid[EDID_BLOCK_LENGTH]);
122 if (retval != 0) {
123 dev_err(dp->dev, "EDID Read failed!\n");
124 return -EIO;
125 }
126 sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
127 if (sum != 0) {
128 dev_err(dp->dev, "EDID bad checksum!\n");
129 return -EIO;
130 }
131
132 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
133 &test_vector);
134 if (test_vector & DPCD_TEST_EDID_READ) {
135 exynos_dp_write_byte_to_dpcd(dp,
136 DPCD_ADDR_TEST_EDID_CHECKSUM,
137 edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
138 exynos_dp_write_byte_to_dpcd(dp,
139 DPCD_ADDR_TEST_RESPONSE,
140 DPCD_TEST_EDID_CHECKSUM_WRITE);
141 }
142 } else {
143 dev_info(dp->dev, "EDID data does not include any extensions.\n");
144
145 /* Read EDID data */
146 retval = exynos_dp_read_bytes_from_i2c(dp,
147 I2C_EDID_DEVICE_ADDR,
148 EDID_HEADER_PATTERN,
149 EDID_BLOCK_LENGTH,
150 &edid[EDID_HEADER_PATTERN]);
151 if (retval != 0) {
152 dev_err(dp->dev, "EDID Read failed!\n");
153 return -EIO;
154 }
155 sum = exynos_dp_calc_edid_check_sum(edid);
156 if (sum != 0) {
157 dev_err(dp->dev, "EDID bad checksum!\n");
158 return -EIO;
159 }
160
161 exynos_dp_read_byte_from_dpcd(dp,
162 DPCD_ADDR_TEST_REQUEST,
163 &test_vector);
164 if (test_vector & DPCD_TEST_EDID_READ) {
165 exynos_dp_write_byte_to_dpcd(dp,
166 DPCD_ADDR_TEST_EDID_CHECKSUM,
167 edid[EDID_CHECKSUM]);
168 exynos_dp_write_byte_to_dpcd(dp,
169 DPCD_ADDR_TEST_RESPONSE,
170 DPCD_TEST_EDID_CHECKSUM_WRITE);
171 }
172 }
173
174 dev_err(dp->dev, "EDID Read success!\n");
175 return 0;
176}
177
178static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
179{
180 u8 buf[12];
181 int i;
182 int retval;
183
184 /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
185 exynos_dp_read_bytes_from_dpcd(dp,
186 DPCD_ADDR_DPCD_REV,
187 12, buf);
188
189 /* Read EDID */
190 for (i = 0; i < 3; i++) {
191 retval = exynos_dp_read_edid(dp);
192 if (retval == 0)
193 break;
194 }
195
196 return retval;
197}
198
199static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
200 bool enable)
201{
202 u8 data;
203
204 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
205
206 if (enable)
207 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
208 DPCD_ENHANCED_FRAME_EN |
209 DPCD_LANE_COUNT_SET(data));
210 else
211 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
212 DPCD_LANE_COUNT_SET(data));
213}
214
215static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
216{
217 u8 data;
218 int retval;
219
220 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
221 retval = DPCD_ENHANCED_FRAME_CAP(data);
222
223 return retval;
224}
225
226static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
227{
228 u8 data;
229
230 data = exynos_dp_is_enhanced_mode_available(dp);
231 exynos_dp_enable_rx_to_enhanced_mode(dp, data);
232 exynos_dp_enable_enhanced_mode(dp, data);
233}
234
235static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
236{
237 exynos_dp_set_training_pattern(dp, DP_NONE);
238
239 exynos_dp_write_byte_to_dpcd(dp,
240 DPCD_ADDR_TRAINING_PATTERN_SET,
241 DPCD_TRAINING_PATTERN_DISABLED);
242}
243
244static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
245 int pre_emphasis, int lane)
246{
247 switch (lane) {
248 case 0:
249 exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
250 break;
251 case 1:
252 exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
253 break;
254
255 case 2:
256 exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
257 break;
258
259 case 3:
260 exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
261 break;
262 }
263}
264
265static void exynos_dp_link_start(struct exynos_dp_device *dp)
266{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900267 u8 buf[4];
Jingoo Hane9474be2012-02-03 18:01:55 +0900268 int lane;
269 int lane_count;
270
271 lane_count = dp->link_train.lane_count;
272
273 dp->link_train.lt_state = CLOCK_RECOVERY;
274 dp->link_train.eq_loop = 0;
275
276 for (lane = 0; lane < lane_count; lane++)
277 dp->link_train.cr_loop[lane] = 0;
278
279 /* Set sink to D0 (Sink Not Ready) mode. */
280 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
281 DPCD_SET_POWER_STATE_D0);
282
283 /* Set link rate and count as you want to establish*/
284 exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
285 exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
286
287 /* Setup RX configuration */
288 buf[0] = dp->link_train.link_rate;
289 buf[1] = dp->link_train.lane_count;
290 exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
291 2, buf);
292
293 /* Set TX pre-emphasis to minimum */
294 for (lane = 0; lane < lane_count; lane++)
295 exynos_dp_set_lane_lane_pre_emphasis(dp,
296 PRE_EMPHASIS_LEVEL_0, lane);
297
298 /* Set training pattern 1 */
299 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
300
301 /* Set RX training pattern */
Jingoo Hane9474be2012-02-03 18:01:55 +0900302 exynos_dp_write_byte_to_dpcd(dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900303 DPCD_ADDR_TRAINING_PATTERN_SET,
304 DPCD_SCRAMBLING_DISABLED |
305 DPCD_TRAINING_PATTERN_1);
Jingoo Hane9474be2012-02-03 18:01:55 +0900306
307 for (lane = 0; lane < lane_count; lane++)
308 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
309 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
310 exynos_dp_write_bytes_to_dpcd(dp,
Jingoo Han123267a2012-07-12 15:10:03 +0900311 DPCD_ADDR_TRAINING_LANE0_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900312 lane_count, buf);
313}
314
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900315static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
Jingoo Hane9474be2012-02-03 18:01:55 +0900316{
317 int shift = (lane & 1) * 4;
318 u8 link_value = link_status[lane>>1];
319
320 return (link_value >> shift) & 0xf;
321}
322
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900323static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900324{
325 int lane;
326 u8 lane_status;
327
328 for (lane = 0; lane < lane_count; lane++) {
329 lane_status = exynos_dp_get_lane_status(link_status, lane);
330 if ((lane_status & DPCD_LANE_CR_DONE) == 0)
331 return -EINVAL;
332 }
333 return 0;
334}
335
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900336static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900337{
338 int lane;
339 u8 lane_align;
340 u8 lane_status;
341
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900342 lane_align = link_align[2];
Jingoo Han1f61ce52012-07-17 17:44:13 +0900343 if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900344 return -EINVAL;
345
346 for (lane = 0; lane < lane_count; lane++) {
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900347 lane_status = exynos_dp_get_lane_status(link_align, lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900348 lane_status &= DPCD_CHANNEL_EQ_BITS;
349 if (lane_status != DPCD_CHANNEL_EQ_BITS)
350 return -EINVAL;
351 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900352
Jingoo Hane9474be2012-02-03 18:01:55 +0900353 return 0;
354}
355
356static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
357 int lane)
358{
359 int shift = (lane & 1) * 4;
360 u8 link_value = adjust_request[lane>>1];
361
362 return (link_value >> shift) & 0x3;
363}
364
365static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
366 u8 adjust_request[2],
367 int lane)
368{
369 int shift = (lane & 1) * 4;
370 u8 link_value = adjust_request[lane>>1];
371
372 return ((link_value >> shift) & 0xc) >> 2;
373}
374
375static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
376 u8 training_lane_set, int lane)
377{
378 switch (lane) {
379 case 0:
380 exynos_dp_set_lane0_link_training(dp, training_lane_set);
381 break;
382 case 1:
383 exynos_dp_set_lane1_link_training(dp, training_lane_set);
384 break;
385
386 case 2:
387 exynos_dp_set_lane2_link_training(dp, training_lane_set);
388 break;
389
390 case 3:
391 exynos_dp_set_lane3_link_training(dp, training_lane_set);
392 break;
393 }
394}
395
396static unsigned int exynos_dp_get_lane_link_training(
397 struct exynos_dp_device *dp,
398 int lane)
399{
400 u32 reg;
401
402 switch (lane) {
403 case 0:
404 reg = exynos_dp_get_lane0_link_training(dp);
405 break;
406 case 1:
407 reg = exynos_dp_get_lane1_link_training(dp);
408 break;
409 case 2:
410 reg = exynos_dp_get_lane2_link_training(dp);
411 break;
412 case 3:
413 reg = exynos_dp_get_lane3_link_training(dp);
414 break;
Jingoo Han64c43df2012-06-20 10:25:48 +0900415 default:
416 WARN_ON(1);
417 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900418 }
419
420 return reg;
421}
422
423static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
424{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900425 exynos_dp_training_pattern_dis(dp);
426 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900427
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900428 dp->link_train.lt_state = FAILED;
Jingoo Hane9474be2012-02-03 18:01:55 +0900429}
430
431static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
432{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900433 u8 link_status[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900434 int lane;
435 int lane_count;
Jingoo Hane9474be2012-02-03 18:01:55 +0900436
Jingoo Han8f802da2012-04-04 16:00:00 +0900437 u8 adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900438 u8 voltage_swing;
439 u8 pre_emphasis;
440 u8 training_lane;
441
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900442 usleep_range(100, 101);
Jingoo Hane9474be2012-02-03 18:01:55 +0900443
Jingoo Hane9474be2012-02-03 18:01:55 +0900444 lane_count = dp->link_train.lane_count;
445
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900446 exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
447 2, link_status);
448
Jingoo Hane9474be2012-02-03 18:01:55 +0900449 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
450 /* set training pattern 2 for EQ */
451 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
452
Jingoo Hane9474be2012-02-03 18:01:55 +0900453 for (lane = 0; lane < lane_count; lane++) {
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900454 exynos_dp_read_bytes_from_dpcd(dp,
455 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
456 2, adjust_request);
Jingoo Hane9474be2012-02-03 18:01:55 +0900457 voltage_swing = exynos_dp_get_adjust_request_voltage(
458 adjust_request, lane);
459 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
460 adjust_request, lane);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900461 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
462 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
463
464 if (voltage_swing == VOLTAGE_LEVEL_3)
465 training_lane |= DPCD_MAX_SWING_REACHED;
466 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
467 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
468
Jingoo Hane9474be2012-02-03 18:01:55 +0900469 dp->link_train.training_lane[lane] = training_lane;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900470
471 exynos_dp_set_lane_link_training(dp,
472 dp->link_train.training_lane[lane],
473 lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900474 }
475
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900476 exynos_dp_write_byte_to_dpcd(dp,
477 DPCD_ADDR_TRAINING_PATTERN_SET,
478 DPCD_SCRAMBLING_DISABLED |
479 DPCD_TRAINING_PATTERN_2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900480
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900481 exynos_dp_write_bytes_to_dpcd(dp,
482 DPCD_ADDR_TRAINING_LANE0_SET,
483 lane_count,
484 dp->link_train.training_lane);
485
486 dev_info(dp->dev, "Link Training Clock Recovery success\n");
487 dp->link_train.lt_state = EQUALIZER_TRAINING;
488 } else {
489 for (lane = 0; lane < lane_count; lane++) {
490 training_lane = exynos_dp_get_lane_link_training(
491 dp, lane);
492 exynos_dp_read_bytes_from_dpcd(dp,
493 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
494 2, adjust_request);
495 voltage_swing = exynos_dp_get_adjust_request_voltage(
496 adjust_request, lane);
497 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
498 adjust_request, lane);
499
500 if (voltage_swing == VOLTAGE_LEVEL_3 ||
501 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
502 dev_err(dp->dev, "voltage or pre emphasis reached max level\n");
503 goto reduce_link_rate;
Jingoo Hane9474be2012-02-03 18:01:55 +0900504 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900505
506 if ((DPCD_VOLTAGE_SWING_GET(training_lane) ==
507 voltage_swing) &&
508 (DPCD_PRE_EMPHASIS_GET(training_lane) ==
509 pre_emphasis)) {
510 dp->link_train.cr_loop[lane]++;
511 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) {
512 dev_err(dp->dev, "CR Max loop\n");
513 goto reduce_link_rate;
514 }
515 }
516
517 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
518 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
519
520 if (voltage_swing == VOLTAGE_LEVEL_3)
521 training_lane |= DPCD_MAX_SWING_REACHED;
522 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
523 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
524
525 dp->link_train.training_lane[lane] = training_lane;
526
527 exynos_dp_set_lane_link_training(dp,
528 dp->link_train.training_lane[lane], lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900529 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900530
531 exynos_dp_write_bytes_to_dpcd(dp,
532 DPCD_ADDR_TRAINING_LANE0_SET,
533 lane_count,
534 dp->link_train.training_lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900535 }
536
537 return 0;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900538
539reduce_link_rate:
540 exynos_dp_reduce_link_rate(dp);
541 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900542}
543
544static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
545{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900546 u8 link_status[2];
547 u8 link_align[3];
Jingoo Hane9474be2012-02-03 18:01:55 +0900548 int lane;
549 int lane_count;
Jingoo Hane9474be2012-02-03 18:01:55 +0900550 u32 reg;
551
Jingoo Han8f802da2012-04-04 16:00:00 +0900552 u8 adjust_request[2];
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900553 u8 voltage_swing;
554 u8 pre_emphasis;
555 u8 training_lane;
Jingoo Hane9474be2012-02-03 18:01:55 +0900556
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900557 usleep_range(400, 401);
Jingoo Hane9474be2012-02-03 18:01:55 +0900558
Jingoo Hane9474be2012-02-03 18:01:55 +0900559 lane_count = dp->link_train.lane_count;
560
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900561 exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS,
562 2, link_status);
563
Jingoo Hane9474be2012-02-03 18:01:55 +0900564 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900565 link_align[0] = link_status[0];
566 link_align[1] = link_status[1];
567
568 exynos_dp_read_byte_from_dpcd(dp,
569 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED,
570 &link_align[2]);
571
572 for (lane = 0; lane < lane_count; lane++) {
573 exynos_dp_read_bytes_from_dpcd(dp,
574 DPCD_ADDR_ADJUST_REQUEST_LANE0_1,
575 2, adjust_request);
576 voltage_swing = exynos_dp_get_adjust_request_voltage(
577 adjust_request, lane);
578 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
579 adjust_request, lane);
580 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
581 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
582
583 if (voltage_swing == VOLTAGE_LEVEL_3)
584 training_lane |= DPCD_MAX_SWING_REACHED;
585 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
586 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
587
588 dp->link_train.training_lane[lane] = training_lane;
589 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900590
Jingoo Hane75478b2012-09-03 17:50:24 +0900591 if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900592 /* traing pattern Set to Normal */
593 exynos_dp_training_pattern_dis(dp);
594
595 dev_info(dp->dev, "Link Training success!\n");
596
597 exynos_dp_get_link_bandwidth(dp, &reg);
598 dp->link_train.link_rate = reg;
599 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
600 dp->link_train.link_rate);
601
602 exynos_dp_get_lane_count(dp, &reg);
603 dp->link_train.lane_count = reg;
604 dev_dbg(dp->dev, "final lane count = %.2x\n",
605 dp->link_train.lane_count);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900606
Jingoo Hane9474be2012-02-03 18:01:55 +0900607 /* set enhanced mode if available */
608 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900609 dp->link_train.lt_state = FINISHED;
610 } else {
611 /* not all locked */
612 dp->link_train.eq_loop++;
613
614 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900615 dev_err(dp->dev, "EQ Max loop\n");
616 goto reduce_link_rate;
Jingoo Hane9474be2012-02-03 18:01:55 +0900617 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900618
619 for (lane = 0; lane < lane_count; lane++)
620 exynos_dp_set_lane_link_training(dp,
621 dp->link_train.training_lane[lane],
622 lane);
623
624 exynos_dp_write_bytes_to_dpcd(dp,
625 DPCD_ADDR_TRAINING_LANE0_SET,
626 lane_count,
627 dp->link_train.training_lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900628 }
629 } else {
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900630 goto reduce_link_rate;
Jingoo Hane9474be2012-02-03 18:01:55 +0900631 }
632
633 return 0;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900634
635reduce_link_rate:
636 exynos_dp_reduce_link_rate(dp);
637 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900638}
639
640static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900641 u8 *bandwidth)
Jingoo Hane9474be2012-02-03 18:01:55 +0900642{
643 u8 data;
644
645 /*
646 * For DP rev.1.1, Maximum link rate of Main Link lanes
647 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
648 */
649 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
650 *bandwidth = data;
651}
652
653static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900654 u8 *lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900655{
656 u8 data;
657
658 /*
659 * For DP rev.1.1, Maximum number of Main Link lanes
660 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
661 */
662 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
663 *lane_count = DPCD_MAX_LANE_COUNT(data);
664}
665
666static void exynos_dp_init_training(struct exynos_dp_device *dp,
667 enum link_lane_count_type max_lane,
668 enum link_rate_type max_rate)
669{
670 /*
671 * MACRO_RST must be applied after the PLL_LOCK to avoid
672 * the DP inter pair skew issue for at least 10 us
673 */
674 exynos_dp_reset_macro(dp);
675
676 /* Initialize by reading RX's DPCD */
677 exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
678 exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
679
680 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
681 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
682 dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
683 dp->link_train.link_rate);
684 dp->link_train.link_rate = LINK_RATE_1_62GBPS;
685 }
686
687 if (dp->link_train.lane_count == 0) {
688 dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
689 dp->link_train.lane_count);
690 dp->link_train.lane_count = (u8)LANE_COUNT1;
691 }
692
693 /* Setup TX lane count & rate */
694 if (dp->link_train.lane_count > max_lane)
695 dp->link_train.lane_count = max_lane;
696 if (dp->link_train.link_rate > max_rate)
697 dp->link_train.link_rate = max_rate;
698
699 /* All DP analog module power up */
700 exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
701}
702
703static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
704{
705 int retval = 0;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900706 int training_finished = 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900707
708 dp->link_train.lt_state = START;
709
710 /* Process here */
711 while (!training_finished) {
712 switch (dp->link_train.lt_state) {
713 case START:
714 exynos_dp_link_start(dp);
715 break;
716 case CLOCK_RECOVERY:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900717 retval = exynos_dp_process_clock_recovery(dp);
718 if (retval)
719 dev_err(dp->dev, "LT CR failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900720 break;
721 case EQUALIZER_TRAINING:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900722 retval = exynos_dp_process_equalizer_training(dp);
723 if (retval)
724 dev_err(dp->dev, "LT EQ failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900725 break;
726 case FINISHED:
727 training_finished = 1;
728 break;
729 case FAILED:
730 return -EREMOTEIO;
731 }
732 }
733
734 return retval;
735}
736
737static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
738 u32 count,
739 u32 bwtype)
740{
741 int i;
742 int retval;
743
744 for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
745 exynos_dp_init_training(dp, count, bwtype);
746 retval = exynos_dp_sw_link_training(dp);
747 if (retval == 0)
748 break;
749
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900750 usleep_range(100, 110);
Jingoo Hane9474be2012-02-03 18:01:55 +0900751 }
752
753 return retval;
754}
755
756static int exynos_dp_config_video(struct exynos_dp_device *dp,
757 struct video_info *video_info)
758{
759 int retval = 0;
760 int timeout_loop = 0;
761 int done_count = 0;
762
763 exynos_dp_config_video_slave_mode(dp, video_info);
764
765 exynos_dp_set_video_color_format(dp, video_info->color_depth,
766 video_info->color_space,
767 video_info->dynamic_range,
768 video_info->ycbcr_coeff);
769
770 if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
771 dev_err(dp->dev, "PLL is not locked yet.\n");
772 return -EINVAL;
773 }
774
775 for (;;) {
776 timeout_loop++;
777 if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
778 break;
779 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
780 dev_err(dp->dev, "Timeout of video streamclk ok\n");
781 return -ETIMEDOUT;
782 }
783
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900784 usleep_range(1, 2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900785 }
786
787 /* Set to use the register calculated M/N video */
788 exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
789
790 /* For video bist, Video timing must be generated by register */
791 exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
792
793 /* Disable video mute */
794 exynos_dp_enable_video_mute(dp, 0);
795
796 /* Configure video slave mode */
797 exynos_dp_enable_video_master(dp, 0);
798
799 /* Enable video */
800 exynos_dp_start_video(dp);
801
802 timeout_loop = 0;
803
804 for (;;) {
805 timeout_loop++;
806 if (exynos_dp_is_video_stream_on(dp) == 0) {
807 done_count++;
808 if (done_count > 10)
809 break;
810 } else if (done_count) {
811 done_count = 0;
812 }
813 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
814 dev_err(dp->dev, "Timeout of video streamclk ok\n");
815 return -ETIMEDOUT;
816 }
817
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900818 usleep_range(1000, 1001);
Jingoo Hane9474be2012-02-03 18:01:55 +0900819 }
820
821 if (retval != 0)
822 dev_err(dp->dev, "Video stream is not detected!\n");
823
824 return retval;
825}
826
827static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
828{
829 u8 data;
830
831 if (enable) {
832 exynos_dp_enable_scrambling(dp);
833
834 exynos_dp_read_byte_from_dpcd(dp,
835 DPCD_ADDR_TRAINING_PATTERN_SET,
836 &data);
837 exynos_dp_write_byte_to_dpcd(dp,
838 DPCD_ADDR_TRAINING_PATTERN_SET,
839 (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
840 } else {
841 exynos_dp_disable_scrambling(dp);
842
843 exynos_dp_read_byte_from_dpcd(dp,
844 DPCD_ADDR_TRAINING_PATTERN_SET,
845 &data);
846 exynos_dp_write_byte_to_dpcd(dp,
847 DPCD_ADDR_TRAINING_PATTERN_SET,
848 (u8)(data | DPCD_SCRAMBLING_DISABLED));
849 }
850}
851
852static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
853{
854 struct exynos_dp_device *dp = arg;
855
856 dev_err(dp->dev, "exynos_dp_irq_handler\n");
857 return IRQ_HANDLED;
858}
859
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900860#ifdef CONFIG_OF
861static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
862{
863 struct device_node *dp_node = dev->of_node;
864 struct exynos_dp_platdata *pd;
865 struct video_info *dp_video_config;
866
867 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
868 if (!pd) {
869 dev_err(dev, "memory allocation for pdata failed\n");
870 return ERR_PTR(-ENOMEM);
871 }
872 dp_video_config = devm_kzalloc(dev,
873 sizeof(*dp_video_config), GFP_KERNEL);
874
875 if (!dp_video_config) {
876 dev_err(dev, "memory allocation for video config failed\n");
877 return ERR_PTR(-ENOMEM);
878 }
879 pd->video_info = dp_video_config;
880
881 dp_video_config->h_sync_polarity =
882 of_property_read_bool(dp_node, "hsync-active-high");
883
884 dp_video_config->v_sync_polarity =
885 of_property_read_bool(dp_node, "vsync-active-high");
886
887 dp_video_config->interlaced =
888 of_property_read_bool(dp_node, "interlaced");
889
890 if (of_property_read_u32(dp_node, "samsung,color-space",
891 &dp_video_config->color_space)) {
892 dev_err(dev, "failed to get color-space\n");
893 return ERR_PTR(-EINVAL);
894 }
895
896 if (of_property_read_u32(dp_node, "samsung,dynamic-range",
897 &dp_video_config->dynamic_range)) {
898 dev_err(dev, "failed to get dynamic-range\n");
899 return ERR_PTR(-EINVAL);
900 }
901
902 if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
903 &dp_video_config->ycbcr_coeff)) {
904 dev_err(dev, "failed to get ycbcr-coeff\n");
905 return ERR_PTR(-EINVAL);
906 }
907
908 if (of_property_read_u32(dp_node, "samsung,color-depth",
909 &dp_video_config->color_depth)) {
910 dev_err(dev, "failed to get color-depth\n");
911 return ERR_PTR(-EINVAL);
912 }
913
914 if (of_property_read_u32(dp_node, "samsung,link-rate",
915 &dp_video_config->link_rate)) {
916 dev_err(dev, "failed to get link-rate\n");
917 return ERR_PTR(-EINVAL);
918 }
919
920 if (of_property_read_u32(dp_node, "samsung,lane-count",
921 &dp_video_config->lane_count)) {
922 dev_err(dev, "failed to get lane-count\n");
923 return ERR_PTR(-EINVAL);
924 }
925
926 return pd;
927}
928
929static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
930{
931 struct device_node *dp_phy_node;
932 u32 phy_base;
933
934 dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy");
935 if (!dp_phy_node) {
936 dev_err(dp->dev, "could not find dptx-phy node\n");
937 return -ENODEV;
938 }
939
940 if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
941 dev_err(dp->dev, "faild to get reg for dptx-phy\n");
942 return -EINVAL;
943 }
944
945 if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
946 &dp->enable_mask)) {
947 dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
948 return -EINVAL;
949 }
950
951 dp->phy_addr = ioremap(phy_base, SZ_4);
952 if (!dp->phy_addr) {
953 dev_err(dp->dev, "failed to ioremap dp-phy\n");
954 return -ENOMEM;
955 }
956
957 return 0;
958}
959
960static void exynos_dp_phy_init(struct exynos_dp_device *dp)
961{
962 u32 reg;
963
964 reg = __raw_readl(dp->phy_addr);
965 reg |= dp->enable_mask;
966 __raw_writel(reg, dp->phy_addr);
967}
968
969static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
970{
971 u32 reg;
972
973 reg = __raw_readl(dp->phy_addr);
974 reg &= ~(dp->enable_mask);
975 __raw_writel(reg, dp->phy_addr);
976}
977#else
978static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
979{
980 return NULL;
981}
982
983static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
984{
985 return -EINVAL;
986}
987
988static void exynos_dp_phy_init(struct exynos_dp_device *dp)
989{
990 return;
991}
992
993static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
994{
995 return;
996}
997#endif /* CONFIG_OF */
998
Jingoo Hane9474be2012-02-03 18:01:55 +0900999static int __devinit exynos_dp_probe(struct platform_device *pdev)
1000{
1001 struct resource *res;
1002 struct exynos_dp_device *dp;
1003 struct exynos_dp_platdata *pdata;
1004
1005 int ret = 0;
1006
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001007 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1008 GFP_KERNEL);
Jingoo Hane9474be2012-02-03 18:01:55 +09001009 if (!dp) {
1010 dev_err(&pdev->dev, "no memory for device data\n");
1011 return -ENOMEM;
1012 }
1013
1014 dp->dev = &pdev->dev;
1015
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001016 if (pdev->dev.of_node) {
1017 pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
1018 if (IS_ERR(pdata))
1019 return PTR_ERR(pdata);
1020
1021 ret = exynos_dp_dt_parse_phydata(dp);
1022 if (ret)
1023 return ret;
1024 } else {
1025 pdata = pdev->dev.platform_data;
1026 if (!pdata) {
1027 dev_err(&pdev->dev, "no platform data\n");
1028 return -EINVAL;
1029 }
1030 }
1031
Damien Cassoud913f362012-08-01 18:20:39 +02001032 dp->clock = devm_clk_get(&pdev->dev, "dp");
Jingoo Hane9474be2012-02-03 18:01:55 +09001033 if (IS_ERR(dp->clock)) {
1034 dev_err(&pdev->dev, "failed to get clock\n");
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001035 return PTR_ERR(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001036 }
1037
Jingoo Han37414fb2012-10-04 15:45:14 +09001038 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001039
1040 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Hane9474be2012-02-03 18:01:55 +09001041
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001042 dp->reg_base = devm_request_and_ioremap(&pdev->dev, res);
Jingoo Hane9474be2012-02-03 18:01:55 +09001043 if (!dp->reg_base) {
1044 dev_err(&pdev->dev, "failed to ioremap\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001045 return -ENOMEM;
Jingoo Hane9474be2012-02-03 18:01:55 +09001046 }
1047
1048 dp->irq = platform_get_irq(pdev, 0);
1049 if (!dp->irq) {
1050 dev_err(&pdev->dev, "failed to get irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001051 return -ENODEV;
Jingoo Hane9474be2012-02-03 18:01:55 +09001052 }
1053
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001054 ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
1055 "exynos-dp", dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001056 if (ret) {
1057 dev_err(&pdev->dev, "failed to request irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001058 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001059 }
1060
1061 dp->video_info = pdata->video_info;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001062
1063 if (pdev->dev.of_node) {
1064 if (dp->phy_addr)
1065 exynos_dp_phy_init(dp);
1066 } else {
1067 if (pdata->phy_init)
1068 pdata->phy_init();
1069 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001070
1071 exynos_dp_init_dp(dp);
1072
1073 ret = exynos_dp_detect_hpd(dp);
1074 if (ret) {
1075 dev_err(&pdev->dev, "unable to detect hpd\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001076 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001077 }
1078
1079 exynos_dp_handle_edid(dp);
1080
1081 ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
1082 dp->video_info->link_rate);
1083 if (ret) {
1084 dev_err(&pdev->dev, "unable to do link train\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001085 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001086 }
1087
1088 exynos_dp_enable_scramble(dp, 1);
1089 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
1090 exynos_dp_enable_enhanced_mode(dp, 1);
1091
1092 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
1093 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
1094
1095 exynos_dp_init_video(dp);
1096 ret = exynos_dp_config_video(dp, dp->video_info);
1097 if (ret) {
1098 dev_err(&pdev->dev, "unable to config video\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001099 return ret;
Jingoo Hane9474be2012-02-03 18:01:55 +09001100 }
1101
1102 platform_set_drvdata(pdev, dp);
1103
1104 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +09001105}
1106
1107static int __devexit exynos_dp_remove(struct platform_device *pdev)
1108{
1109 struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
1110 struct exynos_dp_device *dp = platform_get_drvdata(pdev);
1111
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001112 if (pdev->dev.of_node) {
1113 if (dp->phy_addr)
1114 exynos_dp_phy_exit(dp);
1115 } else {
1116 if (pdata->phy_exit)
1117 pdata->phy_exit();
1118 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001119
Jingoo Han37414fb2012-10-04 15:45:14 +09001120 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001121
Jingoo Hane9474be2012-02-03 18:01:55 +09001122 return 0;
1123}
1124
1125#ifdef CONFIG_PM_SLEEP
1126static int exynos_dp_suspend(struct device *dev)
1127{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001128 struct exynos_dp_platdata *pdata = dev->platform_data;
1129 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001130
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001131 if (dev->of_node) {
1132 if (dp->phy_addr)
1133 exynos_dp_phy_exit(dp);
1134 } else {
1135 if (pdata->phy_exit)
1136 pdata->phy_exit();
1137 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001138
Jingoo Han37414fb2012-10-04 15:45:14 +09001139 clk_disable_unprepare(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001140
1141 return 0;
1142}
1143
1144static int exynos_dp_resume(struct device *dev)
1145{
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001146 struct exynos_dp_platdata *pdata = dev->platform_data;
1147 struct exynos_dp_device *dp = dev_get_drvdata(dev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001148
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001149 if (dev->of_node) {
1150 if (dp->phy_addr)
1151 exynos_dp_phy_init(dp);
1152 } else {
1153 if (pdata->phy_init)
1154 pdata->phy_init();
1155 }
Jingoo Hane9474be2012-02-03 18:01:55 +09001156
Jingoo Han37414fb2012-10-04 15:45:14 +09001157 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001158
1159 exynos_dp_init_dp(dp);
1160
1161 exynos_dp_detect_hpd(dp);
1162 exynos_dp_handle_edid(dp);
1163
1164 exynos_dp_set_link_train(dp, dp->video_info->lane_count,
1165 dp->video_info->link_rate);
1166
1167 exynos_dp_enable_scramble(dp, 1);
1168 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
1169 exynos_dp_enable_enhanced_mode(dp, 1);
1170
1171 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
1172 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
1173
1174 exynos_dp_init_video(dp);
1175 exynos_dp_config_video(dp, dp->video_info);
1176
1177 return 0;
1178}
1179#endif
1180
1181static const struct dev_pm_ops exynos_dp_pm_ops = {
1182 SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
1183};
1184
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001185static const struct of_device_id exynos_dp_match[] = {
1186 { .compatible = "samsung,exynos5-dp" },
1187 {},
1188};
1189MODULE_DEVICE_TABLE(of, exynos_dp_match);
1190
Jingoo Hane9474be2012-02-03 18:01:55 +09001191static struct platform_driver exynos_dp_driver = {
1192 .probe = exynos_dp_probe,
1193 .remove = __devexit_p(exynos_dp_remove),
1194 .driver = {
1195 .name = "exynos-dp",
1196 .owner = THIS_MODULE,
1197 .pm = &exynos_dp_pm_ops,
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001198 .of_match_table = of_match_ptr(exynos_dp_match),
Jingoo Hane9474be2012-02-03 18:01:55 +09001199 },
1200};
1201
1202module_platform_driver(exynos_dp_driver);
1203
1204MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1205MODULE_DESCRIPTION("Samsung SoC DP Driver");
1206MODULE_LICENSE("GPL");