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