18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/component.h> 118c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "msm_drv.h" 158c2ecf20Sopenharmony_ci#include "msm_kms.h" 168c2ecf20Sopenharmony_ci#include "dp_hpd.h" 178c2ecf20Sopenharmony_ci#include "dp_parser.h" 188c2ecf20Sopenharmony_ci#include "dp_power.h" 198c2ecf20Sopenharmony_ci#include "dp_catalog.h" 208c2ecf20Sopenharmony_ci#include "dp_aux.h" 218c2ecf20Sopenharmony_ci#include "dp_reg.h" 228c2ecf20Sopenharmony_ci#include "dp_link.h" 238c2ecf20Sopenharmony_ci#include "dp_panel.h" 248c2ecf20Sopenharmony_ci#include "dp_ctrl.h" 258c2ecf20Sopenharmony_ci#include "dp_display.h" 268c2ecf20Sopenharmony_ci#include "dp_drm.h" 278c2ecf20Sopenharmony_ci#include "dp_audio.h" 288c2ecf20Sopenharmony_ci#include "dp_debug.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic struct msm_dp *g_dp_display; 318c2ecf20Sopenharmony_ci#define HPD_STRING_SIZE 30 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cienum { 348c2ecf20Sopenharmony_ci ISR_DISCONNECTED, 358c2ecf20Sopenharmony_ci ISR_CONNECT_PENDING, 368c2ecf20Sopenharmony_ci ISR_CONNECTED, 378c2ecf20Sopenharmony_ci ISR_HPD_REPLUG_COUNT, 388c2ecf20Sopenharmony_ci ISR_IRQ_HPD_PULSE_COUNT, 398c2ecf20Sopenharmony_ci ISR_HPD_LO_GLITH_COUNT, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* event thread connection state */ 438c2ecf20Sopenharmony_cienum { 448c2ecf20Sopenharmony_ci ST_DISCONNECTED, 458c2ecf20Sopenharmony_ci ST_CONNECT_PENDING, 468c2ecf20Sopenharmony_ci ST_CONNECTED, 478c2ecf20Sopenharmony_ci ST_DISCONNECT_PENDING, 488c2ecf20Sopenharmony_ci ST_DISPLAY_OFF, 498c2ecf20Sopenharmony_ci ST_SUSPENDED, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cienum { 538c2ecf20Sopenharmony_ci EV_NO_EVENT, 548c2ecf20Sopenharmony_ci /* hpd events */ 558c2ecf20Sopenharmony_ci EV_HPD_INIT_SETUP, 568c2ecf20Sopenharmony_ci EV_HPD_PLUG_INT, 578c2ecf20Sopenharmony_ci EV_IRQ_HPD_INT, 588c2ecf20Sopenharmony_ci EV_HPD_REPLUG_INT, 598c2ecf20Sopenharmony_ci EV_HPD_UNPLUG_INT, 608c2ecf20Sopenharmony_ci EV_USER_NOTIFICATION, 618c2ecf20Sopenharmony_ci EV_CONNECT_PENDING_TIMEOUT, 628c2ecf20Sopenharmony_ci EV_DISCONNECT_PENDING_TIMEOUT, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define EVENT_TIMEOUT (HZ/10) /* 100ms */ 668c2ecf20Sopenharmony_ci#define DP_EVENT_Q_MAX 8 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define DP_TIMEOUT_5_SECOND (5000/EVENT_TIMEOUT) 698c2ecf20Sopenharmony_ci#define DP_TIMEOUT_NONE 0 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct dp_event { 748c2ecf20Sopenharmony_ci u32 event_id; 758c2ecf20Sopenharmony_ci u32 data; 768c2ecf20Sopenharmony_ci u32 delay; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct dp_display_private { 808c2ecf20Sopenharmony_ci char *name; 818c2ecf20Sopenharmony_ci int irq; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* state variables */ 848c2ecf20Sopenharmony_ci bool core_initialized; 858c2ecf20Sopenharmony_ci bool hpd_irq_on; 868c2ecf20Sopenharmony_ci bool audio_supported; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci struct platform_device *pdev; 898c2ecf20Sopenharmony_ci struct dentry *root; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci struct dp_usbpd *usbpd; 928c2ecf20Sopenharmony_ci struct dp_parser *parser; 938c2ecf20Sopenharmony_ci struct dp_power *power; 948c2ecf20Sopenharmony_ci struct dp_catalog *catalog; 958c2ecf20Sopenharmony_ci struct drm_dp_aux *aux; 968c2ecf20Sopenharmony_ci struct dp_link *link; 978c2ecf20Sopenharmony_ci struct dp_panel *panel; 988c2ecf20Sopenharmony_ci struct dp_ctrl *ctrl; 998c2ecf20Sopenharmony_ci struct dp_debug *debug; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci struct dp_usbpd_cb usbpd_cb; 1028c2ecf20Sopenharmony_ci struct dp_display_mode dp_mode; 1038c2ecf20Sopenharmony_ci struct msm_dp dp_display; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci bool encoder_mode_set; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* wait for audio signaling */ 1088c2ecf20Sopenharmony_ci struct completion audio_comp; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* event related only access by event thread */ 1118c2ecf20Sopenharmony_ci struct mutex event_mutex; 1128c2ecf20Sopenharmony_ci wait_queue_head_t event_q; 1138c2ecf20Sopenharmony_ci u32 hpd_state; 1148c2ecf20Sopenharmony_ci u32 event_pndx; 1158c2ecf20Sopenharmony_ci u32 event_gndx; 1168c2ecf20Sopenharmony_ci struct task_struct *ev_tsk; 1178c2ecf20Sopenharmony_ci struct dp_event event_list[DP_EVENT_Q_MAX]; 1188c2ecf20Sopenharmony_ci spinlock_t event_lock; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci struct dp_audio *audio; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const struct of_device_id dp_dt_match[] = { 1248c2ecf20Sopenharmony_ci {.compatible = "qcom,sc7180-dp"}, 1258c2ecf20Sopenharmony_ci {} 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int dp_add_event(struct dp_display_private *dp_priv, u32 event, 1298c2ecf20Sopenharmony_ci u32 data, u32 delay) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci unsigned long flag; 1328c2ecf20Sopenharmony_ci struct dp_event *todo; 1338c2ecf20Sopenharmony_ci int pndx; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci spin_lock_irqsave(&dp_priv->event_lock, flag); 1368c2ecf20Sopenharmony_ci pndx = dp_priv->event_pndx + 1; 1378c2ecf20Sopenharmony_ci pndx %= DP_EVENT_Q_MAX; 1388c2ecf20Sopenharmony_ci if (pndx == dp_priv->event_gndx) { 1398c2ecf20Sopenharmony_ci pr_err("event_q is full: pndx=%d gndx=%d\n", 1408c2ecf20Sopenharmony_ci dp_priv->event_pndx, dp_priv->event_gndx); 1418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 1428c2ecf20Sopenharmony_ci return -EPERM; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci todo = &dp_priv->event_list[dp_priv->event_pndx++]; 1458c2ecf20Sopenharmony_ci dp_priv->event_pndx %= DP_EVENT_Q_MAX; 1468c2ecf20Sopenharmony_ci todo->event_id = event; 1478c2ecf20Sopenharmony_ci todo->data = data; 1488c2ecf20Sopenharmony_ci todo->delay = delay; 1498c2ecf20Sopenharmony_ci wake_up(&dp_priv->event_q); 1508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int dp_del_event(struct dp_display_private *dp_priv, u32 event) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci unsigned long flag; 1588c2ecf20Sopenharmony_ci struct dp_event *todo; 1598c2ecf20Sopenharmony_ci u32 gndx; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci spin_lock_irqsave(&dp_priv->event_lock, flag); 1628c2ecf20Sopenharmony_ci if (dp_priv->event_pndx == dp_priv->event_gndx) { 1638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 1648c2ecf20Sopenharmony_ci return -ENOENT; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci gndx = dp_priv->event_gndx; 1688c2ecf20Sopenharmony_ci while (dp_priv->event_pndx != gndx) { 1698c2ecf20Sopenharmony_ci todo = &dp_priv->event_list[gndx]; 1708c2ecf20Sopenharmony_ci if (todo->event_id == event) { 1718c2ecf20Sopenharmony_ci todo->event_id = EV_NO_EVENT; /* deleted */ 1728c2ecf20Sopenharmony_ci todo->delay = 0; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci gndx++; 1758c2ecf20Sopenharmony_ci gndx %= DP_EVENT_Q_MAX; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_civoid dp_display_signal_audio_start(struct msm_dp *dp_display) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct dp_display_private *dp; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci reinit_completion(&dp->audio_comp); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_civoid dp_display_signal_audio_complete(struct msm_dp *dp_display) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct dp_display_private *dp; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci complete_all(&dp->audio_comp); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int dp_hpd_event_thread_start(struct dp_display_private *dp_priv); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int dp_display_bind(struct device *dev, struct device *master, 2038c2ecf20Sopenharmony_ci void *data) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int rc = 0; 2068c2ecf20Sopenharmony_ci struct dp_display_private *dp; 2078c2ecf20Sopenharmony_ci struct drm_device *drm; 2088c2ecf20Sopenharmony_ci struct msm_drm_private *priv; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci drm = dev_get_drvdata(master); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 2138c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 2148c2ecf20Sopenharmony_ci if (!dp) { 2158c2ecf20Sopenharmony_ci DRM_ERROR("DP driver bind failed. Invalid driver data\n"); 2168c2ecf20Sopenharmony_ci return -EINVAL; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci dp->dp_display.drm_dev = drm; 2208c2ecf20Sopenharmony_ci priv = drm->dev_private; 2218c2ecf20Sopenharmony_ci priv->dp = &(dp->dp_display); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci rc = dp->parser->parse(dp->parser); 2248c2ecf20Sopenharmony_ci if (rc) { 2258c2ecf20Sopenharmony_ci DRM_ERROR("device tree parsing failed\n"); 2268c2ecf20Sopenharmony_ci goto end; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci rc = dp_aux_register(dp->aux); 2308c2ecf20Sopenharmony_ci if (rc) { 2318c2ecf20Sopenharmony_ci DRM_ERROR("DRM DP AUX register failed\n"); 2328c2ecf20Sopenharmony_ci goto end; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci rc = dp_power_client_init(dp->power); 2368c2ecf20Sopenharmony_ci if (rc) { 2378c2ecf20Sopenharmony_ci DRM_ERROR("Power client create failed\n"); 2388c2ecf20Sopenharmony_ci goto end; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci rc = dp_register_audio_driver(dev, dp->audio); 2428c2ecf20Sopenharmony_ci if (rc) { 2438c2ecf20Sopenharmony_ci DRM_ERROR("Audio registration Dp failed\n"); 2448c2ecf20Sopenharmony_ci goto end; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci rc = dp_hpd_event_thread_start(dp); 2488c2ecf20Sopenharmony_ci if (rc) { 2498c2ecf20Sopenharmony_ci DRM_ERROR("Event thread create failed\n"); 2508c2ecf20Sopenharmony_ci goto end; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ciend: 2558c2ecf20Sopenharmony_ci return rc; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void dp_display_unbind(struct device *dev, struct device *master, 2598c2ecf20Sopenharmony_ci void *data) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct dp_display_private *dp; 2628c2ecf20Sopenharmony_ci struct drm_device *drm = dev_get_drvdata(master); 2638c2ecf20Sopenharmony_ci struct msm_drm_private *priv = drm->dev_private; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 2668c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 2678c2ecf20Sopenharmony_ci if (!dp) { 2688c2ecf20Sopenharmony_ci DRM_ERROR("Invalid DP driver data\n"); 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* disable all HPD interrupts */ 2738c2ecf20Sopenharmony_ci if (dp->core_initialized) 2748c2ecf20Sopenharmony_ci dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci kthread_stop(dp->ev_tsk); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci dp_power_client_deinit(dp->power); 2798c2ecf20Sopenharmony_ci dp_unregister_audio_driver(dev, dp->audio); 2808c2ecf20Sopenharmony_ci dp_aux_unregister(dp->aux); 2818c2ecf20Sopenharmony_ci priv->dp = NULL; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct component_ops dp_display_comp_ops = { 2858c2ecf20Sopenharmony_ci .bind = dp_display_bind, 2868c2ecf20Sopenharmony_ci .unbind = dp_display_unbind, 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic bool dp_display_is_ds_bridge(struct dp_panel *panel) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & 2928c2ecf20Sopenharmony_ci DP_DWN_STRM_PORT_PRESENT); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic bool dp_display_is_sink_count_zero(struct dp_display_private *dp) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci return dp_display_is_ds_bridge(dp->panel) && 2988c2ecf20Sopenharmony_ci (dp->link->sink_count == 0); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void dp_display_send_hpd_event(struct msm_dp *dp_display) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct dp_display_private *dp; 3048c2ecf20Sopenharmony_ci struct drm_connector *connector; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci connector = dp->dp_display.connector; 3098c2ecf20Sopenharmony_ci drm_helper_hpd_irq_event(connector->dev); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void dp_display_set_encoder_mode(struct dp_display_private *dp) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct msm_drm_private *priv = dp->dp_display.drm_dev->dev_private; 3168c2ecf20Sopenharmony_ci struct msm_kms *kms = priv->kms; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (!dp->encoder_mode_set && dp->dp_display.encoder && 3198c2ecf20Sopenharmony_ci kms->funcs->set_encoder_mode) { 3208c2ecf20Sopenharmony_ci kms->funcs->set_encoder_mode(kms, 3218c2ecf20Sopenharmony_ci dp->dp_display.encoder, false); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci dp->encoder_mode_set = true; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int dp_display_send_hpd_notification(struct dp_display_private *dp, 3288c2ecf20Sopenharmony_ci bool hpd) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci if ((hpd && dp->dp_display.is_connected) || 3318c2ecf20Sopenharmony_ci (!hpd && !dp->dp_display.is_connected)) { 3328c2ecf20Sopenharmony_ci DRM_DEBUG_DP("HPD already %s\n", (hpd ? "on" : "off")); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* reset video pattern flag on disconnect */ 3378c2ecf20Sopenharmony_ci if (!hpd) 3388c2ecf20Sopenharmony_ci dp->panel->video_test = false; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci dp->dp_display.is_connected = hpd; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci dp_display_send_hpd_event(&dp->dp_display); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int dp_display_process_hpd_high(struct dp_display_private *dp) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int rc = 0; 3508c2ecf20Sopenharmony_ci struct edid *edid; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dp->panel->max_dp_lanes = dp->parser->max_dp_lanes; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector); 3558c2ecf20Sopenharmony_ci if (rc) 3568c2ecf20Sopenharmony_ci goto end; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci dp_link_process_request(dp->link); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci edid = dp->panel->edid; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci dp->audio_supported = drm_detect_monitor_audio(edid); 3638c2ecf20Sopenharmony_ci dp_panel_handle_sink_request(dp->panel); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci dp->dp_display.max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; 3668c2ecf20Sopenharmony_ci dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci dp_link_reset_phy_params_vx_px(dp->link); 3698c2ecf20Sopenharmony_ci rc = dp_ctrl_on_link(dp->ctrl); 3708c2ecf20Sopenharmony_ci if (rc) { 3718c2ecf20Sopenharmony_ci DRM_ERROR("failed to complete DP link training\n"); 3728c2ecf20Sopenharmony_ci goto end; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci dp_add_event(dp, EV_USER_NOTIFICATION, true, 0); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ciend: 3788c2ecf20Sopenharmony_ci return rc; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void dp_display_host_init(struct dp_display_private *dp) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci bool flip = false; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (dp->core_initialized) { 3868c2ecf20Sopenharmony_ci DRM_DEBUG_DP("DP core already initialized\n"); 3878c2ecf20Sopenharmony_ci return; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (dp->usbpd->orientation == ORIENTATION_CC2) 3918c2ecf20Sopenharmony_ci flip = true; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci dp_display_set_encoder_mode(dp); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci dp_power_init(dp->power, flip); 3968c2ecf20Sopenharmony_ci dp_ctrl_host_init(dp->ctrl, flip); 3978c2ecf20Sopenharmony_ci dp_aux_init(dp->aux); 3988c2ecf20Sopenharmony_ci dp->core_initialized = true; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void dp_display_host_deinit(struct dp_display_private *dp) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci if (!dp->core_initialized) { 4048c2ecf20Sopenharmony_ci DRM_DEBUG_DP("DP core not initialized\n"); 4058c2ecf20Sopenharmony_ci return; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci dp_ctrl_host_deinit(dp->ctrl); 4098c2ecf20Sopenharmony_ci dp_aux_deinit(dp->aux); 4108c2ecf20Sopenharmony_ci dp_power_deinit(dp->power); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci dp->core_initialized = false; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int dp_display_usbpd_configure_cb(struct device *dev) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci int rc = 0; 4188c2ecf20Sopenharmony_ci struct dp_display_private *dp; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (!dev) { 4218c2ecf20Sopenharmony_ci DRM_ERROR("invalid dev\n"); 4228c2ecf20Sopenharmony_ci rc = -EINVAL; 4238c2ecf20Sopenharmony_ci goto end; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 4278c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 4288c2ecf20Sopenharmony_ci if (!dp) { 4298c2ecf20Sopenharmony_ci DRM_ERROR("no driver data found\n"); 4308c2ecf20Sopenharmony_ci rc = -ENODEV; 4318c2ecf20Sopenharmony_ci goto end; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci dp_display_host_init(dp); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* 4378c2ecf20Sopenharmony_ci * set sink to normal operation mode -- D0 4388c2ecf20Sopenharmony_ci * before dpcd read 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci dp_link_psm_config(dp->link, &dp->panel->link_info, false); 4418c2ecf20Sopenharmony_ci rc = dp_display_process_hpd_high(dp); 4428c2ecf20Sopenharmony_ciend: 4438c2ecf20Sopenharmony_ci return rc; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int dp_display_usbpd_disconnect_cb(struct device *dev) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int rc = 0; 4498c2ecf20Sopenharmony_ci struct dp_display_private *dp; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!dev) { 4528c2ecf20Sopenharmony_ci DRM_ERROR("invalid dev\n"); 4538c2ecf20Sopenharmony_ci rc = -EINVAL; 4548c2ecf20Sopenharmony_ci return rc; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 4588c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 4598c2ecf20Sopenharmony_ci if (!dp) { 4608c2ecf20Sopenharmony_ci DRM_ERROR("no driver data found\n"); 4618c2ecf20Sopenharmony_ci rc = -ENODEV; 4628c2ecf20Sopenharmony_ci return rc; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return rc; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic void dp_display_handle_video_request(struct dp_display_private *dp) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { 4738c2ecf20Sopenharmony_ci dp->panel->video_test = true; 4748c2ecf20Sopenharmony_ci dp_link_send_test_response(dp->link); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int dp_display_handle_port_ststus_changed(struct dp_display_private *dp) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci int rc = 0; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (dp_display_is_sink_count_zero(dp)) { 4838c2ecf20Sopenharmony_ci DRM_DEBUG_DP("sink count is zero, nothing to do\n"); 4848c2ecf20Sopenharmony_ci if (dp->hpd_state != ST_DISCONNECTED) { 4858c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECT_PENDING; 4868c2ecf20Sopenharmony_ci dp_add_event(dp, EV_USER_NOTIFICATION, false, 0); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci } else { 4898c2ecf20Sopenharmony_ci if (dp->hpd_state == ST_DISCONNECTED) { 4908c2ecf20Sopenharmony_ci dp->hpd_state = ST_CONNECT_PENDING; 4918c2ecf20Sopenharmony_ci rc = dp_display_process_hpd_high(dp); 4928c2ecf20Sopenharmony_ci if (rc) 4938c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECTED; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return rc; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int dp_display_handle_irq_hpd(struct dp_display_private *dp) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci u32 sink_request = dp->link->sink_request; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (dp->hpd_state == ST_DISCONNECTED) { 5058c2ecf20Sopenharmony_ci if (sink_request & DP_LINK_STATUS_UPDATED) { 5068c2ecf20Sopenharmony_ci DRM_ERROR("Disconnected, no DP_LINK_STATUS_UPDATED\n"); 5078c2ecf20Sopenharmony_ci return -EINVAL; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci dp_ctrl_handle_sink_request(dp->ctrl); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (sink_request & DP_TEST_LINK_VIDEO_PATTERN) 5148c2ecf20Sopenharmony_ci dp_display_handle_video_request(dp); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return 0; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic int dp_display_usbpd_attention_cb(struct device *dev) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci int rc = 0; 5228c2ecf20Sopenharmony_ci u32 sink_request; 5238c2ecf20Sopenharmony_ci struct dp_display_private *dp; 5248c2ecf20Sopenharmony_ci struct dp_usbpd *hpd; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (!dev) { 5278c2ecf20Sopenharmony_ci DRM_ERROR("invalid dev\n"); 5288c2ecf20Sopenharmony_ci return -EINVAL; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 5328c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 5338c2ecf20Sopenharmony_ci if (!dp) { 5348c2ecf20Sopenharmony_ci DRM_ERROR("no driver data found\n"); 5358c2ecf20Sopenharmony_ci return -ENODEV; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci hpd = dp->usbpd; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* check for any test request issued by sink */ 5418c2ecf20Sopenharmony_ci rc = dp_link_process_request(dp->link); 5428c2ecf20Sopenharmony_ci if (!rc) { 5438c2ecf20Sopenharmony_ci sink_request = dp->link->sink_request; 5448c2ecf20Sopenharmony_ci if (sink_request & DS_PORT_STATUS_CHANGED) 5458c2ecf20Sopenharmony_ci rc = dp_display_handle_port_ststus_changed(dp); 5468c2ecf20Sopenharmony_ci else 5478c2ecf20Sopenharmony_ci rc = dp_display_handle_irq_hpd(dp); 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return rc; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct dp_usbpd *hpd = dp->usbpd; 5568c2ecf20Sopenharmony_ci u32 state; 5578c2ecf20Sopenharmony_ci u32 tout = DP_TIMEOUT_5_SECOND; 5588c2ecf20Sopenharmony_ci int ret; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!hpd) 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci state = dp->hpd_state; 5668c2ecf20Sopenharmony_ci if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { 5678c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 5688c2ecf20Sopenharmony_ci return 0; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (state == ST_CONNECT_PENDING || state == ST_CONNECTED) { 5728c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (state == ST_DISCONNECT_PENDING) { 5778c2ecf20Sopenharmony_ci /* wait until ST_DISCONNECTED */ 5788c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_PLUG_INT, 0, 1); /* delay = 1 */ 5798c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci dp->hpd_state = ST_CONNECT_PENDING; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci hpd->hpd_high = 1; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = dp_display_usbpd_configure_cb(&dp->pdev->dev); 5888c2ecf20Sopenharmony_ci if (ret) { /* link train failed */ 5898c2ecf20Sopenharmony_ci hpd->hpd_high = 0; 5908c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECTED; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (ret == -ECONNRESET) { /* cable unplugged */ 5938c2ecf20Sopenharmony_ci dp->core_initialized = false; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci } else { 5978c2ecf20Sopenharmony_ci /* start sentinel checking in case of missing uevent */ 5988c2ecf20Sopenharmony_ci dp_add_event(dp, EV_CONNECT_PENDING_TIMEOUT, 0, tout); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* uevent will complete connection part */ 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci}; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int dp_display_enable(struct dp_display_private *dp, u32 data); 6088c2ecf20Sopenharmony_cistatic int dp_display_disable(struct dp_display_private *dp, u32 data); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci u32 state; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci state = dp->hpd_state; 6178c2ecf20Sopenharmony_ci if (state == ST_CONNECT_PENDING) { 6188c2ecf20Sopenharmony_ci dp_display_enable(dp, 0); 6198c2ecf20Sopenharmony_ci dp->hpd_state = ST_CONNECTED; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic void dp_display_handle_plugged_change(struct msm_dp *dp_display, 6288c2ecf20Sopenharmony_ci bool plugged) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct dp_display_private *dp; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci dp = container_of(dp_display, 6338c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* notify audio subsystem only if sink supports audio */ 6368c2ecf20Sopenharmony_ci if (dp_display->plugged_cb && dp_display->codec_dev && 6378c2ecf20Sopenharmony_ci dp->audio_supported) 6388c2ecf20Sopenharmony_ci dp_display->plugged_cb(dp_display->codec_dev, plugged); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct dp_usbpd *hpd = dp->usbpd; 6448c2ecf20Sopenharmony_ci u32 state; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (!hpd) 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci state = dp->hpd_state; 6528c2ecf20Sopenharmony_ci if (state == ST_DISCONNECT_PENDING || state == ST_DISCONNECTED) { 6538c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 6548c2ecf20Sopenharmony_ci return 0; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (state == ST_CONNECT_PENDING) { 6588c2ecf20Sopenharmony_ci /* wait until CONNECTED */ 6598c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 1); /* delay = 1 */ 6608c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 6618c2ecf20Sopenharmony_ci return 0; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECT_PENDING; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* disable HPD plug interrupt until disconnect is done */ 6678c2ecf20Sopenharmony_ci dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK 6688c2ecf20Sopenharmony_ci | DP_DP_IRQ_HPD_INT_MASK, false); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci hpd->hpd_high = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* 6738c2ecf20Sopenharmony_ci * We don't need separate work for disconnect as 6748c2ecf20Sopenharmony_ci * connect/attention interrupts are disabled 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci dp_display_usbpd_disconnect_cb(&dp->pdev->dev); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* start sentinel checking in case of missing uevent */ 6798c2ecf20Sopenharmony_ci dp_add_event(dp, EV_DISCONNECT_PENDING_TIMEOUT, 0, DP_TIMEOUT_5_SECOND); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* signal the disconnect event early to ensure proper teardown */ 6828c2ecf20Sopenharmony_ci dp_display_handle_plugged_change(g_dp_display, false); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK | 6858c2ecf20Sopenharmony_ci DP_DP_IRQ_HPD_INT_MASK, true); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* uevent will complete disconnection part */ 6888c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci u32 state; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci state = dp->hpd_state; 6998c2ecf20Sopenharmony_ci if (state == ST_DISCONNECT_PENDING) { 7008c2ecf20Sopenharmony_ci dp_display_disable(dp, 0); 7018c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECTED; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci u32 state; 7128c2ecf20Sopenharmony_ci int ret; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* irq_hpd can happen at either connected or disconnected state */ 7178c2ecf20Sopenharmony_ci state = dp->hpd_state; 7188c2ecf20Sopenharmony_ci if (state == ST_DISPLAY_OFF) { 7198c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci ret = dp_display_usbpd_attention_cb(&dp->pdev->dev); 7248c2ecf20Sopenharmony_ci if (ret == -ECONNRESET) { /* cable unplugged */ 7258c2ecf20Sopenharmony_ci dp->core_initialized = false; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci return 0; 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_cistatic void dp_display_deinit_sub_modules(struct dp_display_private *dp) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci dp_debug_put(dp->debug); 7368c2ecf20Sopenharmony_ci dp_ctrl_put(dp->ctrl); 7378c2ecf20Sopenharmony_ci dp_panel_put(dp->panel); 7388c2ecf20Sopenharmony_ci dp_aux_put(dp->aux); 7398c2ecf20Sopenharmony_ci dp_audio_put(dp->audio); 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int dp_init_sub_modules(struct dp_display_private *dp) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci int rc = 0; 7458c2ecf20Sopenharmony_ci struct device *dev = &dp->pdev->dev; 7468c2ecf20Sopenharmony_ci struct dp_usbpd_cb *cb = &dp->usbpd_cb; 7478c2ecf20Sopenharmony_ci struct dp_panel_in panel_in = { 7488c2ecf20Sopenharmony_ci .dev = dev, 7498c2ecf20Sopenharmony_ci }; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Callback APIs used for cable status change event */ 7528c2ecf20Sopenharmony_ci cb->configure = dp_display_usbpd_configure_cb; 7538c2ecf20Sopenharmony_ci cb->disconnect = dp_display_usbpd_disconnect_cb; 7548c2ecf20Sopenharmony_ci cb->attention = dp_display_usbpd_attention_cb; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci dp->usbpd = dp_hpd_get(dev, cb); 7578c2ecf20Sopenharmony_ci if (IS_ERR(dp->usbpd)) { 7588c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->usbpd); 7598c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize hpd, rc = %d\n", rc); 7608c2ecf20Sopenharmony_ci dp->usbpd = NULL; 7618c2ecf20Sopenharmony_ci goto error; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci dp->parser = dp_parser_get(dp->pdev); 7658c2ecf20Sopenharmony_ci if (IS_ERR(dp->parser)) { 7668c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->parser); 7678c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize parser, rc = %d\n", rc); 7688c2ecf20Sopenharmony_ci dp->parser = NULL; 7698c2ecf20Sopenharmony_ci goto error; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci dp->catalog = dp_catalog_get(dev, &dp->parser->io); 7738c2ecf20Sopenharmony_ci if (IS_ERR(dp->catalog)) { 7748c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->catalog); 7758c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize catalog, rc = %d\n", rc); 7768c2ecf20Sopenharmony_ci dp->catalog = NULL; 7778c2ecf20Sopenharmony_ci goto error; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci dp->power = dp_power_get(dp->parser); 7818c2ecf20Sopenharmony_ci if (IS_ERR(dp->power)) { 7828c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->power); 7838c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize power, rc = %d\n", rc); 7848c2ecf20Sopenharmony_ci dp->power = NULL; 7858c2ecf20Sopenharmony_ci goto error; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci dp->aux = dp_aux_get(dev, dp->catalog); 7898c2ecf20Sopenharmony_ci if (IS_ERR(dp->aux)) { 7908c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->aux); 7918c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize aux, rc = %d\n", rc); 7928c2ecf20Sopenharmony_ci dp->aux = NULL; 7938c2ecf20Sopenharmony_ci goto error; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci dp->link = dp_link_get(dev, dp->aux); 7978c2ecf20Sopenharmony_ci if (IS_ERR(dp->link)) { 7988c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->link); 7998c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize link, rc = %d\n", rc); 8008c2ecf20Sopenharmony_ci dp->link = NULL; 8018c2ecf20Sopenharmony_ci goto error_link; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci panel_in.aux = dp->aux; 8058c2ecf20Sopenharmony_ci panel_in.catalog = dp->catalog; 8068c2ecf20Sopenharmony_ci panel_in.link = dp->link; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci dp->panel = dp_panel_get(&panel_in); 8098c2ecf20Sopenharmony_ci if (IS_ERR(dp->panel)) { 8108c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->panel); 8118c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize panel, rc = %d\n", rc); 8128c2ecf20Sopenharmony_ci dp->panel = NULL; 8138c2ecf20Sopenharmony_ci goto error_link; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux, 8178c2ecf20Sopenharmony_ci dp->power, dp->catalog, dp->parser); 8188c2ecf20Sopenharmony_ci if (IS_ERR(dp->ctrl)) { 8198c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->ctrl); 8208c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc); 8218c2ecf20Sopenharmony_ci dp->ctrl = NULL; 8228c2ecf20Sopenharmony_ci goto error_ctrl; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci dp->audio = dp_audio_get(dp->pdev, dp->panel, dp->catalog); 8268c2ecf20Sopenharmony_ci if (IS_ERR(dp->audio)) { 8278c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->audio); 8288c2ecf20Sopenharmony_ci pr_err("failed to initialize audio, rc = %d\n", rc); 8298c2ecf20Sopenharmony_ci dp->audio = NULL; 8308c2ecf20Sopenharmony_ci goto error_audio; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return rc; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cierror_audio: 8368c2ecf20Sopenharmony_ci dp_ctrl_put(dp->ctrl); 8378c2ecf20Sopenharmony_cierror_ctrl: 8388c2ecf20Sopenharmony_ci dp_panel_put(dp->panel); 8398c2ecf20Sopenharmony_cierror_link: 8408c2ecf20Sopenharmony_ci dp_aux_put(dp->aux); 8418c2ecf20Sopenharmony_cierror: 8428c2ecf20Sopenharmony_ci return rc; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic int dp_display_set_mode(struct msm_dp *dp_display, 8468c2ecf20Sopenharmony_ci struct dp_display_mode *mode) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct dp_display_private *dp; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode); 8538c2ecf20Sopenharmony_ci dp->panel->dp_mode.bpp = mode->bpp; 8548c2ecf20Sopenharmony_ci dp->panel->dp_mode.capabilities = mode->capabilities; 8558c2ecf20Sopenharmony_ci dp_panel_init_panel_info(dp->panel); 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int dp_display_prepare(struct msm_dp *dp) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci return 0; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic int dp_display_enable(struct dp_display_private *dp, u32 data) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci int rc = 0; 8678c2ecf20Sopenharmony_ci struct msm_dp *dp_display; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci dp_display = g_dp_display; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (dp_display->power_on) { 8728c2ecf20Sopenharmony_ci DRM_DEBUG_DP("Link already setup, return\n"); 8738c2ecf20Sopenharmony_ci return 0; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci rc = dp_ctrl_on_stream(dp->ctrl); 8778c2ecf20Sopenharmony_ci if (!rc) 8788c2ecf20Sopenharmony_ci dp_display->power_on = true; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci return rc; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int dp_display_post_enable(struct msm_dp *dp_display) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct dp_display_private *dp; 8868c2ecf20Sopenharmony_ci u32 rate; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci rate = dp->link->link_params.rate; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (dp->audio_supported) { 8938c2ecf20Sopenharmony_ci dp->audio->bw_code = drm_dp_link_rate_to_bw_code(rate); 8948c2ecf20Sopenharmony_ci dp->audio->lane_count = dp->link->link_params.num_lanes; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* signal the connect event late to synchronize video and display */ 8988c2ecf20Sopenharmony_ci dp_display_handle_plugged_change(dp_display, true); 8998c2ecf20Sopenharmony_ci return 0; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic int dp_display_disable(struct dp_display_private *dp, u32 data) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct msm_dp *dp_display; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci dp_display = g_dp_display; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (!dp_display->power_on) 9098c2ecf20Sopenharmony_ci return 0; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* wait only if audio was enabled */ 9128c2ecf20Sopenharmony_ci if (dp_display->audio_enabled) { 9138c2ecf20Sopenharmony_ci /* signal the disconnect event */ 9148c2ecf20Sopenharmony_ci dp_display_handle_plugged_change(dp_display, false); 9158c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&dp->audio_comp, 9168c2ecf20Sopenharmony_ci HZ * 5)) 9178c2ecf20Sopenharmony_ci DRM_ERROR("audio comp timeout\n"); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci dp_display->audio_enabled = false; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci dp_ctrl_off(dp->ctrl); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci dp->core_initialized = false; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci dp_display->power_on = false; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int dp_display_unprepare(struct msm_dp *dp) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ciint dp_display_set_plugged_cb(struct msm_dp *dp_display, 9378c2ecf20Sopenharmony_ci hdmi_codec_plugged_cb fn, struct device *codec_dev) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci bool plugged; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci dp_display->plugged_cb = fn; 9428c2ecf20Sopenharmony_ci dp_display->codec_dev = codec_dev; 9438c2ecf20Sopenharmony_ci plugged = dp_display->is_connected; 9448c2ecf20Sopenharmony_ci dp_display_handle_plugged_change(dp_display, plugged); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ciint dp_display_validate_mode(struct msm_dp *dp, u32 mode_pclk_khz) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci const u32 num_components = 3, default_bpp = 24; 9528c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 9538c2ecf20Sopenharmony_ci struct dp_link_info *link_info; 9548c2ecf20Sopenharmony_ci u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!dp || !mode_pclk_khz || !dp->connector) { 9578c2ecf20Sopenharmony_ci DRM_ERROR("invalid params\n"); 9588c2ecf20Sopenharmony_ci return -EINVAL; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 9628c2ecf20Sopenharmony_ci link_info = &dp_display->panel->link_info; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci mode_bpp = dp->connector->display_info.bpc * num_components; 9658c2ecf20Sopenharmony_ci if (!mode_bpp) 9668c2ecf20Sopenharmony_ci mode_bpp = default_bpp; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci mode_bpp = dp_panel_get_mode_bpp(dp_display->panel, 9698c2ecf20Sopenharmony_ci mode_bpp, mode_pclk_khz); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci mode_rate_khz = mode_pclk_khz * mode_bpp; 9728c2ecf20Sopenharmony_ci supported_rate_khz = link_info->num_lanes * link_info->rate * 8; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (mode_rate_khz > supported_rate_khz) 9758c2ecf20Sopenharmony_ci return MODE_BAD; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return MODE_OK; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ciint dp_display_get_modes(struct msm_dp *dp, 9818c2ecf20Sopenharmony_ci struct dp_display_mode *dp_mode) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 9848c2ecf20Sopenharmony_ci int ret = 0; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (!dp) { 9878c2ecf20Sopenharmony_ci DRM_ERROR("invalid params\n"); 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci ret = dp_panel_get_modes(dp_display->panel, 9948c2ecf20Sopenharmony_ci dp->connector, dp_mode); 9958c2ecf20Sopenharmony_ci if (dp_mode->drm_mode.clock) 9968c2ecf20Sopenharmony_ci dp->max_pclk_khz = dp_mode->drm_mode.clock; 9978c2ecf20Sopenharmony_ci return ret; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cibool dp_display_check_video_test(struct msm_dp *dp) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci return dp_display->panel->video_test; 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ciint dp_display_get_test_bpp(struct msm_dp *dp) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!dp) { 10148c2ecf20Sopenharmony_ci DRM_ERROR("invalid params\n"); 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return dp_link_bit_depth_to_bpp( 10218c2ecf20Sopenharmony_ci dp_display->link->test_video.test_bit_depth); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic void dp_display_config_hpd(struct dp_display_private *dp) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci dp_display_host_init(dp); 10288c2ecf20Sopenharmony_ci dp_catalog_ctrl_hpd_config(dp->catalog); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci /* Enable interrupt first time 10318c2ecf20Sopenharmony_ci * we are leaving dp clocks on during disconnect 10328c2ecf20Sopenharmony_ci * and never disable interrupt 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_ci enable_irq(dp->irq); 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic int hpd_event_thread(void *data) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct dp_display_private *dp_priv; 10408c2ecf20Sopenharmony_ci unsigned long flag; 10418c2ecf20Sopenharmony_ci struct dp_event *todo; 10428c2ecf20Sopenharmony_ci int timeout_mode = 0; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci dp_priv = (struct dp_display_private *)data; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci while (1) { 10478c2ecf20Sopenharmony_ci if (timeout_mode) { 10488c2ecf20Sopenharmony_ci wait_event_timeout(dp_priv->event_q, 10498c2ecf20Sopenharmony_ci (dp_priv->event_pndx == dp_priv->event_gndx) || 10508c2ecf20Sopenharmony_ci kthread_should_stop(), EVENT_TIMEOUT); 10518c2ecf20Sopenharmony_ci } else { 10528c2ecf20Sopenharmony_ci wait_event_interruptible(dp_priv->event_q, 10538c2ecf20Sopenharmony_ci (dp_priv->event_pndx != dp_priv->event_gndx) || 10548c2ecf20Sopenharmony_ci kthread_should_stop()); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (kthread_should_stop()) 10588c2ecf20Sopenharmony_ci break; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci spin_lock_irqsave(&dp_priv->event_lock, flag); 10618c2ecf20Sopenharmony_ci todo = &dp_priv->event_list[dp_priv->event_gndx]; 10628c2ecf20Sopenharmony_ci if (todo->delay) { 10638c2ecf20Sopenharmony_ci struct dp_event *todo_next; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci dp_priv->event_gndx++; 10668c2ecf20Sopenharmony_ci dp_priv->event_gndx %= DP_EVENT_Q_MAX; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* re enter delay event into q */ 10698c2ecf20Sopenharmony_ci todo_next = &dp_priv->event_list[dp_priv->event_pndx++]; 10708c2ecf20Sopenharmony_ci dp_priv->event_pndx %= DP_EVENT_Q_MAX; 10718c2ecf20Sopenharmony_ci todo_next->event_id = todo->event_id; 10728c2ecf20Sopenharmony_ci todo_next->data = todo->data; 10738c2ecf20Sopenharmony_ci todo_next->delay = todo->delay - 1; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* clean up older event */ 10768c2ecf20Sopenharmony_ci todo->event_id = EV_NO_EVENT; 10778c2ecf20Sopenharmony_ci todo->delay = 0; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* switch to timeout mode */ 10808c2ecf20Sopenharmony_ci timeout_mode = 1; 10818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 10828c2ecf20Sopenharmony_ci continue; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* timeout with no events in q */ 10868c2ecf20Sopenharmony_ci if (dp_priv->event_pndx == dp_priv->event_gndx) { 10878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 10888c2ecf20Sopenharmony_ci continue; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci dp_priv->event_gndx++; 10928c2ecf20Sopenharmony_ci dp_priv->event_gndx %= DP_EVENT_Q_MAX; 10938c2ecf20Sopenharmony_ci timeout_mode = 0; 10948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dp_priv->event_lock, flag); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci switch (todo->event_id) { 10978c2ecf20Sopenharmony_ci case EV_HPD_INIT_SETUP: 10988c2ecf20Sopenharmony_ci dp_display_config_hpd(dp_priv); 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci case EV_HPD_PLUG_INT: 11018c2ecf20Sopenharmony_ci dp_hpd_plug_handle(dp_priv, todo->data); 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci case EV_HPD_UNPLUG_INT: 11048c2ecf20Sopenharmony_ci dp_hpd_unplug_handle(dp_priv, todo->data); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case EV_IRQ_HPD_INT: 11078c2ecf20Sopenharmony_ci dp_irq_hpd_handle(dp_priv, todo->data); 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case EV_HPD_REPLUG_INT: 11108c2ecf20Sopenharmony_ci /* do nothing */ 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci case EV_USER_NOTIFICATION: 11138c2ecf20Sopenharmony_ci dp_display_send_hpd_notification(dp_priv, 11148c2ecf20Sopenharmony_ci todo->data); 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci case EV_CONNECT_PENDING_TIMEOUT: 11178c2ecf20Sopenharmony_ci dp_connect_pending_timeout(dp_priv, 11188c2ecf20Sopenharmony_ci todo->data); 11198c2ecf20Sopenharmony_ci break; 11208c2ecf20Sopenharmony_ci case EV_DISCONNECT_PENDING_TIMEOUT: 11218c2ecf20Sopenharmony_ci dp_disconnect_pending_timeout(dp_priv, 11228c2ecf20Sopenharmony_ci todo->data); 11238c2ecf20Sopenharmony_ci break; 11248c2ecf20Sopenharmony_ci default: 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic int dp_hpd_event_thread_start(struct dp_display_private *dp_priv) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci /* set event q to empty */ 11358c2ecf20Sopenharmony_ci dp_priv->event_gndx = 0; 11368c2ecf20Sopenharmony_ci dp_priv->event_pndx = 0; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci dp_priv->ev_tsk = kthread_run(hpd_event_thread, dp_priv, "dp_hpd_handler"); 11398c2ecf20Sopenharmony_ci if (IS_ERR(dp_priv->ev_tsk)) 11408c2ecf20Sopenharmony_ci return PTR_ERR(dp_priv->ev_tsk); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic irqreturn_t dp_display_irq_handler(int irq, void *dev_id) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct dp_display_private *dp = dev_id; 11488c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_HANDLED; 11498c2ecf20Sopenharmony_ci u32 hpd_isr_status; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (!dp) { 11528c2ecf20Sopenharmony_ci DRM_ERROR("invalid data\n"); 11538c2ecf20Sopenharmony_ci return IRQ_NONE; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (hpd_isr_status & 0x0F) { 11598c2ecf20Sopenharmony_ci /* hpd related interrupts */ 11608c2ecf20Sopenharmony_ci if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK || 11618c2ecf20Sopenharmony_ci hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) { 11628c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) { 11668c2ecf20Sopenharmony_ci /* stop sentinel connect pending checking */ 11678c2ecf20Sopenharmony_ci dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT); 11688c2ecf20Sopenharmony_ci dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0); 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) 11728c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_REPLUG_INT, 0, 0); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK) 11758c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* DP controller isr */ 11798c2ecf20Sopenharmony_ci dp_ctrl_isr(dp->ctrl); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* DP aux isr */ 11828c2ecf20Sopenharmony_ci dp_aux_isr(dp->aux); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return ret; 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ciint dp_display_request_irq(struct msm_dp *dp_display) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci int rc = 0; 11908c2ecf20Sopenharmony_ci struct dp_display_private *dp; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (!dp_display) { 11938c2ecf20Sopenharmony_ci DRM_ERROR("invalid input\n"); 11948c2ecf20Sopenharmony_ci return -EINVAL; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0); 12008c2ecf20Sopenharmony_ci if (!dp->irq) { 12018c2ecf20Sopenharmony_ci DRM_ERROR("failed to get irq\n"); 12028c2ecf20Sopenharmony_ci return -EINVAL; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci rc = devm_request_irq(dp_display->drm_dev->dev, dp->irq, 12068c2ecf20Sopenharmony_ci dp_display_irq_handler, 12078c2ecf20Sopenharmony_ci IRQF_TRIGGER_HIGH, "dp_display_isr", dp); 12088c2ecf20Sopenharmony_ci if (rc < 0) { 12098c2ecf20Sopenharmony_ci DRM_ERROR("failed to request IRQ%u: %d\n", 12108c2ecf20Sopenharmony_ci dp->irq, rc); 12118c2ecf20Sopenharmony_ci return rc; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci disable_irq(dp->irq); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci return 0; 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_cistatic int dp_display_probe(struct platform_device *pdev) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci int rc = 0; 12218c2ecf20Sopenharmony_ci struct dp_display_private *dp; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (!pdev || !pdev->dev.of_node) { 12248c2ecf20Sopenharmony_ci DRM_ERROR("pdev not found\n"); 12258c2ecf20Sopenharmony_ci return -ENODEV; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL); 12298c2ecf20Sopenharmony_ci if (!dp) 12308c2ecf20Sopenharmony_ci return -ENOMEM; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci dp->pdev = pdev; 12338c2ecf20Sopenharmony_ci dp->name = "drm_dp"; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci rc = dp_init_sub_modules(dp); 12368c2ecf20Sopenharmony_ci if (rc) { 12378c2ecf20Sopenharmony_ci DRM_ERROR("init sub module failed\n"); 12388c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* setup event q */ 12428c2ecf20Sopenharmony_ci mutex_init(&dp->event_mutex); 12438c2ecf20Sopenharmony_ci g_dp_display = &dp->dp_display; 12448c2ecf20Sopenharmony_ci init_waitqueue_head(&dp->event_q); 12458c2ecf20Sopenharmony_ci spin_lock_init(&dp->event_lock); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* Store DP audio handle inside DP display */ 12488c2ecf20Sopenharmony_ci g_dp_display->dp_audio = dp->audio; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci init_completion(&dp->audio_comp); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, g_dp_display); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci rc = component_add(&pdev->dev, &dp_display_comp_ops); 12558c2ecf20Sopenharmony_ci if (rc) { 12568c2ecf20Sopenharmony_ci DRM_ERROR("component add failed, rc=%d\n", rc); 12578c2ecf20Sopenharmony_ci dp_display_deinit_sub_modules(dp); 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci return rc; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_cistatic int dp_display_remove(struct platform_device *pdev) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct dp_display_private *dp; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci dp = container_of(g_dp_display, 12688c2ecf20Sopenharmony_ci struct dp_display_private, dp_display); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci component_del(&pdev->dev, &dp_display_comp_ops); 12718c2ecf20Sopenharmony_ci dp_display_deinit_sub_modules(dp); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, NULL); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic int dp_pm_resume(struct device *dev) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 12818c2ecf20Sopenharmony_ci struct msm_dp *dp_display = platform_get_drvdata(pdev); 12828c2ecf20Sopenharmony_ci struct dp_display_private *dp; 12838c2ecf20Sopenharmony_ci u32 status; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* start from disconnected state */ 12908c2ecf20Sopenharmony_ci dp->hpd_state = ST_DISCONNECTED; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* turn on dp ctrl/phy */ 12938c2ecf20Sopenharmony_ci dp_display_host_init(dp); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci dp_catalog_ctrl_hpd_config(dp->catalog); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci status = dp_catalog_link_is_connected(dp->catalog); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (status) 13008c2ecf20Sopenharmony_ci dp->dp_display.is_connected = true; 13018c2ecf20Sopenharmony_ci else 13028c2ecf20Sopenharmony_ci dp->dp_display.is_connected = false; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci return 0; 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic int dp_pm_suspend(struct device *dev) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 13128c2ecf20Sopenharmony_ci struct msm_dp *dp_display = platform_get_drvdata(pdev); 13138c2ecf20Sopenharmony_ci struct dp_display_private *dp; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci mutex_lock(&dp->event_mutex); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (dp->core_initialized == true) 13208c2ecf20Sopenharmony_ci dp_display_host_deinit(dp); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci dp->hpd_state = ST_SUSPENDED; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* host_init will be called at pm_resume */ 13258c2ecf20Sopenharmony_ci dp->core_initialized = false; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci mutex_unlock(&dp->event_mutex); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic int dp_pm_prepare(struct device *dev) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic void dp_pm_complete(struct device *dev) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci} 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dp_pm_ops = { 13438c2ecf20Sopenharmony_ci .suspend = dp_pm_suspend, 13448c2ecf20Sopenharmony_ci .resume = dp_pm_resume, 13458c2ecf20Sopenharmony_ci .prepare = dp_pm_prepare, 13468c2ecf20Sopenharmony_ci .complete = dp_pm_complete, 13478c2ecf20Sopenharmony_ci}; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_cistatic struct platform_driver dp_display_driver = { 13508c2ecf20Sopenharmony_ci .probe = dp_display_probe, 13518c2ecf20Sopenharmony_ci .remove = dp_display_remove, 13528c2ecf20Sopenharmony_ci .driver = { 13538c2ecf20Sopenharmony_ci .name = "msm-dp-display", 13548c2ecf20Sopenharmony_ci .of_match_table = dp_dt_match, 13558c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 13568c2ecf20Sopenharmony_ci .pm = &dp_pm_ops, 13578c2ecf20Sopenharmony_ci }, 13588c2ecf20Sopenharmony_ci}; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ciint __init msm_dp_register(void) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci int ret; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci ret = platform_driver_register(&dp_display_driver); 13658c2ecf20Sopenharmony_ci if (ret) 13668c2ecf20Sopenharmony_ci DRM_ERROR("Dp display driver register failed"); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci return ret; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_civoid __exit msm_dp_unregister(void) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci platform_driver_unregister(&dp_display_driver); 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_civoid msm_dp_irq_postinstall(struct msm_dp *dp_display) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct dp_display_private *dp; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (!dp_display) 13818c2ecf20Sopenharmony_ci return; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100); 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_civoid msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) 13898c2ecf20Sopenharmony_ci{ 13908c2ecf20Sopenharmony_ci struct dp_display_private *dp; 13918c2ecf20Sopenharmony_ci struct device *dev; 13928c2ecf20Sopenharmony_ci int rc; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci dp = container_of(dp_display, struct dp_display_private, dp_display); 13958c2ecf20Sopenharmony_ci dev = &dp->pdev->dev; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, 13988c2ecf20Sopenharmony_ci dp->link, &dp->dp_display.connector, 13998c2ecf20Sopenharmony_ci minor); 14008c2ecf20Sopenharmony_ci if (IS_ERR(dp->debug)) { 14018c2ecf20Sopenharmony_ci rc = PTR_ERR(dp->debug); 14028c2ecf20Sopenharmony_ci DRM_ERROR("failed to initialize debug, rc = %d\n", rc); 14038c2ecf20Sopenharmony_ci dp->debug = NULL; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ciint msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, 14088c2ecf20Sopenharmony_ci struct drm_encoder *encoder) 14098c2ecf20Sopenharmony_ci{ 14108c2ecf20Sopenharmony_ci struct msm_drm_private *priv; 14118c2ecf20Sopenharmony_ci struct dp_display_private *dp_priv; 14128c2ecf20Sopenharmony_ci int ret; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (WARN_ON(!encoder) || WARN_ON(!dp_display) || WARN_ON(!dev)) 14158c2ecf20Sopenharmony_ci return -EINVAL; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci priv = dev->dev_private; 14188c2ecf20Sopenharmony_ci dp_display->drm_dev = dev; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci dp_priv = container_of(dp_display, struct dp_display_private, dp_display); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci ret = dp_display_request_irq(dp_display); 14238c2ecf20Sopenharmony_ci if (ret) { 14248c2ecf20Sopenharmony_ci DRM_ERROR("request_irq failed, ret=%d\n", ret); 14258c2ecf20Sopenharmony_ci return ret; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci dp_display->encoder = encoder; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci dp_display->connector = dp_drm_connector_init(dp_display); 14318c2ecf20Sopenharmony_ci if (IS_ERR(dp_display->connector)) { 14328c2ecf20Sopenharmony_ci ret = PTR_ERR(dp_display->connector); 14338c2ecf20Sopenharmony_ci DRM_DEV_ERROR(dev->dev, 14348c2ecf20Sopenharmony_ci "failed to create dp connector: %d\n", ret); 14358c2ecf20Sopenharmony_ci dp_display->connector = NULL; 14368c2ecf20Sopenharmony_ci return ret; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci dp_priv->panel->connector = dp_display->connector; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci priv->connectors[priv->num_connectors++] = dp_display->connector; 14428c2ecf20Sopenharmony_ci return 0; 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ciint msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci int rc = 0; 14488c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 14498c2ecf20Sopenharmony_ci u32 state; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 14528c2ecf20Sopenharmony_ci if (!dp_display->dp_mode.drm_mode.clock) { 14538c2ecf20Sopenharmony_ci DRM_ERROR("invalid params\n"); 14548c2ecf20Sopenharmony_ci return -EINVAL; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci mutex_lock(&dp_display->event_mutex); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* stop sentinel checking */ 14608c2ecf20Sopenharmony_ci dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci rc = dp_display_set_mode(dp, &dp_display->dp_mode); 14638c2ecf20Sopenharmony_ci if (rc) { 14648c2ecf20Sopenharmony_ci DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc); 14658c2ecf20Sopenharmony_ci mutex_unlock(&dp_display->event_mutex); 14668c2ecf20Sopenharmony_ci return rc; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci rc = dp_display_prepare(dp); 14708c2ecf20Sopenharmony_ci if (rc) { 14718c2ecf20Sopenharmony_ci DRM_ERROR("DP display prepare failed, rc=%d\n", rc); 14728c2ecf20Sopenharmony_ci mutex_unlock(&dp_display->event_mutex); 14738c2ecf20Sopenharmony_ci return rc; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci state = dp_display->hpd_state; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (state == ST_DISPLAY_OFF) 14798c2ecf20Sopenharmony_ci dp_display_host_init(dp_display); 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci dp_display_enable(dp_display, 0); 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci rc = dp_display_post_enable(dp); 14848c2ecf20Sopenharmony_ci if (rc) { 14858c2ecf20Sopenharmony_ci DRM_ERROR("DP display post enable failed, rc=%d\n", rc); 14868c2ecf20Sopenharmony_ci dp_display_disable(dp_display, 0); 14878c2ecf20Sopenharmony_ci dp_display_unprepare(dp); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* manual kick off plug event to train link */ 14918c2ecf20Sopenharmony_ci if (state == ST_DISPLAY_OFF) 14928c2ecf20Sopenharmony_ci dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* completed connection */ 14958c2ecf20Sopenharmony_ci dp_display->hpd_state = ST_CONNECTED; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci mutex_unlock(&dp_display->event_mutex); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return rc; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ciint msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci dp_ctrl_push_idle(dp_display->ctrl); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci return 0; 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ciint msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) 15148c2ecf20Sopenharmony_ci{ 15158c2ecf20Sopenharmony_ci int rc = 0; 15168c2ecf20Sopenharmony_ci u32 state; 15178c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci mutex_lock(&dp_display->event_mutex); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* stop sentinel checking */ 15248c2ecf20Sopenharmony_ci dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci dp_display_disable(dp_display, 0); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci rc = dp_display_unprepare(dp); 15298c2ecf20Sopenharmony_ci if (rc) 15308c2ecf20Sopenharmony_ci DRM_ERROR("DP display unprepare failed, rc=%d\n", rc); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci state = dp_display->hpd_state; 15338c2ecf20Sopenharmony_ci if (state == ST_DISCONNECT_PENDING) { 15348c2ecf20Sopenharmony_ci /* completed disconnection */ 15358c2ecf20Sopenharmony_ci dp_display->hpd_state = ST_DISCONNECTED; 15368c2ecf20Sopenharmony_ci } else { 15378c2ecf20Sopenharmony_ci dp_display->hpd_state = ST_DISPLAY_OFF; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci mutex_unlock(&dp_display->event_mutex); 15418c2ecf20Sopenharmony_ci return rc; 15428c2ecf20Sopenharmony_ci} 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_civoid msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, 15458c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 15468c2ecf20Sopenharmony_ci struct drm_display_mode *adjusted_mode) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct dp_display_private *dp_display; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci dp_display = container_of(dp, struct dp_display_private, dp_display); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode)); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci if (dp_display_check_video_test(dp)) 15558c2ecf20Sopenharmony_ci dp_display->dp_mode.bpp = dp_display_get_test_bpp(dp); 15568c2ecf20Sopenharmony_ci else /* Default num_components per pixel = 3 */ 15578c2ecf20Sopenharmony_ci dp_display->dp_mode.bpp = dp->connector->display_info.bpc * 3; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (!dp_display->dp_mode.bpp) 15608c2ecf20Sopenharmony_ci dp_display->dp_mode.bpp = 24; /* Default bpp */ 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci drm_mode_copy(&dp_display->dp_mode.drm_mode, adjusted_mode); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci dp_display->dp_mode.v_active_low = 15658c2ecf20Sopenharmony_ci !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NVSYNC); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci dp_display->dp_mode.h_active_low = 15688c2ecf20Sopenharmony_ci !!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC); 15698c2ecf20Sopenharmony_ci} 1570