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

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

Merge "msm: mdss: hdmi: add hardware ddc rxstatus support"

parents d9969ed9 f721c9d8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
#define __MDSS_HDMI_HDCP_H__

#include "mdss_hdmi_util.h"
#include <video/msm_hdmi_modes.h>
#include <soc/qcom/scm.h>

enum hdmi_hdcp_state {
@@ -35,6 +36,7 @@ struct hdmi_hdcp_init_data {
	struct hdmi_tx_ddc_ctrl *ddc_ctrl;
	u32 phy_addr;
	u32 hdmi_tx_ver;
	struct msm_hdmi_mode_timing_info *timing;
};

struct hdmi_hdcp_ops {
+55 −34
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ struct hdcp2p2_ctrl {
	bool hdcp_txmtr_init; /* Has the HDCP TZ transmitter been initialized */
	struct hdcp_txmtr_ops *txmtr_ops; /* Ops for driver to call into TZ */
	struct hdcp_client_ops *client_ops; /* Ops for driver to export to TZ */
	struct completion rxstatus_completion; /* Rx status interrupt */
};

static int hdcp2p2_authenticate(void *input);
@@ -324,50 +325,51 @@ static int hdcp2p2_read_version(struct hdcp2p2_ctrl *hdcp2p2_ctrl,

/**
 * Work item that polls the sink for an incoming message.
 * Since messages from sink during auth are always in response to messages
 * sent by TX, we know when to expect sink messages, and thus polling is
 * required by the HDCP 2.2 spec
 */
static void hdcp2p2_sink_message_work(struct work_struct *work)
{
	struct hdcp2p2_ctrl *hdcp2p2_ctrl = container_of(work,
			struct hdcp2p2_ctrl, hdcp_sink_message_work);
	struct hdmi_tx_ddc_data ddc_data;
	struct hdmi_tx_hdcp2p2_ddc_data hdcp2p2_ddc_data;
	int rc;
	u16 rx_status;
	int msg_size;
	int wait_cycles = 50; /* 50 20 ms cycles of wait = 1 second total */

	do {
		memset(&ddc_data, 0, sizeof(ddc_data));
		ddc_data.dev_addr = HDCP_SINK_DDC_SLAVE_ADDR;
		ddc_data.offset = HDCP_SINK_DDC_HDCP2_RXSTATUS;
		ddc_data.data_buf = (u8 *)&rx_status;
		ddc_data.data_len = 2;
		ddc_data.request_len = 2;
		ddc_data.retry = 1;
		ddc_data.what = "HDCP2RxStatus";
	u64 mult;
	u64 div;
	struct msm_hdmi_mode_timing_info *timing;

		rc = hdmi_ddc_read(hdcp2p2_ctrl->init_data.ddc_ctrl, &ddc_data);
		if (rc) {
			DEV_ERR("%s: Error %d in read HDCP RX status register",
					__func__, rc);
	if (!hdcp2p2_ctrl) {
		DEV_ERR("%s: invalid hdcp2p2 data\n", __func__);
		return;
	}

		msg_size = rx_status & 0x3FF;
		if (msg_size) {
			DEV_DBG("%s: Message available at sink, size %d\n",
					__func__, msg_size);
			break;
		}

		msleep(20);
	timing = hdcp2p2_ctrl->init_data.timing;

	} while (--wait_cycles);
	/* calculate number of lines sent in 10ms */
	mult = 10000 * ((u64)timing->pixel_freq * 1000);
	div = hdmi_tx_get_v_total(timing) * 1000000;
	if (div)
		do_div(mult, div);
	else
		mult = 0;

	memset(&hdcp2p2_ddc_data, 0, sizeof(hdcp2p2_ddc_data));
	hdcp2p2_ddc_data.ddc_data.what = "HDCP2RxStatus";
	hdcp2p2_ddc_data.ddc_data.data_buf = (u8 *)&msg_size;
	hdcp2p2_ddc_data.ddc_data.data_len = sizeof(msg_size);
	hdcp2p2_ddc_data.rxstatus_field = RXSTATUS_MESSAGE_SIZE;
	hdcp2p2_ddc_data.timer_delay_lines = (u32)mult;
	hdcp2p2_ddc_data.irq_wait_count = 100;
	hdcp2p2_ddc_data.poll_sink = false;

	hdmi_ddc_config(hdcp2p2_ctrl->init_data.ddc_ctrl);
	DEV_DBG("%s: Reading rxstatus, timer delay lines %u\n", __func__,
								(u32)mult);
	rc = hdmi_hdcp2p2_ddc_read_rxstatus(hdcp2p2_ctrl->init_data.ddc_ctrl,
				&hdcp2p2_ddc_data,
				&hdcp2p2_ctrl->rxstatus_completion);

	if (!wait_cycles) {
		DEV_ERR("%s: Timeout in waiting for sink\n", __func__);
	if (rc) {
		DEV_ERR("%s: Could not read rxstatus from sink\n", __func__);
		goto error;
	} else {
		/* Read message from sink now */
@@ -378,6 +380,7 @@ static void hdcp2p2_sink_message_work(struct work_struct *work)
			DEV_ERR("%s: Could not allocate memory\n", __func__);
			goto error;
		}

		message->message_bytes = kmalloc(msg_size, GFP_KERNEL);
		if (!message->message_bytes) {
			DEV_ERR("%s: Could not allocate memory\n", __func__);
@@ -409,6 +412,11 @@ static void hdcp2p2_tz_message_work(struct work_struct *work)
	struct list_head *prev, *next;
	struct hdcp2p2_message *msg;

	if (!hdcp2p2_ctrl) {
		DEV_ERR("%s: invalid hdcp2p2 data\n", __func__);
		return;
	}

	mutex_lock(&hdcp2p2_ctrl->mutex);
	if (list_empty(&hdcp2p2_ctrl->hdcp_sink_messages)) {
		DEV_ERR("%s: No message is available from sink\n", __func__);
@@ -497,6 +505,8 @@ static int hdcp2p2_isr(void *input)
		return -EINVAL;
	}

	DEV_DBG("%s\n INT_CTRL0 is 0x%x\n", __func__,
		DSS_REG_R(hdcp2p2_ctrl->init_data.core_io, HDMI_DDC_INT_CTRL0));
	reg_val = DSS_REG_R(hdcp2p2_ctrl->init_data.core_io,
			HDMI_HDCP_INT_CTRL2);
	if (reg_val & BIT(0)) {
@@ -505,6 +515,15 @@ static int hdcp2p2_isr(void *input)
		DSS_REG_W(hdcp2p2_ctrl->init_data.core_io, HDMI_HDCP_INT_CTRL2,
			reg_val);
	}

	reg_val = DSS_REG_R(hdcp2p2_ctrl->init_data.core_io,
							HDMI_DDC_INT_CTRL0);
	if (reg_val & HDCP2P2_RXSTATUS_MESSAGE_SIZE_MASK) {
		DSS_REG_W(hdcp2p2_ctrl->init_data.core_io, HDMI_DDC_INT_CTRL0,
						reg_val & ~(BIT(31)));
		complete(&hdcp2p2_ctrl->rxstatus_completion);
	}

	return 0;
}

@@ -630,6 +649,7 @@ static int hdcp2p2_send_message_to_sink(void *client_ctx, void *hdcp_handle,
		return rc;
	}

	DEV_DBG("%s: Polling sink for next message\n", __func__);
	/* Start polling sink for the next expected message in the protocol */
	if (!authenticated)
		schedule_work(&hdcp2p2_ctrl->hdcp_sink_message_work);
@@ -739,7 +759,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
	}

	if (init_data->hdmi_tx_ver < MIN_HDMI_TX_MAJOR_VERSION) {
		DEV_DBG("%s: HDMI Tx does not support HDCP 2.2\n", __func__);
		DEV_ERR("%s: HDMI Tx does not support HDCP 2.2\n", __func__);
		return ERR_PTR(-ENODEV);
	}

@@ -765,6 +785,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data)
	INIT_WORK(&hdcp2p2_ctrl->hdcp_tz_message_work,
			hdcp2p2_tz_message_work);
	INIT_LIST_HEAD(&hdcp2p2_ctrl->hdcp_sink_messages);
	init_completion(&hdcp2p2_ctrl->rxstatus_completion);

	hdcp2p2_ctrl->sink_status = SINK_DISCONNECTED;

+1 −0
Original line number Diff line number Diff line
@@ -1285,6 +1285,7 @@ static int hdmi_tx_init_features(struct hdmi_tx_ctrl *hdmi_ctrl)
	hdcp_init_data.notify_status = hdmi_tx_hdcp_cb;
	hdcp_init_data.cb_data = (void *)hdmi_ctrl;
	hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_ver;
	hdcp_init_data.timing = &hdmi_ctrl->vid_cfg.timing;

	/*
	 * Try to initialize both HDCP 1.4 and 2.2 features, decide which one
+236 −0
Original line number Diff line number Diff line
@@ -1345,3 +1345,239 @@ int hdmi_setup_ddc_timers(struct hdmi_tx_ddc_ctrl *ctrl,

	return 0;
}

void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl)
{
	u32 reg_val;

	if (!ctrl) {
		DEV_ERR("%s: Invalid parameters\n", __func__);
		return;
	}

	/*
	 * Clear acks for DDC_REQ, DDC_DONE, DDC_FAILED, RXSTATUS_READY,
	 * RXSTATUS_MSG_SIZE
	 */
	reg_val = BIT(30) | BIT(17) | BIT(13) | BIT(9) | BIT(5) | BIT(1);
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val);

	/* Reset DDC timers */
	reg_val = BIT(0) | DSS_REG_R(ctrl->io, HDMI_HDCP2P2_DDC_CTRL);
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_CTRL, reg_val);
	reg_val = DSS_REG_R(ctrl->io, HDMI_HDCP2P2_DDC_CTRL);
	reg_val &= ~BIT(0);
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_CTRL, reg_val);
}

void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl)
{
	u32 reg_val;
	u32 retry_read = 100;
	bool ddc_hw_not_ready;

	if (!ctrl) {
		DEV_ERR("%s: Invalid parameters\n", __func__);
		return;
	}

	/* Clear RXSTATUS_DDC_DONE interrupt */
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, BIT(5));
	ddc_hw_not_ready = true;

	/* Make sure the interrupt is clear */
	do {
		reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0);
		ddc_hw_not_ready = reg_val & BIT(5);
		if (ddc_hw_not_ready)
			msleep(20);
	} while (ddc_hw_not_ready && --retry_read);

	/* Disable HW DDC access to RxStatus register */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL);
	reg_val &= ~(BIT(1) | BIT(0));
	DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val);
}

int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl,
	struct hdmi_tx_hdcp2p2_ddc_data *hdcp2p2_ddc_data,
	struct completion *rxstatus_completion)
{
	u32 reg_val;
	u32 reg_field_shift;
	u32 reg_field_mask;
	u32 reg_intr_ack_shift;
	u32 reg_intr_mask_shift;
	u32 timeout;
	u32 rxstatus_read_method;
	u32 rxstatus_bytes;
	bool poll_sink;

	if (!hdcp2p2_ddc_data)
		return -EINVAL;

	/* We return a u32 for all RxStatus bits being read */
	if (hdcp2p2_ddc_data->ddc_data.data_len < sizeof(u32))
		return -EINVAL;

	poll_sink = hdcp2p2_ddc_data->poll_sink;

	/*
	 * Setup shifts and masks based on which RxStatus bits we are dealing
	 * with in this call
	 */
	switch (hdcp2p2_ddc_data->rxstatus_field) {
	case RXSTATUS_MESSAGE_SIZE:
		reg_field_shift = HDCP2P2_RXSTATUS_MESSAGE_SIZE_SHIFT;
		reg_field_mask = HDCP2P2_RXSTATUS_MESSAGE_SIZE_MASK;
		reg_intr_ack_shift =
			HDCP2P2_RXSTATUS_MESSAGE_SIZE_ACK_SHIFT;
		reg_intr_mask_shift =
			HDCP2P2_RXSTATUS_MESSAGE_SIZE_INTR_SHIFT;
		break;
	case RXSTATUS_REAUTH_REQ:
		reg_field_shift = HDCP2P2_RXSTATUS_REAUTH_REQ_SHIFT;
		reg_field_mask = HDCP2P2_RXSTATUS_REAUTH_REQ_MASK;
		reg_intr_ack_shift =
			HDCP2P2_RXSTATUS_REAUTH_REQ_ACK_SHIFT;
		reg_intr_mask_shift =
			HDCP2P2_RXSTATUS_REAUTH_REQ_INTR_SHIFT;
		break;
	case RXSTATUS_READY:
		reg_field_shift = HDCP2P2_RXSTATUS_READY_SHIFT;
		reg_field_mask = HDCP2P2_RXSTATUS_READY_MASK;
		reg_intr_ack_shift =
			HDCP2P2_RXSTATUS_READY_ACK_SHIFT;
		reg_intr_mask_shift =
			HDCP2P2_RXSTATUS_READY_INTR_SHIFT;
		break;
	default:
		return -EINVAL;
	}

	DEV_DBG("%s: Requested msg size, shift %u mask %u ack %u mask %u\n",
			__func__, reg_field_shift, reg_field_mask,
			reg_intr_ack_shift, reg_intr_mask_shift);
	/* Disable short read for now, sinks don't support it */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HDCP2P2_DDC_CTRL);
	reg_val |= BIT(4);
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_CTRL, reg_val);

	/* Clear interrupt status bits */
	reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0);
	reg_val &= ~BIT(reg_intr_ack_shift);
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val);

	/*
	 * Setup the DDC timers for HDMI_HDCP2P2_DDC_TIMER_CTRL1 and
	 *  HDMI_HDCP2P2_DDC_TIMER_CTRL2.
	 * Following are the timers:
	 * 1. DDC_REQUEST_TIMER: Timeout in hsyncs in which to wait for the
	 *	HDCP 2.2 sink to respond to an RxStatus request
	 * 2. DDC_URGENT_TIMER: Time period in hsyncs to issue an urgent flag
	 *	when an RxStatus DDC request is made but not accepted by I2C
	 *	engine
	 * 3. DDC_TIMEOUT_TIMER: Timeout in hsyncs which starts counting when
	 *	a request is made and stops when it is accepted by DDC arbiter
	 */
	timeout = hdcp2p2_ddc_data->timer_delay_lines & 0xffff;
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL, timeout);
	/* Set both urgent and hw-timeout fields to the same value */
	DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_TIMER_CTRL2,
			(timeout << 16 | timeout));

	/* Enable the interrupt for the requested field, and enable timeouts */
	reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0);
	reg_val |= BIT(reg_intr_mask_shift);
	reg_val |= BIT(HDCP2P2_RXSTATUS_DDC_FAILED_INTR_MASK);
	DEV_DBG("%s: Enabling interrupts for req field\n", __func__);
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val);

	/*
	 * Enable hardware DDC access to RxStatus register
	 *
	 * HDMI_HW_DDC_CTRL:Bits 1:0 (RXSTATUS_DDC_ENABLE) read like this:
	 *
	 * 0 = disable HW controlled DDC access to RxStatus
	 * 1 = automatic on when HDCP 2.2 is authenticated and loop based on
	 * request timer (i.e. the hardware will loop automatically)
	 * 2 = force on and loop based on request timer (hardware will loop)
	 * 3 = enable by sw trigger and loop until interrupt is generated for
	 * RxStatus.reauth_req, RxStatus.ready or RxStatus.message_Size.
	 *
	 * Depending on the value of ddc_data::poll_sink, we make the decision
	 * to use either SW_TRIGGER(3) (poll_sink = false) which means that the
	 * hardware will poll sink and generate interrupt when sink responds,
	 * or use AUTOMATIC_LOOP(1) (poll_sink = true) which will poll the sink
	 * based on request timer
	 */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL);
	reg_val &= ~(BIT(1) | BIT(0));

	rxstatus_read_method =
		poll_sink ? HDCP2P2_RXSTATUS_HW_DDC_AUTOMATIC_LOOP
			  : HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER;

	if (poll_sink)
		reg_val |= BIT(0);
	else
		reg_val |= (BIT(1) | BIT(0));

	DEV_DBG("%s: Enabling hardware access to rxstatus\n", __func__);
	DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val);

	if (rxstatus_read_method == HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER) {
		/* If we are using SW_TRIGGER, then go ahead and trigger it */
		DSS_REG_W(ctrl->io, HDMI_HDCP2P2_DDC_SW_TRIGGER, 1);

		/*
		 * Now wait for interrupt bits to be set to indicate that the
		 * register is available to read
		 */
		DEV_DBG("%s: HDMI_DDC_INT_CTRL0 is 0x%x, waiting for ISR\n",
			__func__, DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0));
		if (!wait_for_completion_timeout(rxstatus_completion,
						msecs_to_jiffies(200))) {
			DEV_ERR("%s: Timeout in waiting for interrupt\n",
					__func__);
			return -ETIMEDOUT;
		}
	}

	/* Make sure no errors occurred during DDC transaction */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HDCP2P2_DDC_STATUS);

	/* Check for NACK0, NACK1, TIMEOUT, ABORT bits */
	reg_val &= (BIT(12) | BIT(14) | BIT(4) | BIT(8));

	if (reg_val) {
		DEV_ERR("%s: DDC transaction error\n", __func__);
		return -EIO;
	}

	/* Read the RxStatus field that was requested */
	reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0);
	rxstatus_bytes = reg_val;
	rxstatus_bytes &= reg_field_mask;
	rxstatus_bytes >>= reg_field_shift;
	memcpy(hdcp2p2_ddc_data->ddc_data.data_buf,
			&rxstatus_bytes, sizeof(rxstatus_bytes));

	/* Read the RxStatus field that was requested */
	/* Write the interrupt ack back */
	reg_val |= BIT(reg_intr_ack_shift);
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val);

	/* Clear the ack bits and the DDC_FAILED bit next */
	reg_val = DSS_REG_R(ctrl->io, HDMI_DDC_INT_CTRL0);
	reg_val &= ~BIT(reg_intr_ack_shift);
	reg_val &= ~BIT(HDCP2P2_RXSTATUS_DDC_FAILED_INTR_MASK);
	DSS_REG_W(ctrl->io, HDMI_DDC_INT_CTRL0, reg_val);

	/* Disable hardware access to RxStatus register */
	reg_val = DSS_REG_R(ctrl->io, HDMI_HW_DDC_CTRL);
	reg_val &= ~(BIT(1) | BIT(0));
	DSS_REG_W(ctrl->io, HDMI_HW_DDC_CTRL, reg_val);

	return 0;
}
+86 −0
Original line number Diff line number Diff line
@@ -220,6 +220,10 @@
#define HDMI_DDC_INT_CTRL3               (0x0000043C)
#define HDMI_DDC_INT_CTRL4               (0x00000440)
#define HDMI_DDC_INT_CTRL5               (0x00000444)
#define HDMI_HDCP2P2_DDC_CTRL            (0x0000044C)
#define HDMI_HDCP2P2_DDC_TIMER_CTRL      (0x00000450)
#define HDMI_HDCP2P2_DDC_TIMER_CTRL2     (0x00000454)
#define HDMI_HDCP2P2_DDC_STATUS          (0x00000458)
#define HDMI_SCRAMBLER_STATUS_DDC_CTRL   (0x00000464)
#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL    (0x00000468)
#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2   (0x0000046C)
@@ -227,6 +231,7 @@
#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS  (0x00000474)
#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS2 (0x00000478)
#define HDMI_HW_DDC_CTRL                 (0x000004CC)
#define HDMI_HDCP2P2_DDC_SW_TRIGGER      (0x000004D0)
#define HDMI_HDCP_STATUS                 (0x00000500)
#define HDMI_HDCP_INT_CTRL2              (0x00000504)

@@ -297,6 +302,67 @@
#define HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL       (0x00000024)
#define HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA       (0x00000028)

/*
 * Offsets in HDMI_DDC_INT_CTRL0 register
 *
 * The HDMI_DDC_INT_CTRL0 register is intended for HDCP 2.2 RxStatus
 * register manipulation. It reads like this:
 *
 * Bit 31: RXSTATUS_MESSAGE_SIZE_MASK (1 = generate interrupt when size > 0)
 * Bit 30: RXSTATUS_MESSAGE_SIZE_ACK  (1 = Acknowledge message size intr)
 * Bits 29-20: RXSTATUS_MESSAGE_SIZE  (Actual size of message available)
 * Bits 19-18: RXSTATUS_READY_MASK    (1 = generate interrupt when ready = 1
 *				       2 = generate interrupt when ready = 0)
 * Bit 17: RXSTATUS_READY_ACK         (1 = Acknowledge ready bit interrupt)
 * Bit 16: RXSTATUS_READY	      (1 = Rxstatus ready bit read is 1)
 * Bit 15: RXSTATUS_READY_NOT         (1 = Rxstatus ready bit read is 0)
 * Bit 14: RXSTATUS_REAUTH_REQ_MASK   (1 = generate interrupt when reauth is
 *					   requested by sink)
 * Bit 13: RXSTATUS_REAUTH_REQ_ACK    (1 = Acknowledge Reauth req interrupt)
 * Bit 12: RXSTATUS_REAUTH_REQ        (1 = Rxstatus reauth req bit read is 1)
 * Bit 10: RXSTATUS_DDC_FAILED_MASK   (1 = generate interrupt when DDC
 *					   tranasaction fails)
 * Bit 9:  RXSTATUS_DDC_FAILED_ACK    (1 = Acknowledge ddc failure interrupt)
 * Bit 8:  RXSTATUS_DDC_FAILED	      (1 = DDC transaction failed)
 * Bit 6:  RXSTATUS_DDC_DONE_MASK     (1 = generate interrupt when DDC
 *					   transaction completes)
 * Bit 5:  RXSTATUS_DDC_DONE_ACK      (1 = Acknowledge ddc done interrupt)
 * Bit 4:  RXSTATUS_DDC_DONE	      (1 = DDC transaction is done)
 * Bit 2:  RXSTATUS_DDC_REQ_MASK      (1 = generate interrupt when DDC Read
 *					   request for RXstatus is made)
 * Bit 1:  RXSTATUS_DDC_REQ_ACK       (1 = Acknowledge Rxstatus read interrupt)
 * Bit 0:  RXSTATUS_DDC_REQ           (1 = RXStatus DDC read request is made)
 *
 */
#define HDCP2P2_RXSTATUS_MESSAGE_SIZE_SHIFT         20
#define HDCP2P2_RXSTATUS_MESSAGE_SIZE_MASK          0x3ff00000
#define HDCP2P2_RXSTATUS_MESSAGE_SIZE_ACK_SHIFT     30
#define HDCP2P2_RXSTATUS_MESSAGE_SIZE_INTR_SHIFT    31

#define HDCP2P2_RXSTATUS_REAUTH_REQ_SHIFT           12
#define HDCP2P2_RXSTATUS_REAUTH_REQ_MASK             1
#define HDCP2P2_RXSTATUS_REAUTH_REQ_ACK_SHIFT	    13
#define HDCP2P2_RXSTATUS_REAUTH_REQ_INTR_SHIFT	    14

#define HDCP2P2_RXSTATUS_READY_SHIFT		    16
#define HDCP2P2_RXSTATUS_READY_MASK                  1
#define HDCP2P2_RXSTATUS_READY_ACK_SHIFT            17
#define HDCP2P2_RXSTATUS_READY_INTR_SHIFT           18
#define HDCP2P2_RXSTATUS_READY_INTR_MASK            18

#define HDCP2P2_RXSTATUS_DDC_FAILED_SHIFT           8
#define HDCP2P2_RXSTATUS_DDC_FAILED_ACKSHIFT        9
#define HDCP2P2_RXSTATUS_DDC_FAILED_INTR_MASK       10

/*
 * Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be
 * read by the hardware
 */
#define HDCP2P2_RXSTATUS_HW_DDC_DISABLE             0
#define HDCP2P2_RXSTATUS_HW_DDC_AUTOMATIC_LOOP      1
#define HDCP2P2_RXSTATUS_HW_DDC_FORCE_LOOP          2
#define HDCP2P2_RXSTATUS_HW_DDC_SW_TRIGGER          3

enum hdmi_tx_feature_type {
	HDMI_TX_FEAT_EDID,
	HDMI_TX_FEAT_HDCP,
@@ -345,6 +411,21 @@ struct hdmi_tx_ddc_data {
	int retry;
};

enum hdmi_tx_hdcp2p2_rxstatus_field {
	RXSTATUS_MESSAGE_SIZE,
	RXSTATUS_REAUTH_REQ,
	RXSTATUS_READY,
};

struct hdmi_tx_hdcp2p2_ddc_data {
	struct hdmi_tx_ddc_data ddc_data;
	enum hdmi_tx_hdcp2p2_rxstatus_field rxstatus_field;
	u32 timer_delay_lines;
	bool poll_sink;
	int irq_wait_count;
};


struct hdmi_util_ds_data {
	bool ds_registered;
	u32 ds_max_clk;
@@ -396,5 +477,10 @@ int hdmi_scdc_read(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 *val);
int hdmi_scdc_write(struct hdmi_tx_ddc_ctrl *ctrl, u32 data_type, u32 val);
int hdmi_setup_ddc_timers(struct hdmi_tx_ddc_ctrl *ctrl,
			  u32 type, u32 to_in_num_lines);
void hdmi_hdcp2p2_ddc_reset(struct hdmi_tx_ddc_ctrl *ctrl);
void hdmi_hdcp2p2_ddc_disable(struct hdmi_tx_ddc_ctrl *ctrl);
int hdmi_hdcp2p2_ddc_read_rxstatus(struct hdmi_tx_ddc_ctrl *ctrl,
	struct hdmi_tx_hdcp2p2_ddc_data *hdcp2p2_ddc_data,
	struct completion *rxstatus_completion);

#endif /* __HDMI_UTIL_H__ */