msm: mdss: add support for hdcp 1.x interrupt handler
Make hdcp 1.x interrupt handling generic for any supported interface. Add Display-Port interrupt related data and handle interrupts in ISR. Do this dynamically based on which interface is connected like HDMI or DP. Change-Id: I8be206dbc53fd7c757f244dc544241f1d8e1dd1c Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
This commit is contained in:
parent
13c3a0f640
commit
85b28aea37
2 changed files with 131 additions and 39 deletions
|
@ -111,6 +111,8 @@
|
|||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
|
||||
|
||||
#define DP_INTERRUPT_STATUS_2 (0x024)
|
||||
|
||||
struct lane_mapping {
|
||||
char lane0;
|
||||
char lane1;
|
||||
|
|
|
@ -38,13 +38,14 @@
|
|||
#define HDCP_REG_ENABLE 0x01
|
||||
#define HDCP_REG_DISABLE 0x00
|
||||
|
||||
#define HDCP_INT_CLR (BIT(1) | BIT(5) | BIT(7) | BIT(9) | BIT(13))
|
||||
#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \
|
||||
isr->auth_fail_info_ack | isr->tx_req_ack | \
|
||||
isr->encryption_ready_ack | \
|
||||
isr->encryption_not_ready | isr->tx_req_done_ack)
|
||||
|
||||
#define HDMI_AUTH_SUCCESS_ACK BIT(1)
|
||||
#define HDMI_AUTH_SUCCESS_MASK BIT(2)
|
||||
#define HDMI_AUTH_FAIL_ACK BIT(5)
|
||||
#define HDMI_AUTH_FAIL_MASK BIT(6)
|
||||
#define HDMI_AUTH_FAIL_INFO_ACK BIT(7)
|
||||
#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \
|
||||
isr->encryption_ready_mask | \
|
||||
isr->encryption_not_ready_mask)
|
||||
|
||||
#define HDCP_POLL_SLEEP_US (20 * 1000)
|
||||
#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 1000)
|
||||
|
@ -83,6 +84,36 @@ struct hdcp_sink_addr_map {
|
|||
struct hdcp_sink_addr rep;
|
||||
};
|
||||
|
||||
struct hdcp_int_set {
|
||||
/* interrupt register */
|
||||
u32 int_reg;
|
||||
|
||||
/* interrupt enable/disable masks */
|
||||
u32 auth_success_mask;
|
||||
u32 auth_fail_mask;
|
||||
u32 encryption_ready_mask;
|
||||
u32 encryption_not_ready_mask;
|
||||
u32 tx_req_mask;
|
||||
u32 tx_req_done_mask;
|
||||
|
||||
/* interrupt acknowledgment */
|
||||
u32 auth_success_ack;
|
||||
u32 auth_fail_ack;
|
||||
u32 auth_fail_info_ack;
|
||||
u32 encryption_ready_ack;
|
||||
u32 encryption_not_ready_ack;
|
||||
u32 tx_req_ack;
|
||||
u32 tx_req_done_ack;
|
||||
|
||||
/* interrupt status */
|
||||
u32 auth_success_int;
|
||||
u32 auth_fail_int;
|
||||
u32 encryption_ready;
|
||||
u32 encryption_not_ready;
|
||||
u32 tx_req_int;
|
||||
u32 tx_req_done_int;
|
||||
};
|
||||
|
||||
struct hdcp_reg_set {
|
||||
u32 status;
|
||||
u32 keys_offset;
|
||||
|
@ -119,6 +150,8 @@ struct hdcp_reg_set {
|
|||
u32 sec_data10;
|
||||
u32 sec_data11;
|
||||
u32 sec_data12;
|
||||
|
||||
u32 reset;
|
||||
};
|
||||
|
||||
#define HDCP_REG_SET_CLIENT_HDMI \
|
||||
|
@ -140,7 +173,8 @@ struct hdcp_reg_set {
|
|||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
|
||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
|
||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
|
||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12}
|
||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
|
||||
HDMI_HDCP_RESET}
|
||||
|
||||
#define HDCP_REG_SET_CLIENT_DP \
|
||||
{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
|
||||
|
@ -158,7 +192,7 @@ struct hdcp_reg_set {
|
|||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \
|
||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
|
||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
|
||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12}
|
||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, 0}
|
||||
|
||||
#define HDCP_HDMI_SINK_ADDR_MAP \
|
||||
{{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
|
||||
|
@ -174,6 +208,17 @@ struct hdcp_reg_set {
|
|||
{"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \
|
||||
{"aksv", 0x68007, 5}, {"repater", 0x68028, 1} }
|
||||
|
||||
#define HDCP_HDMI_INT_SET \
|
||||
{HDMI_HDCP_INT_CTRL, \
|
||||
BIT(2), BIT(6), 0, 0, 0, 0, \
|
||||
BIT(1), BIT(5), BIT(7), 0, 0, 0, 0, \
|
||||
BIT(0), BIT(4), 0, 0, 0, 0}
|
||||
|
||||
#define HDCP_DP_INT_SET \
|
||||
{DP_INTERRUPT_STATUS_2, \
|
||||
BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \
|
||||
BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \
|
||||
BIT(15), BIT(18), BIT(22), BIT(25), 0, 0}
|
||||
|
||||
struct hdmi_hdcp_ctrl {
|
||||
u32 auth_retries;
|
||||
|
@ -188,6 +233,7 @@ struct hdmi_hdcp_ctrl {
|
|||
struct hdmi_hdcp_init_data init_data;
|
||||
struct hdmi_hdcp_ops *ops;
|
||||
struct hdcp_reg_set reg_set;
|
||||
struct hdcp_int_set int_set;
|
||||
struct hdcp_sink_addr_map sink_addr;
|
||||
};
|
||||
|
||||
|
@ -558,15 +604,16 @@ static void hdmi_hdcp_enable_interrupts(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
{
|
||||
u32 intr_reg;
|
||||
struct dss_io_data *io;
|
||||
struct hdcp_int_set *isr;
|
||||
|
||||
io = hdcp_ctrl->init_data.core_io;
|
||||
isr = &hdcp_ctrl->int_set;
|
||||
|
||||
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||
intr_reg = HDMI_AUTH_SUCCESS_ACK | HDMI_AUTH_SUCCESS_MASK |
|
||||
HDMI_AUTH_FAIL_ACK | HDMI_AUTH_FAIL_MASK |
|
||||
HDMI_AUTH_FAIL_INFO_ACK;
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, intr_reg);
|
||||
}
|
||||
intr_reg = DSS_REG_R(io, isr->int_reg);
|
||||
|
||||
intr_reg |= HDCP_INT_CLR | HDCP_INT_EN;
|
||||
|
||||
DSS_REG_W(io, isr->int_reg, intr_reg);
|
||||
}
|
||||
|
||||
static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
||||
|
@ -1378,6 +1425,8 @@ int hdmi_hdcp_reauthenticate(void *input)
|
|||
{
|
||||
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
|
||||
struct dss_io_data *io;
|
||||
struct hdcp_reg_set *reg_set;
|
||||
struct hdcp_int_set *isr;
|
||||
u32 hdmi_hw_version;
|
||||
u32 ret = 0;
|
||||
|
||||
|
@ -1387,6 +1436,8 @@ int hdmi_hdcp_reauthenticate(void *input)
|
|||
}
|
||||
|
||||
io = hdcp_ctrl->init_data.core_io;
|
||||
reg_set = &hdcp_ctrl->reg_set;
|
||||
isr = &hdcp_ctrl->int_set;
|
||||
|
||||
if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
|
||||
DEV_DBG("%s: %s: invalid state. returning\n", __func__,
|
||||
|
@ -1394,22 +1445,25 @@ int hdmi_hdcp_reauthenticate(void *input)
|
|||
return 0;
|
||||
}
|
||||
|
||||
hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
|
||||
if (hdmi_hw_version >= 0x30030000) {
|
||||
DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1));
|
||||
DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0);
|
||||
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||
hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION);
|
||||
if (hdmi_hw_version >= 0x30030000) {
|
||||
DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1));
|
||||
DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0);
|
||||
}
|
||||
|
||||
/* Wait to be clean on DDC HW engine */
|
||||
hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
|
||||
}
|
||||
|
||||
/* Disable HDCP interrupts */
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
|
||||
DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
|
||||
|
||||
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
|
||||
|
||||
/* Wait to be clean on DDC HW engine */
|
||||
hdmi_hdcp_hw_ddc_clean(hdcp_ctrl);
|
||||
if (reg_set->reset)
|
||||
DSS_REG_W(io, reg_set->reset, BIT(0));
|
||||
|
||||
/* Disable encryption and disable the HDCP block */
|
||||
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
|
||||
DSS_REG_W(io, reg_set->ctrl, 0);
|
||||
|
||||
if (!hdmi_hdcp_load_keys(input))
|
||||
queue_delayed_work(hdcp_ctrl->init_data.workq,
|
||||
|
@ -1425,6 +1479,8 @@ void hdmi_hdcp_off(void *input)
|
|||
{
|
||||
struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input;
|
||||
struct dss_io_data *io;
|
||||
struct hdcp_reg_set *reg_set;
|
||||
struct hdcp_int_set *isr;
|
||||
int rc = 0;
|
||||
|
||||
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
|
||||
|
@ -1433,6 +1489,8 @@ void hdmi_hdcp_off(void *input)
|
|||
}
|
||||
|
||||
io = hdcp_ctrl->init_data.core_io;
|
||||
reg_set = &hdcp_ctrl->reg_set;
|
||||
isr = &hdcp_ctrl->int_set;
|
||||
|
||||
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
|
||||
DEV_DBG("%s: %s: inactive. returning\n", __func__,
|
||||
|
@ -1446,7 +1504,8 @@ void hdmi_hdcp_off(void *input)
|
|||
* reauth works will know that the HDCP session has been turned off.
|
||||
*/
|
||||
mutex_lock(hdcp_ctrl->init_data.mutex);
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0);
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN);
|
||||
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
|
||||
mutex_unlock(hdcp_ctrl->init_data.mutex);
|
||||
|
||||
|
@ -1465,10 +1524,11 @@ void hdmi_hdcp_off(void *input)
|
|||
DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
|
||||
DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0));
|
||||
if (reg_set->reset)
|
||||
DSS_REG_W(io, reg_set->reset, BIT(0));
|
||||
|
||||
/* Disable encryption and disable the HDCP block */
|
||||
DSS_REG_W(io, HDMI_HDCP_CTRL, 0);
|
||||
DSS_REG_W(io, reg_set->ctrl, 0);
|
||||
|
||||
DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
|
||||
} /* hdmi_hdcp_off */
|
||||
|
@ -1479,6 +1539,8 @@ int hdmi_hdcp_isr(void *input)
|
|||
int rc = 0;
|
||||
struct dss_io_data *io;
|
||||
u32 hdcp_int_val;
|
||||
struct hdcp_reg_set *reg_set;
|
||||
struct hdcp_int_set *isr;
|
||||
|
||||
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
|
@ -1487,28 +1549,33 @@ int hdmi_hdcp_isr(void *input)
|
|||
}
|
||||
|
||||
io = hdcp_ctrl->init_data.core_io;
|
||||
reg_set = &hdcp_ctrl->reg_set;
|
||||
isr = &hdcp_ctrl->int_set;
|
||||
|
||||
hdcp_int_val = DSS_REG_R(io, HDMI_HDCP_INT_CTRL);
|
||||
hdcp_int_val = DSS_REG_R(io, isr->int_reg);
|
||||
|
||||
/* Ignore HDCP interrupts if HDCP is disabled */
|
||||
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, HDCP_INT_CLR);
|
||||
DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hdcp_int_val & BIT(0)) {
|
||||
if (hdcp_int_val & isr->auth_success_int) {
|
||||
/* AUTH_SUCCESS_INT */
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(1)));
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->auth_success_ack));
|
||||
DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state)
|
||||
complete_all(&hdcp_ctrl->r0_checked);
|
||||
}
|
||||
|
||||
if (hdcp_int_val & BIT(4)) {
|
||||
if (hdcp_int_val & isr->auth_fail_int) {
|
||||
/* AUTH_FAIL_INT */
|
||||
u32 link_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS);
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(5)));
|
||||
u32 link_status = DSS_REG_R(io, reg_set->status);
|
||||
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->auth_fail_ack));
|
||||
DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
|
||||
__func__, HDCP_STATE_NAME, link_status);
|
||||
if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
|
||||
|
@ -1521,23 +1588,42 @@ int hdmi_hdcp_isr(void *input)
|
|||
}
|
||||
|
||||
/* Clear AUTH_FAIL_INFO as well */
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(7)));
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->auth_fail_info_ack));
|
||||
}
|
||||
|
||||
if (hdcp_int_val & BIT(8)) {
|
||||
if (hdcp_int_val & isr->tx_req_int) {
|
||||
/* DDC_XFER_REQ_INT */
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(9)));
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->tx_req_ack));
|
||||
DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
}
|
||||
|
||||
if (hdcp_int_val & BIT(12)) {
|
||||
if (hdcp_int_val & isr->tx_req_done_int) {
|
||||
/* DDC_XFER_DONE_INT */
|
||||
DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(13)));
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->tx_req_done_ack));
|
||||
DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
}
|
||||
|
||||
if (hdcp_int_val & isr->encryption_ready) {
|
||||
/* Encryption enabled */
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->encryption_ready_ack));
|
||||
DEV_INFO("%s: %s: encryption ready received\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
}
|
||||
|
||||
if (hdcp_int_val & isr->encryption_not_ready) {
|
||||
/* Encryption enabled */
|
||||
DSS_REG_W(io, isr->int_reg,
|
||||
(hdcp_int_val | isr->encryption_not_ready_ack));
|
||||
DEV_INFO("%s: %s: encryption not ready received\n", __func__,
|
||||
HDCP_STATE_NAME);
|
||||
}
|
||||
|
||||
error:
|
||||
return rc;
|
||||
} /* hdmi_hdcp_isr */
|
||||
|
@ -1660,15 +1746,19 @@ static void hdmi_hdcp_update_client_reg_set(struct hdmi_hdcp_ctrl *hdcp_ctrl)
|
|||
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||
struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_HDMI;
|
||||
struct hdcp_sink_addr_map sink_addr = HDCP_HDMI_SINK_ADDR_MAP;
|
||||
struct hdcp_int_set isr = HDCP_HDMI_INT_SET;
|
||||
|
||||
hdcp_ctrl->reg_set = reg_set;
|
||||
hdcp_ctrl->sink_addr = sink_addr;
|
||||
hdcp_ctrl->int_set = isr;
|
||||
} else if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
|
||||
struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP;
|
||||
struct hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP;
|
||||
struct hdcp_int_set isr = HDCP_DP_INT_SET;
|
||||
|
||||
hdcp_ctrl->reg_set = reg_set;
|
||||
hdcp_ctrl->sink_addr = sink_addr;
|
||||
hdcp_ctrl->int_set = isr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue