msm: mdss: hdcp_1x: add cp_irq support
Content Protection IRQ is a mechanism used by HDCP 1.3 protocol over DisplayPort to notify source device about current hdcp status of receiver/repeater device. Handle cp_irq to listen to sink receiver/repeater events and update source hdcp state accordingly. Change-Id: I63ecf6045f13e8b1d75bf6db2135671aa30c9e60 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
This commit is contained in:
parent
1e17007652
commit
8ac9f6ee3c
4 changed files with 251 additions and 130 deletions
|
@ -2599,8 +2599,10 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
|
||||||
pr_debug("Attention: hpd_irq high\n");
|
pr_debug("Attention: hpd_irq high\n");
|
||||||
|
|
||||||
if (dp_drv->power_on && dp_drv->hdcp.ops &&
|
if (dp_drv->power_on && dp_drv->hdcp.ops &&
|
||||||
dp_drv->hdcp.ops->cp_irq)
|
dp_drv->hdcp.ops->cp_irq) {
|
||||||
dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data);
|
if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mdss_dp_process_hpd_irq_high(dp_drv))
|
if (!mdss_dp_process_hpd_irq_high(dp_drv))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -574,18 +574,6 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
|
||||||
|
|
||||||
cdata.context = ctrl->lib_ctx;
|
cdata.context = ctrl->lib_ctx;
|
||||||
|
|
||||||
ctrl->sink_rx_status = 0;
|
|
||||||
rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data,
|
|
||||||
&ctrl->sink_rx_status);
|
|
||||||
|
|
||||||
if (rc) {
|
|
||||||
pr_err("failed to read rx status\n");
|
|
||||||
|
|
||||||
cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
|
|
||||||
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl->sink_rx_status & ctrl->abort_mask) {
|
if (ctrl->sink_rx_status & ctrl->abort_mask) {
|
||||||
if (ctrl->sink_rx_status & BIT(3))
|
if (ctrl->sink_rx_status & BIT(3))
|
||||||
pr_err("reauth_req set by sink\n");
|
pr_err("reauth_req set by sink\n");
|
||||||
|
@ -636,6 +624,7 @@ static void dp_hdcp2p2_auth_work(struct kthread_work *work)
|
||||||
|
|
||||||
static int dp_hdcp2p2_cp_irq(void *input)
|
static int dp_hdcp2p2_cp_irq(void *input)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
struct dp_hdcp2p2_ctrl *ctrl = input;
|
struct dp_hdcp2p2_ctrl *ctrl = input;
|
||||||
|
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
|
@ -643,9 +632,25 @@ static int dp_hdcp2p2_cp_irq(void *input)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctrl->sink_rx_status = 0;
|
||||||
|
rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data,
|
||||||
|
&ctrl->sink_rx_status);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("failed to read rx status\n");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrl->sink_rx_status) {
|
||||||
|
pr_debug("not a hdcp 2.2 irq\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
queue_kthread_work(&ctrl->worker, &ctrl->link);
|
queue_kthread_work(&ctrl->worker, &ctrl->link);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
error:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dp_hdcp2p2_deinit(void *input)
|
void dp_hdcp2p2_deinit(void *input)
|
||||||
|
|
|
@ -185,6 +185,7 @@
|
||||||
#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
|
#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
|
||||||
|
|
||||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
|
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
|
||||||
|
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
|
||||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
|
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
|
||||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
|
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
|
||||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
|
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
|
||||||
|
|
|
@ -72,6 +72,7 @@ struct hdcp_sink_addr_map {
|
||||||
struct hdcp_sink_addr bksv;
|
struct hdcp_sink_addr bksv;
|
||||||
struct hdcp_sink_addr r0;
|
struct hdcp_sink_addr r0;
|
||||||
struct hdcp_sink_addr bstatus;
|
struct hdcp_sink_addr bstatus;
|
||||||
|
struct hdcp_sink_addr cp_irq_status;
|
||||||
struct hdcp_sink_addr ksv_fifo;
|
struct hdcp_sink_addr ksv_fifo;
|
||||||
struct hdcp_sink_addr v_h0;
|
struct hdcp_sink_addr v_h0;
|
||||||
struct hdcp_sink_addr v_h1;
|
struct hdcp_sink_addr v_h1;
|
||||||
|
@ -82,7 +83,6 @@ struct hdcp_sink_addr_map {
|
||||||
/* addresses to write to sink */
|
/* addresses to write to sink */
|
||||||
struct hdcp_sink_addr an;
|
struct hdcp_sink_addr an;
|
||||||
struct hdcp_sink_addr aksv;
|
struct hdcp_sink_addr aksv;
|
||||||
struct hdcp_sink_addr rep;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hdcp_int_set {
|
struct hdcp_int_set {
|
||||||
|
@ -126,7 +126,9 @@ struct hdcp_reg_set {
|
||||||
u32 entropy_ctrl0;
|
u32 entropy_ctrl0;
|
||||||
u32 entropy_ctrl1;
|
u32 entropy_ctrl1;
|
||||||
u32 sha_ctrl;
|
u32 sha_ctrl;
|
||||||
|
u32 sha_data;
|
||||||
u32 sec_sha_ctrl;
|
u32 sec_sha_ctrl;
|
||||||
|
u32 sec_sha_data;
|
||||||
u32 sha_status;
|
u32 sha_status;
|
||||||
|
|
||||||
u32 data0;
|
u32 data0;
|
||||||
|
@ -154,13 +156,17 @@ struct hdcp_reg_set {
|
||||||
|
|
||||||
u32 reset;
|
u32 reset;
|
||||||
u32 reset_bit;
|
u32 reset_bit;
|
||||||
|
|
||||||
|
u32 repeater;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HDCP_REG_SET_CLIENT_HDMI \
|
#define HDCP_REG_SET_CLIENT_HDMI \
|
||||||
{HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \
|
{HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \
|
||||||
HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \
|
HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \
|
||||||
HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \
|
HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \
|
||||||
HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \
|
HDMI_HDCP_SHA_CTRL, HDMI_HDCP_SHA_DATA, \
|
||||||
|
HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \
|
||||||
|
HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, \
|
||||||
HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \
|
HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \
|
||||||
HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \
|
HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \
|
||||||
HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \
|
HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \
|
||||||
|
@ -176,13 +182,14 @@ struct hdcp_reg_set {
|
||||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
|
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
|
||||||
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
|
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, BIT(0)}
|
HDMI_HDCP_RESET, BIT(0), BIT(6)}
|
||||||
|
|
||||||
#define HDCP_REG_SET_CLIENT_DP \
|
#define HDCP_REG_SET_CLIENT_DP \
|
||||||
{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
|
{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
|
||||||
DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
|
DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
|
||||||
DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
|
DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
|
||||||
0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
|
0, 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
|
||||||
|
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \
|
||||||
DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \
|
DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \
|
||||||
DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
|
DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
|
||||||
DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
|
DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
|
||||||
|
@ -195,21 +202,21 @@ struct hdcp_reg_set {
|
||||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
|
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_DATA11, \
|
||||||
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
|
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
|
||||||
DP_SW_RESET, BIT(1)}
|
DP_SW_RESET, BIT(1), BIT(1)}
|
||||||
|
|
||||||
#define HDCP_HDMI_SINK_ADDR_MAP \
|
#define HDCP_HDMI_SINK_ADDR_MAP \
|
||||||
{{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
|
{{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
|
||||||
{"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \
|
{"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \
|
||||||
{"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \
|
{"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \
|
||||||
{"v_h4", 0x30, 4}, {"an", 0x18, 8}, {"aksv", 0x10, 5}, \
|
{"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \
|
||||||
{"repeater", 0x00, 0} }
|
{"aksv", 0x10, 5} }
|
||||||
|
|
||||||
#define HDCP_DP_SINK_ADDR_MAP \
|
#define HDCP_DP_SINK_ADDR_MAP \
|
||||||
{{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
|
{{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
|
||||||
{"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \
|
{"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 2}, \
|
||||||
{"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \
|
{"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \
|
||||||
{"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \
|
{"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \
|
||||||
{"aksv", 0x68007, 5}, {"repeater", 0x68028, 1} }
|
{"an", 0x6800C, 8}, {"aksv", 0x68007, 5} }
|
||||||
|
|
||||||
#define HDCP_HDMI_INT_SET \
|
#define HDCP_HDMI_INT_SET \
|
||||||
{HDMI_HDCP_INT_CTRL, \
|
{HDMI_HDCP_INT_CTRL, \
|
||||||
|
@ -227,17 +234,21 @@ struct hdcp_1x_ctrl {
|
||||||
u32 auth_retries;
|
u32 auth_retries;
|
||||||
u32 tp_msgid;
|
u32 tp_msgid;
|
||||||
u32 tz_hdcp;
|
u32 tz_hdcp;
|
||||||
|
bool sink_r0_ready;
|
||||||
enum hdcp_states hdcp_state;
|
enum hdcp_states hdcp_state;
|
||||||
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
|
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
|
||||||
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
|
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
|
||||||
struct delayed_work hdcp_auth_work;
|
struct delayed_work hdcp_auth_work;
|
||||||
struct work_struct hdcp_int_work;
|
struct work_struct hdcp_int_work;
|
||||||
struct completion r0_checked;
|
struct completion r0_checked;
|
||||||
|
struct completion sink_r0_available;
|
||||||
|
struct completion sink_rep_ready;
|
||||||
struct hdcp_init_data init_data;
|
struct hdcp_init_data init_data;
|
||||||
struct hdcp_ops *ops;
|
struct hdcp_ops *ops;
|
||||||
struct hdcp_reg_set reg_set;
|
struct hdcp_reg_set reg_set;
|
||||||
struct hdcp_int_set int_set;
|
struct hdcp_int_set int_set;
|
||||||
struct hdcp_sink_addr_map sink_addr;
|
struct hdcp_sink_addr_map sink_addr;
|
||||||
|
struct workqueue_struct *workq;
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *hdcp_state_name(enum hdcp_states hdcp_state)
|
const char *hdcp_state_name(enum hdcp_states hdcp_state)
|
||||||
|
@ -527,6 +538,7 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
|
||||||
u8 *buf, bool realign)
|
u8 *buf, bool realign)
|
||||||
{
|
{
|
||||||
u32 rc = 0;
|
u32 rc = 0;
|
||||||
|
int const max_size = 15, edid_read_delay_us = 20;
|
||||||
struct hdmi_tx_ddc_data ddc_data;
|
struct hdmi_tx_ddc_data ddc_data;
|
||||||
|
|
||||||
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||||
|
@ -550,17 +562,30 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
|
||||||
HDCP_STATE_NAME, sink->name);
|
HDCP_STATE_NAME, sink->name);
|
||||||
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
|
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
|
||||||
hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
|
hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
|
||||||
struct edp_cmd cmd = {0};
|
int size = sink->len;
|
||||||
|
|
||||||
cmd.read = 1;
|
do {
|
||||||
cmd.addr = sink->addr;
|
struct edp_cmd cmd = {0};
|
||||||
cmd.out_buf = buf;
|
int read_size;
|
||||||
cmd.len = sink->len;
|
|
||||||
|
|
||||||
rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd);
|
read_size = min(size, max_size);
|
||||||
if (rc)
|
|
||||||
DEV_ERR("%s: %s: %s read failed\n", __func__,
|
cmd.read = 1;
|
||||||
HDCP_STATE_NAME, sink->name);
|
cmd.addr = sink->addr;
|
||||||
|
cmd.len = read_size;
|
||||||
|
cmd.out_buf = buf;
|
||||||
|
|
||||||
|
rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("Aux read failed\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* give sink/repeater time to ready edid */
|
||||||
|
msleep(edid_read_delay_us);
|
||||||
|
buf += read_size;
|
||||||
|
size -= read_size;
|
||||||
|
} while (size > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -621,12 +646,13 @@ static void hdcp_1x_enable_interrupts(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
|
|
||||||
static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc, r0_retry = 3;
|
||||||
|
u32 const r0_read_delay_us = 1;
|
||||||
|
u32 const r0_read_timeout_us = r0_read_delay_us * 10;
|
||||||
u32 link0_aksv_0, link0_aksv_1;
|
u32 link0_aksv_0, link0_aksv_1;
|
||||||
u32 link0_bksv_0, link0_bksv_1;
|
u32 link0_bksv_0, link0_bksv_1;
|
||||||
u32 link0_an_0, link0_an_1;
|
u32 link0_an_0, link0_an_1;
|
||||||
u32 timeout_count;
|
u32 timeout_count;
|
||||||
bool is_match;
|
|
||||||
struct dss_io_data *io;
|
struct dss_io_data *io;
|
||||||
struct dss_io_data *hdcp_io;
|
struct dss_io_data *hdcp_io;
|
||||||
struct hdcp_reg_set *reg_set;
|
struct hdcp_reg_set *reg_set;
|
||||||
|
@ -669,9 +695,8 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
|
|
||||||
hdcp_1x_enable_interrupts(hdcp_ctrl);
|
hdcp_1x_enable_interrupts(hdcp_ctrl);
|
||||||
|
|
||||||
/* receiver (0), repeater (1) */
|
hdcp_ctrl->current_tp.ds_type = bcaps & reg_set->repeater ?
|
||||||
hdcp_ctrl->current_tp.ds_type =
|
DS_REPEATER : DS_RECEIVER;
|
||||||
(bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
|
|
||||||
|
|
||||||
/* Write BCAPS to the hardware */
|
/* Write BCAPS to the hardware */
|
||||||
if (hdcp_ctrl->tz_hdcp) {
|
if (hdcp_ctrl->tz_hdcp) {
|
||||||
|
@ -757,18 +782,6 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
an[6] = (link0_an_1 >> 16) & 0xFF;
|
an[6] = (link0_an_1 >> 16) & 0xFF;
|
||||||
an[7] = (link0_an_1 >> 24) & 0xFF;
|
an[7] = (link0_an_1 >> 24) & 0xFF;
|
||||||
|
|
||||||
rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an);
|
|
||||||
if (IS_ERR_VALUE(rc)) {
|
|
||||||
DEV_ERR("%s: error writing an to sink\n", __func__);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv);
|
|
||||||
if (IS_ERR_VALUE(rc)) {
|
|
||||||
DEV_ERR("%s: error writing aksv to sink\n", __func__);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false);
|
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false);
|
||||||
if (IS_ERR_VALUE(rc)) {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
DEV_ERR("%s: error reading bksv from sink\n", __func__);
|
DEV_ERR("%s: error reading bksv from sink\n", __func__);
|
||||||
|
@ -818,12 +831,6 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
DSS_REG_W(io, reg_set->data1, link0_bksv_1);
|
DSS_REG_W(io, reg_set->data1, link0_bksv_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* HDCP Compliace Test case 1A-01:
|
|
||||||
* Wait here at least 100ms before reading R0'
|
|
||||||
*/
|
|
||||||
msleep(125);
|
|
||||||
|
|
||||||
/* Wait for HDCP R0 computation to be completed */
|
/* Wait for HDCP R0 computation to be completed */
|
||||||
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
|
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
|
||||||
link0_status & BIT(reg_set->r0_offset),
|
link0_status & BIT(reg_set->r0_offset),
|
||||||
|
@ -833,6 +840,38 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an);
|
||||||
|
if (IS_ERR_VALUE(rc)) {
|
||||||
|
DEV_ERR("%s: error writing an to sink\n", __func__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv);
|
||||||
|
if (IS_ERR_VALUE(rc)) {
|
||||||
|
DEV_ERR("%s: error writing aksv to sink\n", __func__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HDCP Compliace Test case 1A-01:
|
||||||
|
* Wait here at least 100ms before reading R0'
|
||||||
|
*/
|
||||||
|
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||||
|
msleep(125);
|
||||||
|
} else {
|
||||||
|
if (!hdcp_ctrl->sink_r0_ready) {
|
||||||
|
reinit_completion(&hdcp_ctrl->sink_r0_available);
|
||||||
|
timeout_count = wait_for_completion_timeout(
|
||||||
|
&hdcp_ctrl->sink_r0_available, HZ / 2);
|
||||||
|
|
||||||
|
if (!timeout_count) {
|
||||||
|
DEV_ERR("sink R0 not ready\n");
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r0_read_retry:
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false);
|
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false);
|
||||||
if (IS_ERR_VALUE(rc)) {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
|
@ -844,37 +883,29 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
buf[1], buf[0]);
|
buf[1], buf[0]);
|
||||||
|
|
||||||
/* Write R0' to HDCP registers and check to see if it is a match */
|
/* Write R0' to HDCP registers and check to see if it is a match */
|
||||||
reinit_completion(&hdcp_ctrl->r0_checked);
|
|
||||||
DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
|
DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
|
||||||
timeout_count = wait_for_completion_timeout(
|
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
|
||||||
&hdcp_ctrl->r0_checked, HZ*2);
|
link0_status & BIT(12),
|
||||||
link0_status = DSS_REG_R(io, reg_set->status);
|
r0_read_delay_us, r0_read_timeout_us);
|
||||||
is_match = link0_status & BIT(12);
|
if (IS_ERR_VALUE(rc)) {
|
||||||
if (!is_match) {
|
DEV_ERR("%s: R0 mismatch\n", __func__);
|
||||||
DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__,
|
if (--r0_retry)
|
||||||
HDCP_STATE_NAME, link0_status);
|
goto r0_read_retry;
|
||||||
if (!timeout_count) {
|
|
||||||
DEV_ERR("%s: %s: Timeout. No R0 mtch. R0'=%02x%02x\n",
|
goto error;
|
||||||
__func__, HDCP_STATE_NAME, buf[1], buf[0]);
|
|
||||||
rc = -ETIMEDOUT;
|
|
||||||
goto error;
|
|
||||||
} else {
|
|
||||||
DEV_ERR("%s: %s: R0 mismatch. R0'=%02x%02x\n", __func__,
|
|
||||||
HDCP_STATE_NAME, buf[1], buf[0]);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEV_DBG("%s: %s: R0 matches\n", __func__, HDCP_STATE_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdcp1_set_enc(true);
|
||||||
|
|
||||||
|
DEV_INFO("%s: %s: Authentication Part I successful\n", __func__,
|
||||||
|
hdcp_ctrl ? HDCP_STATE_NAME : "???");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (rc)
|
DEV_ERR("%s: %s: Authentication Part I failed\n", __func__,
|
||||||
DEV_ERR("%s: %s: Authentication Part I failed\n", __func__,
|
hdcp_ctrl ? HDCP_STATE_NAME : "???");
|
||||||
hdcp_ctrl ? HDCP_STATE_NAME : "???");
|
|
||||||
else
|
|
||||||
DEV_INFO("%s: %s: Authentication Part I successful\n",
|
|
||||||
__func__, HDCP_STATE_NAME);
|
|
||||||
return rc;
|
return rc;
|
||||||
} /* hdcp_1x_authentication_part1 */
|
} /* hdcp_1x_authentication_part1 */
|
||||||
|
|
||||||
|
@ -895,10 +926,6 @@ static int hdcp_1x_set_v_h(struct hdcp_1x_ctrl *hdcp_ctrl,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n",
|
|
||||||
__func__, HDCP_STATE_NAME, rd->sink->name, buf[0], buf[1],
|
|
||||||
buf[2], buf[3]);
|
|
||||||
|
|
||||||
if (!hdcp_ctrl->tz_hdcp)
|
if (!hdcp_ctrl->tz_hdcp)
|
||||||
DSS_REG_W(io, rd->reg_id,
|
DSS_REG_W(io, rd->reg_id,
|
||||||
(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]));
|
(buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]));
|
||||||
|
@ -971,6 +998,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
u32 resp = 0;
|
u32 resp = 0;
|
||||||
u32 ksv_read_retry = 20;
|
u32 ksv_read_retry = 20;
|
||||||
|
int v_retry = 3;
|
||||||
|
|
||||||
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
|
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
|
||||||
DEV_ERR("%s: invalid input\n", __func__);
|
DEV_ERR("%s: invalid input\n", __func__);
|
||||||
|
@ -999,16 +1027,35 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
* Wait until READY bit is set in BCAPS, as per HDCP specifications
|
* Wait until READY bit is set in BCAPS, as per HDCP specifications
|
||||||
* maximum permitted time to check for READY bit is five seconds.
|
* maximum permitted time to check for READY bit is five seconds.
|
||||||
*/
|
*/
|
||||||
timeout_count = 50;
|
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true);
|
||||||
do {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
|
DEV_ERR("%s: error reading bcaps\n", __func__);
|
||||||
&bcaps, true);
|
goto error;
|
||||||
if (IS_ERR_VALUE(rc)) {
|
}
|
||||||
DEV_ERR("%s: error reading bcaps\n", __func__);
|
|
||||||
|
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
|
||||||
|
timeout_count = 50;
|
||||||
|
|
||||||
|
while (!(bcaps & BIT(5)) && --timeout_count) {
|
||||||
|
rc = hdcp_1x_read(hdcp_ctrl,
|
||||||
|
&hdcp_ctrl->sink_addr.bcaps, &bcaps, true);
|
||||||
|
if (IS_ERR_VALUE(rc)) {
|
||||||
|
DEV_ERR("%s: error reading bcaps\n", __func__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reinit_completion(&hdcp_ctrl->sink_rep_ready);
|
||||||
|
timeout_count = wait_for_completion_timeout(
|
||||||
|
&hdcp_ctrl->sink_rep_ready, HZ * 5);
|
||||||
|
|
||||||
|
if (!timeout_count) {
|
||||||
|
DEV_ERR("sink not ready with DS KSV list\n");
|
||||||
|
rc = -EINVAL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
msleep(100);
|
}
|
||||||
} while (!(bcaps & BIT(5)) && --timeout_count);
|
|
||||||
|
|
||||||
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
|
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
|
||||||
buf, true);
|
buf, true);
|
||||||
|
@ -1043,20 +1090,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
down_stream_devices = bstatus & 0x7F;
|
down_stream_devices = bstatus & 0x7F;
|
||||||
if (down_stream_devices == 0) {
|
|
||||||
/*
|
DEV_DBG("%s: DEVICE_COUNT %d\n", __func__, down_stream_devices);
|
||||||
* If no downstream devices are attached to the repeater
|
|
||||||
* then part II fails.
|
|
||||||
* todo: The other approach would be to continue PART II.
|
|
||||||
*/
|
|
||||||
DEV_ERR("%s: %s: No downstream devices\n", __func__,
|
|
||||||
HDCP_STATE_NAME);
|
|
||||||
rc = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cascaded repeater depth */
|
/* Cascaded repeater depth */
|
||||||
repeater_cascade_depth = (bstatus >> 8) & 0x7;
|
repeater_cascade_depth = (bstatus >> 8) & 0x7;
|
||||||
|
DEV_DBG("%s: DEPTH %d\n", __func__, repeater_cascade_depth);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HDCP Compliance 1B-05:
|
* HDCP Compliance 1B-05:
|
||||||
|
@ -1064,6 +1103,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
* exceed max_devices_connected from bit 7 of Bstatus.
|
* exceed max_devices_connected from bit 7 of Bstatus.
|
||||||
*/
|
*/
|
||||||
max_devs_exceeded = (bstatus & BIT(7)) >> 7;
|
max_devs_exceeded = (bstatus & BIT(7)) >> 7;
|
||||||
|
DEV_DBG("%s: MAX_DEVS_EXCEEDED %d\n", __func__, max_devs_exceeded);
|
||||||
if (max_devs_exceeded == 0x01) {
|
if (max_devs_exceeded == 0x01) {
|
||||||
DEV_ERR("%s: %s: no. of devs connected exceeds max allowed",
|
DEV_ERR("%s: %s: no. of devs connected exceeds max allowed",
|
||||||
__func__, HDCP_STATE_NAME);
|
__func__, HDCP_STATE_NAME);
|
||||||
|
@ -1077,6 +1117,8 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
* exceed max_cascade_connected from bit 11 of Bstatus.
|
* exceed max_cascade_connected from bit 11 of Bstatus.
|
||||||
*/
|
*/
|
||||||
max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
|
max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
|
||||||
|
DEV_DBG("%s: MAX CASCADE_EXCEEDED %d\n", __func__,
|
||||||
|
max_cascade_exceeded);
|
||||||
if (max_cascade_exceeded == 0x01) {
|
if (max_cascade_exceeded == 0x01) {
|
||||||
DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed",
|
DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed",
|
||||||
__func__, HDCP_STATE_NAME);
|
__func__, HDCP_STATE_NAME);
|
||||||
|
@ -1096,7 +1138,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
ksv_bytes = 5 * down_stream_devices;
|
ksv_bytes = 5 * down_stream_devices;
|
||||||
hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes;
|
hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes;
|
||||||
|
|
||||||
do {
|
while (ksv_bytes && --ksv_read_retry) {
|
||||||
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo,
|
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo,
|
||||||
ksv_fifo, false);
|
ksv_fifo, false);
|
||||||
if (IS_ERR_VALUE(rc)) {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
|
@ -1108,19 +1150,24 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
* read from the KSV FIFO register.
|
* read from the KSV FIFO register.
|
||||||
*/
|
*/
|
||||||
msleep(25);
|
msleep(25);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} while (rc && --ksv_read_retry);
|
}
|
||||||
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
DEV_ERR("%s: error reading ksv_fifo\n", __func__);
|
DEV_ERR("%s: error reading ksv_fifo\n", __func__);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
v_read_retry:
|
||||||
rc = hdcp_1x_transfer_v_h(hdcp_ctrl);
|
rc = hdcp_1x_transfer_v_h(hdcp_ctrl);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
/* do not proceed further if no downstream device connected */
|
||||||
|
if (!ksv_bytes)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write KSV FIFO to HDCP_SHA_DATA.
|
* Write KSV FIFO to HDCP_SHA_DATA.
|
||||||
* This is done 1 byte at time starting with the LSB.
|
* This is done 1 byte at time starting with the LSB.
|
||||||
|
@ -1161,7 +1208,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
if (hdcp_ctrl->tz_hdcp) {
|
if (hdcp_ctrl->tz_hdcp) {
|
||||||
memset(scm_buf, 0x00, sizeof(scm_buf));
|
memset(scm_buf, 0x00, sizeof(scm_buf));
|
||||||
|
|
||||||
scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
|
scm_buf[0].addr = phy_addr + reg_set->sha_data;
|
||||||
scm_buf[0].val = ksv_fifo[i] << 16;
|
scm_buf[0].val = ksv_fifo[i] << 16;
|
||||||
|
|
||||||
ret = hdcp_scm_call(scm_buf, &resp);
|
ret = hdcp_scm_call(scm_buf, &resp);
|
||||||
|
@ -1173,10 +1220,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
}
|
}
|
||||||
} else if (hdcp_ctrl->init_data.sec_access) {
|
} else if (hdcp_ctrl->init_data.sec_access) {
|
||||||
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
|
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
|
||||||
reg_set->sec_sha_ctrl,
|
reg_set->sec_sha_data,
|
||||||
ksv_fifo[i] << 16);
|
ksv_fifo[i] << 16);
|
||||||
} else {
|
} else {
|
||||||
DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16);
|
DSS_REG_W_ND(io, reg_set->sha_data, ksv_fifo[i] << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1199,7 +1246,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
if (hdcp_ctrl->tz_hdcp) {
|
if (hdcp_ctrl->tz_hdcp) {
|
||||||
memset(scm_buf, 0x00, sizeof(scm_buf));
|
memset(scm_buf, 0x00, sizeof(scm_buf));
|
||||||
|
|
||||||
scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
|
scm_buf[0].addr = phy_addr + reg_set->sha_data;
|
||||||
scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1;
|
scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1;
|
||||||
|
|
||||||
ret = hdcp_scm_call(scm_buf, &resp);
|
ret = hdcp_scm_call(scm_buf, &resp);
|
||||||
|
@ -1211,10 +1258,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
}
|
}
|
||||||
} else if (hdcp_ctrl->init_data.sec_access) {
|
} else if (hdcp_ctrl->init_data.sec_access) {
|
||||||
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
|
DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
|
||||||
reg_set->sec_sha_ctrl,
|
reg_set->sec_sha_data,
|
||||||
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
|
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
|
||||||
} else {
|
} else {
|
||||||
DSS_REG_W_ND(io, reg_set->sha_ctrl,
|
DSS_REG_W_ND(io, reg_set->sha_data,
|
||||||
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
|
(ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1223,7 +1270,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
sha_status & BIT(4),
|
sha_status & BIT(4),
|
||||||
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
|
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
|
||||||
if (IS_ERR_VALUE(rc)) {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
DEV_ERR("%s: comp not done\n", __func__);
|
DEV_ERR("%s: V computation not done\n", __func__);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,8 +1279,9 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
status & BIT(reg_set->v_offset),
|
status & BIT(reg_set->v_offset),
|
||||||
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
|
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
|
||||||
if (IS_ERR_VALUE(rc)) {
|
if (IS_ERR_VALUE(rc)) {
|
||||||
DEV_ERR("%s: V not ready\n", __func__);
|
DEV_ERR("%s: V mismatch\n", __func__);
|
||||||
goto error;
|
if (--v_retry)
|
||||||
|
goto v_read_retry;
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1330,6 +1378,8 @@ static void hdcp_1x_auth_work(struct work_struct *work)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdcp_ctrl->sink_r0_ready = false;
|
||||||
|
|
||||||
io = hdcp_ctrl->init_data.core_io;
|
io = hdcp_ctrl->init_data.core_io;
|
||||||
/* Enabling Software DDC for HDMI and REF timer for DP */
|
/* Enabling Software DDC for HDMI and REF timer for DP */
|
||||||
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
|
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
|
||||||
|
@ -1388,8 +1438,6 @@ error:
|
||||||
hdcp_ctrl->init_data.cb_data,
|
hdcp_ctrl->init_data.cb_data,
|
||||||
hdcp_ctrl->hdcp_state);
|
hdcp_ctrl->hdcp_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
hdcp1_set_enc(true);
|
|
||||||
} else {
|
} else {
|
||||||
DEV_DBG("%s: %s: HDCP state changed during authentication\n",
|
DEV_DBG("%s: %s: HDCP state changed during authentication\n",
|
||||||
__func__, HDCP_STATE_NAME);
|
__func__, HDCP_STATE_NAME);
|
||||||
|
@ -1419,12 +1467,12 @@ int hdcp_1x_authenticate(void *input)
|
||||||
if (!hdcp_1x_load_keys(input)) {
|
if (!hdcp_1x_load_keys(input)) {
|
||||||
flush_delayed_work(&hdcp_ctrl->hdcp_auth_work);
|
flush_delayed_work(&hdcp_ctrl->hdcp_auth_work);
|
||||||
|
|
||||||
queue_delayed_work(hdcp_ctrl->init_data.workq,
|
queue_delayed_work(hdcp_ctrl->workq,
|
||||||
&hdcp_ctrl->hdcp_auth_work, HZ/2);
|
&hdcp_ctrl->hdcp_auth_work, HZ/2);
|
||||||
} else {
|
} else {
|
||||||
flush_work(&hdcp_ctrl->hdcp_int_work);
|
flush_work(&hdcp_ctrl->hdcp_int_work);
|
||||||
|
|
||||||
queue_work(hdcp_ctrl->init_data.workq,
|
queue_work(hdcp_ctrl->workq,
|
||||||
&hdcp_ctrl->hdcp_int_work);
|
&hdcp_ctrl->hdcp_int_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1478,10 +1526,10 @@ int hdcp_1x_reauthenticate(void *input)
|
||||||
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
|
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
|
||||||
|
|
||||||
if (!hdcp_1x_load_keys(input))
|
if (!hdcp_1x_load_keys(input))
|
||||||
queue_delayed_work(hdcp_ctrl->init_data.workq,
|
queue_delayed_work(hdcp_ctrl->workq,
|
||||||
&hdcp_ctrl->hdcp_auth_work, HZ);
|
&hdcp_ctrl->hdcp_auth_work, HZ);
|
||||||
else
|
else
|
||||||
queue_work(hdcp_ctrl->init_data.workq,
|
queue_work(hdcp_ctrl->workq,
|
||||||
&hdcp_ctrl->hdcp_int_work);
|
&hdcp_ctrl->hdcp_int_work);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1531,7 +1579,7 @@ void hdcp_1x_off(void *input)
|
||||||
* No more reauthentiaction attempts will be scheduled since we
|
* No more reauthentiaction attempts will be scheduled since we
|
||||||
* set the currect state to inactive.
|
* set the currect state to inactive.
|
||||||
*/
|
*/
|
||||||
rc = cancel_delayed_work_sync(&hdcp_ctrl->hdcp_auth_work);
|
rc = cancel_delayed_work(&hdcp_ctrl->hdcp_auth_work);
|
||||||
if (rc)
|
if (rc)
|
||||||
DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__,
|
DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__,
|
||||||
HDCP_STATE_NAME);
|
HDCP_STATE_NAME);
|
||||||
|
@ -1549,6 +1597,8 @@ void hdcp_1x_off(void *input)
|
||||||
|
|
||||||
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
|
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
|
||||||
|
|
||||||
|
hdcp_ctrl->sink_r0_ready = false;
|
||||||
|
|
||||||
DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
|
DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
|
||||||
} /* hdcp_1x_off */
|
} /* hdcp_1x_off */
|
||||||
|
|
||||||
|
@ -1599,7 +1649,7 @@ int hdcp_1x_isr(void *input)
|
||||||
__func__, HDCP_STATE_NAME, link_status);
|
__func__, HDCP_STATE_NAME, link_status);
|
||||||
if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
|
if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
|
||||||
/* Inform HDMI Tx of the failure */
|
/* Inform HDMI Tx of the failure */
|
||||||
queue_work(hdcp_ctrl->init_data.workq,
|
queue_work(hdcp_ctrl->workq,
|
||||||
&hdcp_ctrl->hdcp_int_work);
|
&hdcp_ctrl->hdcp_int_work);
|
||||||
/* todo: print debug log with auth fail reason */
|
/* todo: print debug log with auth fail reason */
|
||||||
} else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
|
} else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
|
||||||
|
@ -1785,6 +1835,9 @@ void hdcp_1x_deinit(void *input)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdcp_ctrl->workq)
|
||||||
|
destroy_workqueue(hdcp_ctrl->workq);
|
||||||
|
|
||||||
sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj,
|
sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj,
|
||||||
&hdcp_1x_fs_attr_group);
|
&hdcp_1x_fs_attr_group);
|
||||||
|
|
||||||
|
@ -1812,12 +1865,61 @@ static void hdcp_1x_update_client_reg_set(struct hdcp_1x_ctrl *hdcp_ctrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hdcp_1x_cp_irq(void *input)
|
||||||
|
{
|
||||||
|
struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
|
||||||
|
u8 buf = 0;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
if (!hdcp_ctrl) {
|
||||||
|
DEV_ERR("%s: invalid input\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.cp_irq_status,
|
||||||
|
&buf, false);
|
||||||
|
if (IS_ERR_VALUE(ret)) {
|
||||||
|
DEV_ERR("%s: error reading cp_irq_status\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
DEV_DBG("%s: not a hdcp 1.x irq\n", __func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf & BIT(2)) || (buf & BIT(3))) {
|
||||||
|
DEV_ERR("%s: REAUTH REQUIRED\n", __func__);
|
||||||
|
|
||||||
|
queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf & BIT(1)) {
|
||||||
|
DEV_DBG("%s: R0' AVAILABLE\n", __func__);
|
||||||
|
hdcp_ctrl->sink_r0_ready = true;
|
||||||
|
complete_all(&hdcp_ctrl->sink_r0_available);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf & BIT(0)) {
|
||||||
|
DEV_DBG("%s: KSVs READY\n", __func__);
|
||||||
|
complete_all(&hdcp_ctrl->sink_rep_ready);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void *hdcp_1x_init(struct hdcp_init_data *init_data)
|
void *hdcp_1x_init(struct hdcp_init_data *init_data)
|
||||||
{
|
{
|
||||||
struct hdcp_1x_ctrl *hdcp_ctrl = NULL;
|
struct hdcp_1x_ctrl *hdcp_ctrl = NULL;
|
||||||
|
char name[20];
|
||||||
int ret;
|
int ret;
|
||||||
static struct hdcp_ops ops = {
|
static struct hdcp_ops ops = {
|
||||||
.isr = hdcp_1x_isr,
|
.isr = hdcp_1x_isr,
|
||||||
|
.cp_irq = hdcp_1x_cp_irq,
|
||||||
.reauthenticate = hdcp_1x_reauthenticate,
|
.reauthenticate = hdcp_1x_reauthenticate,
|
||||||
.authenticate = hdcp_1x_authenticate,
|
.authenticate = hdcp_1x_authenticate,
|
||||||
.off = hdcp_1x_off
|
.off = hdcp_1x_off
|
||||||
|
@ -1844,6 +1946,15 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
|
||||||
hdcp_ctrl->init_data = *init_data;
|
hdcp_ctrl->init_data = *init_data;
|
||||||
hdcp_ctrl->ops = &ops;
|
hdcp_ctrl->ops = &ops;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "hdcp_1x_%d",
|
||||||
|
hdcp_ctrl->init_data.client_id);
|
||||||
|
|
||||||
|
hdcp_ctrl->workq = create_workqueue(name);
|
||||||
|
if (!hdcp_ctrl->workq) {
|
||||||
|
DEV_ERR("%s: Error creating workqueue\n", __func__);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
hdcp_1x_update_client_reg_set(hdcp_ctrl);
|
hdcp_1x_update_client_reg_set(hdcp_ctrl);
|
||||||
|
|
||||||
if (sysfs_create_group(init_data->sysfs_kobj,
|
if (sysfs_create_group(init_data->sysfs_kobj,
|
||||||
|
@ -1857,6 +1968,8 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
|
||||||
|
|
||||||
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
|
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
|
||||||
init_completion(&hdcp_ctrl->r0_checked);
|
init_completion(&hdcp_ctrl->r0_checked);
|
||||||
|
init_completion(&hdcp_ctrl->sink_r0_available);
|
||||||
|
init_completion(&hdcp_ctrl->sink_rep_ready);
|
||||||
|
|
||||||
if (!hdcp_ctrl->init_data.sec_access) {
|
if (!hdcp_ctrl->init_data.sec_access) {
|
||||||
ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP);
|
ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP);
|
||||||
|
|
Loading…
Add table
Reference in a new issue