Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16a6dc2a authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm: add HDCP 1x module for MSM DRM driver"

parents 92e373a7 02b2b76f
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ msm_drm-y := \
	hdmi/hdmi_connector.o \
	hdmi/hdmi_hdcp.o \
	hdmi/hdmi_i2c.o \
	hdmi/hdmi_util.o \
	hdmi/hdmi_phy_8960.o \
	hdmi/hdmi_phy_8x60.o \
	hdmi/hdmi_phy_8x74.o \
@@ -50,7 +51,8 @@ msm_drm-y := \
	sde_dbg_evtlog.o \
	sde_io_util.o \
	dba_bridge.o \
	sde_edid_parser.o
	sde_edid_parser.o \
	sde_hdcp_1x.o

# use drm gpu driver only if qcom_kgsl driver not available
ifneq ($(CONFIG_QCOM_KGSL),y)
@@ -101,6 +103,7 @@ msm_drm-$(CONFIG_DRM_MSM_DSI_STAGING) += dsi-staging/dsi_phy.o \
				dsi-staging/dsi_display_test.o

msm_drm-$(CONFIG_DRM_SDE_HDMI) += \
	hdmi-staging/sde_hdmi_util.o \
	hdmi-staging/sde_hdmi.o \
	hdmi-staging/sde_hdmi_bridge.o \
	hdmi-staging/sde_hdmi_audio.o \
+213 −82
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "msm_drv.h"
#include "sde_hdmi.h"
#include "sde_hdmi_regs.h"
#include "hdmi.h"

static DEFINE_MUTEX(sde_hdmi_list_lock);
static LIST_HEAD(sde_hdmi_list);
@@ -426,6 +427,118 @@ static u64 _sde_hdmi_clip_valid_pclk(struct drm_display_mode *mode, u64 pclk_in)
	return pclk_clip;
}

static void sde_hdmi_tx_hdcp_cb(void *ptr, enum sde_hdcp_states status)
{
	struct sde_hdmi *hdmi_ctrl = (struct sde_hdmi *)ptr;
	struct hdmi *hdmi;

	if (!hdmi_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return;
	}

	hdmi = hdmi_ctrl->ctrl.ctrl;
	hdmi_ctrl->hdcp_status = status;
	queue_delayed_work(hdmi->workq, &hdmi_ctrl->hdcp_cb_work, HZ/4);
}

void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl)
{

	if (!hdmi_ctrl) {
		SDE_ERROR("%s: invalid input\n", __func__);
		return;
	}

	if (hdmi_ctrl->hdcp_ops)
		hdmi_ctrl->hdcp_ops->off(hdmi_ctrl->hdcp_data);

	flush_delayed_work(&hdmi_ctrl->hdcp_cb_work);

	hdmi_ctrl->hdcp_ops = NULL;
}

static void sde_hdmi_tx_hdcp_cb_work(struct work_struct *work)
{
	struct sde_hdmi *hdmi_ctrl = NULL;
	struct delayed_work *dw = to_delayed_work(work);
	int rc = 0;
	struct hdmi *hdmi;

	hdmi_ctrl = container_of(dw, struct sde_hdmi, hdcp_cb_work);
	if (!hdmi_ctrl) {
		DEV_DBG("%s: invalid input\n", __func__);
		return;
	}

	hdmi = hdmi_ctrl->ctrl.ctrl;

	switch (hdmi_ctrl->hdcp_status) {
	case HDCP_STATE_AUTHENTICATED:
		hdmi_ctrl->auth_state = true;

		if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) &&
			sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
			rc = sde_hdmi_config_avmute(hdmi, false);
		}

		if (hdmi_ctrl->hdcp1_use_sw_keys &&
			hdmi_ctrl->hdcp14_present) {
			if (!hdmi_ctrl->hdcp22_present)
				hdcp1_set_enc(true);
		}
		break;
	case HDCP_STATE_AUTH_FAIL:
		if (hdmi_ctrl->hdcp1_use_sw_keys && hdmi_ctrl->hdcp14_present) {
			if (hdmi_ctrl->auth_state && !hdmi_ctrl->hdcp22_present)
				hdcp1_set_enc(false);
		}

		hdmi_ctrl->auth_state = false;

		if (sde_hdmi_tx_is_encryption_set(hdmi_ctrl) ||
			!sde_hdmi_tx_is_stream_shareable(hdmi_ctrl))
			rc = sde_hdmi_config_avmute(hdmi, true);

		if (sde_hdmi_tx_is_panel_on(hdmi_ctrl)) {
			pr_debug("%s: Reauthenticating\n", __func__);
			if (hdmi_ctrl->hdcp_ops && hdmi_ctrl->hdcp_data) {
				rc = hdmi_ctrl->hdcp_ops->reauthenticate(
					 hdmi_ctrl->hdcp_data);
				if (rc)
					pr_err("%s: HDCP reauth failed. rc=%d\n",
						   __func__, rc);
			} else
				pr_err("%s: NULL HDCP Ops and Data\n",
					   __func__);
		} else {
			pr_debug("%s: Not reauthenticating. Cable not conn\n",
					 __func__);
		}

		break;
	case HDCP_STATE_AUTH_ENC_NONE:
		hdmi_ctrl->enc_lvl = HDCP_STATE_AUTH_ENC_NONE;
		if (sde_hdmi_tx_is_panel_on(hdmi_ctrl))
			rc = sde_hdmi_config_avmute(hdmi, false);
		break;
	case HDCP_STATE_AUTH_ENC_1X:
	case HDCP_STATE_AUTH_ENC_2P2:
		hdmi_ctrl->enc_lvl = hdmi_ctrl->hdcp_status;

		if (sde_hdmi_tx_is_panel_on(hdmi_ctrl) &&
			sde_hdmi_tx_is_stream_shareable(hdmi_ctrl)) {
			rc = sde_hdmi_config_avmute(hdmi, false);
		} else {
			rc = sde_hdmi_config_avmute(hdmi, true);
		}
		break;
	default:
		break;
		/* do nothing */
	}
}

/**
 * _sde_hdmi_update_pll_delta() - Update the HDMI pixel clock as per input ppm
 *
@@ -920,6 +1033,12 @@ static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
	else
		cec_notifier_set_phys_addr(display->notifier,
			CEC_PHYS_ADDR_INVALID);

}

static void _sde_hdmi_init_ddc(struct sde_hdmi *display, struct hdmi *hdmi)
{
	display->ddc_ctrl.io = &display->io[HDMI_TX_CORE_IO];
}

static void _sde_hdmi_map_regs(struct sde_hdmi *display, struct hdmi *hdmi)
@@ -1023,8 +1142,14 @@ static irqreturn_t _sde_hdmi_irq(int irq, void *dev_id)
	hdmi_i2c_irq(hdmi->i2c);

	/* Process HDCP: */
	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_irq(hdmi->hdcp_ctrl);
	if (sde_hdmi->hdcp_ops && sde_hdmi->hdcp_data) {
		if (sde_hdmi->hdcp_ops->isr) {
			if (sde_hdmi->hdcp_ops->isr(
				sde_hdmi->hdcp_data))
				DEV_ERR("%s: hdcp_1x_isr failed\n",
						__func__);
		}
	}

	/* Process CEC: */
	_sde_hdmi_cec_irq(sde_hdmi);
@@ -1203,84 +1328,8 @@ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
			power_on ? "Enable" : "Disable", ctrl);
}

int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
					  u8 *data, u16 data_len)
{
	int rc;
	int retry = 5;
	struct i2c_msg msgs[] = {
		{
			.addr   = addr >> 1,
			.flags  = 0,
			.len    = 1,
			.buf    = &offset,
		}, {
			.addr   = addr >> 1,
			.flags  = I2C_M_RD,
			.len    = data_len,
			.buf    = data,
		}
	};

	SDE_HDMI_DEBUG("Start DDC read");
 retry:
	rc = i2c_transfer(hdmi->i2c, msgs, 2);

	retry--;
	if (rc == 2)
		rc = 0;
	else if (retry > 0)
		goto retry;
	else
		rc = -EIO;

	SDE_HDMI_DEBUG("End DDC read %d", rc);

	return rc;
}

#define DDC_WRITE_MAX_BYTE_NUM 32

int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
					   u8 *data, u16 data_len)
{
	int rc;
	int retry = 10;
	u8 buf[DDC_WRITE_MAX_BYTE_NUM];
	struct i2c_msg msgs[] = {
		{
			.addr   = addr >> 1,
			.flags  = 0,
			.len    = 1,
		}
	};

	SDE_HDMI_DEBUG("Start DDC write");
	if (data_len > (DDC_WRITE_MAX_BYTE_NUM - 1)) {
		SDE_ERROR("%s: write size too big\n", __func__);
		return -ERANGE;
	}

	buf[0] = offset;
	memcpy(&buf[1], data, data_len);
	msgs[0].buf = buf;
	msgs[0].len = data_len + 1;
 retry:
	rc = i2c_transfer(hdmi->i2c, msgs, 1);

	retry--;
	if (rc == 1)
		rc = 0;
	else if (retry > 0)
		goto retry;
	else
		rc = -EIO;

	SDE_HDMI_DEBUG("End DDC write %d", rc);

	return rc;
}

int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val)
{
	int rc = 0;
@@ -1337,7 +1386,8 @@ int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val)
		break;
	}

	rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len);
	rc = hdmi_ddc_read(hdmi, dev_addr, offset, data_buf,
					   data_len, true);
	if (rc) {
		SDE_ERROR("DDC Read failed for %d\n", data_type);
		return rc;
@@ -1409,8 +1459,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val)
		dev_addr = 0xA8;
		data_len = 1;
		offset = HDMI_SCDC_TMDS_CONFIG;
		rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, &read_val,
							   data_len);
		rc = hdmi_ddc_read(hdmi, dev_addr, offset, &read_val,
						   data_len, true);
		if (rc) {
			SDE_ERROR("scdc read failed\n");
			return rc;
@@ -1434,7 +1484,8 @@ int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val)
		return -EINVAL;
	}

	rc = sde_hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len);
	rc = hdmi_ddc_write(hdmi, dev_addr, offset, data_buf,
						data_len, true);
	if (rc) {
		SDE_ERROR("DDC Read failed for %d\n", data_type);
		return rc;
@@ -1631,6 +1682,50 @@ static int sde_hdmi_tx_check_capability(struct sde_hdmi *sde_hdmi)
	return ret;
} /* hdmi_tx_check_capability */

static int _sde_hdmi_init_hdcp(struct sde_hdmi *hdmi_ctrl)
{
	struct sde_hdcp_init_data hdcp_init_data;
	void *hdcp_data;
	int rc = 0;
	struct hdmi *hdmi;

	if (!hdmi_ctrl) {
		SDE_ERROR("sde_hdmi is NULL\n");
		return -EINVAL;
	}

	hdmi = hdmi_ctrl->ctrl.ctrl;
	hdcp_init_data.phy_addr      = hdmi->mmio_phy_addr;
	hdcp_init_data.core_io       = &hdmi_ctrl->io[HDMI_TX_CORE_IO];
	hdcp_init_data.qfprom_io     = &hdmi_ctrl->io[HDMI_TX_QFPROM_IO];
	hdcp_init_data.hdcp_io       = &hdmi_ctrl->io[HDMI_TX_HDCP_IO];
	hdcp_init_data.mutex         = &hdmi_ctrl->hdcp_mutex;
	hdcp_init_data.workq         = hdmi->workq;
	hdcp_init_data.notify_status = sde_hdmi_tx_hdcp_cb;
	hdcp_init_data.cb_data       = (void *)hdmi_ctrl;
	hdcp_init_data.hdmi_tx_ver   = hdmi_ctrl->hdmi_tx_major_version;
	hdcp_init_data.sec_access    = true;
	hdcp_init_data.client_id     = HDCP_CLIENT_HDMI;
	hdcp_init_data.ddc_ctrl      = &hdmi_ctrl->ddc_ctrl;

	if (hdmi_ctrl->hdcp14_present) {
		hdcp_data = sde_hdcp_1x_init(&hdcp_init_data);

		if (IS_ERR_OR_NULL(hdcp_data)) {
			DEV_ERR("%s: hdcp 1.4 init failed\n", __func__);
			rc = -EINVAL;
			kfree(hdcp_data);
			goto end;
		} else {
			hdmi_ctrl->hdcp_feature_data[SDE_HDCP_1x] = hdcp_data;
			SDE_HDMI_DEBUG("%s: HDCP 1.4 initialized\n", __func__);
		}
	}

end:
	return rc;
}

int sde_hdmi_connector_post_init(struct drm_connector *connector,
		void *info,
		void *display)
@@ -1664,7 +1759,36 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector,
		SDE_ERROR("failed to enable HPD: %d\n", rc);

	_sde_hdmi_get_tx_version(sde_hdmi);

	sde_hdmi_tx_check_capability(sde_hdmi);

	_sde_hdmi_init_hdcp(sde_hdmi);

	return rc;
}

int sde_hdmi_start_hdcp(struct drm_connector *connector)
{
	int rc;
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;
	struct hdmi *hdmi = display->ctrl.ctrl;

	if (!hdmi) {
		SDE_ERROR("%s: invalid input\n", __func__);
		return -EINVAL;
	}

	if (!sde_hdmi_tx_is_hdcp_enabled(display))
		return 0;

	if (sde_hdmi_tx_is_encryption_set(display))
		sde_hdmi_config_avmute(hdmi, true);

	rc = display->hdcp_ops->authenticate(display->hdcp_data);
	if (rc)
		SDE_ERROR("%s: hdcp auth failed. rc=%d\n", __func__, rc);

	return rc;
}

@@ -1781,6 +1905,9 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display)
		SDE_ERROR("Invalid params\n");
		return -EINVAL;
	}
	if (display->hdcp_feature_data[SDE_HDCP_1x])
		sde_hdcp_1x_deinit(display->hdcp_feature_data[SDE_HDCP_1x]);

	return 0;
}

@@ -1864,7 +1991,11 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
	display->drm_dev = drm;

	_sde_hdmi_map_regs(display, priv->hdmi);
	_sde_hdmi_init_ddc(display, priv->hdmi);

	INIT_DELAYED_WORK(&display->hdcp_cb_work,
					  sde_hdmi_tx_hdcp_cb_work);
	mutex_init(&display->hdcp_mutex);
	mutex_unlock(&display->display_lock);
	return rc;

+59 −27
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/of_device.h>
#include <linux/msm_ext_display.h>
#include <linux/hdcp_qseecom.h>

#include <drm/drmP.h>
#include <drm/drm_crtc.h>
@@ -29,6 +30,8 @@
#include "sde_connector.h"
#include "msm_drv.h"
#include "sde_edid_parser.h"
#include "sde_hdmi_util.h"
#include "sde_hdcp.h"

#ifdef HDMI_DEBUG_ENABLE
#define SDE_HDMI_DEBUG(fmt, args...)   SDE_ERROR(fmt, ##args)
@@ -82,6 +85,11 @@ enum hdmi_tx_io_type {
	HDMI_TX_MAX_IO
};

enum hdmi_tx_feature_type {
	SDE_HDCP_1x,
	SDE_HDCP_2P2
};

/**
 * struct sde_hdmi - hdmi display information
 * @pdev:             Pointer to platform device.
@@ -112,7 +120,7 @@ struct sde_hdmi {
	const char *display_type;
	struct list_head list;
	struct mutex display_lock;

	struct mutex hdcp_mutex;
	struct sde_hdmi_ctrl ctrl;

	struct platform_device *ext_pdev;
@@ -130,6 +138,18 @@ struct sde_hdmi {
	u32 max_pclk_khz;
	bool hdcp1_use_sw_keys;
	u32 hdcp14_present;
	u32 hdcp22_present;
	u8 hdcp_status;
	u32 enc_lvl;
	bool auth_state;
	/*hold final data
	 *based on hdcp support
	 */
	void *hdcp_data;
	/*hold hdcp init data*/
	void *hdcp_feature_data[2];
	struct sde_hdcp_ops *hdcp_ops;
	struct sde_hdmi_tx_ddc_ctrl ddc_ctrl;
	struct work_struct hpd_work;
	bool codec_ready;
	bool client_notify_pending;
@@ -137,6 +157,7 @@ struct sde_hdmi {
	struct irq_domain *irq_domain;
	struct cec_notifier *notifier;

	struct delayed_work hdcp_cb_work;
	struct dss_io_data io[HDMI_TX_MAX_IO];
	/* DEBUG FS */
	struct dentry *root;
@@ -337,32 +358,6 @@ struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi);
 */
void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on);

/**
 * sde_hdmi_ddc_read() - common hdmi ddc read API.
 * @hdmi:          Handle to the hdmi.
 * @addr:          Command address.
 * @offset:        Command offset.
 * @data:          Data buffer for read back.
 * @data_len:      Data buffer length.
 *
 * Return: error code.
 */
int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
					  u8 *data, u16 data_len);

/**
 * sde_hdmi_ddc_write() - common hdmi ddc write API.
 * @hdmi:          Handle to the hdmi.
 * @addr:          Command address.
 * @offset:        Command offset.
 * @data:          Data buffer for write.
 * @data_len:      Data buffer length.
 *
 * Return: error code.
 */
int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
					   u8 *data, u16 data_len);

/**
 * sde_hdmi_scdc_read() - hdmi 2.0 ddc read API.
 * @hdmi:          Handle to the hdmi.
@@ -429,6 +424,13 @@ void sde_hdmi_notify_clients(struct sde_hdmi *display, bool connected);
void sde_hdmi_ack_state(struct drm_connector *connector,
	enum drm_connector_status status);

bool sde_hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl);
bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl);
int sde_hdmi_start_hdcp(struct drm_connector *connector);
void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl);

#else /*#ifdef CONFIG_DRM_SDE_HDMI*/

static inline u32 sde_hdmi_get_num_of_displays(void)
@@ -487,12 +489,42 @@ static inline int sde_hdmi_dev_deinit(struct sde_hdmi *display)
	return 0;
}

bool hdmi_tx_is_hdcp_enabled(struct sde_hdmi *hdmi_ctrl)
{
	return false;
}

bool sde_hdmi_tx_is_encryption_set(struct sde_hdmi *hdmi_ctrl)
{
	return false;
}

bool sde_hdmi_tx_is_stream_shareable(struct sde_hdmi *hdmi_ctrl)
{
	return false;
}

bool sde_hdmi_tx_is_panel_on(struct sde_hdmi *hdmi_ctrl)
{
	return false;
}

static inline int sde_hdmi_drm_init(struct sde_hdmi *display,
				struct drm_encoder *enc)
{
	return 0;
}

int sde_hdmi_start_hdcp(struct drm_connector *connector)
{
	return 0;
}

void sde_hdmi_hdcp_off(struct sde_hdmi *hdmi_ctrl)
{

}

static inline int sde_hdmi_drm_deinit(struct sde_hdmi *display)
{
	return 0;
+0 −34
Original line number Diff line number Diff line
@@ -355,37 +355,3 @@ void sde_hdmi_audio_off(struct hdmi *hdmi)
	SDE_DEBUG("HDMI Audio: Disabled\n");
}
int sde_hdmi_config_avmute(struct hdmi *hdmi, bool set)
{
	u32 av_mute_status;
	bool av_pkt_en = false;

	if (!hdmi) {
		SDE_ERROR("invalid HDMI Ctrl\n");
		return -ENODEV;
	}

	av_mute_status = hdmi_read(hdmi, HDMI_GC);

	if (set) {
		if (!(av_mute_status & BIT(0))) {
			hdmi_write(hdmi, HDMI_GC, av_mute_status | BIT(0));
			av_pkt_en = true;
		}
	} else {
		if (av_mute_status & BIT(0)) {
			hdmi_write(hdmi, HDMI_GC, av_mute_status & ~BIT(0));
			av_pkt_en = true;
		}
	}

	/* Enable AV Mute tranmission here */
	if (av_pkt_en)
		hdmi_write(hdmi, HDMI_VBI_PKT_CTRL,
			hdmi_read(hdmi, HDMI_VBI_PKT_CTRL) | (BIT(4) & BIT(5)));

	SDE_DEBUG("AVMUTE %s\n", set ? "set" : "cleared");

	return 0;
}
+39 −2
Original line number Diff line number Diff line
@@ -396,8 +396,45 @@ static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
	mutex_unlock(&display->display_lock);
}

static void sde_hdmi_update_hdcp_info(struct drm_connector *connector)
{
	void *fd = NULL;
	struct sde_hdcp_ops *ops = NULL;
	struct sde_connector *c_conn = to_sde_connector(connector);
	struct sde_hdmi *display = (struct sde_hdmi *)c_conn->display;

	if (!display) {
		DEV_ERR("%s: invalid input\n", __func__);
		return;
	}

	if (!display->hdcp22_present) {
		if (display->hdcp1_use_sw_keys) {
			display->hdcp14_present =
				hdcp1_check_if_supported_load_app();
		}
		if (display->hdcp14_present) {
			fd = display->hdcp_feature_data[SDE_HDCP_1x];
			if (fd)
				ops = sde_hdcp_1x_start(fd);
		}
	}

	/* update internal data about hdcp */
	display->hdcp_data = fd;
	display->hdcp_ops = ops;
}

static void _sde_hdmi_bridge_enable(struct drm_bridge *bridge)
{
	struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
	struct hdmi *hdmi = sde_hdmi_bridge->hdmi;

	/* need to update hdcp info here to ensure right HDCP support*/
	sde_hdmi_update_hdcp_info(hdmi->connector);

	/* start HDCP authentication */
	sde_hdmi_start_hdcp(hdmi->connector);
}

static void _sde_hdmi_bridge_disable(struct drm_bridge *bridge)
@@ -414,8 +451,8 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)

	sde_hdmi_notify_clients(display, display->connected);

	if (hdmi->hdcp_ctrl && hdmi->is_hdcp_supported)
		hdmi_hdcp_ctrl_off(hdmi->hdcp_ctrl);
	if (sde_hdmi_tx_is_hdcp_enabled(display))
		sde_hdmi_hdcp_off(display);

	sde_hdmi_audio_off(hdmi);

Loading