.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Analogix DP (Display Port) core interface driver. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2012 Samsung Electronics Co., Ltd. |
---|
5 | 6 | * 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 | 7 | */ |
---|
12 | 8 | |
---|
13 | | -#include <linux/module.h> |
---|
14 | | -#include <linux/platform_device.h> |
---|
15 | | -#include <linux/err.h> |
---|
16 | 9 | #include <linux/clk.h> |
---|
| 10 | +#include <linux/component.h> |
---|
| 11 | +#include <linux/extcon-provider.h> |
---|
| 12 | +#include <linux/err.h> |
---|
| 13 | +#include <linux/gpio/consumer.h> |
---|
| 14 | +#include <linux/interrupt.h> |
---|
17 | 15 | #include <linux/io.h> |
---|
18 | 16 | #include <linux/iopoll.h> |
---|
19 | | -#include <linux/interrupt.h> |
---|
| 17 | +#include <linux/irq.h> |
---|
| 18 | +#include <linux/module.h> |
---|
20 | 19 | #include <linux/of.h> |
---|
21 | | -#include <linux/of_gpio.h> |
---|
22 | | -#include <linux/gpio/consumer.h> |
---|
23 | | -#include <linux/component.h> |
---|
24 | 20 | #include <linux/phy/phy.h> |
---|
25 | | - |
---|
26 | | -#include <drm/drmP.h> |
---|
27 | | -#include <drm/drm_atomic_helper.h> |
---|
28 | | -#include <drm/drm_crtc.h> |
---|
29 | | -#include <drm/drm_crtc_helper.h> |
---|
30 | | -#include <drm/drm_panel.h> |
---|
| 21 | +#include <linux/platform_device.h> |
---|
31 | 22 | |
---|
32 | 23 | #include <drm/bridge/analogix_dp.h> |
---|
| 24 | +#include <drm/drm_atomic.h> |
---|
| 25 | +#include <drm/drm_atomic_helper.h> |
---|
| 26 | +#include <drm/drm_bridge.h> |
---|
| 27 | +#include <drm/drm_crtc.h> |
---|
| 28 | +#include <drm/drm_device.h> |
---|
| 29 | +#include <drm/drm_panel.h> |
---|
| 30 | +#include <drm/drm_print.h> |
---|
| 31 | +#include <drm/drm_probe_helper.h> |
---|
33 | 32 | |
---|
34 | 33 | #include "analogix_dp_core.h" |
---|
35 | 34 | #include "analogix_dp_reg.h" |
---|
.. | .. |
---|
37 | 36 | #define to_dp(nm) container_of(nm, struct analogix_dp_device, nm) |
---|
38 | 37 | |
---|
39 | 38 | static const bool verify_fast_training; |
---|
| 39 | + |
---|
| 40 | +#ifdef CONFIG_NO_GKI |
---|
| 41 | +#undef EXTCON_DISP_DP |
---|
| 42 | +#define EXTCON_DISP_DP EXTCON_DISP_EDP |
---|
| 43 | +#endif |
---|
| 44 | + |
---|
| 45 | +static const unsigned int analogix_dp_cable[] = { |
---|
| 46 | + EXTCON_DISP_DP, |
---|
| 47 | + EXTCON_NONE, |
---|
| 48 | +}; |
---|
40 | 49 | |
---|
41 | 50 | struct bridge_init { |
---|
42 | 51 | struct i2c_client *client; |
---|
.. | .. |
---|
89 | 98 | return 0; |
---|
90 | 99 | } |
---|
91 | 100 | |
---|
92 | | -static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, |
---|
93 | | - bool prepare) |
---|
| 101 | +static int analogix_dp_panel_prepare(struct analogix_dp_device *dp) |
---|
94 | 102 | { |
---|
95 | | - int ret = 0; |
---|
| 103 | + int ret; |
---|
96 | 104 | |
---|
97 | 105 | mutex_lock(&dp->panel_lock); |
---|
98 | 106 | |
---|
99 | | - if (prepare == dp->panel_is_prepared) |
---|
| 107 | + if (dp->panel_is_prepared) |
---|
100 | 108 | goto out; |
---|
101 | 109 | |
---|
102 | | - if (prepare) |
---|
103 | | - ret = drm_panel_prepare(dp->plat_data->panel); |
---|
104 | | - else |
---|
105 | | - ret = drm_panel_unprepare(dp->plat_data->panel); |
---|
| 110 | + ret = drm_panel_prepare(dp->plat_data->panel); |
---|
106 | 111 | if (ret) |
---|
107 | 112 | goto out; |
---|
108 | 113 | |
---|
109 | | - dp->panel_is_prepared = prepare; |
---|
| 114 | + dp->panel_is_prepared = true; |
---|
| 115 | + |
---|
110 | 116 | out: |
---|
111 | 117 | mutex_unlock(&dp->panel_lock); |
---|
112 | | - return ret; |
---|
| 118 | + return 0; |
---|
| 119 | +} |
---|
| 120 | + |
---|
| 121 | +static int analogix_dp_panel_unprepare(struct analogix_dp_device *dp) |
---|
| 122 | +{ |
---|
| 123 | + int ret; |
---|
| 124 | + |
---|
| 125 | + mutex_lock(&dp->panel_lock); |
---|
| 126 | + |
---|
| 127 | + if (!dp->panel_is_prepared) |
---|
| 128 | + goto out; |
---|
| 129 | + |
---|
| 130 | + ret = drm_panel_unprepare(dp->plat_data->panel); |
---|
| 131 | + if (ret) |
---|
| 132 | + goto out; |
---|
| 133 | + |
---|
| 134 | + dp->panel_is_prepared = false; |
---|
| 135 | + |
---|
| 136 | +out: |
---|
| 137 | + mutex_unlock(&dp->panel_lock); |
---|
| 138 | + return 0; |
---|
113 | 139 | } |
---|
114 | 140 | |
---|
115 | 141 | static int analogix_dp_detect_hpd(struct analogix_dp_device *dp) |
---|
116 | 142 | { |
---|
117 | | - int timeout_loop = 0; |
---|
118 | | - |
---|
119 | | - while (timeout_loop < DP_TIMEOUT_LOOP_COUNT) { |
---|
120 | | - if (analogix_dp_get_plug_in_status(dp) == 0) |
---|
121 | | - return 0; |
---|
122 | | - |
---|
123 | | - timeout_loop++; |
---|
124 | | - usleep_range(1000, 1100); |
---|
125 | | - } |
---|
126 | | - |
---|
127 | | - /* |
---|
128 | | - * Some edp screen do not have hpd signal, so we can't just |
---|
129 | | - * return failed when hpd plug in detect failed, DT property |
---|
130 | | - * "force-hpd" would indicate whether driver need this. |
---|
131 | | - */ |
---|
132 | | - if (!dp->force_hpd) |
---|
133 | | - return -ETIMEDOUT; |
---|
134 | | - |
---|
135 | | - /* |
---|
136 | | - * The eDP TRM indicate that if HPD_STATUS(RO) is 0, AUX CH |
---|
137 | | - * will not work, so we need to give a force hpd action to |
---|
138 | | - * set HPD_STATUS manually. |
---|
139 | | - */ |
---|
140 | | - dev_dbg(dp->dev, "failed to get hpd plug status, try to force hpd\n"); |
---|
141 | | - |
---|
142 | | - analogix_dp_force_hpd(dp); |
---|
| 143 | + if (dp->force_hpd) |
---|
| 144 | + analogix_dp_force_hpd(dp); |
---|
143 | 145 | |
---|
144 | 146 | if (analogix_dp_get_plug_in_status(dp) != 0) { |
---|
145 | 147 | dev_err(dp->dev, "failed to get hpd plug in status\n"); |
---|
146 | 148 | return -EINVAL; |
---|
147 | 149 | } |
---|
148 | 150 | |
---|
149 | | - dev_dbg(dp->dev, "success to get plug in status after force hpd\n"); |
---|
150 | | - |
---|
151 | 151 | return 0; |
---|
152 | 152 | } |
---|
153 | 153 | |
---|
154 | | -int analogix_dp_psr_enabled(struct analogix_dp_device *dp) |
---|
155 | | -{ |
---|
156 | | - |
---|
157 | | - return dp->psr_enable; |
---|
158 | | -} |
---|
159 | | -EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled); |
---|
160 | | - |
---|
161 | | -int analogix_dp_enable_psr(struct analogix_dp_device *dp) |
---|
162 | | -{ |
---|
163 | | - struct edp_vsc_psr psr_vsc; |
---|
164 | | - |
---|
165 | | - if (!dp->psr_enable) |
---|
166 | | - return 0; |
---|
167 | | - |
---|
168 | | - /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
---|
169 | | - memset(&psr_vsc, 0, sizeof(psr_vsc)); |
---|
170 | | - psr_vsc.sdp_header.HB0 = 0; |
---|
171 | | - psr_vsc.sdp_header.HB1 = 0x7; |
---|
172 | | - psr_vsc.sdp_header.HB2 = 0x2; |
---|
173 | | - psr_vsc.sdp_header.HB3 = 0x8; |
---|
174 | | - |
---|
175 | | - psr_vsc.DB0 = 0; |
---|
176 | | - psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; |
---|
177 | | - |
---|
178 | | - return analogix_dp_send_psr_spd(dp, &psr_vsc, true); |
---|
179 | | -} |
---|
180 | | -EXPORT_SYMBOL_GPL(analogix_dp_enable_psr); |
---|
181 | | - |
---|
182 | | -int analogix_dp_disable_psr(struct analogix_dp_device *dp) |
---|
183 | | -{ |
---|
184 | | - struct edp_vsc_psr psr_vsc; |
---|
185 | | - int ret; |
---|
186 | | - |
---|
187 | | - if (!dp->psr_enable) |
---|
188 | | - return 0; |
---|
189 | | - |
---|
190 | | - /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
---|
191 | | - memset(&psr_vsc, 0, sizeof(psr_vsc)); |
---|
192 | | - psr_vsc.sdp_header.HB0 = 0; |
---|
193 | | - psr_vsc.sdp_header.HB1 = 0x7; |
---|
194 | | - psr_vsc.sdp_header.HB2 = 0x2; |
---|
195 | | - psr_vsc.sdp_header.HB3 = 0x8; |
---|
196 | | - |
---|
197 | | - psr_vsc.DB0 = 0; |
---|
198 | | - psr_vsc.DB1 = 0; |
---|
199 | | - |
---|
200 | | - ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0); |
---|
201 | | - if (ret != 1) { |
---|
202 | | - dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret); |
---|
203 | | - return ret; |
---|
204 | | - } |
---|
205 | | - |
---|
206 | | - return analogix_dp_send_psr_spd(dp, &psr_vsc, false); |
---|
207 | | -} |
---|
208 | | -EXPORT_SYMBOL_GPL(analogix_dp_disable_psr); |
---|
209 | | - |
---|
210 | | -static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) |
---|
| 154 | +static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp) |
---|
211 | 155 | { |
---|
212 | 156 | unsigned char psr_version; |
---|
213 | 157 | int ret; |
---|
214 | 158 | |
---|
215 | | - if (!of_property_read_bool(dp->dev->of_node, "support-psr")) |
---|
| 159 | + if (!device_property_read_bool(dp->dev, "support-psr")) |
---|
216 | 160 | return 0; |
---|
217 | 161 | |
---|
218 | 162 | ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version); |
---|
219 | 163 | if (ret != 1) { |
---|
220 | 164 | dev_err(dp->dev, "failed to get PSR version, disable it\n"); |
---|
221 | | - return ret; |
---|
| 165 | + return false; |
---|
222 | 166 | } |
---|
223 | 167 | |
---|
224 | 168 | dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version); |
---|
225 | | - |
---|
226 | | - dp->psr_enable = (psr_version & DP_PSR_IS_SUPPORTED) ? true : false; |
---|
227 | | - |
---|
228 | | - return 0; |
---|
| 169 | + return psr_version & DP_PSR_IS_SUPPORTED; |
---|
229 | 170 | } |
---|
230 | 171 | |
---|
231 | 172 | static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp) |
---|
.. | .. |
---|
248 | 189 | } |
---|
249 | 190 | |
---|
250 | 191 | /* Main-Link transmitter remains active during PSR active states */ |
---|
251 | | - psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION; |
---|
| 192 | + psr_en = DP_PSR_CRC_VERIFICATION; |
---|
252 | 193 | ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); |
---|
253 | 194 | if (ret != 1) { |
---|
254 | 195 | dev_err(dp->dev, "failed to set panel psr\n"); |
---|
.. | .. |
---|
256 | 197 | } |
---|
257 | 198 | |
---|
258 | 199 | /* Enable psr function */ |
---|
259 | | - psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE | |
---|
260 | | - DP_PSR_CRC_VERIFICATION; |
---|
| 200 | + psr_en = DP_PSR_ENABLE | DP_PSR_CRC_VERIFICATION; |
---|
261 | 201 | ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en); |
---|
262 | 202 | if (ret != 1) { |
---|
263 | 203 | dev_err(dp->dev, "failed to set panel psr\n"); |
---|
.. | .. |
---|
266 | 206 | |
---|
267 | 207 | analogix_dp_enable_psr_crc(dp); |
---|
268 | 208 | |
---|
| 209 | + dp->psr_supported = true; |
---|
| 210 | + |
---|
269 | 211 | return 0; |
---|
270 | 212 | end: |
---|
271 | 213 | dev_err(dp->dev, "enable psr fail, force to disable psr\n"); |
---|
272 | | - dp->psr_enable = false; |
---|
273 | 214 | |
---|
274 | 215 | return ret; |
---|
275 | 216 | } |
---|
.. | .. |
---|
359 | 300 | return ret < 0 ? ret : 0; |
---|
360 | 301 | } |
---|
361 | 302 | |
---|
| 303 | +static bool analogix_dp_get_vrr_capable(struct analogix_dp_device *dp) |
---|
| 304 | +{ |
---|
| 305 | + struct drm_connector *connector = &dp->connector; |
---|
| 306 | + struct drm_display_info *info = &connector->display_info; |
---|
| 307 | + |
---|
| 308 | + if (!info->monitor_range.max_vfreq) |
---|
| 309 | + return false; |
---|
| 310 | + if (!info->monitor_range.min_vfreq) |
---|
| 311 | + return false; |
---|
| 312 | + if (info->monitor_range.max_vfreq < info->monitor_range.min_vfreq) |
---|
| 313 | + return false; |
---|
| 314 | + if (!drm_dp_sink_can_do_video_without_timing_msa(dp->dpcd)) |
---|
| 315 | + return false; |
---|
| 316 | + |
---|
| 317 | + return true; |
---|
| 318 | +} |
---|
| 319 | + |
---|
362 | 320 | static int analogix_dp_link_start(struct analogix_dp_device *dp) |
---|
363 | 321 | { |
---|
364 | 322 | u8 buf[4]; |
---|
.. | .. |
---|
385 | 343 | |
---|
386 | 344 | /* Spread AMP if required, enable 8b/10b coding */ |
---|
387 | 345 | buf[0] = analogix_dp_ssc_supported(dp) ? DP_SPREAD_AMP_0_5 : 0; |
---|
| 346 | + if (analogix_dp_get_vrr_capable(dp)) |
---|
| 347 | + buf[0] |= DP_MSA_TIMING_PAR_IGNORE_EN; |
---|
388 | 348 | buf[1] = DP_SET_ANSI_8B10B; |
---|
389 | 349 | retval = drm_dp_dpcd_write(&dp->aux, DP_DOWNSPREAD_CTRL, buf, 2); |
---|
390 | 350 | if (retval < 0) |
---|
.. | .. |
---|
537 | 497 | u8 link_status[2], adjust_request[2]; |
---|
538 | 498 | u8 training_pattern = TRAINING_PTN2; |
---|
539 | 499 | |
---|
540 | | - usleep_range(100, 101); |
---|
| 500 | + drm_dp_link_train_clock_recovery_delay(dp->dpcd); |
---|
541 | 501 | |
---|
542 | 502 | lane_count = dp->link_train.lane_count; |
---|
543 | 503 | |
---|
544 | 504 | retval = drm_dp_dpcd_read(&dp->aux, DP_LANE0_1_STATUS, link_status, 2); |
---|
545 | | - if (retval < 0) |
---|
546 | | - return retval; |
---|
547 | | - |
---|
548 | | - retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
---|
549 | | - adjust_request, 2); |
---|
550 | 505 | if (retval < 0) |
---|
551 | 506 | return retval; |
---|
552 | 507 | |
---|
.. | .. |
---|
564 | 519 | if (retval < 0) |
---|
565 | 520 | return retval; |
---|
566 | 521 | |
---|
567 | | - dev_info(dp->dev, "Link Training Clock Recovery success\n"); |
---|
| 522 | + dev_dbg(dp->dev, "Link Training Clock Recovery success\n"); |
---|
568 | 523 | dp->link_train.lt_state = EQUALIZER_TRAINING; |
---|
| 524 | + |
---|
| 525 | + return 0; |
---|
569 | 526 | } else { |
---|
| 527 | + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
---|
| 528 | + adjust_request, 2); |
---|
| 529 | + if (retval < 0) |
---|
| 530 | + return retval; |
---|
| 531 | + |
---|
570 | 532 | for (lane = 0; lane < lane_count; lane++) { |
---|
571 | 533 | training_lane = analogix_dp_get_lane_link_training( |
---|
572 | 534 | dp, lane); |
---|
.. | .. |
---|
591 | 553 | return -EIO; |
---|
592 | 554 | } |
---|
593 | 555 | } |
---|
594 | | - |
---|
595 | | - analogix_dp_get_adjust_training_lane(dp, adjust_request); |
---|
596 | | - analogix_dp_set_lane_link_training(dp); |
---|
597 | | - |
---|
598 | | - retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, |
---|
599 | | - dp->link_train.training_lane, |
---|
600 | | - lane_count); |
---|
601 | | - if (retval < 0) |
---|
602 | | - return retval; |
---|
603 | 556 | } |
---|
| 557 | + |
---|
| 558 | + analogix_dp_get_adjust_training_lane(dp, adjust_request); |
---|
| 559 | + analogix_dp_set_lane_link_training(dp); |
---|
| 560 | + |
---|
| 561 | + retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, |
---|
| 562 | + dp->link_train.training_lane, lane_count); |
---|
| 563 | + if (retval < 0) |
---|
| 564 | + return retval; |
---|
604 | 565 | |
---|
605 | 566 | return 0; |
---|
606 | 567 | } |
---|
.. | .. |
---|
611 | 572 | u32 reg; |
---|
612 | 573 | u8 link_align, link_status[2], adjust_request[2]; |
---|
613 | 574 | |
---|
614 | | - usleep_range(400, 401); |
---|
| 575 | + drm_dp_link_train_channel_eq_delay(dp->dpcd); |
---|
615 | 576 | |
---|
616 | 577 | lane_count = dp->link_train.lane_count; |
---|
617 | 578 | |
---|
.. | .. |
---|
624 | 585 | return -EIO; |
---|
625 | 586 | } |
---|
626 | 587 | |
---|
627 | | - retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
---|
628 | | - adjust_request, 2); |
---|
629 | | - if (retval < 0) |
---|
630 | | - return retval; |
---|
631 | | - |
---|
632 | 588 | retval = drm_dp_dpcd_readb(&dp->aux, DP_LANE_ALIGN_STATUS_UPDATED, |
---|
633 | 589 | &link_align); |
---|
634 | 590 | if (retval < 0) |
---|
635 | 591 | return retval; |
---|
636 | | - |
---|
637 | | - analogix_dp_get_adjust_training_lane(dp, adjust_request); |
---|
638 | 592 | |
---|
639 | 593 | if (!analogix_dp_channel_eq_ok(link_status, link_align, lane_count)) { |
---|
640 | 594 | /* traing pattern Set to Normal */ |
---|
.. | .. |
---|
642 | 596 | if (retval < 0) |
---|
643 | 597 | return retval; |
---|
644 | 598 | |
---|
645 | | - dev_info(dp->dev, "Link Training success!\n"); |
---|
| 599 | + dev_dbg(dp->dev, "Link Training success!\n"); |
---|
646 | 600 | analogix_dp_get_link_bandwidth(dp, ®); |
---|
647 | 601 | dp->link_train.link_rate = reg; |
---|
648 | 602 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", |
---|
.. | .. |
---|
667 | 621 | return -EIO; |
---|
668 | 622 | } |
---|
669 | 623 | |
---|
| 624 | + retval = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
---|
| 625 | + adjust_request, 2); |
---|
| 626 | + if (retval < 0) |
---|
| 627 | + return retval; |
---|
| 628 | + |
---|
| 629 | + analogix_dp_get_adjust_training_lane(dp, adjust_request); |
---|
670 | 630 | analogix_dp_set_lane_link_training(dp); |
---|
671 | 631 | |
---|
672 | 632 | retval = drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, |
---|
.. | .. |
---|
677 | 637 | return 0; |
---|
678 | 638 | } |
---|
679 | 639 | |
---|
680 | | -static void analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, |
---|
681 | | - u8 *bandwidth) |
---|
| 640 | +static int analogix_dp_get_max_rx_bandwidth(struct analogix_dp_device *dp, |
---|
| 641 | + u8 *bandwidth) |
---|
682 | 642 | { |
---|
683 | 643 | u8 data; |
---|
| 644 | + int ret; |
---|
684 | 645 | |
---|
685 | 646 | /* |
---|
686 | 647 | * For DP rev.1.1, Maximum link rate of Main Link lanes |
---|
.. | .. |
---|
688 | 649 | * For DP rev.1.2, Maximum link rate of Main Link lanes |
---|
689 | 650 | * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps, 0x14 = 5.4Gbps |
---|
690 | 651 | */ |
---|
691 | | - drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); |
---|
| 652 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LINK_RATE, &data); |
---|
| 653 | + if (ret < 0) |
---|
| 654 | + return ret; |
---|
| 655 | + |
---|
692 | 656 | *bandwidth = data; |
---|
| 657 | + |
---|
| 658 | + return 0; |
---|
693 | 659 | } |
---|
694 | 660 | |
---|
695 | | -static void analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, |
---|
696 | | - u8 *lane_count) |
---|
| 661 | +static int analogix_dp_get_max_rx_lane_count(struct analogix_dp_device *dp, |
---|
| 662 | + u8 *lane_count) |
---|
697 | 663 | { |
---|
698 | 664 | u8 data; |
---|
| 665 | + int ret; |
---|
699 | 666 | |
---|
700 | 667 | /* |
---|
701 | 668 | * For DP rev.1.1, Maximum number of Main Link lanes |
---|
702 | 669 | * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes |
---|
703 | 670 | */ |
---|
704 | | - drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); |
---|
| 671 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_LANE_COUNT, &data); |
---|
| 672 | + if (ret < 0) |
---|
| 673 | + return ret; |
---|
| 674 | + |
---|
705 | 675 | *lane_count = DPCD_MAX_LANE_COUNT(data); |
---|
| 676 | + |
---|
| 677 | + return 0; |
---|
706 | 678 | } |
---|
707 | 679 | |
---|
708 | 680 | static int analogix_dp_full_link_train(struct analogix_dp_device *dp, |
---|
709 | 681 | u32 max_lanes, u32 max_rate) |
---|
710 | 682 | { |
---|
| 683 | + struct video_info *video = &dp->video_info; |
---|
711 | 684 | int retval = 0; |
---|
712 | 685 | bool training_finished = false; |
---|
713 | 686 | u8 dpcd; |
---|
.. | .. |
---|
722 | 695 | analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); |
---|
723 | 696 | analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); |
---|
724 | 697 | |
---|
725 | | - if ((dp->link_train.link_rate != DP_LINK_BW_1_62) && |
---|
726 | | - (dp->link_train.link_rate != DP_LINK_BW_2_7) && |
---|
727 | | - (dp->link_train.link_rate != DP_LINK_BW_5_4)) { |
---|
728 | | - dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n", |
---|
729 | | - dp->link_train.link_rate); |
---|
730 | | - dp->link_train.link_rate = DP_LINK_BW_1_62; |
---|
731 | | - } |
---|
| 698 | + /* Setup TX lane count & rate */ |
---|
| 699 | + dp->link_train.lane_count = min_t(u32, dp->link_train.lane_count, max_lanes); |
---|
| 700 | + dp->link_train.link_rate = min_t(u32, dp->link_train.link_rate, max_rate); |
---|
732 | 701 | |
---|
733 | | - if (dp->link_train.lane_count == 0) { |
---|
734 | | - dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n", |
---|
735 | | - dp->link_train.lane_count); |
---|
736 | | - dp->link_train.lane_count = (u8)LANE_COUNT1; |
---|
| 702 | + if (!analogix_dp_bandwidth_ok(dp, &video->mode, |
---|
| 703 | + drm_dp_bw_code_to_link_rate(dp->link_train.link_rate), |
---|
| 704 | + dp->link_train.lane_count)) { |
---|
| 705 | + dev_err(dp->dev, "bandwidth overflow\n"); |
---|
| 706 | + return -EINVAL; |
---|
737 | 707 | } |
---|
738 | 708 | |
---|
739 | 709 | drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &dpcd); |
---|
740 | 710 | dp->link_train.ssc = !!(dpcd & DP_MAX_DOWNSPREAD_0_5); |
---|
741 | | - |
---|
742 | | - /* Setup TX lane count & rate */ |
---|
743 | | - if (dp->link_train.lane_count > max_lanes) |
---|
744 | | - dp->link_train.lane_count = max_lanes; |
---|
745 | | - if (dp->link_train.link_rate > max_rate) |
---|
746 | | - dp->link_train.link_rate = max_rate; |
---|
747 | 711 | |
---|
748 | 712 | /* All DP analog module power up */ |
---|
749 | 713 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 0); |
---|
.. | .. |
---|
881 | 845 | analogix_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0); |
---|
882 | 846 | |
---|
883 | 847 | /* For video bist, Video timing must be generated by register */ |
---|
884 | | - analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE); |
---|
| 848 | + analogix_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_REGISTER); |
---|
885 | 849 | |
---|
886 | 850 | /* Disable video mute */ |
---|
887 | 851 | analogix_dp_enable_video_mute(dp, 0); |
---|
.. | .. |
---|
943 | 907 | return ret < 0 ? ret : 0; |
---|
944 | 908 | } |
---|
945 | 909 | |
---|
| 910 | +static u8 analogix_dp_autotest_phy_pattern(struct analogix_dp_device *dp) |
---|
| 911 | +{ |
---|
| 912 | + struct drm_dp_phy_test_params *data = &dp->compliance.phytest; |
---|
| 913 | + |
---|
| 914 | + if (drm_dp_get_phy_test_pattern(&dp->aux, data)) { |
---|
| 915 | + dev_err(dp->dev, "DP Phy Test pattern AUX read failure\n"); |
---|
| 916 | + return DP_TEST_NAK; |
---|
| 917 | + } |
---|
| 918 | + |
---|
| 919 | + if (data->link_rate > drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate)) { |
---|
| 920 | + dev_err(dp->dev, "invalid link rate = 0x%x\n", data->link_rate); |
---|
| 921 | + return DP_TEST_NAK; |
---|
| 922 | + } |
---|
| 923 | + |
---|
| 924 | + /* Set test active flag here so userspace doesn't interrupt things */ |
---|
| 925 | + dp->compliance.test_active = true; |
---|
| 926 | + |
---|
| 927 | + return DP_TEST_ACK; |
---|
| 928 | +} |
---|
| 929 | + |
---|
| 930 | +static void analogix_dp_handle_test_request(struct analogix_dp_device *dp) |
---|
| 931 | +{ |
---|
| 932 | + u8 response = DP_TEST_NAK; |
---|
| 933 | + u8 request = 0; |
---|
| 934 | + int ret; |
---|
| 935 | + |
---|
| 936 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_TEST_REQUEST, &request); |
---|
| 937 | + if (ret < 0) { |
---|
| 938 | + dev_err(dp->dev, "Could not read test request from sink\n"); |
---|
| 939 | + goto update_status; |
---|
| 940 | + } |
---|
| 941 | + |
---|
| 942 | + switch (request) { |
---|
| 943 | + case DP_TEST_LINK_PHY_TEST_PATTERN: |
---|
| 944 | + dev_info(dp->dev, "PHY_PATTERN test requested\n"); |
---|
| 945 | + response = analogix_dp_autotest_phy_pattern(dp); |
---|
| 946 | + break; |
---|
| 947 | + default: |
---|
| 948 | + dev_err(dp->dev, "Invalid test request '%02x'\n", request); |
---|
| 949 | + break; |
---|
| 950 | + } |
---|
| 951 | + |
---|
| 952 | + if (response & DP_TEST_ACK) |
---|
| 953 | + dp->compliance.test_type = request; |
---|
| 954 | + |
---|
| 955 | +update_status: |
---|
| 956 | + ret = drm_dp_dpcd_writeb(&dp->aux, DP_TEST_RESPONSE, response); |
---|
| 957 | + if (ret < 0) |
---|
| 958 | + dev_err(dp->dev, "Could not write test response to sink\n"); |
---|
| 959 | +} |
---|
| 960 | + |
---|
| 961 | +void analogix_dp_check_device_service_irq(struct analogix_dp_device *dp) |
---|
| 962 | +{ |
---|
| 963 | + u8 val; |
---|
| 964 | + int ret; |
---|
| 965 | + |
---|
| 966 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, &val); |
---|
| 967 | + if (ret < 0 || !val) |
---|
| 968 | + return; |
---|
| 969 | + |
---|
| 970 | + ret = drm_dp_dpcd_writeb(&dp->aux, DP_DEVICE_SERVICE_IRQ_VECTOR, val); |
---|
| 971 | + if (ret < 0) |
---|
| 972 | + return; |
---|
| 973 | + |
---|
| 974 | + if (val & DP_AUTOMATED_TEST_REQUEST) |
---|
| 975 | + analogix_dp_handle_test_request(dp); |
---|
| 976 | +} |
---|
| 977 | +EXPORT_SYMBOL_GPL(analogix_dp_check_device_service_irq); |
---|
| 978 | + |
---|
| 979 | +static void analogix_dp_process_phy_request(struct analogix_dp_device *dp) |
---|
| 980 | +{ |
---|
| 981 | + struct drm_dp_phy_test_params *data = &dp->compliance.phytest; |
---|
| 982 | + u8 spread, adjust_request[2]; |
---|
| 983 | + int ret; |
---|
| 984 | + |
---|
| 985 | + dp->link_train.link_rate = drm_dp_link_rate_to_bw_code(data->link_rate); |
---|
| 986 | + dp->link_train.lane_count = data->num_lanes; |
---|
| 987 | + |
---|
| 988 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &spread); |
---|
| 989 | + if (ret < 0) { |
---|
| 990 | + dev_err(dp->dev, "Could not read ssc from sink\n"); |
---|
| 991 | + return; |
---|
| 992 | + } |
---|
| 993 | + |
---|
| 994 | + dp->link_train.ssc = !!(spread & DP_MAX_DOWNSPREAD_0_5); |
---|
| 995 | + |
---|
| 996 | + ret = drm_dp_dpcd_read(&dp->aux, DP_ADJUST_REQUEST_LANE0_1, |
---|
| 997 | + adjust_request, 2); |
---|
| 998 | + if (ret < 0) { |
---|
| 999 | + dev_err(dp->dev, "Could not read swing/pre-emphasis\n"); |
---|
| 1000 | + return; |
---|
| 1001 | + } |
---|
| 1002 | + |
---|
| 1003 | + analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate); |
---|
| 1004 | + analogix_dp_set_lane_count(dp, dp->link_train.lane_count); |
---|
| 1005 | + analogix_dp_get_adjust_training_lane(dp, adjust_request); |
---|
| 1006 | + analogix_dp_set_lane_link_training(dp); |
---|
| 1007 | + |
---|
| 1008 | + switch (data->phy_pattern) { |
---|
| 1009 | + case DP_PHY_TEST_PATTERN_NONE: |
---|
| 1010 | + dev_info(dp->dev, "Disable Phy Test Pattern\n"); |
---|
| 1011 | + analogix_dp_set_training_pattern(dp, DP_NONE); |
---|
| 1012 | + break; |
---|
| 1013 | + case DP_PHY_TEST_PATTERN_D10_2: |
---|
| 1014 | + dev_info(dp->dev, "Set D10.2 Phy Test Pattern\n"); |
---|
| 1015 | + analogix_dp_set_training_pattern(dp, D10_2); |
---|
| 1016 | + break; |
---|
| 1017 | + case DP_PHY_TEST_PATTERN_PRBS7: |
---|
| 1018 | + dev_info(dp->dev, "Set PRBS7 Phy Test Pattern\n"); |
---|
| 1019 | + analogix_dp_set_training_pattern(dp, PRBS7); |
---|
| 1020 | + break; |
---|
| 1021 | + case DP_PHY_TEST_PATTERN_80BIT_CUSTOM: |
---|
| 1022 | + dev_info(dp->dev, "Set 80Bit Custom Phy Test Pattern\n"); |
---|
| 1023 | + analogix_dp_set_training_pattern(dp, TEST_PATTERN_80BIT); |
---|
| 1024 | + break; |
---|
| 1025 | + case DP_PHY_TEST_PATTERN_CP2520: |
---|
| 1026 | + dev_info(dp->dev, "Set HBR2 compliance Phy Test Pattern\n"); |
---|
| 1027 | + analogix_dp_set_training_pattern(dp, TEST_PATTERN_HBR2); |
---|
| 1028 | + break; |
---|
| 1029 | + default: |
---|
| 1030 | + dev_err(dp->dev, "Invalid Phy Test Pattern: %d\n", data->phy_pattern); |
---|
| 1031 | + return; |
---|
| 1032 | + } |
---|
| 1033 | + |
---|
| 1034 | + drm_dp_set_phy_test_pattern(&dp->aux, data, 0x11); |
---|
| 1035 | +} |
---|
| 1036 | + |
---|
| 1037 | +void analogix_dp_phy_test(struct analogix_dp_device *dp) |
---|
| 1038 | +{ |
---|
| 1039 | + struct drm_device *dev = dp->drm_dev; |
---|
| 1040 | + struct drm_modeset_acquire_ctx ctx; |
---|
| 1041 | + int ret; |
---|
| 1042 | + |
---|
| 1043 | + DRM_DEV_INFO(dp->dev, "PHY test\n"); |
---|
| 1044 | + |
---|
| 1045 | + drm_modeset_acquire_init(&ctx, 0); |
---|
| 1046 | + for (;;) { |
---|
| 1047 | + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); |
---|
| 1048 | + if (ret != -EDEADLK) |
---|
| 1049 | + break; |
---|
| 1050 | + |
---|
| 1051 | + drm_modeset_backoff(&ctx); |
---|
| 1052 | + } |
---|
| 1053 | + |
---|
| 1054 | + analogix_dp_process_phy_request(dp); |
---|
| 1055 | + drm_modeset_drop_locks(&ctx); |
---|
| 1056 | + drm_modeset_acquire_fini(&ctx); |
---|
| 1057 | +} |
---|
| 1058 | +EXPORT_SYMBOL_GPL(analogix_dp_phy_test); |
---|
| 1059 | + |
---|
946 | 1060 | static irqreturn_t analogix_dp_hpd_irq_handler(int irq, void *arg) |
---|
947 | 1061 | { |
---|
948 | 1062 | struct analogix_dp_device *dp = arg; |
---|
.. | .. |
---|
953 | 1067 | return IRQ_HANDLED; |
---|
954 | 1068 | } |
---|
955 | 1069 | |
---|
956 | | -static irqreturn_t analogix_dp_hardirq(int irq, void *arg) |
---|
957 | | -{ |
---|
958 | | - struct analogix_dp_device *dp = arg; |
---|
959 | | - irqreturn_t ret = IRQ_NONE; |
---|
960 | | - enum dp_irq_type irq_type; |
---|
961 | | - |
---|
962 | | - irq_type = analogix_dp_get_irq_type(dp); |
---|
963 | | - if (irq_type != DP_IRQ_TYPE_UNKNOWN) { |
---|
964 | | - analogix_dp_mute_hpd_interrupt(dp); |
---|
965 | | - ret = IRQ_WAKE_THREAD; |
---|
966 | | - } |
---|
967 | | - |
---|
968 | | - return ret; |
---|
969 | | -} |
---|
970 | | - |
---|
971 | 1070 | static irqreturn_t analogix_dp_irq_thread(int irq, void *arg) |
---|
972 | 1071 | { |
---|
973 | 1072 | struct analogix_dp_device *dp = arg; |
---|
974 | | - enum dp_irq_type irq_type; |
---|
975 | 1073 | |
---|
976 | | - irq_type = analogix_dp_get_irq_type(dp); |
---|
977 | | - if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN || |
---|
978 | | - irq_type & DP_IRQ_TYPE_HP_CABLE_OUT) { |
---|
979 | | - dev_dbg(dp->dev, "Detected cable status changed!\n"); |
---|
980 | | - if (dp->drm_dev) |
---|
981 | | - drm_helper_hpd_irq_event(dp->drm_dev); |
---|
982 | | - } |
---|
983 | | - |
---|
984 | | - if (irq_type != DP_IRQ_TYPE_UNKNOWN) { |
---|
985 | | - analogix_dp_clear_hotplug_interrupts(dp); |
---|
986 | | - analogix_dp_unmute_hpd_interrupt(dp); |
---|
987 | | - } |
---|
| 1074 | + analogix_dp_irq_handler(dp); |
---|
988 | 1075 | |
---|
989 | 1076 | return IRQ_HANDLED; |
---|
990 | 1077 | } |
---|
.. | .. |
---|
1005 | 1092 | return 0; |
---|
1006 | 1093 | } |
---|
1007 | 1094 | |
---|
| 1095 | +static int analogix_dp_link_power_up(struct analogix_dp_device *dp) |
---|
| 1096 | +{ |
---|
| 1097 | + u8 value; |
---|
| 1098 | + int ret; |
---|
| 1099 | + |
---|
| 1100 | + if (dp->dpcd[DP_DPCD_REV] < 0x11) |
---|
| 1101 | + return 0; |
---|
| 1102 | + |
---|
| 1103 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); |
---|
| 1104 | + if (ret < 0) |
---|
| 1105 | + return ret; |
---|
| 1106 | + |
---|
| 1107 | + value &= ~DP_SET_POWER_MASK; |
---|
| 1108 | + value |= DP_SET_POWER_D0; |
---|
| 1109 | + |
---|
| 1110 | + ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); |
---|
| 1111 | + if (ret < 0) |
---|
| 1112 | + return ret; |
---|
| 1113 | + |
---|
| 1114 | + usleep_range(1000, 2000); |
---|
| 1115 | + |
---|
| 1116 | + return 0; |
---|
| 1117 | +} |
---|
| 1118 | + |
---|
| 1119 | +static int analogix_dp_link_power_down(struct analogix_dp_device *dp) |
---|
| 1120 | +{ |
---|
| 1121 | + u8 value; |
---|
| 1122 | + int ret; |
---|
| 1123 | + |
---|
| 1124 | + if (dp->dpcd[DP_DPCD_REV] < 0x11) |
---|
| 1125 | + return 0; |
---|
| 1126 | + |
---|
| 1127 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_SET_POWER, &value); |
---|
| 1128 | + if (ret < 0) |
---|
| 1129 | + return ret; |
---|
| 1130 | + |
---|
| 1131 | + value &= ~DP_SET_POWER_MASK; |
---|
| 1132 | + value |= DP_SET_POWER_D3; |
---|
| 1133 | + |
---|
| 1134 | + ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, value); |
---|
| 1135 | + if (ret < 0) |
---|
| 1136 | + return ret; |
---|
| 1137 | + |
---|
| 1138 | + return 0; |
---|
| 1139 | +} |
---|
| 1140 | + |
---|
1008 | 1141 | static int analogix_dp_commit(struct analogix_dp_device *dp) |
---|
1009 | 1142 | { |
---|
1010 | 1143 | struct video_info *video = &dp->video_info; |
---|
1011 | 1144 | int ret; |
---|
| 1145 | + |
---|
| 1146 | + ret = drm_dp_read_dpcd_caps(&dp->aux, dp->dpcd); |
---|
| 1147 | + if (ret < 0) { |
---|
| 1148 | + dev_err(dp->dev, "failed to read dpcd caps: %d\n", ret); |
---|
| 1149 | + return ret; |
---|
| 1150 | + } |
---|
| 1151 | + |
---|
| 1152 | + ret = analogix_dp_link_power_up(dp); |
---|
| 1153 | + if (ret) { |
---|
| 1154 | + dev_err(dp->dev, "failed to power up link: %d\n", ret); |
---|
| 1155 | + return ret; |
---|
| 1156 | + } |
---|
1012 | 1157 | |
---|
1013 | 1158 | if (device_property_read_bool(dp->dev, "panel-self-test")) |
---|
1014 | 1159 | return drm_dp_dpcd_writeb(&dp->aux, DP_EDP_CONFIGURATION_SET, |
---|
.. | .. |
---|
1018 | 1163 | if (ret) { |
---|
1019 | 1164 | dev_err(dp->dev, "unable to do link train, ret=%d\n", ret); |
---|
1020 | 1165 | return ret; |
---|
1021 | | - } |
---|
1022 | | - |
---|
1023 | | - if (!analogix_dp_bandwidth_ok(dp, &video->mode, |
---|
1024 | | - drm_dp_bw_code_to_link_rate(dp->link_train.link_rate), |
---|
1025 | | - dp->link_train.lane_count)) { |
---|
1026 | | - dev_err(dp->dev, "bandwidth overflow\n"); |
---|
1027 | | - return -EINVAL; |
---|
1028 | 1166 | } |
---|
1029 | 1167 | |
---|
1030 | 1168 | ret = analogix_dp_enable_scramble(dp, 1); |
---|
.. | .. |
---|
1045 | 1183 | return ret; |
---|
1046 | 1184 | } |
---|
1047 | 1185 | |
---|
1048 | | - ret = analogix_dp_detect_sink_psr(dp); |
---|
1049 | | - if (ret) |
---|
1050 | | - return ret; |
---|
1051 | | - |
---|
1052 | 1186 | /* Check whether panel supports fast training */ |
---|
1053 | 1187 | ret = analogix_dp_fast_link_train_detection(dp); |
---|
1054 | 1188 | if (ret) |
---|
1055 | | - dp->psr_enable = false; |
---|
| 1189 | + return ret; |
---|
1056 | 1190 | |
---|
1057 | | - if (dp->psr_enable) { |
---|
| 1191 | + if (analogix_dp_detect_sink_psr(dp)) { |
---|
1058 | 1192 | ret = analogix_dp_enable_sink_psr(dp); |
---|
1059 | 1193 | if (ret) |
---|
1060 | 1194 | return ret; |
---|
1061 | 1195 | } |
---|
1062 | 1196 | |
---|
| 1197 | + return ret; |
---|
| 1198 | +} |
---|
| 1199 | + |
---|
| 1200 | +static int analogix_dp_enable_psr(struct analogix_dp_device *dp) |
---|
| 1201 | +{ |
---|
| 1202 | + struct dp_sdp psr_vsc; |
---|
| 1203 | + int ret; |
---|
| 1204 | + u8 sink; |
---|
| 1205 | + |
---|
| 1206 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink); |
---|
| 1207 | + if (ret != 1) |
---|
| 1208 | + DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret); |
---|
| 1209 | + else if (sink == DP_PSR_SINK_ACTIVE_RFB) |
---|
| 1210 | + return 0; |
---|
| 1211 | + |
---|
| 1212 | + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
---|
| 1213 | + memset(&psr_vsc, 0, sizeof(psr_vsc)); |
---|
| 1214 | + psr_vsc.sdp_header.HB0 = 0; |
---|
| 1215 | + psr_vsc.sdp_header.HB1 = 0x7; |
---|
| 1216 | + psr_vsc.sdp_header.HB2 = 0x2; |
---|
| 1217 | + psr_vsc.sdp_header.HB3 = 0x8; |
---|
| 1218 | + psr_vsc.db[0] = 0; |
---|
| 1219 | + psr_vsc.db[1] = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID; |
---|
| 1220 | + |
---|
| 1221 | + ret = analogix_dp_send_psr_spd(dp, &psr_vsc, true); |
---|
| 1222 | + if (!ret) { |
---|
| 1223 | + analogix_dp_set_analog_power_down(dp, POWER_ALL, true); |
---|
| 1224 | + |
---|
| 1225 | + if (dp->phy) { |
---|
| 1226 | + union phy_configure_opts phy_cfg = {0}; |
---|
| 1227 | + |
---|
| 1228 | + phy_cfg.dp.lanes = 0; |
---|
| 1229 | + phy_cfg.dp.set_lanes = true; |
---|
| 1230 | + ret = phy_configure(dp->phy, &phy_cfg); |
---|
| 1231 | + if (ret) |
---|
| 1232 | + return ret; |
---|
| 1233 | + } |
---|
| 1234 | + } |
---|
1063 | 1235 | |
---|
1064 | 1236 | return ret; |
---|
| 1237 | +} |
---|
| 1238 | + |
---|
| 1239 | +static int analogix_dp_disable_psr(struct analogix_dp_device *dp) |
---|
| 1240 | +{ |
---|
| 1241 | + struct dp_sdp psr_vsc; |
---|
| 1242 | + int ret; |
---|
| 1243 | + u8 sink; |
---|
| 1244 | + |
---|
| 1245 | + analogix_dp_set_analog_power_down(dp, POWER_ALL, false); |
---|
| 1246 | + |
---|
| 1247 | + ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0); |
---|
| 1248 | + if (ret != 1) { |
---|
| 1249 | + DRM_DEV_ERROR(dp->dev, "Failed to set DP Power0 %d\n", ret); |
---|
| 1250 | + return ret; |
---|
| 1251 | + } |
---|
| 1252 | + |
---|
| 1253 | + ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink); |
---|
| 1254 | + if (ret != 1) { |
---|
| 1255 | + DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret); |
---|
| 1256 | + return ret; |
---|
| 1257 | + } else if (sink == DP_PSR_SINK_INACTIVE) { |
---|
| 1258 | + DRM_DEV_ERROR(dp->dev, "sink inactive, skip disable psr"); |
---|
| 1259 | + return 0; |
---|
| 1260 | + } |
---|
| 1261 | + |
---|
| 1262 | + ret = analogix_dp_train_link(dp); |
---|
| 1263 | + if (ret) { |
---|
| 1264 | + DRM_DEV_ERROR(dp->dev, "Failed to train the link %d\n", ret); |
---|
| 1265 | + return ret; |
---|
| 1266 | + } |
---|
| 1267 | + |
---|
| 1268 | + /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
---|
| 1269 | + memset(&psr_vsc, 0, sizeof(psr_vsc)); |
---|
| 1270 | + psr_vsc.sdp_header.HB0 = 0; |
---|
| 1271 | + psr_vsc.sdp_header.HB1 = 0x7; |
---|
| 1272 | + psr_vsc.sdp_header.HB2 = 0x2; |
---|
| 1273 | + psr_vsc.sdp_header.HB3 = 0x8; |
---|
| 1274 | + |
---|
| 1275 | + psr_vsc.db[0] = 0; |
---|
| 1276 | + psr_vsc.db[1] = 0; |
---|
| 1277 | + |
---|
| 1278 | + return analogix_dp_send_psr_spd(dp, &psr_vsc, true); |
---|
1065 | 1279 | } |
---|
1066 | 1280 | |
---|
1067 | 1281 | static int analogix_dp_get_modes(struct drm_connector *connector) |
---|
.. | .. |
---|
1070 | 1284 | struct edid *edid; |
---|
1071 | 1285 | int ret, num_modes = 0; |
---|
1072 | 1286 | |
---|
| 1287 | + if (dp->plat_data->right && dp->plat_data->right->plat_data->bridge) { |
---|
| 1288 | + struct drm_bridge *bridge = dp->plat_data->right->plat_data->bridge; |
---|
| 1289 | + |
---|
| 1290 | + if (bridge->ops & DRM_BRIDGE_OP_MODES) { |
---|
| 1291 | + if (!drm_bridge_get_modes(bridge, connector)) |
---|
| 1292 | + return 0; |
---|
| 1293 | + } |
---|
| 1294 | + } |
---|
| 1295 | + |
---|
1073 | 1296 | if (dp->plat_data->panel) |
---|
1074 | | - num_modes += drm_panel_get_modes(dp->plat_data->panel); |
---|
| 1297 | + num_modes += drm_panel_get_modes(dp->plat_data->panel, connector); |
---|
| 1298 | + |
---|
| 1299 | + if (dp->plat_data->bridge) |
---|
| 1300 | + num_modes += drm_bridge_get_modes(dp->plat_data->bridge, connector); |
---|
1075 | 1301 | |
---|
1076 | 1302 | if (!num_modes) { |
---|
1077 | | - if (dp->plat_data->panel) { |
---|
1078 | | - ret = analogix_dp_prepare_panel(dp, true); |
---|
1079 | | - if (ret) { |
---|
1080 | | - DRM_ERROR("Failed to prepare panel (%d)\n", ret); |
---|
1081 | | - return 0; |
---|
1082 | | - } |
---|
1083 | | - } |
---|
| 1303 | + ret = analogix_dp_phy_power_on(dp); |
---|
| 1304 | + if (ret) |
---|
| 1305 | + return 0; |
---|
1084 | 1306 | |
---|
1085 | | - pm_runtime_get_sync(dp->dev); |
---|
| 1307 | + if (dp->plat_data->panel) |
---|
| 1308 | + analogix_dp_panel_prepare(dp); |
---|
| 1309 | + |
---|
1086 | 1310 | edid = drm_get_edid(connector, &dp->aux.ddc); |
---|
1087 | | - pm_runtime_put(dp->dev); |
---|
1088 | 1311 | if (edid) { |
---|
1089 | 1312 | drm_connector_update_edid_property(&dp->connector, |
---|
1090 | 1313 | edid); |
---|
1091 | 1314 | num_modes += drm_add_edid_modes(&dp->connector, edid); |
---|
1092 | 1315 | kfree(edid); |
---|
1093 | 1316 | } |
---|
| 1317 | + |
---|
| 1318 | + analogix_dp_phy_power_off(dp); |
---|
1094 | 1319 | } |
---|
1095 | 1320 | |
---|
1096 | 1321 | if (dp->plat_data->get_modes) |
---|
1097 | 1322 | num_modes += dp->plat_data->get_modes(dp->plat_data, connector); |
---|
| 1323 | + |
---|
| 1324 | + if (num_modes > 0 && dp->plat_data->split_mode) { |
---|
| 1325 | + struct drm_display_mode *mode; |
---|
| 1326 | + |
---|
| 1327 | + list_for_each_entry(mode, &connector->probed_modes, head) |
---|
| 1328 | + dp->plat_data->convert_to_split_mode(mode); |
---|
| 1329 | + } |
---|
1098 | 1330 | |
---|
1099 | 1331 | return num_modes; |
---|
1100 | 1332 | } |
---|
.. | .. |
---|
1107 | 1339 | return dp->encoder; |
---|
1108 | 1340 | } |
---|
1109 | 1341 | |
---|
1110 | | -static int analogix_dp_loader_protect(struct drm_connector *connector, bool on) |
---|
| 1342 | + |
---|
| 1343 | +static int analogix_dp_atomic_check(struct drm_connector *connector, |
---|
| 1344 | + struct drm_atomic_state *state) |
---|
1111 | 1345 | { |
---|
1112 | 1346 | struct analogix_dp_device *dp = to_dp(connector); |
---|
1113 | | - int ret; |
---|
| 1347 | + struct drm_connector_state *conn_state; |
---|
| 1348 | + struct drm_crtc_state *crtc_state; |
---|
1114 | 1349 | |
---|
1115 | | - if (dp->plat_data->panel) |
---|
1116 | | - drm_panel_loader_protect(dp->plat_data->panel, on); |
---|
| 1350 | + conn_state = drm_atomic_get_new_connector_state(state, connector); |
---|
| 1351 | + if (WARN_ON(!conn_state)) |
---|
| 1352 | + return -ENODEV; |
---|
1117 | 1353 | |
---|
1118 | | - if (on) { |
---|
1119 | | - dp->dpms_mode = DRM_MODE_DPMS_ON; |
---|
| 1354 | + conn_state->self_refresh_aware = true; |
---|
1120 | 1355 | |
---|
1121 | | - pm_runtime_get_sync(dp->dev); |
---|
| 1356 | + if (!conn_state->crtc) |
---|
| 1357 | + return 0; |
---|
1122 | 1358 | |
---|
1123 | | - analogix_dp_phy_power_on(dp); |
---|
| 1359 | + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); |
---|
| 1360 | + if (!crtc_state) |
---|
| 1361 | + return 0; |
---|
1124 | 1362 | |
---|
1125 | | - ret = analogix_dp_detect_sink_psr(dp); |
---|
1126 | | - if (ret) |
---|
1127 | | - return ret; |
---|
1128 | | - |
---|
1129 | | - if (dp->psr_enable) { |
---|
1130 | | - ret = analogix_dp_enable_sink_psr(dp); |
---|
1131 | | - if (ret) |
---|
1132 | | - return ret; |
---|
1133 | | - } |
---|
1134 | | - } |
---|
| 1363 | + if (crtc_state->self_refresh_active && !dp->psr_supported) |
---|
| 1364 | + return -EINVAL; |
---|
1135 | 1365 | |
---|
1136 | 1366 | return 0; |
---|
1137 | 1367 | } |
---|
1138 | 1368 | |
---|
1139 | 1369 | static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = { |
---|
1140 | | - .loader_protect = analogix_dp_loader_protect, |
---|
1141 | 1370 | .get_modes = analogix_dp_get_modes, |
---|
1142 | 1371 | .best_encoder = analogix_dp_best_encoder, |
---|
| 1372 | + .atomic_check = analogix_dp_atomic_check, |
---|
1143 | 1373 | }; |
---|
1144 | 1374 | |
---|
1145 | 1375 | static enum drm_connector_status |
---|
1146 | | -analogix_dp_detect(struct drm_connector *connector, bool force) |
---|
| 1376 | +analogix_dp_detect(struct analogix_dp_device *dp) |
---|
1147 | 1377 | { |
---|
1148 | | - struct analogix_dp_device *dp = to_dp(connector); |
---|
1149 | 1378 | enum drm_connector_status status = connector_status_disconnected; |
---|
1150 | 1379 | int ret; |
---|
1151 | 1380 | |
---|
1152 | | - if (dp->plat_data->panel) { |
---|
1153 | | - ret = analogix_dp_prepare_panel(dp, true); |
---|
1154 | | - if (ret) { |
---|
1155 | | - DRM_ERROR("Failed to prepare panel (%d)\n", ret); |
---|
1156 | | - return ret; |
---|
1157 | | - } |
---|
| 1381 | + ret = analogix_dp_phy_power_on(dp); |
---|
| 1382 | + if (ret) { |
---|
| 1383 | + extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, false); |
---|
| 1384 | + return connector_status_disconnected; |
---|
1158 | 1385 | } |
---|
1159 | 1386 | |
---|
1160 | | - pm_runtime_get_sync(dp->dev); |
---|
1161 | | - if (!analogix_dp_detect_hpd(dp)) |
---|
| 1387 | + if (dp->plat_data->panel) |
---|
| 1388 | + analogix_dp_panel_prepare(dp); |
---|
| 1389 | + |
---|
| 1390 | + if (!analogix_dp_detect_hpd(dp)) { |
---|
| 1391 | + ret = analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate); |
---|
| 1392 | + if (ret) { |
---|
| 1393 | + dev_err(dp->dev, "failed to read max link rate\n"); |
---|
| 1394 | + goto out; |
---|
| 1395 | + } |
---|
| 1396 | + |
---|
| 1397 | + ret = analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count); |
---|
| 1398 | + if (ret) { |
---|
| 1399 | + dev_err(dp->dev, "failed to read max lane count\n"); |
---|
| 1400 | + goto out; |
---|
| 1401 | + } |
---|
| 1402 | + |
---|
1162 | 1403 | status = connector_status_connected; |
---|
1163 | | - pm_runtime_put(dp->dev); |
---|
| 1404 | + } |
---|
| 1405 | + |
---|
| 1406 | + if (dp->plat_data->bridge) { |
---|
| 1407 | + struct drm_bridge *next_bridge = dp->plat_data->bridge; |
---|
| 1408 | + |
---|
| 1409 | + if (next_bridge->ops & DRM_BRIDGE_OP_DETECT) |
---|
| 1410 | + status = drm_bridge_detect(next_bridge); |
---|
| 1411 | + } |
---|
| 1412 | + |
---|
| 1413 | +out: |
---|
| 1414 | + analogix_dp_phy_power_off(dp); |
---|
| 1415 | + |
---|
| 1416 | + if (status == connector_status_connected) |
---|
| 1417 | + extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, true); |
---|
| 1418 | + else |
---|
| 1419 | + extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, false); |
---|
1164 | 1420 | |
---|
1165 | 1421 | return status; |
---|
1166 | 1422 | } |
---|
1167 | 1423 | |
---|
1168 | | -static int |
---|
1169 | | -analogix_dp_atomic_connector_get_property(struct drm_connector *connector, |
---|
1170 | | - const struct drm_connector_state *state, |
---|
1171 | | - struct drm_property *property, |
---|
1172 | | - uint64_t *val) |
---|
| 1424 | +static enum drm_connector_status |
---|
| 1425 | +analogix_dp_connector_detect(struct drm_connector *connector, bool force) |
---|
1173 | 1426 | { |
---|
1174 | 1427 | struct analogix_dp_device *dp = to_dp(connector); |
---|
1175 | | - const struct analogix_dp_property_ops *ops = dp->plat_data->property_ops; |
---|
1176 | 1428 | |
---|
1177 | | - if (ops && ops->get_property) |
---|
1178 | | - return ops->get_property(connector, state, property, |
---|
1179 | | - val, dp->plat_data); |
---|
| 1429 | + if (dp->plat_data->right && analogix_dp_detect(dp->plat_data->right) != connector_status_connected) |
---|
| 1430 | + return connector_status_disconnected; |
---|
| 1431 | + |
---|
| 1432 | + return analogix_dp_detect(dp); |
---|
| 1433 | +} |
---|
| 1434 | + |
---|
| 1435 | +static void analogix_dp_connector_force(struct drm_connector *connector) |
---|
| 1436 | +{ |
---|
| 1437 | + struct analogix_dp_device *dp = to_dp(connector); |
---|
| 1438 | + |
---|
| 1439 | + if (connector->status == connector_status_connected) |
---|
| 1440 | + extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, true); |
---|
1180 | 1441 | else |
---|
1181 | | - return -EINVAL; |
---|
| 1442 | + extcon_set_state_sync(dp->extcon, EXTCON_DISP_DP, false); |
---|
1182 | 1443 | } |
---|
1183 | 1444 | |
---|
1184 | 1445 | static const struct drm_connector_funcs analogix_dp_connector_funcs = { |
---|
1185 | 1446 | .fill_modes = drm_helper_probe_single_connector_modes, |
---|
1186 | | - .detect = analogix_dp_detect, |
---|
| 1447 | + .detect = analogix_dp_connector_detect, |
---|
1187 | 1448 | .destroy = drm_connector_cleanup, |
---|
1188 | 1449 | .reset = drm_atomic_helper_connector_reset, |
---|
1189 | 1450 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
---|
1190 | 1451 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
---|
1191 | | - .atomic_get_property = analogix_dp_atomic_connector_get_property, |
---|
| 1452 | + .force = analogix_dp_connector_force, |
---|
1192 | 1453 | }; |
---|
1193 | 1454 | |
---|
1194 | | -static int analogix_dp_bridge_attach(struct drm_bridge *bridge) |
---|
| 1455 | +static int analogix_dp_bridge_attach(struct drm_bridge *bridge, |
---|
| 1456 | + enum drm_bridge_attach_flags flags) |
---|
1195 | 1457 | { |
---|
1196 | 1458 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
1197 | 1459 | struct drm_encoder *encoder = dp->encoder; |
---|
.. | .. |
---|
1203 | 1465 | return -ENODEV; |
---|
1204 | 1466 | } |
---|
1205 | 1467 | |
---|
| 1468 | + if (dp->plat_data->bridge) { |
---|
| 1469 | + ret = drm_bridge_attach(bridge->encoder, dp->plat_data->bridge, bridge, |
---|
| 1470 | + dp->plat_data->skip_connector ? |
---|
| 1471 | + 0 : DRM_BRIDGE_ATTACH_NO_CONNECTOR); |
---|
| 1472 | + if (ret) { |
---|
| 1473 | + DRM_ERROR("Failed to attach external bridge: %d\n", ret); |
---|
| 1474 | + return ret; |
---|
| 1475 | + } |
---|
| 1476 | + } |
---|
| 1477 | + |
---|
| 1478 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) |
---|
| 1479 | + return 0; |
---|
| 1480 | + |
---|
1206 | 1481 | if (!dp->plat_data->skip_connector) { |
---|
1207 | | - const struct analogix_dp_property_ops *ops = dp->plat_data->property_ops; |
---|
| 1482 | + int connector_type = DRM_MODE_CONNECTOR_eDP; |
---|
| 1483 | + |
---|
| 1484 | + if (dp->plat_data->bridge && |
---|
| 1485 | + dp->plat_data->bridge->type != DRM_MODE_CONNECTOR_Unknown) |
---|
| 1486 | + connector_type = dp->plat_data->bridge->type; |
---|
1208 | 1487 | |
---|
1209 | 1488 | connector = &dp->connector; |
---|
1210 | 1489 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
---|
| 1490 | + if (dp->plat_data->bridge && dp->plat_data->bridge->ops & DRM_BRIDGE_OP_DETECT) |
---|
| 1491 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT | |
---|
| 1492 | + DRM_CONNECTOR_POLL_DISCONNECT; |
---|
1211 | 1493 | |
---|
1212 | 1494 | ret = drm_connector_init(dp->drm_dev, connector, |
---|
1213 | 1495 | &analogix_dp_connector_funcs, |
---|
1214 | | - DRM_MODE_CONNECTOR_eDP); |
---|
| 1496 | + connector_type); |
---|
1215 | 1497 | if (ret) { |
---|
1216 | 1498 | DRM_ERROR("Failed to initialize connector with drm\n"); |
---|
1217 | 1499 | return ret; |
---|
.. | .. |
---|
1220 | 1502 | drm_connector_helper_add(connector, |
---|
1221 | 1503 | &analogix_dp_connector_helper_funcs); |
---|
1222 | 1504 | drm_connector_attach_encoder(connector, encoder); |
---|
1223 | | - |
---|
1224 | | - if (ops && ops->attach_properties) |
---|
1225 | | - ops->attach_properties(connector); |
---|
1226 | 1505 | } |
---|
1227 | 1506 | |
---|
1228 | 1507 | /* |
---|
.. | .. |
---|
1231 | 1510 | * plat_data->attch return, that's why we record the connector |
---|
1232 | 1511 | * point after plat attached. |
---|
1233 | 1512 | */ |
---|
1234 | | - if (dp->plat_data->attach) { |
---|
1235 | | - ret = dp->plat_data->attach(dp->plat_data, bridge, connector); |
---|
1236 | | - if (ret) { |
---|
1237 | | - DRM_ERROR("Failed at platform attch func\n"); |
---|
1238 | | - return ret; |
---|
1239 | | - } |
---|
1240 | | - } |
---|
1241 | | - |
---|
1242 | | - if (dp->plat_data->panel) { |
---|
1243 | | - ret = drm_panel_attach(dp->plat_data->panel, &dp->connector); |
---|
| 1513 | + if (dp->plat_data->attach) { |
---|
| 1514 | + ret = dp->plat_data->attach(dp->plat_data, bridge, connector); |
---|
1244 | 1515 | if (ret) { |
---|
1245 | | - DRM_ERROR("Failed to attach panel\n"); |
---|
| 1516 | + DRM_ERROR("Failed at platform attach func\n"); |
---|
1246 | 1517 | return ret; |
---|
1247 | 1518 | } |
---|
1248 | 1519 | } |
---|
.. | .. |
---|
1250 | 1521 | return 0; |
---|
1251 | 1522 | } |
---|
1252 | 1523 | |
---|
1253 | | -static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge) |
---|
| 1524 | +static void analogix_dp_bridge_detach(struct drm_bridge *bridge) |
---|
1254 | 1525 | { |
---|
1255 | 1526 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
1256 | | - int ret; |
---|
1257 | 1527 | |
---|
1258 | | - if (dp->plat_data->panel) { |
---|
1259 | | - ret = analogix_dp_prepare_panel(dp, true); |
---|
1260 | | - if (ret) |
---|
1261 | | - DRM_ERROR("failed to setup the panel ret = %d\n", ret); |
---|
1262 | | - } |
---|
| 1528 | + if (dp->plat_data->detach) |
---|
| 1529 | + dp->plat_data->detach(dp->plat_data, bridge); |
---|
| 1530 | +} |
---|
| 1531 | + |
---|
| 1532 | +static |
---|
| 1533 | +struct drm_crtc *analogix_dp_get_old_crtc(struct analogix_dp_device *dp, |
---|
| 1534 | + struct drm_atomic_state *state) |
---|
| 1535 | +{ |
---|
| 1536 | + struct drm_encoder *encoder = dp->encoder; |
---|
| 1537 | + struct drm_connector *connector; |
---|
| 1538 | + struct drm_connector_state *conn_state; |
---|
| 1539 | + |
---|
| 1540 | + connector = drm_atomic_get_old_connector_for_encoder(state, encoder); |
---|
| 1541 | + if (!connector) |
---|
| 1542 | + return NULL; |
---|
| 1543 | + |
---|
| 1544 | + conn_state = drm_atomic_get_old_connector_state(state, connector); |
---|
| 1545 | + if (!conn_state) |
---|
| 1546 | + return NULL; |
---|
| 1547 | + |
---|
| 1548 | + return conn_state->crtc; |
---|
| 1549 | +} |
---|
| 1550 | + |
---|
| 1551 | +static |
---|
| 1552 | +struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, |
---|
| 1553 | + struct drm_atomic_state *state) |
---|
| 1554 | +{ |
---|
| 1555 | + struct drm_bridge *bridge = &dp->bridge; |
---|
| 1556 | + struct drm_encoder *encoder = bridge->encoder; |
---|
| 1557 | + struct drm_connector *connector; |
---|
| 1558 | + struct drm_connector_state *conn_state; |
---|
| 1559 | + |
---|
| 1560 | + connector = drm_atomic_get_new_connector_for_encoder(state, encoder); |
---|
| 1561 | + if (!connector) |
---|
| 1562 | + return NULL; |
---|
| 1563 | + |
---|
| 1564 | + conn_state = drm_atomic_get_new_connector_state(state, connector); |
---|
| 1565 | + if (!conn_state) |
---|
| 1566 | + return NULL; |
---|
| 1567 | + |
---|
| 1568 | + return conn_state->crtc; |
---|
| 1569 | +} |
---|
| 1570 | + |
---|
| 1571 | +static void |
---|
| 1572 | +analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, |
---|
| 1573 | + struct drm_bridge_state *old_bridge_state) |
---|
| 1574 | +{ |
---|
| 1575 | + struct drm_atomic_state *old_state = old_bridge_state->base.state; |
---|
| 1576 | + struct analogix_dp_device *dp = bridge->driver_private; |
---|
| 1577 | + struct drm_crtc *crtc; |
---|
| 1578 | + struct drm_crtc_state *old_crtc_state; |
---|
| 1579 | + |
---|
| 1580 | + crtc = analogix_dp_get_new_crtc(dp, old_state); |
---|
| 1581 | + if (!crtc) |
---|
| 1582 | + return; |
---|
| 1583 | + |
---|
| 1584 | + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); |
---|
| 1585 | + /* Don't touch the panel if we're coming back from PSR */ |
---|
| 1586 | + if (old_crtc_state && old_crtc_state->self_refresh_active) |
---|
| 1587 | + return; |
---|
| 1588 | + |
---|
| 1589 | + if (dp->plat_data->panel) |
---|
| 1590 | + analogix_dp_panel_prepare(dp); |
---|
1263 | 1591 | } |
---|
1264 | 1592 | |
---|
1265 | 1593 | static int analogix_dp_set_bridge(struct analogix_dp_device *dp) |
---|
1266 | 1594 | { |
---|
1267 | 1595 | int ret; |
---|
1268 | 1596 | |
---|
1269 | | - pm_runtime_get_sync(dp->dev); |
---|
1270 | | - |
---|
1271 | 1597 | if (dp->plat_data->power_on_start) |
---|
1272 | 1598 | dp->plat_data->power_on_start(dp->plat_data); |
---|
1273 | 1599 | |
---|
1274 | | - analogix_dp_phy_power_on(dp); |
---|
| 1600 | + ret = analogix_dp_phy_power_on(dp); |
---|
| 1601 | + if (ret) |
---|
| 1602 | + return ret; |
---|
1275 | 1603 | |
---|
1276 | 1604 | ret = analogix_dp_init_dp(dp); |
---|
1277 | 1605 | if (ret) |
---|
.. | .. |
---|
1300 | 1628 | if (dp->plat_data->power_on_end) |
---|
1301 | 1629 | dp->plat_data->power_on_end(dp->plat_data); |
---|
1302 | 1630 | |
---|
1303 | | - enable_irq(dp->irq); |
---|
1304 | 1631 | return 0; |
---|
1305 | 1632 | |
---|
1306 | 1633 | out_dp_init: |
---|
1307 | 1634 | analogix_dp_phy_power_off(dp); |
---|
1308 | 1635 | if (dp->plat_data->power_off) |
---|
1309 | 1636 | dp->plat_data->power_off(dp->plat_data); |
---|
1310 | | - pm_runtime_put_sync(dp->dev); |
---|
1311 | | - |
---|
1312 | 1637 | return ret; |
---|
1313 | 1638 | } |
---|
1314 | 1639 | |
---|
1315 | | -static void analogix_dp_bridge_enable(struct drm_bridge *bridge) |
---|
| 1640 | +static void analogix_dp_modeset_retry_work_fn(struct work_struct *work) |
---|
1316 | 1641 | { |
---|
| 1642 | + struct analogix_dp_device *dp = |
---|
| 1643 | + container_of(work, typeof(*dp), modeset_retry_work); |
---|
| 1644 | + |
---|
| 1645 | + /* Send Hotplug uevent so userspace can reprobe */ |
---|
| 1646 | + drm_kms_helper_hotplug_event(dp->bridge.dev); |
---|
| 1647 | +} |
---|
| 1648 | + |
---|
| 1649 | +static void |
---|
| 1650 | +analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, |
---|
| 1651 | + struct drm_bridge_state *old_bridge_state) |
---|
| 1652 | +{ |
---|
| 1653 | + struct drm_atomic_state *old_state = old_bridge_state->base.state; |
---|
1317 | 1654 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
| 1655 | + struct drm_crtc *crtc; |
---|
| 1656 | + struct drm_crtc_state *old_crtc_state; |
---|
1318 | 1657 | int timeout_loop = 0; |
---|
| 1658 | + int ret; |
---|
| 1659 | + |
---|
| 1660 | + crtc = analogix_dp_get_new_crtc(dp, old_state); |
---|
| 1661 | + if (!crtc) |
---|
| 1662 | + return; |
---|
| 1663 | + |
---|
| 1664 | + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, crtc); |
---|
| 1665 | + /* Not a full enable, just disable PSR and continue */ |
---|
| 1666 | + if (old_crtc_state && old_crtc_state->self_refresh_active) { |
---|
| 1667 | + ret = analogix_dp_disable_psr(dp); |
---|
| 1668 | + if (ret) |
---|
| 1669 | + DRM_ERROR("Failed to disable psr %d\n", ret); |
---|
| 1670 | + return; |
---|
| 1671 | + } |
---|
1319 | 1672 | |
---|
1320 | 1673 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) |
---|
1321 | 1674 | return; |
---|
.. | .. |
---|
1331 | 1684 | usleep_range(10, 11); |
---|
1332 | 1685 | } |
---|
1333 | 1686 | dev_err(dp->dev, "too many times retry set bridge, give it up\n"); |
---|
| 1687 | + |
---|
| 1688 | + /* Schedule a Hotplug Uevent to userspace to start modeset */ |
---|
| 1689 | + schedule_work(&dp->modeset_retry_work); |
---|
1334 | 1690 | } |
---|
1335 | 1691 | |
---|
1336 | 1692 | static void analogix_dp_bridge_disable(struct drm_bridge *bridge) |
---|
1337 | 1693 | { |
---|
1338 | 1694 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
1339 | | - int ret; |
---|
1340 | 1695 | |
---|
1341 | 1696 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) |
---|
1342 | 1697 | return; |
---|
.. | .. |
---|
1348 | 1703 | } |
---|
1349 | 1704 | } |
---|
1350 | 1705 | |
---|
1351 | | - disable_irq(dp->irq); |
---|
| 1706 | + if (!analogix_dp_get_plug_in_status(dp)) |
---|
| 1707 | + analogix_dp_link_power_down(dp); |
---|
1352 | 1708 | |
---|
1353 | 1709 | if (dp->plat_data->power_off) |
---|
1354 | 1710 | dp->plat_data->power_off(dp->plat_data); |
---|
1355 | 1711 | |
---|
1356 | | - analogix_dp_reset_aux(dp); |
---|
1357 | 1712 | analogix_dp_set_analog_power_down(dp, POWER_ALL, 1); |
---|
1358 | 1713 | analogix_dp_phy_power_off(dp); |
---|
1359 | 1714 | |
---|
1360 | | - pm_runtime_put_sync(dp->dev); |
---|
| 1715 | + if (dp->plat_data->panel) |
---|
| 1716 | + analogix_dp_panel_unprepare(dp); |
---|
1361 | 1717 | |
---|
1362 | | - if (dp->plat_data->panel) { |
---|
1363 | | - ret = analogix_dp_prepare_panel(dp, false); |
---|
1364 | | - if (ret) |
---|
1365 | | - DRM_ERROR("failed to setup the panel ret = %d\n", ret); |
---|
1366 | | - } |
---|
1367 | | - |
---|
1368 | | - dp->psr_enable = false; |
---|
1369 | 1718 | dp->fast_train_enable = false; |
---|
| 1719 | + dp->psr_supported = false; |
---|
1370 | 1720 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
---|
1371 | 1721 | } |
---|
1372 | 1722 | |
---|
| 1723 | +void analogix_dp_disable(struct analogix_dp_device *dp) |
---|
| 1724 | +{ |
---|
| 1725 | + analogix_dp_bridge_disable(&dp->bridge); |
---|
| 1726 | +} |
---|
| 1727 | +EXPORT_SYMBOL_GPL(analogix_dp_disable); |
---|
| 1728 | + |
---|
| 1729 | +static void |
---|
| 1730 | +analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, |
---|
| 1731 | + struct drm_bridge_state *old_bridge_state) |
---|
| 1732 | +{ |
---|
| 1733 | + struct drm_atomic_state *old_state = old_bridge_state->base.state; |
---|
| 1734 | + struct analogix_dp_device *dp = bridge->driver_private; |
---|
| 1735 | + struct drm_crtc *old_crtc, *new_crtc; |
---|
| 1736 | + struct drm_crtc_state *old_crtc_state = NULL; |
---|
| 1737 | + struct drm_crtc_state *new_crtc_state = NULL; |
---|
| 1738 | + int ret; |
---|
| 1739 | + |
---|
| 1740 | + new_crtc = analogix_dp_get_new_crtc(dp, old_state); |
---|
| 1741 | + if (!new_crtc) |
---|
| 1742 | + goto out; |
---|
| 1743 | + |
---|
| 1744 | + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, new_crtc); |
---|
| 1745 | + if (!new_crtc_state) |
---|
| 1746 | + goto out; |
---|
| 1747 | + |
---|
| 1748 | + /* Don't do a full disable on PSR transitions */ |
---|
| 1749 | + if (new_crtc_state->self_refresh_active) |
---|
| 1750 | + return; |
---|
| 1751 | + |
---|
| 1752 | +out: |
---|
| 1753 | + old_crtc = analogix_dp_get_old_crtc(dp, old_state); |
---|
| 1754 | + if (old_crtc) { |
---|
| 1755 | + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, |
---|
| 1756 | + old_crtc); |
---|
| 1757 | + |
---|
| 1758 | + /* When moving from PSR to fully disabled, exit PSR first. */ |
---|
| 1759 | + if (old_crtc_state && old_crtc_state->self_refresh_active) { |
---|
| 1760 | + ret = analogix_dp_disable_psr(dp); |
---|
| 1761 | + if (ret) |
---|
| 1762 | + DRM_ERROR("Failed to disable psr (%d)\n", ret); |
---|
| 1763 | + } |
---|
| 1764 | + } |
---|
| 1765 | + |
---|
| 1766 | + analogix_dp_bridge_disable(bridge); |
---|
| 1767 | +} |
---|
| 1768 | + |
---|
| 1769 | +static void |
---|
| 1770 | +analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, |
---|
| 1771 | + struct drm_bridge_state *old_bridge_state) |
---|
| 1772 | +{ |
---|
| 1773 | + struct drm_atomic_state *old_state = old_bridge_state->base.state; |
---|
| 1774 | + struct analogix_dp_device *dp = bridge->driver_private; |
---|
| 1775 | + struct drm_crtc *crtc; |
---|
| 1776 | + struct drm_crtc_state *new_crtc_state; |
---|
| 1777 | + int ret; |
---|
| 1778 | + |
---|
| 1779 | + crtc = analogix_dp_get_new_crtc(dp, old_state); |
---|
| 1780 | + if (!crtc) |
---|
| 1781 | + return; |
---|
| 1782 | + |
---|
| 1783 | + new_crtc_state = drm_atomic_get_new_crtc_state(old_state, crtc); |
---|
| 1784 | + if (!new_crtc_state || !new_crtc_state->self_refresh_active) |
---|
| 1785 | + return; |
---|
| 1786 | + |
---|
| 1787 | + ret = analogix_dp_enable_psr(dp); |
---|
| 1788 | + if (ret) |
---|
| 1789 | + DRM_ERROR("Failed to enable psr (%d)\n", ret); |
---|
| 1790 | +} |
---|
| 1791 | + |
---|
1373 | 1792 | static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, |
---|
1374 | | - struct drm_display_mode *orig_mode, |
---|
1375 | | - struct drm_display_mode *mode) |
---|
| 1793 | + const struct drm_display_mode *orig_mode, |
---|
| 1794 | + const struct drm_display_mode *adj_mode) |
---|
1376 | 1795 | { |
---|
1377 | 1796 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
1378 | 1797 | struct drm_display_info *display_info = &dp->connector.display_info; |
---|
1379 | 1798 | struct video_info *video = &dp->video_info; |
---|
| 1799 | + struct drm_display_mode *mode = &video->mode; |
---|
1380 | 1800 | struct device_node *dp_node = dp->dev->of_node; |
---|
1381 | 1801 | int vic; |
---|
1382 | 1802 | |
---|
1383 | | - drm_mode_copy(&video->mode, mode); |
---|
| 1803 | + drm_mode_copy(mode, adj_mode); |
---|
| 1804 | + if (dp->plat_data->split_mode) |
---|
| 1805 | + dp->plat_data->convert_to_origin_mode(mode); |
---|
1384 | 1806 | |
---|
1385 | 1807 | /* Input video interlaces & hsync pol & vsync pol */ |
---|
1386 | 1808 | video->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); |
---|
1387 | | - video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); |
---|
1388 | | - video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); |
---|
| 1809 | + if (dp->plat_data->dev_type == RK3588_EDP) { |
---|
| 1810 | + video->v_sync_polarity = true; |
---|
| 1811 | + video->h_sync_polarity = true; |
---|
| 1812 | + } else { |
---|
| 1813 | + video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); |
---|
| 1814 | + video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); |
---|
| 1815 | + } |
---|
1389 | 1816 | |
---|
1390 | 1817 | /* Input video dynamic_range & colorimetry */ |
---|
1391 | 1818 | vic = drm_match_cea_mode(mode); |
---|
.. | .. |
---|
1449 | 1876 | video->interlaced = true; |
---|
1450 | 1877 | } |
---|
1451 | 1878 | |
---|
| 1879 | +static bool analogix_dp_link_config_validate(u8 link_rate, u8 lane_count) |
---|
| 1880 | +{ |
---|
| 1881 | + switch (link_rate) { |
---|
| 1882 | + case DP_LINK_BW_1_62: |
---|
| 1883 | + case DP_LINK_BW_2_7: |
---|
| 1884 | + case DP_LINK_BW_5_4: |
---|
| 1885 | + break; |
---|
| 1886 | + default: |
---|
| 1887 | + return false; |
---|
| 1888 | + } |
---|
| 1889 | + |
---|
| 1890 | + switch (lane_count) { |
---|
| 1891 | + case 1: |
---|
| 1892 | + case 2: |
---|
| 1893 | + case 4: |
---|
| 1894 | + break; |
---|
| 1895 | + default: |
---|
| 1896 | + return false; |
---|
| 1897 | + } |
---|
| 1898 | + |
---|
| 1899 | + return true; |
---|
| 1900 | +} |
---|
| 1901 | + |
---|
1452 | 1902 | static enum drm_mode_status |
---|
1453 | 1903 | analogix_dp_bridge_mode_valid(struct drm_bridge *bridge, |
---|
| 1904 | + const struct drm_display_info *info, |
---|
1454 | 1905 | const struct drm_display_mode *mode) |
---|
1455 | 1906 | { |
---|
1456 | 1907 | struct analogix_dp_device *dp = bridge->driver_private; |
---|
| 1908 | + struct drm_display_mode m; |
---|
| 1909 | + u32 max_link_rate, max_lane_count; |
---|
1457 | 1910 | |
---|
1458 | | - if (!analogix_dp_bandwidth_ok(dp, mode, |
---|
1459 | | - drm_dp_bw_code_to_link_rate(dp->video_info.max_link_rate), |
---|
1460 | | - dp->video_info.max_lane_count)) |
---|
| 1911 | + drm_mode_copy(&m, mode); |
---|
| 1912 | + |
---|
| 1913 | + if (dp->plat_data->split_mode) |
---|
| 1914 | + dp->plat_data->convert_to_origin_mode(&m); |
---|
| 1915 | + |
---|
| 1916 | + max_link_rate = min_t(u32, dp->video_info.max_link_rate, |
---|
| 1917 | + dp->link_train.link_rate); |
---|
| 1918 | + max_lane_count = min_t(u32, dp->video_info.max_lane_count, |
---|
| 1919 | + dp->link_train.lane_count); |
---|
| 1920 | + if (analogix_dp_link_config_validate(max_link_rate, max_lane_count) && |
---|
| 1921 | + !analogix_dp_bandwidth_ok(dp, &m, |
---|
| 1922 | + drm_dp_bw_code_to_link_rate(max_link_rate), |
---|
| 1923 | + max_lane_count)) |
---|
1461 | 1924 | return MODE_BAD; |
---|
1462 | 1925 | |
---|
1463 | 1926 | return MODE_OK; |
---|
1464 | 1927 | } |
---|
1465 | 1928 | |
---|
1466 | | -static void analogix_dp_bridge_nop(struct drm_bridge *bridge) |
---|
1467 | | -{ |
---|
1468 | | - /* do nothing */ |
---|
1469 | | -} |
---|
1470 | | - |
---|
1471 | 1929 | static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { |
---|
1472 | | - .pre_enable = analogix_dp_bridge_pre_enable, |
---|
1473 | | - .enable = analogix_dp_bridge_enable, |
---|
1474 | | - .disable = analogix_dp_bridge_disable, |
---|
1475 | | - .post_disable = analogix_dp_bridge_nop, |
---|
| 1930 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
---|
| 1931 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
---|
| 1932 | + .atomic_reset = drm_atomic_helper_bridge_reset, |
---|
| 1933 | + .atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable, |
---|
| 1934 | + .atomic_enable = analogix_dp_bridge_atomic_enable, |
---|
| 1935 | + .atomic_disable = analogix_dp_bridge_atomic_disable, |
---|
| 1936 | + .atomic_post_disable = analogix_dp_bridge_atomic_post_disable, |
---|
1476 | 1937 | .mode_set = analogix_dp_bridge_mode_set, |
---|
1477 | 1938 | .attach = analogix_dp_bridge_attach, |
---|
| 1939 | + .detach = analogix_dp_bridge_detach, |
---|
1478 | 1940 | .mode_valid = analogix_dp_bridge_mode_valid, |
---|
1479 | 1941 | }; |
---|
1480 | 1942 | |
---|
1481 | | -static int analogix_dp_create_bridge(struct drm_device *drm_dev, |
---|
1482 | | - struct analogix_dp_device *dp) |
---|
| 1943 | +static int analogix_dp_bridge_init(struct analogix_dp_device *dp) |
---|
1483 | 1944 | { |
---|
1484 | | - struct drm_bridge *bridge; |
---|
| 1945 | + struct drm_bridge *bridge = &dp->bridge; |
---|
1485 | 1946 | int ret; |
---|
1486 | 1947 | |
---|
1487 | | - bridge = devm_kzalloc(drm_dev->dev, sizeof(*bridge), GFP_KERNEL); |
---|
1488 | | - if (!bridge) { |
---|
1489 | | - DRM_ERROR("failed to allocate for drm bridge\n"); |
---|
1490 | | - return -ENOMEM; |
---|
| 1948 | + if (!dp->plat_data->left) { |
---|
| 1949 | + ret = drm_bridge_attach(dp->encoder, bridge, NULL, 0); |
---|
| 1950 | + if (ret) { |
---|
| 1951 | + DRM_ERROR("failed to attach drm bridge\n"); |
---|
| 1952 | + return ret; |
---|
| 1953 | + } |
---|
1491 | 1954 | } |
---|
1492 | 1955 | |
---|
1493 | | - dp->bridge = bridge; |
---|
| 1956 | + if (dp->plat_data->right) { |
---|
| 1957 | + struct analogix_dp_device *secondary = dp->plat_data->right; |
---|
| 1958 | + struct drm_bridge *last_bridge = |
---|
| 1959 | + list_last_entry(&bridge->encoder->bridge_chain, |
---|
| 1960 | + struct drm_bridge, chain_node); |
---|
1494 | 1961 | |
---|
1495 | | - bridge->driver_private = dp; |
---|
1496 | | - bridge->funcs = &analogix_dp_bridge_funcs; |
---|
1497 | | - |
---|
1498 | | - ret = drm_bridge_attach(dp->encoder, bridge, NULL); |
---|
1499 | | - if (ret) { |
---|
1500 | | - DRM_ERROR("failed to attach drm bridge\n"); |
---|
1501 | | - return -EINVAL; |
---|
| 1962 | + ret = drm_bridge_attach(dp->encoder, &secondary->bridge, last_bridge, |
---|
| 1963 | + DRM_BRIDGE_ATTACH_NO_CONNECTOR); |
---|
| 1964 | + if (ret) |
---|
| 1965 | + return ret; |
---|
1502 | 1966 | } |
---|
1503 | 1967 | |
---|
1504 | 1968 | return 0; |
---|
| 1969 | +} |
---|
| 1970 | + |
---|
| 1971 | +static u32 analogix_dp_parse_link_frequencies(struct analogix_dp_device *dp) |
---|
| 1972 | +{ |
---|
| 1973 | + struct device_node *node = dp->dev->of_node; |
---|
| 1974 | + struct device_node *endpoint; |
---|
| 1975 | + u64 frequency = 0; |
---|
| 1976 | + int cnt; |
---|
| 1977 | + |
---|
| 1978 | + endpoint = of_graph_get_endpoint_by_regs(node, 1, 0); |
---|
| 1979 | + if (!endpoint) |
---|
| 1980 | + return 0; |
---|
| 1981 | + |
---|
| 1982 | + cnt = of_property_count_u64_elems(endpoint, "link-frequencies"); |
---|
| 1983 | + if (cnt > 0) |
---|
| 1984 | + of_property_read_u64_index(endpoint, "link-frequencies", |
---|
| 1985 | + cnt - 1, &frequency); |
---|
| 1986 | + of_node_put(endpoint); |
---|
| 1987 | + |
---|
| 1988 | + if (!frequency) |
---|
| 1989 | + return 0; |
---|
| 1990 | + |
---|
| 1991 | + do_div(frequency, 10 * 1000); /* symbol rate kbytes */ |
---|
| 1992 | + |
---|
| 1993 | + switch (frequency) { |
---|
| 1994 | + case 162000: |
---|
| 1995 | + case 270000: |
---|
| 1996 | + case 540000: |
---|
| 1997 | + break; |
---|
| 1998 | + default: |
---|
| 1999 | + dev_err(dp->dev, "invalid link frequency value: %lld\n", frequency); |
---|
| 2000 | + return 0; |
---|
| 2001 | + } |
---|
| 2002 | + |
---|
| 2003 | + return frequency; |
---|
1505 | 2004 | } |
---|
1506 | 2005 | |
---|
1507 | 2006 | static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp) |
---|
1508 | 2007 | { |
---|
1509 | 2008 | struct device_node *dp_node = dp->dev->of_node; |
---|
1510 | 2009 | struct video_info *video_info = &dp->video_info; |
---|
| 2010 | + struct property *prop; |
---|
| 2011 | + int ret, len, num_lanes; |
---|
| 2012 | + u32 max_link_rate; |
---|
1511 | 2013 | |
---|
1512 | 2014 | switch (dp->plat_data->dev_type) { |
---|
1513 | 2015 | case RK3288_DP: |
---|
1514 | | - case RK3368_EDP: |
---|
1515 | 2016 | case RK3568_EDP: |
---|
| 2017 | + /* |
---|
| 2018 | + * Like Rk3288 DisplayPort TRM indicate that "Main link |
---|
| 2019 | + * containing 4 physical lanes of 2.7/1.62 Gbps/lane". |
---|
| 2020 | + */ |
---|
1516 | 2021 | video_info->max_link_rate = 0x0A; |
---|
1517 | 2022 | video_info->max_lane_count = 0x04; |
---|
1518 | 2023 | break; |
---|
1519 | 2024 | case RK3399_EDP: |
---|
| 2025 | + case RK3588_EDP: |
---|
1520 | 2026 | video_info->max_link_rate = 0x14; |
---|
1521 | 2027 | video_info->max_lane_count = 0x04; |
---|
1522 | 2028 | break; |
---|
.. | .. |
---|
1532 | 2038 | break; |
---|
1533 | 2039 | } |
---|
1534 | 2040 | |
---|
| 2041 | + max_link_rate = analogix_dp_parse_link_frequencies(dp); |
---|
| 2042 | + if (max_link_rate && max_link_rate < drm_dp_bw_code_to_link_rate(video_info->max_link_rate)) |
---|
| 2043 | + video_info->max_link_rate = drm_dp_link_rate_to_bw_code(max_link_rate); |
---|
| 2044 | + |
---|
1535 | 2045 | video_info->video_bist_enable = |
---|
1536 | 2046 | of_property_read_bool(dp_node, "analogix,video-bist-enable"); |
---|
| 2047 | + video_info->force_stream_valid = |
---|
| 2048 | + of_property_read_bool(dp_node, "analogix,force-stream-valid"); |
---|
| 2049 | + |
---|
| 2050 | + prop = of_find_property(dp_node, "data-lanes", &len); |
---|
| 2051 | + if (!prop) { |
---|
| 2052 | + video_info->lane_map[0] = 0; |
---|
| 2053 | + video_info->lane_map[1] = 1; |
---|
| 2054 | + video_info->lane_map[2] = 2; |
---|
| 2055 | + video_info->lane_map[3] = 3; |
---|
| 2056 | + DRM_DEV_DEBUG(dp->dev, "failed to find data lane mapping, using default\n"); |
---|
| 2057 | + return 0; |
---|
| 2058 | + } |
---|
| 2059 | + |
---|
| 2060 | + num_lanes = len / sizeof(u32); |
---|
| 2061 | + |
---|
| 2062 | + if (num_lanes < 1 || num_lanes > 4 || num_lanes == 3) { |
---|
| 2063 | + DRM_DEV_ERROR(dp->dev, "bad number of data lanes\n"); |
---|
| 2064 | + return -EINVAL; |
---|
| 2065 | + } |
---|
| 2066 | + |
---|
| 2067 | + video_info->max_lane_count = num_lanes; |
---|
| 2068 | + |
---|
| 2069 | + ret = of_property_read_u32_array(dp_node, "data-lanes", |
---|
| 2070 | + video_info->lane_map, num_lanes); |
---|
| 2071 | + if (ret) { |
---|
| 2072 | + DRM_DEV_ERROR(dp->dev, "failed to read lane data\n"); |
---|
| 2073 | + return ret; |
---|
| 2074 | + } |
---|
1537 | 2075 | |
---|
1538 | 2076 | return 0; |
---|
1539 | 2077 | } |
---|
.. | .. |
---|
1542 | 2080 | struct drm_dp_aux_msg *msg) |
---|
1543 | 2081 | { |
---|
1544 | 2082 | struct analogix_dp_device *dp = to_dp(aux); |
---|
| 2083 | + int ret; |
---|
1545 | 2084 | |
---|
1546 | | - return analogix_dp_transfer(dp, msg); |
---|
| 2085 | + pm_runtime_get_sync(dp->dev); |
---|
| 2086 | + |
---|
| 2087 | + ret = analogix_dp_detect_hpd(dp); |
---|
| 2088 | + if (ret) |
---|
| 2089 | + goto out; |
---|
| 2090 | + |
---|
| 2091 | + ret = analogix_dp_transfer(dp, msg); |
---|
| 2092 | +out: |
---|
| 2093 | + pm_runtime_put(dp->dev); |
---|
| 2094 | + |
---|
| 2095 | + return ret; |
---|
1547 | 2096 | } |
---|
1548 | 2097 | |
---|
1549 | 2098 | int analogix_dp_audio_hw_params(struct analogix_dp_device *dp, |
---|
.. | .. |
---|
1588 | 2137 | } |
---|
1589 | 2138 | EXPORT_SYMBOL_GPL(analogix_dp_audio_get_eld); |
---|
1590 | 2139 | |
---|
| 2140 | +static void analogix_dp_link_train_restore(struct analogix_dp_device *dp) |
---|
| 2141 | +{ |
---|
| 2142 | + u32 link_rate, lane_count; |
---|
| 2143 | + u8 lane, spread; |
---|
| 2144 | + |
---|
| 2145 | + analogix_dp_get_link_bandwidth(dp, &link_rate); |
---|
| 2146 | + analogix_dp_get_lane_count(dp, &lane_count); |
---|
| 2147 | + drm_dp_dpcd_readb(&dp->aux, DP_MAX_DOWNSPREAD, &spread); |
---|
| 2148 | + |
---|
| 2149 | + dp->link_train.link_rate = link_rate; |
---|
| 2150 | + dp->link_train.lane_count = lane_count; |
---|
| 2151 | + dp->link_train.enhanced_framing = analogix_dp_get_enhanced_mode(dp); |
---|
| 2152 | + dp->link_train.ssc = !!(spread & DP_MAX_DOWNSPREAD_0_5); |
---|
| 2153 | + |
---|
| 2154 | + for (lane = 0; lane < 4; lane++) |
---|
| 2155 | + dp->link_train.training_lane[lane] = |
---|
| 2156 | + analogix_dp_get_lane_link_training(dp, lane); |
---|
| 2157 | +} |
---|
| 2158 | + |
---|
| 2159 | +int analogix_dp_loader_protect(struct analogix_dp_device *dp) |
---|
| 2160 | +{ |
---|
| 2161 | + u8 link_status[DP_LINK_STATUS_SIZE]; |
---|
| 2162 | + int ret; |
---|
| 2163 | + |
---|
| 2164 | + ret = analogix_dp_phy_power_on(dp); |
---|
| 2165 | + if (ret) |
---|
| 2166 | + return ret; |
---|
| 2167 | + |
---|
| 2168 | + dp->dpms_mode = DRM_MODE_DPMS_ON; |
---|
| 2169 | + |
---|
| 2170 | + analogix_dp_link_train_restore(dp); |
---|
| 2171 | + |
---|
| 2172 | + ret = analogix_dp_fast_link_train_detection(dp); |
---|
| 2173 | + if (ret) |
---|
| 2174 | + goto err_disable; |
---|
| 2175 | + |
---|
| 2176 | + if (analogix_dp_detect_sink_psr(dp)) { |
---|
| 2177 | + ret = analogix_dp_enable_sink_psr(dp); |
---|
| 2178 | + if (ret) |
---|
| 2179 | + goto err_disable; |
---|
| 2180 | + } |
---|
| 2181 | + |
---|
| 2182 | + ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); |
---|
| 2183 | + if (ret < 0) { |
---|
| 2184 | + dev_err(dp->dev, "Failed to read link status\n"); |
---|
| 2185 | + goto err_disable; |
---|
| 2186 | + } |
---|
| 2187 | + |
---|
| 2188 | + if (!drm_dp_channel_eq_ok(link_status, dp->link_train.lane_count)) { |
---|
| 2189 | + dev_err(dp->dev, "Channel EQ or CR not ok\n"); |
---|
| 2190 | + ret = -EINVAL; |
---|
| 2191 | + goto err_disable; |
---|
| 2192 | + } |
---|
| 2193 | + |
---|
| 2194 | + return 0; |
---|
| 2195 | + |
---|
| 2196 | +err_disable: |
---|
| 2197 | + analogix_dp_disable(dp); |
---|
| 2198 | + return ret; |
---|
| 2199 | +} |
---|
| 2200 | +EXPORT_SYMBOL_GPL(analogix_dp_loader_protect); |
---|
| 2201 | + |
---|
1591 | 2202 | struct analogix_dp_device * |
---|
1592 | | -analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, |
---|
1593 | | - struct analogix_dp_plat_data *plat_data) |
---|
| 2203 | +analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) |
---|
1594 | 2204 | { |
---|
1595 | 2205 | struct platform_device *pdev = to_platform_device(dev); |
---|
1596 | 2206 | struct analogix_dp_device *dp; |
---|
.. | .. |
---|
1608 | 2218 | |
---|
1609 | 2219 | dp->dev = &pdev->dev; |
---|
1610 | 2220 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
---|
| 2221 | + INIT_WORK(&dp->modeset_retry_work, analogix_dp_modeset_retry_work_fn); |
---|
1611 | 2222 | |
---|
1612 | 2223 | mutex_init(&dp->panel_lock); |
---|
1613 | 2224 | dp->panel_is_prepared = false; |
---|
.. | .. |
---|
1639 | 2250 | } |
---|
1640 | 2251 | } |
---|
1641 | 2252 | |
---|
| 2253 | + ret = devm_clk_bulk_get_all(dev, &dp->clks); |
---|
| 2254 | + if (ret < 0) { |
---|
| 2255 | + dev_err(dev, "failed to get clocks %d\n", ret); |
---|
| 2256 | + return ERR_PTR(ret); |
---|
| 2257 | + } |
---|
| 2258 | + |
---|
| 2259 | + dp->nr_clks = ret; |
---|
| 2260 | + |
---|
1642 | 2261 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
1643 | 2262 | |
---|
1644 | 2263 | dp->reg_base = devm_ioremap_resource(&pdev->dev, res); |
---|
.. | .. |
---|
1659 | 2278 | } |
---|
1660 | 2279 | |
---|
1661 | 2280 | if (dp->hpd_gpiod) { |
---|
1662 | | - dp->hpd_irq = gpiod_to_irq(dp->hpd_gpiod); |
---|
1663 | | - if (dp->hpd_irq < 0) |
---|
1664 | | - return ERR_PTR(-EINVAL); |
---|
1665 | | - |
---|
1666 | | - ret = devm_request_threaded_irq(dev, dp->hpd_irq, NULL, |
---|
| 2281 | + ret = devm_request_threaded_irq(dev, |
---|
| 2282 | + gpiod_to_irq(dp->hpd_gpiod), |
---|
| 2283 | + NULL, |
---|
1667 | 2284 | analogix_dp_hpd_irq_handler, |
---|
1668 | 2285 | IRQF_TRIGGER_RISING | |
---|
1669 | 2286 | IRQF_TRIGGER_FALLING | |
---|
.. | .. |
---|
1682 | 2299 | } |
---|
1683 | 2300 | |
---|
1684 | 2301 | irq_set_status_flags(dp->irq, IRQ_NOAUTOEN); |
---|
1685 | | - ret = devm_request_threaded_irq(&pdev->dev, dp->irq, |
---|
1686 | | - analogix_dp_hardirq, |
---|
| 2302 | + ret = devm_request_threaded_irq(dev, dp->irq, NULL, |
---|
1687 | 2303 | analogix_dp_irq_thread, |
---|
1688 | | - 0, "analogix-dp", dp); |
---|
| 2304 | + IRQF_ONESHOT, dev_name(dev), dp); |
---|
1689 | 2305 | if (ret) { |
---|
1690 | 2306 | dev_err(&pdev->dev, "failed to request irq\n"); |
---|
1691 | | - goto err_disable_pm_runtime; |
---|
| 2307 | + return ERR_PTR(ret); |
---|
1692 | 2308 | } |
---|
| 2309 | + |
---|
| 2310 | + dp->extcon = devm_extcon_dev_allocate(dev, analogix_dp_cable); |
---|
| 2311 | + if (IS_ERR(dp->extcon)) { |
---|
| 2312 | + dev_err(dev, "failed to allocate extcon device\n"); |
---|
| 2313 | + return ERR_CAST(dp->extcon); |
---|
| 2314 | + } |
---|
| 2315 | + |
---|
| 2316 | + ret = devm_extcon_dev_register(dev, dp->extcon); |
---|
| 2317 | + if (ret) { |
---|
| 2318 | + dev_err(dev, "failed to register extcon device\n"); |
---|
| 2319 | + return ERR_PTR(ret); |
---|
| 2320 | + } |
---|
| 2321 | + |
---|
| 2322 | + dp->bridge.driver_private = dp; |
---|
| 2323 | + dp->bridge.funcs = &analogix_dp_bridge_funcs; |
---|
| 2324 | + |
---|
| 2325 | + return dp; |
---|
| 2326 | +} |
---|
| 2327 | +EXPORT_SYMBOL_GPL(analogix_dp_probe); |
---|
| 2328 | + |
---|
| 2329 | +int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) |
---|
| 2330 | +{ |
---|
| 2331 | + int ret; |
---|
1693 | 2332 | |
---|
1694 | 2333 | dp->drm_dev = drm_dev; |
---|
1695 | 2334 | dp->encoder = dp->plat_data->encoder; |
---|
1696 | 2335 | |
---|
1697 | 2336 | dp->aux.name = "DP-AUX"; |
---|
1698 | 2337 | dp->aux.transfer = analogix_dpaux_transfer; |
---|
1699 | | - dp->aux.dev = &pdev->dev; |
---|
| 2338 | + dp->aux.dev = dp->dev; |
---|
1700 | 2339 | |
---|
1701 | 2340 | ret = drm_dp_aux_register(&dp->aux); |
---|
1702 | 2341 | if (ret) |
---|
1703 | | - return ERR_PTR(ret); |
---|
| 2342 | + return ret; |
---|
1704 | 2343 | |
---|
1705 | | - pm_runtime_enable(dev); |
---|
| 2344 | + pm_runtime_enable(dp->dev); |
---|
| 2345 | + pm_runtime_get_sync(dp->dev); |
---|
| 2346 | + analogix_dp_init(dp); |
---|
1706 | 2347 | |
---|
1707 | | - ret = analogix_dp_create_bridge(drm_dev, dp); |
---|
| 2348 | + ret = analogix_dp_bridge_init(dp); |
---|
1708 | 2349 | if (ret) { |
---|
1709 | | - DRM_ERROR("failed to create bridge (%d)\n", ret); |
---|
| 2350 | + DRM_ERROR("failed to init bridge (%d)\n", ret); |
---|
1710 | 2351 | goto err_disable_pm_runtime; |
---|
1711 | 2352 | } |
---|
1712 | 2353 | |
---|
1713 | | - return dp; |
---|
| 2354 | + enable_irq(dp->irq); |
---|
| 2355 | + |
---|
| 2356 | + return 0; |
---|
1714 | 2357 | |
---|
1715 | 2358 | err_disable_pm_runtime: |
---|
| 2359 | + pm_runtime_put(dp->dev); |
---|
| 2360 | + pm_runtime_disable(dp->dev); |
---|
| 2361 | + drm_dp_aux_unregister(&dp->aux); |
---|
1716 | 2362 | |
---|
1717 | | - pm_runtime_disable(dev); |
---|
1718 | | - |
---|
1719 | | - return ERR_PTR(ret); |
---|
| 2363 | + return ret; |
---|
1720 | 2364 | } |
---|
1721 | 2365 | EXPORT_SYMBOL_GPL(analogix_dp_bind); |
---|
1722 | 2366 | |
---|
1723 | 2367 | void analogix_dp_unbind(struct analogix_dp_device *dp) |
---|
1724 | 2368 | { |
---|
1725 | | - analogix_dp_bridge_disable(dp->bridge); |
---|
1726 | | - dp->connector.funcs->destroy(&dp->connector); |
---|
1727 | | - |
---|
1728 | | - if (dp->plat_data->panel) { |
---|
1729 | | - if (drm_panel_unprepare(dp->plat_data->panel)) |
---|
1730 | | - DRM_ERROR("failed to turnoff the panel\n"); |
---|
1731 | | - if (drm_panel_detach(dp->plat_data->panel)) |
---|
1732 | | - DRM_ERROR("failed to detach the panel\n"); |
---|
1733 | | - } |
---|
1734 | | - |
---|
| 2369 | + disable_irq(dp->irq); |
---|
| 2370 | + if (dp->connector.funcs->destroy) |
---|
| 2371 | + dp->connector.funcs->destroy(&dp->connector); |
---|
1735 | 2372 | drm_dp_aux_unregister(&dp->aux); |
---|
| 2373 | + pm_runtime_put(dp->dev); |
---|
1736 | 2374 | pm_runtime_disable(dp->dev); |
---|
1737 | 2375 | } |
---|
1738 | 2376 | EXPORT_SYMBOL_GPL(analogix_dp_unbind); |
---|
1739 | 2377 | |
---|
1740 | | -#ifdef CONFIG_PM |
---|
| 2378 | +void analogix_dp_remove(struct analogix_dp_device *dp) |
---|
| 2379 | +{ |
---|
| 2380 | + cancel_work_sync(&dp->modeset_retry_work); |
---|
| 2381 | +} |
---|
| 2382 | +EXPORT_SYMBOL_GPL(analogix_dp_remove); |
---|
| 2383 | + |
---|
1741 | 2384 | int analogix_dp_suspend(struct analogix_dp_device *dp) |
---|
1742 | 2385 | { |
---|
1743 | | - if (dp->hpd_gpiod) |
---|
1744 | | - disable_irq(dp->hpd_irq); |
---|
1745 | | - |
---|
1746 | | - if (dp->plat_data->panel) { |
---|
1747 | | - if (drm_panel_unprepare(dp->plat_data->panel)) |
---|
1748 | | - DRM_ERROR("failed to turnoff the panel\n"); |
---|
1749 | | - } |
---|
| 2386 | + pm_runtime_force_suspend(dp->dev); |
---|
1750 | 2387 | |
---|
1751 | 2388 | return 0; |
---|
1752 | 2389 | } |
---|
.. | .. |
---|
1754 | 2391 | |
---|
1755 | 2392 | int analogix_dp_resume(struct analogix_dp_device *dp) |
---|
1756 | 2393 | { |
---|
1757 | | - if (dp->plat_data->panel) { |
---|
1758 | | - if (drm_panel_prepare(dp->plat_data->panel)) { |
---|
1759 | | - DRM_ERROR("failed to setup the panel\n"); |
---|
1760 | | - return -EBUSY; |
---|
1761 | | - } |
---|
1762 | | - } |
---|
1763 | | - |
---|
1764 | | - if (dp->hpd_gpiod) |
---|
1765 | | - enable_irq(dp->hpd_irq); |
---|
| 2394 | + pm_runtime_force_resume(dp->dev); |
---|
| 2395 | + analogix_dp_init(dp); |
---|
1766 | 2396 | |
---|
1767 | 2397 | return 0; |
---|
1768 | 2398 | } |
---|
1769 | 2399 | EXPORT_SYMBOL_GPL(analogix_dp_resume); |
---|
1770 | | -#endif |
---|
| 2400 | + |
---|
| 2401 | +int analogix_dp_runtime_suspend(struct analogix_dp_device *dp) |
---|
| 2402 | +{ |
---|
| 2403 | + clk_bulk_disable_unprepare(dp->nr_clks, dp->clks); |
---|
| 2404 | + |
---|
| 2405 | + return 0; |
---|
| 2406 | +} |
---|
| 2407 | +EXPORT_SYMBOL_GPL(analogix_dp_runtime_suspend); |
---|
| 2408 | + |
---|
| 2409 | +int analogix_dp_runtime_resume(struct analogix_dp_device *dp) |
---|
| 2410 | +{ |
---|
| 2411 | + return clk_bulk_prepare_enable(dp->nr_clks, dp->clks); |
---|
| 2412 | +} |
---|
| 2413 | +EXPORT_SYMBOL_GPL(analogix_dp_runtime_resume); |
---|
1771 | 2414 | |
---|
1772 | 2415 | int analogix_dp_start_crc(struct drm_connector *connector) |
---|
1773 | 2416 | { |
---|