msm: mdss: hdmi: add hardware ddc rxstatus support

Support reading rxstatus through hardware interrupts.
Reading rxstatus through hardware allows locality
deadlines to be enforced.

Change-Id: Ic56b3e5c27f2410c7b060a6d5c7c88e0770dc16b
Signed-off-by: Alhad Purnapatre <alhadp@codeaurora.org>
Signed-off-by: Casey Piper <cpiper@codeaurora.org>
This commit is contained in:
Casey Piper 2015-07-02 10:39:36 -07:00 committed by David Keitel
parent 00ebebb0e9
commit bbdb824e97
5 changed files with 378 additions and 32 deletions

View file

@ -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 {

View file

@ -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 */
u64 mult;
u64 div;
struct msm_hdmi_mode_timing_info *timing;
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";
if (!hdcp2p2_ctrl) {
DEV_ERR("%s: invalid hdcp2p2 data\n", __func__);
return;
}
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);
return;
}
timing = hdcp2p2_ctrl->init_data.timing;
msg_size = rx_status & 0x3FF;
if (msg_size) {
DEV_DBG("%s: Message available at sink, size %d\n",
__func__, msg_size);
break;
}
/* 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;
msleep(20);
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;
} while (--wait_cycles);
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;

View file

@ -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

View file

@ -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;
}

View file

@ -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__ */