blob: 05ce947e3347ce84ecfbfc35ec442895acccfe01 [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>
Jingoo Hane9474be2012-02-03 18:01:55 +090015#include <linux/err.h>
16#include <linux/clk.h>
17#include <linux/io.h>
18#include <linux/interrupt.h>
19#include <linux/delay.h>
Ajay Kumarc4e235c2012-10-13 05:48:00 +090020#include <linux/of.h>
Jingoo Han8114fab2013-10-16 21:58:16 +053021#include <linux/phy/phy.h>
Sean Paul1417f102014-01-30 16:19:23 -050022#include <video/of_display_timing.h>
23#include <video/of_videomode.h>
Jingoo Hane9474be2012-02-03 18:01:55 +090024
Sean Paul1417f102014-01-30 16:19:23 -050025#include <drm/drmP.h>
26
27#include "exynos_drm_drv.h"
Jingoo Hane9474be2012-02-03 18:01:55 +090028#include "exynos_dp_core.h"
29
30static int exynos_dp_init_dp(struct exynos_dp_device *dp)
31{
32 exynos_dp_reset(dp);
33
Jingoo Han24db03a2012-05-25 16:21:08 +090034 exynos_dp_swreset(dp);
35
Jingoo Han75435c72012-08-23 19:55:13 +090036 exynos_dp_init_analog_param(dp);
37 exynos_dp_init_interrupt(dp);
38
Jingoo Hane9474be2012-02-03 18:01:55 +090039 /* SW defined function Normal operation */
40 exynos_dp_enable_sw_function(dp);
41
42 exynos_dp_config_interrupt(dp);
43 exynos_dp_init_analog_func(dp);
44
45 exynos_dp_init_hpd(dp);
46 exynos_dp_init_aux(dp);
47
48 return 0;
49}
50
51static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
52{
53 int timeout_loop = 0;
54
Jingoo Hane9474be2012-02-03 18:01:55 +090055 while (exynos_dp_get_plug_in_status(dp) != 0) {
56 timeout_loop++;
57 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
58 dev_err(dp->dev, "failed to get hpd plug status\n");
59 return -ETIMEDOUT;
60 }
Jingoo Hana2c81bc2012-07-18 18:50:59 +090061 usleep_range(10, 11);
Jingoo Hane9474be2012-02-03 18:01:55 +090062 }
63
64 return 0;
65}
66
67static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
68{
69 int i;
70 unsigned char sum = 0;
71
72 for (i = 0; i < EDID_BLOCK_LENGTH; i++)
73 sum = sum + edid_data[i];
74
75 return sum;
76}
77
78static int exynos_dp_read_edid(struct exynos_dp_device *dp)
79{
80 unsigned char edid[EDID_BLOCK_LENGTH * 2];
81 unsigned int extend_block = 0;
82 unsigned char sum;
83 unsigned char test_vector;
84 int retval;
85
86 /*
87 * EDID device address is 0x50.
88 * However, if necessary, you must have set upper address
89 * into E-EDID in I2C device, 0x30.
90 */
91
92 /* Read Extension Flag, Number of 128-byte EDID extension blocks */
Sean Paul99f54152012-11-01 02:13:00 +000093 retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
Jingoo Hane9474be2012-02-03 18:01:55 +090094 EDID_EXTENSION_FLAG,
95 &extend_block);
Sean Paul99f54152012-11-01 02:13:00 +000096 if (retval)
97 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +090098
99 if (extend_block > 0) {
100 dev_dbg(dp->dev, "EDID data includes a single extension!\n");
101
102 /* Read EDID data */
103 retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
104 EDID_HEADER_PATTERN,
105 EDID_BLOCK_LENGTH,
106 &edid[EDID_HEADER_PATTERN]);
107 if (retval != 0) {
108 dev_err(dp->dev, "EDID Read failed!\n");
109 return -EIO;
110 }
111 sum = exynos_dp_calc_edid_check_sum(edid);
112 if (sum != 0) {
113 dev_err(dp->dev, "EDID bad checksum!\n");
114 return -EIO;
115 }
116
117 /* Read additional EDID data */
118 retval = exynos_dp_read_bytes_from_i2c(dp,
119 I2C_EDID_DEVICE_ADDR,
120 EDID_BLOCK_LENGTH,
121 EDID_BLOCK_LENGTH,
122 &edid[EDID_BLOCK_LENGTH]);
123 if (retval != 0) {
124 dev_err(dp->dev, "EDID Read failed!\n");
125 return -EIO;
126 }
127 sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
128 if (sum != 0) {
129 dev_err(dp->dev, "EDID bad checksum!\n");
130 return -EIO;
131 }
132
133 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
134 &test_vector);
135 if (test_vector & DPCD_TEST_EDID_READ) {
136 exynos_dp_write_byte_to_dpcd(dp,
137 DPCD_ADDR_TEST_EDID_CHECKSUM,
138 edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
139 exynos_dp_write_byte_to_dpcd(dp,
140 DPCD_ADDR_TEST_RESPONSE,
141 DPCD_TEST_EDID_CHECKSUM_WRITE);
142 }
143 } else {
144 dev_info(dp->dev, "EDID data does not include any extensions.\n");
145
146 /* Read EDID data */
147 retval = exynos_dp_read_bytes_from_i2c(dp,
148 I2C_EDID_DEVICE_ADDR,
149 EDID_HEADER_PATTERN,
150 EDID_BLOCK_LENGTH,
151 &edid[EDID_HEADER_PATTERN]);
152 if (retval != 0) {
153 dev_err(dp->dev, "EDID Read failed!\n");
154 return -EIO;
155 }
156 sum = exynos_dp_calc_edid_check_sum(edid);
157 if (sum != 0) {
158 dev_err(dp->dev, "EDID bad checksum!\n");
159 return -EIO;
160 }
161
162 exynos_dp_read_byte_from_dpcd(dp,
163 DPCD_ADDR_TEST_REQUEST,
164 &test_vector);
165 if (test_vector & DPCD_TEST_EDID_READ) {
166 exynos_dp_write_byte_to_dpcd(dp,
167 DPCD_ADDR_TEST_EDID_CHECKSUM,
168 edid[EDID_CHECKSUM]);
169 exynos_dp_write_byte_to_dpcd(dp,
170 DPCD_ADDR_TEST_RESPONSE,
171 DPCD_TEST_EDID_CHECKSUM_WRITE);
172 }
173 }
174
175 dev_err(dp->dev, "EDID Read success!\n");
176 return 0;
177}
178
179static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
180{
181 u8 buf[12];
182 int i;
183 int retval;
184
185 /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
Sean Paul99f54152012-11-01 02:13:00 +0000186 retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
187 12, buf);
188 if (retval)
189 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900190
191 /* Read EDID */
192 for (i = 0; i < 3; i++) {
193 retval = exynos_dp_read_edid(dp);
Sean Paul99f54152012-11-01 02:13:00 +0000194 if (!retval)
Jingoo Hane9474be2012-02-03 18:01:55 +0900195 break;
196 }
197
198 return retval;
199}
200
201static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
202 bool enable)
203{
204 u8 data;
205
206 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
207
208 if (enable)
209 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
210 DPCD_ENHANCED_FRAME_EN |
211 DPCD_LANE_COUNT_SET(data));
212 else
213 exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
214 DPCD_LANE_COUNT_SET(data));
215}
216
217static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
218{
219 u8 data;
220 int retval;
221
222 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
223 retval = DPCD_ENHANCED_FRAME_CAP(data);
224
225 return retval;
226}
227
228static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
229{
230 u8 data;
231
232 data = exynos_dp_is_enhanced_mode_available(dp);
233 exynos_dp_enable_rx_to_enhanced_mode(dp, data);
234 exynos_dp_enable_enhanced_mode(dp, data);
235}
236
237static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
238{
239 exynos_dp_set_training_pattern(dp, DP_NONE);
240
241 exynos_dp_write_byte_to_dpcd(dp,
242 DPCD_ADDR_TRAINING_PATTERN_SET,
243 DPCD_TRAINING_PATTERN_DISABLED);
244}
245
246static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
247 int pre_emphasis, int lane)
248{
249 switch (lane) {
250 case 0:
251 exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
252 break;
253 case 1:
254 exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
255 break;
256
257 case 2:
258 exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
259 break;
260
261 case 3:
262 exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
263 break;
264 }
265}
266
Sean Paulace2d7f2012-10-31 23:21:00 +0000267static int exynos_dp_link_start(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900268{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900269 u8 buf[4];
Sean Paul49ce41f2012-10-31 23:21:00 +0000270 int lane, lane_count, pll_tries, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900271
272 lane_count = dp->link_train.lane_count;
273
274 dp->link_train.lt_state = CLOCK_RECOVERY;
275 dp->link_train.eq_loop = 0;
276
277 for (lane = 0; lane < lane_count; lane++)
278 dp->link_train.cr_loop[lane] = 0;
279
Jingoo Hane9474be2012-02-03 18:01:55 +0900280 /* Set link rate and count as you want to establish*/
281 exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
282 exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
283
284 /* Setup RX configuration */
285 buf[0] = dp->link_train.link_rate;
286 buf[1] = dp->link_train.lane_count;
Sean Paulace2d7f2012-10-31 23:21:00 +0000287 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
Jingoo Hane9474be2012-02-03 18:01:55 +0900288 2, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000289 if (retval)
290 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900291
292 /* Set TX pre-emphasis to minimum */
293 for (lane = 0; lane < lane_count; lane++)
294 exynos_dp_set_lane_lane_pre_emphasis(dp,
295 PRE_EMPHASIS_LEVEL_0, lane);
296
Sean Paul49ce41f2012-10-31 23:21:00 +0000297 /* Wait for PLL lock */
298 pll_tries = 0;
299 while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
300 if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
301 dev_err(dp->dev, "Wait for PLL lock timed out\n");
302 return -ETIMEDOUT;
303 }
304
305 pll_tries++;
306 usleep_range(90, 120);
307 }
308
Jingoo Hane9474be2012-02-03 18:01:55 +0900309 /* Set training pattern 1 */
310 exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
311
312 /* Set RX training pattern */
Sean Paulfadec4b2012-10-31 23:21:00 +0000313 retval = exynos_dp_write_byte_to_dpcd(dp,
314 DPCD_ADDR_TRAINING_PATTERN_SET,
315 DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
316 if (retval)
317 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900318
319 for (lane = 0; lane < lane_count; lane++)
320 buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
321 DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
Sean Paulfadec4b2012-10-31 23:21:00 +0000322
323 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
324 lane_count, buf);
Sean Paulace2d7f2012-10-31 23:21:00 +0000325
326 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900327}
328
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900329static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
Jingoo Hane9474be2012-02-03 18:01:55 +0900330{
331 int shift = (lane & 1) * 4;
332 u8 link_value = link_status[lane>>1];
333
334 return (link_value >> shift) & 0xf;
335}
336
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900337static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900338{
339 int lane;
340 u8 lane_status;
341
342 for (lane = 0; lane < lane_count; lane++) {
343 lane_status = exynos_dp_get_lane_status(link_status, lane);
344 if ((lane_status & DPCD_LANE_CR_DONE) == 0)
345 return -EINVAL;
346 }
347 return 0;
348}
349
Sean Paulfadec4b2012-10-31 23:21:00 +0000350static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
351 int lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900352{
353 int lane;
Jingoo Hane9474be2012-02-03 18:01:55 +0900354 u8 lane_status;
355
Sean Paulfadec4b2012-10-31 23:21:00 +0000356 if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
Jingoo Hane9474be2012-02-03 18:01:55 +0900357 return -EINVAL;
358
359 for (lane = 0; lane < lane_count; lane++) {
Sean Paulfadec4b2012-10-31 23:21:00 +0000360 lane_status = exynos_dp_get_lane_status(link_status, lane);
Jingoo Hane9474be2012-02-03 18:01:55 +0900361 lane_status &= DPCD_CHANNEL_EQ_BITS;
362 if (lane_status != DPCD_CHANNEL_EQ_BITS)
363 return -EINVAL;
364 }
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900365
Jingoo Hane9474be2012-02-03 18:01:55 +0900366 return 0;
367}
368
369static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
370 int lane)
371{
372 int shift = (lane & 1) * 4;
373 u8 link_value = adjust_request[lane>>1];
374
375 return (link_value >> shift) & 0x3;
376}
377
378static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
379 u8 adjust_request[2],
380 int lane)
381{
382 int shift = (lane & 1) * 4;
383 u8 link_value = adjust_request[lane>>1];
384
385 return ((link_value >> shift) & 0xc) >> 2;
386}
387
388static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
389 u8 training_lane_set, int lane)
390{
391 switch (lane) {
392 case 0:
393 exynos_dp_set_lane0_link_training(dp, training_lane_set);
394 break;
395 case 1:
396 exynos_dp_set_lane1_link_training(dp, training_lane_set);
397 break;
398
399 case 2:
400 exynos_dp_set_lane2_link_training(dp, training_lane_set);
401 break;
402
403 case 3:
404 exynos_dp_set_lane3_link_training(dp, training_lane_set);
405 break;
406 }
407}
408
409static unsigned int exynos_dp_get_lane_link_training(
410 struct exynos_dp_device *dp,
411 int lane)
412{
413 u32 reg;
414
415 switch (lane) {
416 case 0:
417 reg = exynos_dp_get_lane0_link_training(dp);
418 break;
419 case 1:
420 reg = exynos_dp_get_lane1_link_training(dp);
421 break;
422 case 2:
423 reg = exynos_dp_get_lane2_link_training(dp);
424 break;
425 case 3:
426 reg = exynos_dp_get_lane3_link_training(dp);
427 break;
Jingoo Han64c43df2012-06-20 10:25:48 +0900428 default:
429 WARN_ON(1);
430 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900431 }
432
433 return reg;
434}
435
436static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
437{
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900438 exynos_dp_training_pattern_dis(dp);
439 exynos_dp_set_enhanced_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900440
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900441 dp->link_train.lt_state = FAILED;
Jingoo Hane9474be2012-02-03 18:01:55 +0900442}
443
Sean Paulfadec4b2012-10-31 23:21:00 +0000444static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
445 u8 adjust_request[2])
446{
447 int lane, lane_count;
448 u8 voltage_swing, pre_emphasis, training_lane;
449
450 lane_count = dp->link_train.lane_count;
451 for (lane = 0; lane < lane_count; lane++) {
452 voltage_swing = exynos_dp_get_adjust_request_voltage(
453 adjust_request, lane);
454 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
455 adjust_request, lane);
456 training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
457 DPCD_PRE_EMPHASIS_SET(pre_emphasis);
458
459 if (voltage_swing == VOLTAGE_LEVEL_3)
460 training_lane |= DPCD_MAX_SWING_REACHED;
461 if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
462 training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
463
464 dp->link_train.training_lane[lane] = training_lane;
465 }
466}
467
Jingoo Hane9474be2012-02-03 18:01:55 +0900468static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
469{
Sean Paulace2d7f2012-10-31 23:21:00 +0000470 int lane, lane_count, retval;
Sean Paulfadec4b2012-10-31 23:21:00 +0000471 u8 voltage_swing, pre_emphasis, training_lane;
472 u8 link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900473
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900474 usleep_range(100, 101);
Jingoo Hane9474be2012-02-03 18:01:55 +0900475
Jingoo Hane9474be2012-02-03 18:01:55 +0900476 lane_count = dp->link_train.lane_count;
477
Sean Paulfadec4b2012-10-31 23:21:00 +0000478 retval = exynos_dp_read_bytes_from_dpcd(dp,
479 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
480 if (retval)
481 return retval;
482
483 retval = exynos_dp_read_bytes_from_dpcd(dp,
484 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
Sean Paulace2d7f2012-10-31 23:21:00 +0000485 if (retval)
486 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900487
Jingoo Hane9474be2012-02-03 18:01:55 +0900488 if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
489 /* set training pattern 2 for EQ */
490 exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
491
Sean Paulace2d7f2012-10-31 23:21:00 +0000492 retval = exynos_dp_write_byte_to_dpcd(dp,
Sean Paulfadec4b2012-10-31 23:21:00 +0000493 DPCD_ADDR_TRAINING_PATTERN_SET,
494 DPCD_SCRAMBLING_DISABLED |
495 DPCD_TRAINING_PATTERN_2);
Sean Paulace2d7f2012-10-31 23:21:00 +0000496 if (retval)
497 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900498
499 dev_info(dp->dev, "Link Training Clock Recovery success\n");
500 dp->link_train.lt_state = EQUALIZER_TRAINING;
501 } else {
502 for (lane = 0; lane < lane_count; lane++) {
503 training_lane = exynos_dp_get_lane_link_training(
504 dp, lane);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900505 voltage_swing = exynos_dp_get_adjust_request_voltage(
506 adjust_request, lane);
507 pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
508 adjust_request, lane);
509
Sean Paulfadec4b2012-10-31 23:21:00 +0000510 if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
511 voltage_swing &&
512 DPCD_PRE_EMPHASIS_GET(training_lane) ==
513 pre_emphasis)
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900514 dp->link_train.cr_loop[lane]++;
Sean Paulfadec4b2012-10-31 23:21:00 +0000515
516 if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
517 voltage_swing == VOLTAGE_LEVEL_3 ||
518 pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
519 dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
520 dp->link_train.cr_loop[lane],
521 voltage_swing, pre_emphasis);
522 exynos_dp_reduce_link_rate(dp);
523 return -EIO;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900524 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900525 }
526 }
527
Sean Paulfadec4b2012-10-31 23:21:00 +0000528 exynos_dp_get_adjust_training_lane(dp, adjust_request);
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900529
Sean Paulfadec4b2012-10-31 23:21:00 +0000530 for (lane = 0; lane < lane_count; lane++)
531 exynos_dp_set_lane_link_training(dp,
532 dp->link_train.training_lane[lane], lane);
533
534 retval = exynos_dp_write_bytes_to_dpcd(dp,
535 DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
536 dp->link_train.training_lane);
537 if (retval)
538 return retval;
539
540 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900541}
542
543static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
544{
Sean Paulace2d7f2012-10-31 23:21:00 +0000545 int lane, lane_count, retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900546 u32 reg;
Sean Paulfadec4b2012-10-31 23:21:00 +0000547 u8 link_align, link_status[2], adjust_request[2];
Jingoo Hane9474be2012-02-03 18:01:55 +0900548
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900549 usleep_range(400, 401);
Jingoo Hane9474be2012-02-03 18:01:55 +0900550
Jingoo Hane9474be2012-02-03 18:01:55 +0900551 lane_count = dp->link_train.lane_count;
552
Sean Paulfadec4b2012-10-31 23:21:00 +0000553 retval = exynos_dp_read_bytes_from_dpcd(dp,
554 DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
Sean Paulace2d7f2012-10-31 23:21:00 +0000555 if (retval)
556 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900557
Sean Paulfadec4b2012-10-31 23:21:00 +0000558 if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
559 exynos_dp_reduce_link_rate(dp);
560 return -EIO;
Jingoo Hane9474be2012-02-03 18:01:55 +0900561 }
562
Sean Paulfadec4b2012-10-31 23:21:00 +0000563 retval = exynos_dp_read_bytes_from_dpcd(dp,
564 DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
565 if (retval)
566 return retval;
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900567
Sean Paulfadec4b2012-10-31 23:21:00 +0000568 retval = exynos_dp_read_byte_from_dpcd(dp,
569 DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
570 if (retval)
571 return retval;
572
573 exynos_dp_get_adjust_training_lane(dp, adjust_request);
574
575 if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
576 /* traing pattern Set to Normal */
577 exynos_dp_training_pattern_dis(dp);
578
579 dev_info(dp->dev, "Link Training success!\n");
580
581 exynos_dp_get_link_bandwidth(dp, &reg);
582 dp->link_train.link_rate = reg;
583 dev_dbg(dp->dev, "final bandwidth = %.2x\n",
584 dp->link_train.link_rate);
585
586 exynos_dp_get_lane_count(dp, &reg);
587 dp->link_train.lane_count = reg;
588 dev_dbg(dp->dev, "final lane count = %.2x\n",
589 dp->link_train.lane_count);
590
591 /* set enhanced mode if available */
592 exynos_dp_set_enhanced_mode(dp);
593 dp->link_train.lt_state = FINISHED;
594
595 return 0;
596 }
597
598 /* not all locked */
599 dp->link_train.eq_loop++;
600
601 if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
602 dev_err(dp->dev, "EQ Max loop\n");
603 exynos_dp_reduce_link_rate(dp);
604 return -EIO;
605 }
606
607 for (lane = 0; lane < lane_count; lane++)
608 exynos_dp_set_lane_link_training(dp,
609 dp->link_train.training_lane[lane], lane);
610
611 retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
612 lane_count, dp->link_train.training_lane);
613
614 return retval;
Jingoo Hane9474be2012-02-03 18:01:55 +0900615}
616
617static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900618 u8 *bandwidth)
Jingoo Hane9474be2012-02-03 18:01:55 +0900619{
620 u8 data;
621
622 /*
623 * For DP rev.1.1, Maximum link rate of Main Link lanes
624 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
625 */
626 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
627 *bandwidth = data;
628}
629
630static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900631 u8 *lane_count)
Jingoo Hane9474be2012-02-03 18:01:55 +0900632{
633 u8 data;
634
635 /*
636 * For DP rev.1.1, Maximum number of Main Link lanes
637 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
638 */
639 exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
640 *lane_count = DPCD_MAX_LANE_COUNT(data);
641}
642
643static void exynos_dp_init_training(struct exynos_dp_device *dp,
644 enum link_lane_count_type max_lane,
645 enum link_rate_type max_rate)
646{
647 /*
648 * MACRO_RST must be applied after the PLL_LOCK to avoid
649 * the DP inter pair skew issue for at least 10 us
650 */
651 exynos_dp_reset_macro(dp);
652
653 /* Initialize by reading RX's DPCD */
654 exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
655 exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
656
657 if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
658 (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
659 dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
660 dp->link_train.link_rate);
661 dp->link_train.link_rate = LINK_RATE_1_62GBPS;
662 }
663
664 if (dp->link_train.lane_count == 0) {
665 dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
666 dp->link_train.lane_count);
667 dp->link_train.lane_count = (u8)LANE_COUNT1;
668 }
669
670 /* Setup TX lane count & rate */
671 if (dp->link_train.lane_count > max_lane)
672 dp->link_train.lane_count = max_lane;
673 if (dp->link_train.link_rate > max_rate)
674 dp->link_train.link_rate = max_rate;
675
676 /* All DP analog module power up */
677 exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
678}
679
680static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
681{
Sean Paulace2d7f2012-10-31 23:21:00 +0000682 int retval = 0, training_finished = 0;
Jingoo Hane9474be2012-02-03 18:01:55 +0900683
684 dp->link_train.lt_state = START;
685
686 /* Process here */
Sean Paulace2d7f2012-10-31 23:21:00 +0000687 while (!retval && !training_finished) {
Jingoo Hane9474be2012-02-03 18:01:55 +0900688 switch (dp->link_train.lt_state) {
689 case START:
Sean Paulace2d7f2012-10-31 23:21:00 +0000690 retval = exynos_dp_link_start(dp);
691 if (retval)
692 dev_err(dp->dev, "LT link start failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900693 break;
694 case CLOCK_RECOVERY:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900695 retval = exynos_dp_process_clock_recovery(dp);
696 if (retval)
697 dev_err(dp->dev, "LT CR failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900698 break;
699 case EQUALIZER_TRAINING:
Jingoo Hand5c0eed2012-07-19 13:52:59 +0900700 retval = exynos_dp_process_equalizer_training(dp);
701 if (retval)
702 dev_err(dp->dev, "LT EQ failed!\n");
Jingoo Hane9474be2012-02-03 18:01:55 +0900703 break;
704 case FINISHED:
705 training_finished = 1;
706 break;
707 case FAILED:
708 return -EREMOTEIO;
709 }
710 }
Sean Paulace2d7f2012-10-31 23:21:00 +0000711 if (retval)
712 dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
Jingoo Hane9474be2012-02-03 18:01:55 +0900713
714 return retval;
715}
716
717static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
718 u32 count,
719 u32 bwtype)
720{
721 int i;
722 int retval;
723
724 for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
725 exynos_dp_init_training(dp, count, bwtype);
726 retval = exynos_dp_sw_link_training(dp);
727 if (retval == 0)
728 break;
729
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900730 usleep_range(100, 110);
Jingoo Hane9474be2012-02-03 18:01:55 +0900731 }
732
733 return retval;
734}
735
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900736static int exynos_dp_config_video(struct exynos_dp_device *dp)
Jingoo Hane9474be2012-02-03 18:01:55 +0900737{
738 int retval = 0;
739 int timeout_loop = 0;
740 int done_count = 0;
741
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900742 exynos_dp_config_video_slave_mode(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900743
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900744 exynos_dp_set_video_color_format(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +0900745
746 if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
747 dev_err(dp->dev, "PLL is not locked yet.\n");
748 return -EINVAL;
749 }
750
751 for (;;) {
752 timeout_loop++;
753 if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
754 break;
755 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
756 dev_err(dp->dev, "Timeout of video streamclk ok\n");
757 return -ETIMEDOUT;
758 }
759
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900760 usleep_range(1, 2);
Jingoo Hane9474be2012-02-03 18:01:55 +0900761 }
762
763 /* Set to use the register calculated M/N video */
764 exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
765
766 /* For video bist, Video timing must be generated by register */
767 exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
768
769 /* Disable video mute */
770 exynos_dp_enable_video_mute(dp, 0);
771
772 /* Configure video slave mode */
773 exynos_dp_enable_video_master(dp, 0);
774
775 /* Enable video */
776 exynos_dp_start_video(dp);
777
778 timeout_loop = 0;
779
780 for (;;) {
781 timeout_loop++;
782 if (exynos_dp_is_video_stream_on(dp) == 0) {
783 done_count++;
784 if (done_count > 10)
785 break;
786 } else if (done_count) {
787 done_count = 0;
788 }
789 if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
790 dev_err(dp->dev, "Timeout of video streamclk ok\n");
791 return -ETIMEDOUT;
792 }
793
Jingoo Hana2c81bc2012-07-18 18:50:59 +0900794 usleep_range(1000, 1001);
Jingoo Hane9474be2012-02-03 18:01:55 +0900795 }
796
797 if (retval != 0)
798 dev_err(dp->dev, "Video stream is not detected!\n");
799
800 return retval;
801}
802
803static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
804{
805 u8 data;
806
807 if (enable) {
808 exynos_dp_enable_scrambling(dp);
809
810 exynos_dp_read_byte_from_dpcd(dp,
811 DPCD_ADDR_TRAINING_PATTERN_SET,
812 &data);
813 exynos_dp_write_byte_to_dpcd(dp,
814 DPCD_ADDR_TRAINING_PATTERN_SET,
815 (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
816 } else {
817 exynos_dp_disable_scrambling(dp);
818
819 exynos_dp_read_byte_from_dpcd(dp,
820 DPCD_ADDR_TRAINING_PATTERN_SET,
821 &data);
822 exynos_dp_write_byte_to_dpcd(dp,
823 DPCD_ADDR_TRAINING_PATTERN_SET,
824 (u8)(data | DPCD_SCRAMBLING_DISABLED));
825 }
826}
827
828static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
829{
830 struct exynos_dp_device *dp = arg;
831
Sean Paulc30ffb92012-11-01 19:13:46 +0900832 enum dp_irq_type irq_type;
833
834 irq_type = exynos_dp_get_irq_type(dp);
835 switch (irq_type) {
836 case DP_IRQ_TYPE_HP_CABLE_IN:
837 dev_dbg(dp->dev, "Received irq - cable in\n");
838 schedule_work(&dp->hotplug_work);
839 exynos_dp_clear_hotplug_interrupts(dp);
840 break;
841 case DP_IRQ_TYPE_HP_CABLE_OUT:
842 dev_dbg(dp->dev, "Received irq - cable out\n");
843 exynos_dp_clear_hotplug_interrupts(dp);
844 break;
845 case DP_IRQ_TYPE_HP_CHANGE:
846 /*
847 * We get these change notifications once in a while, but there
848 * is nothing we can do with them. Just ignore it for now and
849 * only handle cable changes.
850 */
851 dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
852 exynos_dp_clear_hotplug_interrupts(dp);
853 break;
854 default:
855 dev_err(dp->dev, "Received irq - unknown type!\n");
856 break;
857 }
Jingoo Hane9474be2012-02-03 18:01:55 +0900858 return IRQ_HANDLED;
859}
860
Sean Paul784fa9a2012-11-09 13:55:08 +0900861static void exynos_dp_hotplug(struct work_struct *work)
862{
863 struct exynos_dp_device *dp;
864 int ret;
865
866 dp = container_of(work, struct exynos_dp_device, hotplug_work);
867
868 ret = exynos_dp_detect_hpd(dp);
869 if (ret) {
Sean Paulc30ffb92012-11-01 19:13:46 +0900870 /* Cable has been disconnected, we're done */
Sean Paul784fa9a2012-11-09 13:55:08 +0900871 return;
872 }
873
874 ret = exynos_dp_handle_edid(dp);
875 if (ret) {
876 dev_err(dp->dev, "unable to handle edid\n");
877 return;
878 }
879
880 ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
881 dp->video_info->link_rate);
882 if (ret) {
883 dev_err(dp->dev, "unable to do link train\n");
884 return;
885 }
886
887 exynos_dp_enable_scramble(dp, 1);
888 exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
889 exynos_dp_enable_enhanced_mode(dp, 1);
890
891 exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
892 exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
893
894 exynos_dp_init_video(dp);
Ajay Kumar3fcb6eb2012-11-09 14:05:06 +0900895 ret = exynos_dp_config_video(dp);
Sean Paul784fa9a2012-11-09 13:55:08 +0900896 if (ret)
897 dev_err(dp->dev, "unable to config video\n");
898}
899
Sean Paul1417f102014-01-30 16:19:23 -0500900static bool exynos_dp_display_is_connected(struct exynos_drm_display *display)
901{
902 return true;
903}
904
905static void *exynos_dp_get_panel(struct exynos_drm_display *display)
906{
907 struct exynos_dp_device *dp = display->ctx;
908
909 return &dp->panel;
910}
911
912static int exynos_dp_check_mode(struct exynos_drm_display *display,
913 struct drm_display_mode *mode)
914{
915 return 0;
916}
917
Sean Paul12f5ad62014-01-30 16:19:25 -0500918static void exynos_dp_phy_init(struct exynos_dp_device *dp)
919{
920 if (dp->phy) {
921 phy_power_on(dp->phy);
922 } else if (dp->phy_addr) {
923 u32 reg;
924
925 reg = __raw_readl(dp->phy_addr);
926 reg |= dp->enable_mask;
927 __raw_writel(reg, dp->phy_addr);
928 }
929}
930
931static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
932{
933 if (dp->phy) {
934 phy_power_off(dp->phy);
935 } else if (dp->phy_addr) {
936 u32 reg;
937
938 reg = __raw_readl(dp->phy_addr);
939 reg &= ~(dp->enable_mask);
940 __raw_writel(reg, dp->phy_addr);
941 }
942}
943
944static void exynos_dp_poweron(struct exynos_dp_device *dp)
945{
946 if (dp->dpms_mode == DRM_MODE_DPMS_ON)
947 return;
948
949 clk_prepare_enable(dp->clock);
950 exynos_dp_phy_init(dp);
951 exynos_dp_init_dp(dp);
952 enable_irq(dp->irq);
953}
954
955static void exynos_dp_poweroff(struct exynos_dp_device *dp)
956{
957 if (dp->dpms_mode != DRM_MODE_DPMS_ON)
958 return;
959
960 disable_irq(dp->irq);
961 flush_work(&dp->hotplug_work);
962 exynos_dp_phy_exit(dp);
963 clk_disable_unprepare(dp->clock);
964}
965
966static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
967{
968 struct exynos_dp_device *dp = display->ctx;
969
970 switch (mode) {
971 case DRM_MODE_DPMS_ON:
972 exynos_dp_poweron(dp);
973 break;
974 case DRM_MODE_DPMS_STANDBY:
975 case DRM_MODE_DPMS_SUSPEND:
976 case DRM_MODE_DPMS_OFF:
977 exynos_dp_poweroff(dp);
978 break;
979 default:
980 break;
981 };
982 dp->dpms_mode = mode;
983}
984
Sean Paul1417f102014-01-30 16:19:23 -0500985static struct exynos_drm_display_ops exynos_dp_display_ops = {
986 .is_connected = exynos_dp_display_is_connected,
987 .get_panel = exynos_dp_get_panel,
988 .check_mode = exynos_dp_check_mode,
Sean Paul12f5ad62014-01-30 16:19:25 -0500989 .dpms = exynos_dp_dpms,
Sean Paul1417f102014-01-30 16:19:23 -0500990};
991
992static struct exynos_drm_display exynos_dp_display = {
993 .type = EXYNOS_DISPLAY_TYPE_LCD,
994 .ops = &exynos_dp_display_ops,
995};
996
Jingoo Hanf9b1e012013-10-16 21:58:15 +0530997static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
Ajay Kumarc4e235c2012-10-13 05:48:00 +0900998{
999 struct device_node *dp_node = dev->of_node;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001000 struct video_info *dp_video_config;
1001
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001002 dp_video_config = devm_kzalloc(dev,
1003 sizeof(*dp_video_config), GFP_KERNEL);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001004 if (!dp_video_config) {
1005 dev_err(dev, "memory allocation for video config failed\n");
1006 return ERR_PTR(-ENOMEM);
1007 }
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001008
1009 dp_video_config->h_sync_polarity =
1010 of_property_read_bool(dp_node, "hsync-active-high");
1011
1012 dp_video_config->v_sync_polarity =
1013 of_property_read_bool(dp_node, "vsync-active-high");
1014
1015 dp_video_config->interlaced =
1016 of_property_read_bool(dp_node, "interlaced");
1017
1018 if (of_property_read_u32(dp_node, "samsung,color-space",
1019 &dp_video_config->color_space)) {
1020 dev_err(dev, "failed to get color-space\n");
1021 return ERR_PTR(-EINVAL);
1022 }
1023
1024 if (of_property_read_u32(dp_node, "samsung,dynamic-range",
1025 &dp_video_config->dynamic_range)) {
1026 dev_err(dev, "failed to get dynamic-range\n");
1027 return ERR_PTR(-EINVAL);
1028 }
1029
1030 if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
1031 &dp_video_config->ycbcr_coeff)) {
1032 dev_err(dev, "failed to get ycbcr-coeff\n");
1033 return ERR_PTR(-EINVAL);
1034 }
1035
1036 if (of_property_read_u32(dp_node, "samsung,color-depth",
1037 &dp_video_config->color_depth)) {
1038 dev_err(dev, "failed to get color-depth\n");
1039 return ERR_PTR(-EINVAL);
1040 }
1041
1042 if (of_property_read_u32(dp_node, "samsung,link-rate",
1043 &dp_video_config->link_rate)) {
1044 dev_err(dev, "failed to get link-rate\n");
1045 return ERR_PTR(-EINVAL);
1046 }
1047
1048 if (of_property_read_u32(dp_node, "samsung,lane-count",
1049 &dp_video_config->lane_count)) {
1050 dev_err(dev, "failed to get lane-count\n");
1051 return ERR_PTR(-EINVAL);
1052 }
1053
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301054 return dp_video_config;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001055}
1056
1057static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
1058{
Jingoo Hand3ed9702013-02-21 16:42:37 -08001059 struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001060 u32 phy_base;
Jingoo Hand3ed9702013-02-21 16:42:37 -08001061 int ret = 0;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001062
Jingoo Hand3ed9702013-02-21 16:42:37 -08001063 dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001064 if (!dp_phy_node) {
Jingoo Han8114fab2013-10-16 21:58:16 +05301065 dp->phy = devm_phy_get(dp->dev, "dp");
1066 if (IS_ERR(dp->phy))
1067 return PTR_ERR(dp->phy);
1068 else
1069 return 0;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001070 }
1071
1072 if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
Masanari Iida1051e9b2013-03-31 01:23:50 +09001073 dev_err(dp->dev, "failed to get reg for dptx-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -08001074 ret = -EINVAL;
1075 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001076 }
1077
1078 if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
1079 &dp->enable_mask)) {
Masanari Iida1051e9b2013-03-31 01:23:50 +09001080 dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -08001081 ret = -EINVAL;
1082 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001083 }
1084
1085 dp->phy_addr = ioremap(phy_base, SZ_4);
1086 if (!dp->phy_addr) {
1087 dev_err(dp->dev, "failed to ioremap dp-phy\n");
Jingoo Hand3ed9702013-02-21 16:42:37 -08001088 ret = -ENOMEM;
1089 goto err;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001090 }
1091
Jingoo Hand3ed9702013-02-21 16:42:37 -08001092err:
1093 of_node_put(dp_phy_node);
1094
1095 return ret;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001096}
1097
Sean Paul1417f102014-01-30 16:19:23 -05001098static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
1099{
1100 int ret;
1101
1102 ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm,
1103 OF_USE_NATIVE_MODE);
1104 if (ret) {
1105 DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
1106 return ret;
1107 }
1108 return 0;
1109}
1110
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001111static int exynos_dp_probe(struct platform_device *pdev)
Jingoo Hane9474be2012-02-03 18:01:55 +09001112{
1113 struct resource *res;
1114 struct exynos_dp_device *dp;
Jingoo Hane9474be2012-02-03 18:01:55 +09001115
1116 int ret = 0;
1117
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001118 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1119 GFP_KERNEL);
Jingoo Hane9474be2012-02-03 18:01:55 +09001120 if (!dp) {
1121 dev_err(&pdev->dev, "no memory for device data\n");
1122 return -ENOMEM;
1123 }
1124
1125 dp->dev = &pdev->dev;
Sean Paul12f5ad62014-01-30 16:19:25 -05001126 dp->dpms_mode = DRM_MODE_DPMS_OFF;
Jingoo Hane9474be2012-02-03 18:01:55 +09001127
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301128 dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
1129 if (IS_ERR(dp->video_info))
1130 return PTR_ERR(dp->video_info);
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001131
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301132 ret = exynos_dp_dt_parse_phydata(dp);
1133 if (ret)
1134 return ret;
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001135
Sean Paul1417f102014-01-30 16:19:23 -05001136 ret = exynos_dp_dt_parse_panel(dp);
1137 if (ret)
1138 return ret;
1139
Damien Cassoud913f362012-08-01 18:20:39 +02001140 dp->clock = devm_clk_get(&pdev->dev, "dp");
Jingoo Hane9474be2012-02-03 18:01:55 +09001141 if (IS_ERR(dp->clock)) {
1142 dev_err(&pdev->dev, "failed to get clock\n");
Jingoo Han4d10ecf82012-05-25 16:20:45 +09001143 return PTR_ERR(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001144 }
1145
Jingoo Han37414fb2012-10-04 15:45:14 +09001146 clk_prepare_enable(dp->clock);
Jingoo Hane9474be2012-02-03 18:01:55 +09001147
1148 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Jingoo Hane9474be2012-02-03 18:01:55 +09001149
Thierry Redingbc3bad12013-01-21 11:09:23 +01001150 dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
1151 if (IS_ERR(dp->reg_base))
1152 return PTR_ERR(dp->reg_base);
Jingoo Hane9474be2012-02-03 18:01:55 +09001153
1154 dp->irq = platform_get_irq(pdev, 0);
Sean Paul1cefc1d2012-10-31 23:21:00 +00001155 if (dp->irq == -ENXIO) {
Jingoo Hane9474be2012-02-03 18:01:55 +09001156 dev_err(&pdev->dev, "failed to get irq\n");
Damien Cassoud913f362012-08-01 18:20:39 +02001157 return -ENODEV;
Jingoo Hane9474be2012-02-03 18:01:55 +09001158 }
1159
Sean Paul784fa9a2012-11-09 13:55:08 +09001160 INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
1161
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301162 exynos_dp_phy_init(dp);
Jingoo Hane9474be2012-02-03 18:01:55 +09001163
1164 exynos_dp_init_dp(dp);
1165
Ajay Kumar22ce19c2012-11-09 13:59:09 +09001166 ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
1167 "exynos-dp", dp);
1168 if (ret) {
1169 dev_err(&pdev->dev, "failed to request irq\n");
1170 return ret;
1171 }
Sean Paul12f5ad62014-01-30 16:19:25 -05001172 disable_irq(dp->irq);
Jingoo Hane9474be2012-02-03 18:01:55 +09001173
Sean Paul1417f102014-01-30 16:19:23 -05001174 exynos_dp_display.ctx = dp;
Sean Paul12f5ad62014-01-30 16:19:25 -05001175
1176 platform_set_drvdata(pdev, &exynos_dp_display);
Sean Paul1417f102014-01-30 16:19:23 -05001177 exynos_drm_display_register(&exynos_dp_display);
1178
Jingoo Hane9474be2012-02-03 18:01:55 +09001179 return 0;
Jingoo Hane9474be2012-02-03 18:01:55 +09001180}
1181
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001182static int exynos_dp_remove(struct platform_device *pdev)
Jingoo Hane9474be2012-02-03 18:01:55 +09001183{
Sean Paul12f5ad62014-01-30 16:19:25 -05001184 struct exynos_drm_display *display = platform_get_drvdata(pdev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001185
Sean Paul12f5ad62014-01-30 16:19:25 -05001186 exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
Sean Paul1417f102014-01-30 16:19:23 -05001187 exynos_drm_display_unregister(&exynos_dp_display);
1188
Jingoo Hane9474be2012-02-03 18:01:55 +09001189 return 0;
1190}
1191
1192#ifdef CONFIG_PM_SLEEP
1193static int exynos_dp_suspend(struct device *dev)
1194{
Sean Paul12f5ad62014-01-30 16:19:25 -05001195 struct platform_device *pdev = to_platform_device(dev);
1196 struct exynos_drm_display *display = platform_get_drvdata(pdev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001197
Sean Paul12f5ad62014-01-30 16:19:25 -05001198 exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
Jingoo Hane9474be2012-02-03 18:01:55 +09001199 return 0;
1200}
1201
1202static int exynos_dp_resume(struct device *dev)
1203{
Sean Paul12f5ad62014-01-30 16:19:25 -05001204 struct platform_device *pdev = to_platform_device(dev);
1205 struct exynos_drm_display *display = platform_get_drvdata(pdev);
Jingoo Hane9474be2012-02-03 18:01:55 +09001206
Sean Paul12f5ad62014-01-30 16:19:25 -05001207 exynos_dp_dpms(display, DRM_MODE_DPMS_ON);
Jingoo Hane9474be2012-02-03 18:01:55 +09001208 return 0;
1209}
1210#endif
1211
1212static const struct dev_pm_ops exynos_dp_pm_ops = {
1213 SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
1214};
1215
Ajay Kumarc4e235c2012-10-13 05:48:00 +09001216static const struct of_device_id exynos_dp_match[] = {
1217 { .compatible = "samsung,exynos5-dp" },
1218 {},
1219};
1220MODULE_DEVICE_TABLE(of, exynos_dp_match);
1221
Sean Paul1417f102014-01-30 16:19:23 -05001222struct platform_driver dp_driver = {
Jingoo Hane9474be2012-02-03 18:01:55 +09001223 .probe = exynos_dp_probe,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001224 .remove = exynos_dp_remove,
Jingoo Hane9474be2012-02-03 18:01:55 +09001225 .driver = {
1226 .name = "exynos-dp",
1227 .owner = THIS_MODULE,
1228 .pm = &exynos_dp_pm_ops,
Jingoo Hanf9b1e012013-10-16 21:58:15 +05301229 .of_match_table = exynos_dp_match,
Jingoo Hane9474be2012-02-03 18:01:55 +09001230 },
1231};
1232
Jingoo Hane9474be2012-02-03 18:01:55 +09001233MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
1234MODULE_DESCRIPTION("Samsung SoC DP Driver");
1235MODULE_LICENSE("GPL");