.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd |
---|
3 | 4 | * Author: Chris Zhong <zyw@rock-chips.com> |
---|
4 | | - * |
---|
5 | | - * This software is licensed under the terms of the GNU General Public |
---|
6 | | - * License version 2, as published by the Free Software Foundation, and |
---|
7 | | - * may be copied, distributed, and modified under those terms. |
---|
8 | | - * |
---|
9 | | - * This program is distributed in the hope that it will be useful, |
---|
10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
12 | | - * GNU General Public License for more details. |
---|
13 | 5 | */ |
---|
14 | | - |
---|
15 | | -#include <drm/drmP.h> |
---|
16 | | -#include <drm/drm_atomic_helper.h> |
---|
17 | | -#include <drm/drm_crtc_helper.h> |
---|
18 | | -#include <drm/drm_dp_helper.h> |
---|
19 | | -#include <drm/drm_edid.h> |
---|
20 | | -#include <drm/drm_of.h> |
---|
21 | 6 | |
---|
22 | 7 | #include <linux/clk.h> |
---|
23 | 8 | #include <linux/component.h> |
---|
24 | | -#include <linux/extcon.h> |
---|
25 | 9 | #include <linux/firmware.h> |
---|
26 | | -#include <linux/regmap.h> |
---|
27 | | -#include <linux/reset.h> |
---|
28 | 10 | #include <linux/mfd/syscon.h> |
---|
29 | 11 | #include <linux/phy/phy.h> |
---|
30 | | -#include <uapi/linux/videodev2.h> |
---|
| 12 | +#include <linux/regmap.h> |
---|
| 13 | +#include <linux/reset.h> |
---|
31 | 14 | |
---|
32 | 15 | #include <sound/hdmi-codec.h> |
---|
| 16 | + |
---|
| 17 | +#include <drm/drm_atomic_helper.h> |
---|
| 18 | +#include <drm/drm_dp_helper.h> |
---|
| 19 | +#include <drm/drm_edid.h> |
---|
| 20 | +#include <drm/drm_of.h> |
---|
| 21 | +#include <drm/drm_probe_helper.h> |
---|
| 22 | +#include <drm/drm_simple_kms_helper.h> |
---|
33 | 23 | |
---|
34 | 24 | #include "cdn-dp-core.h" |
---|
35 | 25 | #include "cdn-dp-reg.h" |
---|
.. | .. |
---|
152 | 142 | |
---|
153 | 143 | static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) |
---|
154 | 144 | { |
---|
155 | | - struct extcon_dev *edev = port->extcon; |
---|
156 | | - union extcon_property_value property; |
---|
157 | | - int dptx; |
---|
158 | | - u8 lanes; |
---|
159 | | - |
---|
160 | | - dptx = extcon_get_state(edev, EXTCON_DISP_DP); |
---|
161 | | - if (dptx > 0) { |
---|
162 | | - extcon_get_property(edev, EXTCON_DISP_DP, |
---|
163 | | - EXTCON_PROP_USB_SS, &property); |
---|
164 | | - if (property.intval) |
---|
165 | | - lanes = 2; |
---|
166 | | - else |
---|
167 | | - lanes = 4; |
---|
168 | | - } else { |
---|
169 | | - lanes = 0; |
---|
170 | | - } |
---|
171 | | - |
---|
172 | | - return lanes; |
---|
| 145 | + return phy_get_bus_width(port->phy); |
---|
173 | 146 | } |
---|
174 | 147 | |
---|
175 | 148 | static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) |
---|
.. | .. |
---|
203 | 176 | static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) |
---|
204 | 177 | { |
---|
205 | 178 | unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS); |
---|
206 | | - struct cdn_dp_port *port; |
---|
207 | 179 | u8 sink_count = 0; |
---|
208 | 180 | |
---|
209 | 181 | if (dp->active_port < 0 || dp->active_port >= dp->ports) { |
---|
210 | 182 | DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n"); |
---|
211 | 183 | return false; |
---|
212 | 184 | } |
---|
213 | | - |
---|
214 | | - port = dp->port[dp->active_port]; |
---|
215 | 185 | |
---|
216 | 186 | /* |
---|
217 | 187 | * Attempt to read sink count, retry in case the sink may not be ready. |
---|
.. | .. |
---|
220 | 190 | * some docks need more time to power up. |
---|
221 | 191 | */ |
---|
222 | 192 | while (time_before(jiffies, timeout)) { |
---|
223 | | - if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) |
---|
224 | | - return false; |
---|
225 | | - |
---|
226 | 193 | if (!cdn_dp_get_sink_count(dp, &sink_count)) |
---|
227 | 194 | return sink_count ? true : false; |
---|
228 | 195 | |
---|
.. | .. |
---|
253 | 220 | drm_connector_cleanup(connector); |
---|
254 | 221 | } |
---|
255 | 222 | |
---|
256 | | -static int |
---|
257 | | -cdn_dp_atomic_connector_get_property(struct drm_connector *connector, |
---|
258 | | - const struct drm_connector_state *state, |
---|
259 | | - struct drm_property *property, |
---|
260 | | - uint64_t *val) |
---|
| 223 | +static void cdn_dp_oob_hotplug_event(struct drm_connector *connector) |
---|
261 | 224 | { |
---|
262 | 225 | struct cdn_dp_device *dp = connector_to_dp(connector); |
---|
263 | | - struct rockchip_drm_private *private = connector->dev->dev_private; |
---|
264 | 226 | |
---|
265 | | - if (property == private->connector_id_prop) { |
---|
266 | | - *val = dp->id; |
---|
267 | | - return 0; |
---|
268 | | - } |
---|
269 | | - |
---|
270 | | - DRM_ERROR("failed to get rockchip CDN DP property\n"); |
---|
271 | | - return -EINVAL; |
---|
| 227 | + schedule_delayed_work(&dp->event_work, msecs_to_jiffies(100)); |
---|
272 | 228 | } |
---|
273 | 229 | |
---|
274 | 230 | static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = { |
---|
.. | .. |
---|
278 | 234 | .reset = drm_atomic_helper_connector_reset, |
---|
279 | 235 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
---|
280 | 236 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
---|
281 | | - .atomic_get_property = cdn_dp_atomic_connector_get_property, |
---|
282 | 237 | }; |
---|
283 | 238 | |
---|
284 | 239 | static int cdn_dp_connector_get_modes(struct drm_connector *connector) |
---|
.. | .. |
---|
298 | 253 | if (ret) |
---|
299 | 254 | drm_connector_update_edid_property(connector, |
---|
300 | 255 | edid); |
---|
301 | | - } else { |
---|
302 | | - ret = rockchip_drm_add_modes_noedid(connector); |
---|
303 | | - |
---|
304 | | - dev_info(dp->dev, "failed to get edid\n"); |
---|
305 | 256 | } |
---|
306 | 257 | mutex_unlock(&dp->lock); |
---|
307 | 258 | |
---|
308 | 259 | return ret; |
---|
309 | 260 | } |
---|
310 | 261 | |
---|
311 | | -static int cdn_dp_connector_mode_valid(struct drm_connector *connector, |
---|
312 | | - struct drm_display_mode *mode) |
---|
| 262 | +static enum drm_mode_status |
---|
| 263 | +cdn_dp_connector_mode_valid(struct drm_connector *connector, |
---|
| 264 | + struct drm_display_mode *mode) |
---|
313 | 265 | { |
---|
314 | 266 | struct cdn_dp_device *dp = connector_to_dp(connector); |
---|
315 | 267 | struct drm_display_info *display_info = &dp->connector.display_info; |
---|
316 | 268 | u32 requested, actual, rate, sink_max, source_max = 0; |
---|
317 | | - struct drm_encoder *encoder = connector->encoder; |
---|
318 | | - enum drm_mode_status status = MODE_OK; |
---|
319 | | - struct drm_device *dev = connector->dev; |
---|
320 | | - struct rockchip_drm_private *priv = dev->dev_private; |
---|
321 | | - struct drm_crtc *crtc; |
---|
322 | 269 | u8 lanes, bpc; |
---|
323 | 270 | |
---|
324 | 271 | /* If DP is disconnected, every mode is invalid */ |
---|
.. | .. |
---|
336 | 283 | bpc = 8; |
---|
337 | 284 | break; |
---|
338 | 285 | } |
---|
339 | | - |
---|
340 | | - if (!IS_ALIGNED(mode->hdisplay * bpc, 8)) |
---|
341 | | - return MODE_H_ILLEGAL; |
---|
342 | 286 | |
---|
343 | 287 | requested = mode->clock * bpc * 3 / 1000; |
---|
344 | 288 | |
---|
.. | .. |
---|
360 | 304 | "requested=%d, actual=%d, clock=%d\n", |
---|
361 | 305 | requested, actual, mode->clock); |
---|
362 | 306 | return MODE_CLOCK_HIGH; |
---|
363 | | - } |
---|
364 | | - |
---|
365 | | - if (!encoder) { |
---|
366 | | - const struct drm_connector_helper_funcs *funcs; |
---|
367 | | - |
---|
368 | | - funcs = connector->helper_private; |
---|
369 | | - if (funcs->atomic_best_encoder) |
---|
370 | | - encoder = funcs->atomic_best_encoder(connector, |
---|
371 | | - connector->state); |
---|
372 | | - else if (funcs->best_encoder) |
---|
373 | | - encoder = funcs->best_encoder(connector); |
---|
374 | | - else |
---|
375 | | - encoder = drm_atomic_helper_best_encoder(connector); |
---|
376 | | - } |
---|
377 | | - |
---|
378 | | - if (!encoder || !encoder->possible_crtcs) |
---|
379 | | - return MODE_BAD; |
---|
380 | | - /* |
---|
381 | | - * ensure all drm display mode can work, if someone want support more |
---|
382 | | - * resolutions, please limit the possible_crtc, only connect to |
---|
383 | | - * needed crtc. |
---|
384 | | - */ |
---|
385 | | - drm_for_each_crtc(crtc, connector->dev) { |
---|
386 | | - int pipe = drm_crtc_index(crtc); |
---|
387 | | - const struct rockchip_crtc_funcs *funcs = |
---|
388 | | - priv->crtc_funcs[pipe]; |
---|
389 | | - |
---|
390 | | - if (!(encoder->possible_crtcs & drm_crtc_mask(crtc))) |
---|
391 | | - continue; |
---|
392 | | - if (!funcs || !funcs->mode_valid) |
---|
393 | | - continue; |
---|
394 | | - |
---|
395 | | - status = funcs->mode_valid(crtc, mode, |
---|
396 | | - DRM_MODE_CONNECTOR_HDMIA); |
---|
397 | | - if (status != MODE_OK) |
---|
398 | | - return status; |
---|
399 | 307 | } |
---|
400 | 308 | |
---|
401 | 309 | return MODE_OK; |
---|
.. | .. |
---|
458 | 366 | |
---|
459 | 367 | static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) |
---|
460 | 368 | { |
---|
461 | | - union extcon_property_value property; |
---|
462 | 369 | int ret; |
---|
463 | 370 | |
---|
464 | 371 | if (!port->phy_enabled) { |
---|
.. | .. |
---|
485 | 392 | goto err_power_on; |
---|
486 | 393 | } |
---|
487 | 394 | |
---|
488 | | - ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, |
---|
489 | | - EXTCON_PROP_USB_TYPEC_POLARITY, &property); |
---|
490 | | - if (ret) { |
---|
491 | | - DRM_DEV_ERROR(dp->dev, "get property failed\n"); |
---|
492 | | - goto err_power_on; |
---|
493 | | - } |
---|
494 | | - |
---|
495 | 395 | port->lanes = cdn_dp_get_port_lanes(port); |
---|
496 | | - ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); |
---|
| 396 | + ret = cdn_dp_set_host_cap(dp, port->lanes, 0); |
---|
497 | 397 | if (ret) { |
---|
498 | 398 | DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", |
---|
499 | 399 | ret); |
---|
.. | .. |
---|
555 | 455 | cdn_dp_set_firmware_active(dp, false); |
---|
556 | 456 | cdn_dp_clk_disable(dp); |
---|
557 | 457 | dp->active = false; |
---|
558 | | - dp->link.rate = 0; |
---|
559 | | - dp->link.num_lanes = 0; |
---|
| 458 | + dp->max_lanes = 0; |
---|
| 459 | + dp->max_rate = 0; |
---|
560 | 460 | if (!dp->connected) { |
---|
561 | 461 | kfree(dp->edid); |
---|
562 | 462 | dp->edid = NULL; |
---|
.. | .. |
---|
639 | 539 | video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); |
---|
640 | 540 | video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); |
---|
641 | 541 | |
---|
642 | | - memcpy(&dp->mode, adjusted, sizeof(*mode)); |
---|
| 542 | + drm_mode_copy(&dp->mode, adjusted); |
---|
643 | 543 | } |
---|
644 | 544 | |
---|
645 | 545 | static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) |
---|
.. | .. |
---|
648 | 548 | struct cdn_dp_port *port = cdn_dp_connected_port(dp); |
---|
649 | 549 | u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd); |
---|
650 | 550 | |
---|
651 | | - if (!port || !dp->link.rate || !dp->link.num_lanes) |
---|
| 551 | + if (!port || !dp->max_rate || !dp->max_lanes) |
---|
652 | 552 | return false; |
---|
653 | 553 | |
---|
654 | 554 | if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) != |
---|
.. | .. |
---|
729 | 629 | static void cdn_dp_encoder_disable(struct drm_encoder *encoder) |
---|
730 | 630 | { |
---|
731 | 631 | struct cdn_dp_device *dp = encoder_to_dp(encoder); |
---|
732 | | - struct drm_crtc *crtc = encoder->crtc; |
---|
733 | | - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); |
---|
734 | 632 | int ret; |
---|
735 | 633 | |
---|
736 | 634 | mutex_lock(&dp->lock); |
---|
.. | .. |
---|
753 | 651 | * run the event_work to re-connect it. |
---|
754 | 652 | */ |
---|
755 | 653 | if (!dp->connected && cdn_dp_connected_port(dp)) |
---|
756 | | - schedule_work(&dp->event_work); |
---|
757 | | - |
---|
758 | | - s->output_if &= ~VOP_OUTPUT_IF_DP0; |
---|
| 654 | + schedule_delayed_work(&dp->event_work, 0); |
---|
759 | 655 | } |
---|
760 | 656 | |
---|
761 | 657 | static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder, |
---|
762 | 658 | struct drm_crtc_state *crtc_state, |
---|
763 | 659 | struct drm_connector_state *conn_state) |
---|
764 | 660 | { |
---|
765 | | - struct cdn_dp_device *dp = encoder_to_dp(encoder); |
---|
766 | | - struct drm_display_info *di = &dp->connector.display_info; |
---|
767 | 661 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); |
---|
768 | 662 | |
---|
769 | | - switch (di->bpc) { |
---|
770 | | - case 6: |
---|
771 | | - s->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; |
---|
772 | | - break; |
---|
773 | | - case 8: |
---|
774 | | - default: |
---|
775 | | - s->bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
---|
776 | | - break; |
---|
777 | | - } |
---|
778 | | - |
---|
779 | 663 | s->output_mode = ROCKCHIP_OUT_MODE_AAAA; |
---|
780 | | - s->output_if |= VOP_OUTPUT_IF_DP0; |
---|
781 | 664 | s->output_type = DRM_MODE_CONNECTOR_DisplayPort; |
---|
782 | 665 | s->tv_state = &conn_state->tv; |
---|
783 | | - s->eotf = TRADITIONAL_GAMMA_SDR; |
---|
784 | | - s->color_space = V4L2_COLORSPACE_DEFAULT; |
---|
785 | 666 | |
---|
786 | 667 | return 0; |
---|
787 | 668 | } |
---|
.. | .. |
---|
791 | 672 | .enable = cdn_dp_encoder_enable, |
---|
792 | 673 | .disable = cdn_dp_encoder_disable, |
---|
793 | 674 | .atomic_check = cdn_dp_encoder_atomic_check, |
---|
794 | | -}; |
---|
795 | | - |
---|
796 | | -static const struct drm_encoder_funcs cdn_dp_encoder_funcs = { |
---|
797 | | - .destroy = drm_encoder_cleanup, |
---|
798 | 675 | }; |
---|
799 | 676 | |
---|
800 | 677 | static int cdn_dp_parse_dt(struct cdn_dp_device *dp) |
---|
.. | .. |
---|
868 | 745 | return 0; |
---|
869 | 746 | } |
---|
870 | 747 | |
---|
871 | | -struct dp_sdp { |
---|
872 | | - struct dp_sdp_header sdp_header; |
---|
873 | | - u8 db[28]; |
---|
874 | | -} __packed; |
---|
875 | | - |
---|
876 | | -static int cdn_dp_setup_audio_infoframe(struct cdn_dp_device *dp) |
---|
877 | | -{ |
---|
878 | | - struct dp_sdp infoframe_sdp; |
---|
879 | | - struct hdmi_audio_infoframe frame; |
---|
880 | | - u8 buffer[14]; |
---|
881 | | - ssize_t err; |
---|
882 | | - |
---|
883 | | - /* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */ |
---|
884 | | - memset(&infoframe_sdp, 0, sizeof(infoframe_sdp)); |
---|
885 | | - infoframe_sdp.sdp_header.HB0 = 0; |
---|
886 | | - infoframe_sdp.sdp_header.HB1 = HDMI_INFOFRAME_TYPE_AUDIO; |
---|
887 | | - infoframe_sdp.sdp_header.HB2 = 0x1b; |
---|
888 | | - infoframe_sdp.sdp_header.HB3 = 0x48; |
---|
889 | | - |
---|
890 | | - err = hdmi_audio_infoframe_init(&frame); |
---|
891 | | - if (err < 0) { |
---|
892 | | - DRM_DEV_ERROR(dp->dev, "Failed to setup audio infoframe: %zd\n", |
---|
893 | | - err); |
---|
894 | | - return err; |
---|
895 | | - } |
---|
896 | | - |
---|
897 | | - frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; |
---|
898 | | - frame.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; |
---|
899 | | - frame.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; |
---|
900 | | - frame.channels = 0; |
---|
901 | | - |
---|
902 | | - err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); |
---|
903 | | - if (err < 0) { |
---|
904 | | - DRM_DEV_ERROR(dp->dev, "Failed to pack audio infoframe: %zd\n", |
---|
905 | | - err); |
---|
906 | | - return err; |
---|
907 | | - } |
---|
908 | | - |
---|
909 | | - memcpy(&infoframe_sdp.db[0], &buffer[HDMI_INFOFRAME_HEADER_SIZE], |
---|
910 | | - sizeof(buffer) - HDMI_INFOFRAME_HEADER_SIZE); |
---|
911 | | - |
---|
912 | | - cdn_dp_infoframe_set(dp, 0, (u8 *)&infoframe_sdp, |
---|
913 | | - sizeof(infoframe_sdp), 0x84); |
---|
914 | | - |
---|
915 | | - return 0; |
---|
916 | | -} |
---|
917 | | - |
---|
918 | 748 | static int cdn_dp_audio_hw_params(struct device *dev, void *data, |
---|
919 | 749 | struct hdmi_codec_daifmt *daifmt, |
---|
920 | 750 | struct hdmi_codec_params *params) |
---|
.. | .. |
---|
929 | 759 | |
---|
930 | 760 | mutex_lock(&dp->lock); |
---|
931 | 761 | if (!dp->active) { |
---|
932 | | - ret = 0; |
---|
| 762 | + ret = -ENODEV; |
---|
933 | 763 | goto out; |
---|
934 | 764 | } |
---|
935 | 765 | |
---|
.. | .. |
---|
945 | 775 | ret = -EINVAL; |
---|
946 | 776 | goto out; |
---|
947 | 777 | } |
---|
948 | | - |
---|
949 | | - ret = cdn_dp_setup_audio_infoframe(dp); |
---|
950 | | - if (ret) |
---|
951 | | - goto out; |
---|
952 | 778 | |
---|
953 | 779 | ret = cdn_dp_audio_config(dp, &audio); |
---|
954 | 780 | if (!ret) |
---|
.. | .. |
---|
975 | 801 | mutex_unlock(&dp->lock); |
---|
976 | 802 | } |
---|
977 | 803 | |
---|
978 | | -static int cdn_dp_audio_digital_mute(struct device *dev, void *data, |
---|
979 | | - bool enable) |
---|
| 804 | +static int cdn_dp_audio_mute_stream(struct device *dev, void *data, |
---|
| 805 | + bool enable, int direction) |
---|
980 | 806 | { |
---|
981 | 807 | struct cdn_dp_device *dp = dev_get_drvdata(dev); |
---|
982 | 808 | int ret; |
---|
983 | 809 | |
---|
984 | 810 | mutex_lock(&dp->lock); |
---|
985 | 811 | if (!dp->active) { |
---|
986 | | - ret = 0; |
---|
| 812 | + ret = -ENODEV; |
---|
987 | 813 | goto out; |
---|
988 | 814 | } |
---|
989 | 815 | |
---|
.. | .. |
---|
1007 | 833 | static const struct hdmi_codec_ops audio_codec_ops = { |
---|
1008 | 834 | .hw_params = cdn_dp_audio_hw_params, |
---|
1009 | 835 | .audio_shutdown = cdn_dp_audio_shutdown, |
---|
1010 | | - .digital_mute = cdn_dp_audio_digital_mute, |
---|
| 836 | + .mute_stream = cdn_dp_audio_mute_stream, |
---|
1011 | 837 | .get_eld = cdn_dp_audio_get_eld, |
---|
| 838 | + .no_capture_mute = 1, |
---|
1012 | 839 | }; |
---|
1013 | 840 | |
---|
1014 | 841 | static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, |
---|
.. | .. |
---|
1043 | 870 | mutex_unlock(&dp->lock); |
---|
1044 | 871 | |
---|
1045 | 872 | while (time_before(jiffies, timeout)) { |
---|
1046 | | - ret = request_firmware_direct(&dp->fw, CDN_DP_FIRMWARE, |
---|
1047 | | - dp->dev); |
---|
| 873 | + ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); |
---|
1048 | 874 | if (ret == -ENOENT) { |
---|
1049 | 875 | msleep(sleep); |
---|
1050 | 876 | sleep *= 2; |
---|
.. | .. |
---|
1067 | 893 | return ret; |
---|
1068 | 894 | } |
---|
1069 | 895 | |
---|
1070 | | -static bool cdn_dp_needs_link_retrain(struct cdn_dp_device *dp) |
---|
1071 | | -{ |
---|
1072 | | - u8 link_status[DP_LINK_STATUS_SIZE]; |
---|
1073 | | - |
---|
1074 | | - /* |
---|
1075 | | - * Validate the cached values of link parameters before attempting to |
---|
1076 | | - * retrain. |
---|
1077 | | - */ |
---|
1078 | | - if (!dp->link.rate || !dp->link.num_lanes) |
---|
1079 | | - return false; |
---|
1080 | | - |
---|
1081 | | - if (drm_dp_dpcd_read_link_status(&dp->aux, link_status) < 0) |
---|
1082 | | - return false; |
---|
1083 | | - |
---|
1084 | | - /* Retrain if Channel EQ or CR not ok */ |
---|
1085 | | - return !drm_dp_channel_eq_ok(link_status, dp->link.num_lanes); |
---|
1086 | | -} |
---|
1087 | | - |
---|
1088 | 896 | static void cdn_dp_pd_event_work(struct work_struct *work) |
---|
1089 | 897 | { |
---|
1090 | | - struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, |
---|
| 898 | + struct cdn_dp_device *dp = container_of(to_delayed_work(work), struct cdn_dp_device, |
---|
1091 | 899 | event_work); |
---|
1092 | 900 | struct drm_connector *connector = &dp->connector; |
---|
1093 | 901 | enum drm_connector_status old_status; |
---|
.. | .. |
---|
1125 | 933 | dp->connected = false; |
---|
1126 | 934 | |
---|
1127 | 935 | /* Enabled and connected with a sink, re-train if requested */ |
---|
1128 | | - } else if (cdn_dp_needs_link_retrain(dp)) { |
---|
1129 | | - unsigned int rate = dp->link.rate; |
---|
1130 | | - unsigned int lanes = dp->link.num_lanes; |
---|
| 936 | + } else if (!cdn_dp_check_link_status(dp)) { |
---|
| 937 | + unsigned int rate = dp->max_rate; |
---|
| 938 | + unsigned int lanes = dp->max_lanes; |
---|
1131 | 939 | struct drm_display_mode *mode = &dp->mode; |
---|
1132 | 940 | |
---|
1133 | 941 | DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n"); |
---|
.. | .. |
---|
1140 | 948 | |
---|
1141 | 949 | /* If training result is changed, update the video config */ |
---|
1142 | 950 | if (mode->clock && |
---|
1143 | | - (rate != dp->link.rate || lanes != dp->link.num_lanes)) { |
---|
| 951 | + (rate != dp->max_rate || lanes != dp->max_lanes)) { |
---|
1144 | 952 | ret = cdn_dp_config_video(dp); |
---|
1145 | 953 | if (ret) { |
---|
1146 | 954 | dp->connected = false; |
---|
.. | .. |
---|
1158 | 966 | connector->status = connector->funcs->detect(connector, false); |
---|
1159 | 967 | if (old_status != connector->status) |
---|
1160 | 968 | drm_kms_helper_hotplug_event(dp->drm_dev); |
---|
1161 | | -} |
---|
1162 | | - |
---|
1163 | | -static int cdn_dp_pd_event(struct notifier_block *nb, |
---|
1164 | | - unsigned long event, void *priv) |
---|
1165 | | -{ |
---|
1166 | | - struct cdn_dp_port *port = container_of(nb, struct cdn_dp_port, |
---|
1167 | | - event_nb); |
---|
1168 | | - struct cdn_dp_device *dp = port->dp; |
---|
1169 | | - |
---|
1170 | | - /* |
---|
1171 | | - * It would be nice to be able to just do the work inline right here. |
---|
1172 | | - * However, we need to make a bunch of calls that might sleep in order |
---|
1173 | | - * to turn on the block/phy, so use a worker instead. |
---|
1174 | | - */ |
---|
1175 | | - schedule_work(&dp->event_work); |
---|
1176 | | - |
---|
1177 | | - return NOTIFY_DONE; |
---|
1178 | 969 | } |
---|
1179 | 970 | |
---|
1180 | 971 | static ssize_t cdn_dp_aux_transfer(struct drm_dp_aux *aux, |
---|
.. | .. |
---|
1216 | 1007 | struct cdn_dp_device *dp = dev_get_drvdata(dev); |
---|
1217 | 1008 | struct drm_encoder *encoder; |
---|
1218 | 1009 | struct drm_connector *connector; |
---|
1219 | | - struct cdn_dp_port *port; |
---|
1220 | 1010 | struct drm_device *drm_dev = data; |
---|
1221 | | - struct rockchip_drm_private *private = drm_dev->dev_private; |
---|
1222 | | - int ret, i; |
---|
| 1011 | + int ret; |
---|
1223 | 1012 | |
---|
1224 | 1013 | ret = cdn_dp_parse_dt(dp); |
---|
1225 | 1014 | if (ret < 0) |
---|
.. | .. |
---|
1238 | 1027 | if (ret) |
---|
1239 | 1028 | return ret; |
---|
1240 | 1029 | |
---|
1241 | | - INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); |
---|
| 1030 | + INIT_DELAYED_WORK(&dp->event_work, cdn_dp_pd_event_work); |
---|
1242 | 1031 | |
---|
1243 | 1032 | encoder = &dp->encoder; |
---|
1244 | 1033 | |
---|
1245 | | - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, |
---|
1246 | | - dev->of_node); |
---|
| 1034 | + encoder->possible_crtcs = rockchip_drm_of_find_possible_crtcs(drm_dev, |
---|
| 1035 | + dev->of_node); |
---|
1247 | 1036 | DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs); |
---|
1248 | 1037 | |
---|
1249 | | - ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs, |
---|
1250 | | - DRM_MODE_ENCODER_TMDS, NULL); |
---|
| 1038 | + ret = drm_simple_encoder_init(drm_dev, encoder, |
---|
| 1039 | + DRM_MODE_ENCODER_TMDS); |
---|
1251 | 1040 | if (ret) { |
---|
1252 | 1041 | DRM_ERROR("failed to initialize encoder with drm\n"); |
---|
1253 | 1042 | return ret; |
---|
.. | .. |
---|
1274 | 1063 | DRM_ERROR("failed to attach connector and encoder\n"); |
---|
1275 | 1064 | goto err_free_connector; |
---|
1276 | 1065 | } |
---|
1277 | | - drm_object_attach_property(&connector->base, private->connector_id_prop, 0); |
---|
1278 | 1066 | |
---|
1279 | | - for (i = 0; i < dp->ports; i++) { |
---|
1280 | | - port = dp->port[i]; |
---|
1281 | | - |
---|
1282 | | - port->event_nb.notifier_call = cdn_dp_pd_event; |
---|
1283 | | - ret = devm_extcon_register_notifier(dp->dev, port->extcon, |
---|
1284 | | - EXTCON_DISP_DP, |
---|
1285 | | - &port->event_nb); |
---|
1286 | | - if (ret) { |
---|
1287 | | - DRM_DEV_ERROR(dev, |
---|
1288 | | - "register EXTCON_DISP_DP notifier err\n"); |
---|
1289 | | - goto err_free_connector; |
---|
1290 | | - } |
---|
1291 | | - } |
---|
| 1067 | + dp->sub_dev.connector = &dp->connector; |
---|
| 1068 | + dp->sub_dev.of_node = dev->of_node; |
---|
| 1069 | + dp->sub_dev.oob_hotplug_event = cdn_dp_oob_hotplug_event; |
---|
| 1070 | + rockchip_drm_register_sub_dev(&dp->sub_dev); |
---|
1292 | 1071 | |
---|
1293 | 1072 | pm_runtime_enable(dev); |
---|
1294 | 1073 | |
---|
1295 | | - schedule_work(&dp->event_work); |
---|
| 1074 | + schedule_delayed_work(&dp->event_work, 0); |
---|
1296 | 1075 | |
---|
1297 | 1076 | return 0; |
---|
1298 | 1077 | |
---|
.. | .. |
---|
1309 | 1088 | struct drm_encoder *encoder = &dp->encoder; |
---|
1310 | 1089 | struct drm_connector *connector = &dp->connector; |
---|
1311 | 1090 | |
---|
1312 | | - cancel_work_sync(&dp->event_work); |
---|
| 1091 | + cancel_delayed_work_sync(&dp->event_work); |
---|
1313 | 1092 | cdn_dp_encoder_disable(encoder); |
---|
1314 | 1093 | encoder->funcs->destroy(encoder); |
---|
1315 | 1094 | connector->funcs->destroy(connector); |
---|
.. | .. |
---|
1340 | 1119 | return ret; |
---|
1341 | 1120 | } |
---|
1342 | 1121 | |
---|
1343 | | -static int cdn_dp_resume(struct device *dev) |
---|
| 1122 | +static __maybe_unused int cdn_dp_resume(struct device *dev) |
---|
1344 | 1123 | { |
---|
1345 | 1124 | struct cdn_dp_device *dp = dev_get_drvdata(dev); |
---|
1346 | 1125 | |
---|
1347 | 1126 | mutex_lock(&dp->lock); |
---|
1348 | 1127 | dp->suspended = false; |
---|
1349 | 1128 | if (dp->fw_loaded) |
---|
1350 | | - schedule_work(&dp->event_work); |
---|
| 1129 | + schedule_delayed_work(&dp->event_work, 0); |
---|
1351 | 1130 | mutex_unlock(&dp->lock); |
---|
1352 | 1131 | |
---|
1353 | 1132 | return 0; |
---|
.. | .. |
---|
1360 | 1139 | struct cdn_dp_data *dp_data; |
---|
1361 | 1140 | struct cdn_dp_port *port; |
---|
1362 | 1141 | struct cdn_dp_device *dp; |
---|
1363 | | - struct extcon_dev *extcon; |
---|
1364 | 1142 | struct phy *phy; |
---|
1365 | | - int i, id; |
---|
| 1143 | + int i; |
---|
1366 | 1144 | |
---|
1367 | 1145 | dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); |
---|
1368 | 1146 | if (!dp) |
---|
1369 | 1147 | return -ENOMEM; |
---|
1370 | | - id = of_alias_get_id(dev->of_node, "dp"); |
---|
1371 | | - if (id < 0) |
---|
1372 | | - id = 0; |
---|
1373 | | - |
---|
1374 | | - dp->id = id; |
---|
1375 | 1148 | dp->dev = dev; |
---|
1376 | 1149 | |
---|
1377 | 1150 | match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); |
---|
1378 | 1151 | dp_data = (struct cdn_dp_data *)match->data; |
---|
1379 | 1152 | |
---|
1380 | 1153 | for (i = 0; i < dp_data->max_phy; i++) { |
---|
1381 | | - extcon = extcon_get_edev_by_phandle(dev, i); |
---|
1382 | 1154 | phy = devm_of_phy_get_by_index(dev, dev->of_node, i); |
---|
1383 | 1155 | |
---|
1384 | | - if (PTR_ERR(extcon) == -EPROBE_DEFER || |
---|
1385 | | - PTR_ERR(phy) == -EPROBE_DEFER) |
---|
| 1156 | + if (PTR_ERR(phy) == -EPROBE_DEFER) |
---|
1386 | 1157 | return -EPROBE_DEFER; |
---|
1387 | 1158 | |
---|
1388 | | - if (IS_ERR(extcon) || IS_ERR(phy)) |
---|
| 1159 | + if (IS_ERR(phy)) |
---|
1389 | 1160 | continue; |
---|
1390 | 1161 | |
---|
1391 | 1162 | port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); |
---|
1392 | 1163 | if (!port) |
---|
1393 | 1164 | return -ENOMEM; |
---|
1394 | 1165 | |
---|
1395 | | - port->extcon = extcon; |
---|
1396 | 1166 | port->phy = phy; |
---|
1397 | 1167 | port->dp = dp; |
---|
1398 | 1168 | port->id = i; |
---|
.. | .. |
---|
1400 | 1170 | } |
---|
1401 | 1171 | |
---|
1402 | 1172 | if (!dp->ports) { |
---|
1403 | | - DRM_DEV_ERROR(dev, "missing extcon or phy\n"); |
---|
| 1173 | + DRM_DEV_ERROR(dev, "missing phy\n"); |
---|
1404 | 1174 | return -EINVAL; |
---|
1405 | 1175 | } |
---|
1406 | 1176 | |
---|