summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2016-12-02 11:56:51 -0800
committerAjay Singh Parmar <aparmar@codeaurora.org>2016-12-08 14:02:25 -0800
commit8dac9cfe736da6f5d7d12602899d47b8ae10cbda (patch)
tree9bc055c1a0531c6e0a4d89a3d495388c01b88efa /drivers/video
parent368fecd7df5b203a5ce684a0c77726a5690c1147 (diff)
msm: mdss: hdcp_1x: fix compliance failure
1B-01 DP HDCP compliance test needs either poll RxStatus or wait for CP_IRQ to fetch the list of Downstream devices' KSVs. Currently, hdcp_1x module waits for CP_IRQ but compliance test equipment fails this test as source is unable to read KSVs within allowed time due to software delays. Poll RxStatus register in sink to get KSVs ready status so that KSVs can be read as soon as sink mark them as ready. Also, re-factor the code as per the specification. Change-Id: Ieefa13dfc9e154b005329b01e2769266a1954ddb Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/msm/mdss_hdcp_1x.c1168
1 files changed, 619 insertions, 549 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
index 44a3ad993909..9df54e0cb517 100644
--- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c
+++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
@@ -24,7 +24,7 @@
#include "mdss_dp_util.h"
#include "video/msm_hdmi_hdcp_mgr.h"
-#define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state))
+#define HDCP_STATE_NAME (hdcp_state_name(hdcp->hdcp_state))
/* HDCP Keys state based on HDMI_HDCP_LINK0_STATUS:KEYS_STATE */
#define HDCP_KEYS_STATE_NO_KEYS 0
@@ -37,8 +37,6 @@
#define HDCP_KEYS_STATE_RESERVED 7
#define TZ_HDCP_CMD_ID 0x00004401
-#define HDCP_REG_ENABLE 0x01
-#define HDCP_REG_DISABLE 0x00
#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \
isr->auth_fail_info_ack | isr->tx_req_ack | \
@@ -52,6 +50,8 @@
#define HDCP_POLL_SLEEP_US (20 * 1000)
#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100)
+#define hdcp_1x_state(x) (hdcp->hdcp_state == x)
+
struct hdcp_sink_addr {
char *name;
u32 addr;
@@ -211,19 +211,19 @@ struct hdcp_reg_set {
BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \
BIT(15), BIT(18), BIT(22), BIT(25), 0, 0}
-struct hdcp_1x_ctrl {
- u32 auth_retries;
+struct hdcp_1x {
+ u8 bcaps;
u32 tp_msgid;
+ u32 an_0, an_1, aksv_0, aksv_1;
bool sink_r0_ready;
bool reauth;
+ bool ksv_ready;
enum hdcp_states hdcp_state;
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
struct delayed_work hdcp_auth_work;
- struct work_struct hdcp_int_work;
struct completion r0_checked;
struct completion sink_r0_available;
- struct completion sink_rep_ready;
struct hdcp_init_data init_data;
struct hdcp_ops *ops;
struct hdcp_reg_set reg_set;
@@ -241,7 +241,7 @@ const char *hdcp_state_name(enum hdcp_states hdcp_state)
case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL";
default: return "???";
}
-} /* hdcp_state_name */
+}
static int hdcp_1x_count_one(u8 *array, u8 len)
{
@@ -250,9 +250,9 @@ static int hdcp_1x_count_one(u8 *array, u8 len)
for (j = 0; j < 8; j++)
count += (((array[i] >> j) & 0x1) ? 1 : 0);
return count;
-} /* hdcp_1x_count_one */
+}
-static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void reset_hdcp_ddc_failures(struct hdcp_1x *hdcp)
{
int hdcp_ddc_ctrl1_reg;
int hdcp_ddc_status;
@@ -260,12 +260,12 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
int nack0;
struct dss_io_data *io;
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
return;
}
- io = hdcp_ctrl->init_data.core_io;
+ io = hdcp->init_data.core_io;
/* Check for any DDC transfer failures */
hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
@@ -335,7 +335,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
} /* reset_hdcp_ddc_failures */
-static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void hdcp_1x_hw_ddc_clean(struct hdcp_1x *hdcp)
{
struct dss_io_data *io = NULL;
u32 hdcp_ddc_status, ddc_hw_status;
@@ -344,12 +344,12 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl)
bool ddc_hw_not_ready, xfer_not_done, hw_not_done;
u32 timeout_count;
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
return;
}
- io = hdcp_ctrl->init_data.core_io;
+ io = hdcp->init_data.core_io;
if (!io->base) {
pr_err("core io not inititalized\n");
return;
@@ -394,27 +394,27 @@ static int hdcp_1x_load_keys(void *input)
u8 aksv[5];
struct dss_io_data *io;
struct dss_io_data *qfprom_io;
- struct hdcp_1x_ctrl *hdcp_ctrl = input;
+ struct hdcp_1x *hdcp = input;
struct hdcp_reg_set *reg_set;
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
- !hdcp_ctrl->init_data.qfprom_io) {
+ if (!hdcp || !hdcp->init_data.core_io ||
+ !hdcp->init_data.qfprom_io) {
pr_err("invalid input\n");
rc = -EINVAL;
goto end;
}
- if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) &&
- (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state)) {
+ if (!hdcp_1x_state(HDCP_STATE_INACTIVE) &&
+ !hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
pr_err("%s: invalid state. returning\n",
HDCP_STATE_NAME);
rc = -EINVAL;
goto end;
}
- io = hdcp_ctrl->init_data.core_io;
- qfprom_io = hdcp_ctrl->init_data.qfprom_io;
- reg_set = &hdcp_ctrl->reg_set;
+ io = hdcp->init_data.core_io;
+ qfprom_io = hdcp->init_data.qfprom_io;
+ reg_set = &hdcp->reg_set;
/* On compatible hardware, use SW keys */
reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION);
@@ -438,7 +438,7 @@ static int hdcp_1x_load_keys(void *input)
ksv_lsb_addr = HDCP_KSV_LSB;
ksv_msb_addr = HDCP_KSV_MSB;
- if (hdcp_ctrl->init_data.sec_access) {
+ if (hdcp->init_data.sec_access) {
ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET;
ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET;
}
@@ -476,12 +476,12 @@ static int hdcp_1x_load_keys(void *input)
/* enable hdcp engine */
DSS_REG_W(io, reg_set->ctrl, 0x1);
- hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING;
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATING;
end:
return rc;
}
-static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
+static int hdcp_1x_read(struct hdcp_1x *hdcp,
struct hdcp_sink_addr *sink,
u8 *buf, bool realign)
{
@@ -489,8 +489,8 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
int const max_size = 15, edid_read_delay_us = 20;
struct hdmi_tx_ddc_data ddc_data;
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
- reset_hdcp_ddc_failures(hdcp_ctrl);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ reset_hdcp_ddc_failures(hdcp);
memset(&ddc_data, 0, sizeof(ddc_data));
ddc_data.dev_addr = 0x74;
@@ -502,14 +502,14 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
ddc_data.what = sink->name;
ddc_data.retry_align = realign;
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
+ hdcp->init_data.ddc_ctrl->ddc_data = ddc_data;
- rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
+ rc = hdmi_ddc_read(hdcp->init_data.ddc_ctrl);
if (rc)
pr_err("%s: %s read failed\n",
HDCP_STATE_NAME, sink->name);
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
- hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ hdcp->init_data.client_id == HDCP_CLIENT_DP) {
int size = sink->len;
do {
@@ -523,7 +523,7 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
cmd.len = read_size;
cmd.out_buf = buf;
- rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd);
+ rc = dp_aux_read(hdcp->init_data.cb_data, &cmd);
if (rc) {
pr_err("Aux read failed\n");
break;
@@ -539,13 +539,13 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
return rc;
}
-static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl,
+static int hdcp_1x_write(struct hdcp_1x *hdcp,
struct hdcp_sink_addr *sink, u8 *buf)
{
int rc = 0;
struct hdmi_tx_ddc_data ddc_data;
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
memset(&ddc_data, 0, sizeof(ddc_data));
ddc_data.dev_addr = 0x74;
@@ -553,21 +553,21 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl,
ddc_data.data_buf = buf;
ddc_data.data_len = sink->len;
ddc_data.what = sink->name;
- hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data;
+ hdcp->init_data.ddc_ctrl->ddc_data = ddc_data;
- rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl);
+ rc = hdmi_ddc_write(hdcp->init_data.ddc_ctrl);
if (rc)
pr_err("%s: %s write failed\n",
HDCP_STATE_NAME, sink->name);
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
- hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ hdcp->init_data.client_id == HDCP_CLIENT_DP) {
struct edp_cmd cmd = {0};
cmd.addr = sink->addr;
cmd.len = sink->len;
cmd.datap = buf;
- rc = dp_aux_write(hdcp_ctrl->init_data.cb_data, &cmd);
+ rc = dp_aux_write(hdcp->init_data.cb_data, &cmd);
if (rc)
pr_err("%s: %s read failed\n",
HDCP_STATE_NAME, sink->name);
@@ -576,14 +576,14 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl,
return rc;
}
-static void hdcp_1x_enable_interrupts(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void hdcp_1x_enable_interrupts(struct hdcp_1x *hdcp)
{
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;
+ io = hdcp->init_data.core_io;
+ isr = &hdcp->int_set;
intr_reg = DSS_REG_R(io, isr->int_reg);
@@ -592,59 +592,49 @@ static void hdcp_1x_enable_interrupts(struct hdcp_1x_ctrl *hdcp_ctrl)
DSS_REG_W(io, isr->int_reg, intr_reg);
}
-static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
+static int hdcp_1x_read_bcaps(struct hdcp_1x *hdcp)
{
- 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_bksv_0, link0_bksv_1;
- u32 link0_an_0, link0_an_1;
- u32 timeout_count;
- struct dss_io_data *io;
- struct dss_io_data *hdcp_io;
- struct hdcp_reg_set *reg_set;
- u8 aksv[5], *bksv = NULL;
- u8 an[8];
- u8 bcaps = 0;
- u32 link0_status = 0;
- u8 buf[0xFF];
- u32 phy_addr;
-
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
- !hdcp_ctrl->init_data.qfprom_io) {
- pr_err("invalid input\n");
- rc = -EINVAL;
- goto error;
- }
-
- phy_addr = hdcp_ctrl->init_data.phy_addr;
- bksv = hdcp_ctrl->current_tp.bksv;
- io = hdcp_ctrl->init_data.core_io;
- hdcp_io = hdcp_ctrl->init_data.hdcp_io;
- reg_set = &hdcp_ctrl->reg_set;
+ int rc;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
- if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- pr_err("%s: invalid state. returning\n",
- HDCP_STATE_NAME);
- rc = -EINVAL;
- goto error;
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
}
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
- &bcaps, false);
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, false);
if (IS_ERR_VALUE(rc)) {
pr_err("error reading bcaps\n");
goto error;
}
- hdcp_1x_enable_interrupts(hdcp_ctrl);
+ pr_debug("bcaps read: 0x%x\n", hdcp->bcaps);
- hdcp_ctrl->current_tp.ds_type = bcaps & reg_set->repeater ?
+ hdcp->current_tp.ds_type = hdcp->bcaps & reg_set->repeater ?
DS_REPEATER : DS_RECEIVER;
+ pr_debug("ds: %s\n", hdcp->current_tp.ds_type == DS_REPEATER ?
+ "repeater" : "receiver");
+
/* Write BCAPS to the hardware */
- DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps);
+ DSS_REG_W(hdcp_io, reg_set->sec_data12, hdcp->bcaps);
+error:
+ return rc;
+}
+
+static int hdcp_1x_wait_for_hw_ready(struct hdcp_1x *hdcp)
+{
+ int rc;
+ u32 link0_status;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
/* Wait for HDCP keys to be checked and validated */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
@@ -673,56 +663,107 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
/* As per hardware recommendations, wait before reading An */
msleep(20);
+error:
+ return rc;
+}
- /*
- * As per hardware recommendation, for DP, read AN0 and AN1 again
- * with a delay of 1 micro second each.
- */
- link0_an_0 = DSS_REG_R(io, reg_set->data5);
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+static int hdcp_1x_send_an_aksv_to_sink(struct hdcp_1x *hdcp)
+{
+ int rc;
+ u8 an[8], aksv[5];
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ an[0] = hdcp->an_0 & 0xFF;
+ an[1] = (hdcp->an_0 >> 8) & 0xFF;
+ an[2] = (hdcp->an_0 >> 16) & 0xFF;
+ an[3] = (hdcp->an_0 >> 24) & 0xFF;
+ an[4] = hdcp->an_1 & 0xFF;
+ an[5] = (hdcp->an_1 >> 8) & 0xFF;
+ an[6] = (hdcp->an_1 >> 16) & 0xFF;
+ an[7] = (hdcp->an_1 >> 24) & 0xFF;
+
+ pr_debug("an read: 0x%2x%2x%2x%2x%2x%2x%2x%2x\n",
+ an[7], an[6], an[5], an[4], an[3], an[2], an[1], an[0]);
+
+ rc = hdcp_1x_write(hdcp, &hdcp->sink_addr.an, an);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error writing an to sink\n");
+ goto error;
+ }
+
+ /* Copy An and AKSV to byte arrays for transmission */
+ aksv[0] = hdcp->aksv_0 & 0xFF;
+ aksv[1] = (hdcp->aksv_0 >> 8) & 0xFF;
+ aksv[2] = (hdcp->aksv_0 >> 16) & 0xFF;
+ aksv[3] = (hdcp->aksv_0 >> 24) & 0xFF;
+ aksv[4] = hdcp->aksv_1 & 0xFF;
+
+ pr_debug("aksv read: 0x%2x%2x%2x%2x%2x\n",
+ aksv[4], aksv[3], aksv[2], aksv[1], aksv[0]);
+
+ rc = hdcp_1x_write(hdcp, &hdcp->sink_addr.aksv, aksv);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error writing aksv to sink\n");
+ goto error;
+ }
+error:
+ return rc;
+}
+
+static int hdcp_1x_read_an_aksv_from_hw(struct hdcp_1x *hdcp)
+{
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
udelay(1);
- link0_an_0 = DSS_REG_R(io, reg_set->data5);
+ hdcp->an_0 = DSS_REG_R(io, reg_set->data5);
}
- link0_an_1 = DSS_REG_R(io, reg_set->data6);
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_DP) {
udelay(1);
- link0_an_1 = DSS_REG_R(io, reg_set->data6);
+ hdcp->an_1 = DSS_REG_R(io, reg_set->data6);
}
/* Read AKSV */
- link0_aksv_0 = DSS_REG_R(io, reg_set->data3);
- link0_aksv_1 = DSS_REG_R(io, reg_set->data4);
+ hdcp->aksv_0 = DSS_REG_R(io, reg_set->data3);
+ hdcp->aksv_1 = DSS_REG_R(io, reg_set->data4);
- /* Copy An and AKSV to byte arrays for transmission */
- aksv[0] = link0_aksv_0 & 0xFF;
- aksv[1] = (link0_aksv_0 >> 8) & 0xFF;
- aksv[2] = (link0_aksv_0 >> 16) & 0xFF;
- aksv[3] = (link0_aksv_0 >> 24) & 0xFF;
- aksv[4] = link0_aksv_1 & 0xFF;
-
- an[0] = link0_an_0 & 0xFF;
- an[1] = (link0_an_0 >> 8) & 0xFF;
- an[2] = (link0_an_0 >> 16) & 0xFF;
- an[3] = (link0_an_0 >> 24) & 0xFF;
- an[4] = link0_an_1 & 0xFF;
- an[5] = (link0_an_1 >> 8) & 0xFF;
- an[6] = (link0_an_1 >> 16) & 0xFF;
- an[7] = (link0_an_1 >> 24) & 0xFF;
-
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false);
+ return 0;
+}
+
+static int hdcp_1x_get_bksv_from_sink(struct hdcp_1x *hdcp)
+{
+ int rc;
+ u8 *bksv = hdcp->current_tp.bksv;
+ u32 link0_bksv_0, link0_bksv_1;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io;
+
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.bksv, bksv, false);
if (IS_ERR_VALUE(rc)) {
pr_err("error reading bksv from sink\n");
goto error;
}
+ pr_debug("bksv read: 0x%2x%2x%2x%2x%2x\n",
+ bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
+
/* check there are 20 ones in BKSV */
if (hdcp_1x_count_one(bksv, 5) != 20) {
pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n",
HDCP_STATE_NAME);
- pr_err("%s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
- HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2],
- bksv[1], bksv[0]);
rc = -EINVAL;
goto error;
}
@@ -732,11 +773,27 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
link0_bksv_1 = bksv[4];
- pr_debug("%s: BKSV=%02x%08x\n", HDCP_STATE_NAME,
- link0_bksv_1, link0_bksv_0);
DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
+error:
+ return rc;
+}
+
+static int hdcp_1x_verify_r0(struct hdcp_1x *hdcp)
+{
+ int rc, r0_retry = 3;
+ u8 buf[2];
+ u32 link0_status, timeout_count;
+ u32 const r0_read_delay_us = 1;
+ u32 const r0_read_timeout_us = r0_read_delay_us * 10;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
/* Wait for HDCP R0 computation to be completed */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
@@ -747,84 +804,99 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
goto error;
}
- rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an);
- if (IS_ERR_VALUE(rc)) {
- pr_err("error writing an to sink\n");
- goto error;
- }
-
- rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv);
- if (IS_ERR_VALUE(rc)) {
- pr_err("error writing aksv to sink\n");
- 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);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ msleep(100);
} else {
- if (!hdcp_ctrl->sink_r0_ready) {
- reinit_completion(&hdcp_ctrl->sink_r0_available);
+ if (!hdcp->sink_r0_ready) {
+ reinit_completion(&hdcp->sink_r0_available);
timeout_count = wait_for_completion_timeout(
- &hdcp_ctrl->sink_r0_available, HZ / 2);
+ &hdcp->sink_r0_available, HZ / 2);
- if (!timeout_count || hdcp_ctrl->reauth) {
+ if (!timeout_count || hdcp->reauth) {
pr_err("sink R0 not ready\n");
rc = -EINVAL;
goto error;
}
}
}
-r0_read_retry:
- memset(buf, 0, sizeof(buf));
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false);
- if (IS_ERR_VALUE(rc)) {
- pr_err("error reading R0' from sink\n");
- goto error;
+
+ do {
+ memset(buf, 0, sizeof(buf));
+
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.r0,
+ buf, false);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error reading R0' from sink\n");
+ goto error;
+ }
+
+ pr_debug("sink R0'read: %2x%2x\n", buf[1], buf[0]);
+
+ DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
+
+ rc = readl_poll_timeout(io->base + reg_set->status,
+ link0_status, link0_status & BIT(12),
+ r0_read_delay_us, r0_read_timeout_us);
+ } while (rc && --r0_retry);
+error:
+ return rc;
+}
+
+static int hdcp_1x_authentication_part1(struct hdcp_1x *hdcp)
+{
+ int rc;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
}
- pr_debug("%s: R0'=%02x%02x\n", HDCP_STATE_NAME,
- buf[1], buf[0]);
+ hdcp_1x_enable_interrupts(hdcp);
- /* Write R0' to HDCP registers and check to see if it is a match */
- DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
- rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
- link0_status & BIT(12),
- r0_read_delay_us, r0_read_timeout_us);
- if (IS_ERR_VALUE(rc)) {
- pr_err("R0 mismatch\n");
- if (--r0_retry)
- goto r0_read_retry;
+ rc = hdcp_1x_read_bcaps(hdcp);
+ if (rc)
+ goto error;
+ rc = hdcp_1x_wait_for_hw_ready(hdcp);
+ if (rc)
goto error;
- }
- hdcp1_set_enc(true);
+ rc = hdcp_1x_read_an_aksv_from_hw(hdcp);
+ if (rc)
+ goto error;
- pr_debug("%s: Authentication Part I successful\n",
- hdcp_ctrl ? HDCP_STATE_NAME : "???");
+ rc = hdcp_1x_get_bksv_from_sink(hdcp);
+ if (rc)
+ goto error;
- return 0;
+ rc = hdcp_1x_send_an_aksv_to_sink(hdcp);
+ if (rc)
+ goto error;
+ rc = hdcp_1x_verify_r0(hdcp);
+ if (rc)
+ goto error;
+
+ pr_info("SUCCESSFUL\n");
+
+ return 0;
error:
- pr_err("%s: Authentication Part I failed\n",
- hdcp_ctrl ? HDCP_STATE_NAME : "???");
+ pr_err("%s: FAILED\n", HDCP_STATE_NAME);
return rc;
-} /* hdcp_1x_authentication_part1 */
+}
-static int hdcp_1x_set_v_h(struct hdcp_1x_ctrl *hdcp_ctrl,
+static int hdcp_1x_set_v_h(struct hdcp_1x *hdcp,
struct hdcp_1x_reg_data *rd, u8 *buf)
{
int rc;
- struct dss_io_data *io;
+ struct dss_io_data *io = hdcp->init_data.hdcp_io;
- io = hdcp_ctrl->init_data.hdcp_io;
-
- rc = hdcp_1x_read(hdcp_ctrl, rd->sink, buf, false);
+ rc = hdcp_1x_read(hdcp, rd->sink, buf, false);
if (IS_ERR_VALUE(rc)) {
pr_err("error reading %s\n", rd->sink->name);
goto end;
@@ -836,125 +908,70 @@ end:
return rc;
}
-static int hdcp_1x_transfer_v_h(struct hdcp_1x_ctrl *hdcp_ctrl)
+static int hdcp_1x_transfer_v_h(struct hdcp_1x *hdcp)
{
int rc = 0;
u8 buf[4];
u32 phy_addr;
- struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
struct hdcp_1x_reg_data reg_data[] = {
- {reg_set->sec_data7, &hdcp_ctrl->sink_addr.v_h0},
- {reg_set->sec_data8, &hdcp_ctrl->sink_addr.v_h1},
- {reg_set->sec_data9, &hdcp_ctrl->sink_addr.v_h2},
- {reg_set->sec_data10, &hdcp_ctrl->sink_addr.v_h3},
- {reg_set->sec_data11, &hdcp_ctrl->sink_addr.v_h4},
+ {reg_set->sec_data7, &hdcp->sink_addr.v_h0},
+ {reg_set->sec_data8, &hdcp->sink_addr.v_h1},
+ {reg_set->sec_data9, &hdcp->sink_addr.v_h2},
+ {reg_set->sec_data10, &hdcp->sink_addr.v_h3},
+ {reg_set->sec_data11, &hdcp->sink_addr.v_h4},
};
u32 size = ARRAY_SIZE(reg_data);
u32 iter = 0;
- phy_addr = hdcp_ctrl->init_data.phy_addr;
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ phy_addr = hdcp->init_data.phy_addr;
for (iter = 0; iter < size; iter++) {
struct hdcp_1x_reg_data *rd = reg_data + iter;
memset(buf, 0, sizeof(buf));
- hdcp_1x_set_v_h(hdcp_ctrl, rd, buf);
+ hdcp_1x_set_v_h(hdcp, rd, buf);
}
return rc;
}
-static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
+static int hdcp_1x_validate_downstream(struct hdcp_1x *hdcp)
{
- int rc, i;
- u32 timeout_count, down_stream_devices = 0;
- u32 repeater_cascade_depth = 0;
- u8 buf[0xFF];
- u8 *ksv_fifo = NULL;
- u8 bcaps = 0;
- u16 bstatus = 0, max_devs_exceeded = 0, max_cascade_exceeded = 0;
- u32 status = 0, sha_status = 0;
- u32 ksv_bytes;
- struct dss_io_data *io;
- struct hdcp_reg_set *reg_set;
- u32 phy_addr;
- u32 ksv_read_retry = 20;
- int v_retry = 3;
-
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- pr_err("invalid input\n");
- rc = -EINVAL;
- goto error;
- }
-
- phy_addr = hdcp_ctrl->init_data.phy_addr;
- reg_set = &hdcp_ctrl->reg_set;
-
- if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- pr_debug("%s: invalid state. returning\n",
- HDCP_STATE_NAME);
- rc = -EINVAL;
- goto error;
- }
-
- ksv_fifo = hdcp_ctrl->current_tp.ksv_list;
-
- io = hdcp_ctrl->init_data.core_io;
-
- memset(buf, 0, sizeof(buf));
- memset(ksv_fifo, 0, sizeof(hdcp_ctrl->current_tp.ksv_list));
-
- /*
- * Wait until READY bit is set in BCAPS, as per HDCP specifications
- * maximum permitted time to check for READY bit is five seconds.
- */
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true);
- if (IS_ERR_VALUE(rc)) {
- pr_err("error reading bcaps\n");
- goto error;
- }
-
- 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)) {
- pr_err("error reading bcaps\n");
- 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 || hdcp_ctrl->reauth) {
- pr_err("sink not ready with DS KSV list\n");
- rc = -EINVAL;
- goto error;
- }
+ int rc;
+ u8 buf[2];
+ u8 device_count, depth;
+ u8 max_cascade_exceeded, max_devs_exceeded;
+ u16 bstatus;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
}
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.bstatus,
buf, true);
if (IS_ERR_VALUE(rc)) {
pr_err("error reading bstatus\n");
- goto error;
+ goto end;
}
bstatus = buf[1];
bstatus = (bstatus << 8) | buf[0];
- down_stream_devices = bstatus & 0x7F;
+ device_count = bstatus & 0x7F;
- pr_debug("DEVICE_COUNT %d\n", down_stream_devices);
+ pr_debug("device count %d\n", device_count);
/* Cascaded repeater depth */
- repeater_cascade_depth = (bstatus >> 8) & 0x7;
- pr_debug("DEPTH %d\n", repeater_cascade_depth);
+ depth = (bstatus >> 8) & 0x7;
+ pr_debug("depth %d\n", depth);
/*
* HDCP Compliance 1B-05:
@@ -962,12 +979,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
* exceed max_devices_connected from bit 7 of Bstatus.
*/
max_devs_exceeded = (bstatus & BIT(7)) >> 7;
- pr_debug("MAX_DEVS_EXCEEDED %d\n", max_devs_exceeded);
if (max_devs_exceeded == 0x01) {
- pr_err("%s: no. of devs connected exceeds max allowed",
- HDCP_STATE_NAME);
+ pr_err("no. of devs connected exceed max allowed\n");
rc = -EINVAL;
- goto error;
+ goto end;
}
/*
@@ -976,77 +991,78 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
* exceed max_cascade_connected from bit 11 of Bstatus.
*/
max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
- pr_debug("MAX CASCADE_EXCEEDED %d\n",
- max_cascade_exceeded);
if (max_cascade_exceeded == 0x01) {
- pr_err("%s: no. of cascade conn exceeds max allowed",
- HDCP_STATE_NAME);
+ pr_err("no. of cascade connections exceed max allowed\n");
rc = -EINVAL;
- goto error;
+ goto end;
}
- /*
- * Read KSV FIFO over DDC
- * Key Slection vector FIFO Used to pull downstream KSVs
- * from HDCP Repeaters.
- * All bytes (DEVICE_COUNT * 5) must be read in a single,
- * auto incrementing access.
- * All bytes read as 0x00 for HDCP Receivers that are not
- * HDCP Repeaters (REPEATER == 0).
- */
- ksv_bytes = 5 * down_stream_devices;
- hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes;
+ /* Update topology information */
+ hdcp->current_tp.dev_count = device_count;
+ hdcp->current_tp.max_cascade_exceeded = max_cascade_exceeded;
+ hdcp->current_tp.max_dev_exceeded = max_devs_exceeded;
+ hdcp->current_tp.depth = depth;
+
+ DSS_REG_W(hdcp->init_data.hdcp_io,
+ reg_set->sec_data12, hdcp->bcaps | (bstatus << 8));
+end:
+ return rc;
+}
+
+static int hdcp_1x_read_ksv_fifo(struct hdcp_1x *hdcp)
+{
+ u32 ksv_read_retry = 20, ksv_bytes, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ memset(ksv_fifo, 0, sizeof(hdcp->current_tp.ksv_list));
+
+ /* each KSV is 5 bytes long */
+ ksv_bytes = 5 * hdcp->current_tp.dev_count;
+ hdcp->sink_addr.ksv_fifo.len = ksv_bytes;
while (ksv_bytes && --ksv_read_retry) {
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo,
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.ksv_fifo,
ksv_fifo, false);
- if (IS_ERR_VALUE(rc)) {
- pr_debug("could not read ksv fifo (%d)\n",
+ if (IS_ERR_VALUE(rc))
+ pr_err("could not read ksv fifo (%d)\n",
ksv_read_retry);
- /*
- * HDCP Compliace Test case 1B-01:
- * Wait here until all the ksv bytes have been
- * read from the KSV FIFO register.
- */
- msleep(25);
- } else {
+ else
break;
- }
- }
-
- if (rc) {
- pr_err("error reading ksv_fifo\n");
- goto error;
}
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_data12, bcaps | (bstatus << 8));
-v_read_retry:
- rc = hdcp_1x_transfer_v_h(hdcp_ctrl);
if (rc)
- goto error;
+ pr_err("error reading ksv_fifo\n");
- /* do not proceed further if no downstream device connected */
- if (!ksv_bytes)
- goto error;
+ return rc;
+}
- /*
- * Write KSV FIFO to HDCP_SHA_DATA.
- * This is done 1 byte at time starting with the LSB.
- * On the very last byte write, the HDCP_SHA_DATA_DONE bit[0]
- */
+static int hdcp_1x_write_ksv_fifo(struct hdcp_1x *hdcp)
+{
+ int i, rc = 0;
+ u8 *ksv_fifo = hdcp->current_tp.ksv_list;
+ u32 ksv_bytes = hdcp->sink_addr.ksv_fifo.len;
+ struct dss_io_data *io = hdcp->init_data.core_io;
+ struct dss_io_data *sec_io = hdcp->init_data.hdcp_io;
+ struct hdcp_reg_set *reg_set = &hdcp->reg_set;
+ u32 sha_status = 0, status;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
- /* First, reset SHA engine */
- /* Next, enable SHA engine, SEL=DIGA_HDCP */
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl, HDCP_REG_ENABLE);
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl, HDCP_REG_DISABLE);
+ /* reset SHA Controller */
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x1);
+ DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x0);
for (i = 0; i < ksv_bytes - 1; i++) {
/* Write KSV byte and do not set DONE bit[0] */
- DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_data, ksv_fifo[i] << 16);
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data, ksv_fifo[i] << 16);
/*
* Once 64 bytes have been written, we need to poll for
@@ -1065,8 +1081,8 @@ v_read_retry:
}
/* Write l to DONE bit[0] */
- DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_data, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
+ DSS_REG_W_ND(sec_io, reg_set->sec_sha_data,
+ (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
/* Now wait for HDCP_SHA_COMP_DONE */
rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
@@ -1083,43 +1099,136 @@ v_read_retry:
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
pr_err("V mismatch\n");
- if (--v_retry)
- goto v_read_retry;
+ rc = -EINVAL;
+ }
+error:
+ return rc;
+}
+
+static int hdcp_1x_wait_for_ksv_ready(struct hdcp_1x *hdcp)
+{
+ int rc, timeout;
+
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Wait until READY bit is set in BCAPS, as per HDCP specifications
+ * maximum permitted time to check for READY bit is five seconds.
+ */
+ rc = hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, true);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) {
+ timeout = 50;
+
+ while (!(hdcp->bcaps & BIT(5)) && --timeout) {
+ rc = hdcp_1x_read(hdcp,
+ &hdcp->sink_addr.bcaps,
+ &hdcp->bcaps, true);
+ if (IS_ERR_VALUE(rc) ||
+ !hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+ msleep(100);
+ }
+ } else {
+ u8 cp_buf = 0;
+ struct hdcp_sink_addr *sink =
+ &hdcp->sink_addr.cp_irq_status;
+
+ timeout = jiffies_to_msecs(jiffies);
+
+ while (1) {
+ rc = hdcp_1x_read(hdcp, sink, &cp_buf, false);
+ if (rc)
+ goto error;
+
+ if (cp_buf & BIT(0))
+ break;
+
+ /* max timeout of 5 sec as per hdcp 1.x spec */
+ if (abs(timeout - jiffies_to_msecs(jiffies)) > 5000) {
+ timeout = 0;
+ break;
+ }
+
+ if (hdcp->ksv_ready || hdcp->reauth ||
+ !hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ break;
+
+ /* re-read after a minimum delay */
+ msleep(20);
+ }
+ }
+
+ if (!timeout || hdcp->reauth ||
+ !hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("DS KSV not ready\n");
+ rc = -EINVAL;
+ } else {
+ hdcp->ksv_ready = true;
}
error:
+ return rc;
+}
+
+static int hdcp_1x_authentication_part2(struct hdcp_1x *hdcp)
+{
+ int rc;
+ int v_retry = 3;
+
+ rc = hdcp_1x_validate_downstream(hdcp);
if (rc)
- pr_err("%s: Authentication Part II failed\n",
- hdcp_ctrl ? HDCP_STATE_NAME : "???");
- else
- pr_debug("%s: Authentication Part II successful\n",
- HDCP_STATE_NAME);
+ goto error;
+
+ rc = hdcp_1x_read_ksv_fifo(hdcp);
+ if (rc)
+ goto error;
+
+ do {
+ rc = hdcp_1x_transfer_v_h(hdcp);
+ if (rc)
+ goto error;
- if (!hdcp_ctrl) {
- pr_err("hdcp_ctrl null. Topology not updated\n");
- return rc;
+ /* do not proceed further if no device connected */
+ if (!hdcp->current_tp.dev_count)
+ goto error;
+
+ rc = hdcp_1x_write_ksv_fifo(hdcp);
+ } while (--v_retry && rc);
+error:
+ if (rc) {
+ pr_err("%s: FAILED\n", HDCP_STATE_NAME);
+ } else {
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+
+ pr_info("SUCCESSFUL\n");
}
- /* Update topology information */
- hdcp_ctrl->current_tp.dev_count = down_stream_devices;
- hdcp_ctrl->current_tp.max_cascade_exceeded = max_cascade_exceeded;
- hdcp_ctrl->current_tp.max_dev_exceeded = max_devs_exceeded;
- hdcp_ctrl->current_tp.depth = repeater_cascade_depth;
return rc;
-} /* hdcp_1x_authentication_part2 */
+}
-static void hdcp_1x_cache_topology(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void hdcp_1x_cache_topology(struct hdcp_1x *hdcp)
{
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
return;
}
- memcpy((void *)&hdcp_ctrl->cached_tp,
- (void *) &hdcp_ctrl->current_tp,
- sizeof(hdcp_ctrl->cached_tp));
+ memcpy((void *)&hdcp->cached_tp,
+ (void *) &hdcp->current_tp,
+ sizeof(hdcp->cached_tp));
}
-static void hdcp_1x_notify_topology(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void hdcp_1x_notify_topology(struct hdcp_1x *hdcp)
{
char a[16], b[16];
char *envp[] = {
@@ -1131,152 +1240,124 @@ static void hdcp_1x_notify_topology(struct hdcp_1x_ctrl *hdcp_ctrl)
snprintf(envp[1], 16, "%d", (int)DOWN_CHECK_TOPOLOGY);
snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
- kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp);
+ kobject_uevent_env(hdcp->init_data.sysfs_kobj, KOBJ_CHANGE, envp);
pr_debug("Event Sent: %s msgID = %s srcID = %s\n",
envp[0], envp[1], envp[2]);
}
-static void hdcp_1x_int_work(struct work_struct *work)
+static void hdcp_1x_update_auth_status(struct hdcp_1x *hdcp)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = container_of(work,
- struct hdcp_1x_ctrl, hdcp_int_work);
-
- if (!hdcp_ctrl) {
- pr_err("invalid input\n");
- return;
- }
-
- if (hdcp_ctrl->hdcp_state == HDCP_STATE_AUTHENTICATED)
+ if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ hdcp_1x_cache_topology(hdcp);
+ hdcp_1x_notify_topology(hdcp);
+ } else {
hdcp1_set_enc(false);
+ }
- mutex_lock(hdcp_ctrl->init_data.mutex);
- hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
- mutex_unlock(hdcp_ctrl->init_data.mutex);
-
- if (hdcp_ctrl->init_data.notify_status) {
- hdcp_ctrl->init_data.notify_status(
- hdcp_ctrl->init_data.cb_data,
- hdcp_ctrl->hdcp_state);
+ if (hdcp->init_data.notify_status &&
+ !hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ hdcp->init_data.notify_status(
+ hdcp->init_data.cb_data,
+ hdcp->hdcp_state);
}
-} /* hdcp_1x_int_work */
+}
static void hdcp_1x_auth_work(struct work_struct *work)
{
int rc;
struct delayed_work *dw = to_delayed_work(work);
- struct hdcp_1x_ctrl *hdcp_ctrl = container_of(dw,
- struct hdcp_1x_ctrl, hdcp_auth_work);
+ struct hdcp_1x *hdcp = container_of(dw,
+ struct hdcp_1x, hdcp_auth_work);
struct dss_io_data *io;
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
return;
}
- if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- pr_debug("%s: invalid state. returning\n",
- HDCP_STATE_NAME);
+ if (!hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ pr_err("invalid state\n");
return;
}
- hdcp_ctrl->sink_r0_ready = false;
- hdcp_ctrl->reauth = false;
+ hdcp->sink_r0_ready = false;
+ hdcp->reauth = false;
+ hdcp->ksv_ready = false;
- io = hdcp_ctrl->init_data.core_io;
+ io = hdcp->init_data.core_io;
/* Enabling Software DDC for HDMI and REF timer for DP */
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
HDMI_DDC_ARBITRATION) & ~(BIT(4)));
- else if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP)
+ else if (hdcp->init_data.client_id == HDCP_CLIENT_DP)
DSS_REG_W(io, DP_DP_HPD_REFTIMER, 0x10013);
- rc = hdcp_1x_authentication_part1(hdcp_ctrl);
- if (rc) {
- pr_debug("%s: HDCP Auth Part I failed\n",
- HDCP_STATE_NAME);
- goto error;
- }
+ /*
+ * program hw to enable encryption as soon as
+ * authentication is successful.
+ */
+ hdcp1_set_enc(true);
- if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) {
- rc = hdcp_1x_authentication_part2(hdcp_ctrl);
- if (rc) {
- pr_debug("%s: HDCP Auth Part II failed\n",
- HDCP_STATE_NAME);
- goto error;
- }
+ rc = hdcp_1x_authentication_part1(hdcp);
+ if (rc)
+ goto end;
+
+ if (hdcp->current_tp.ds_type == DS_REPEATER) {
+ rc = hdcp_1x_wait_for_ksv_ready(hdcp);
+ if (rc)
+ goto end;
} else {
- pr_debug("Downstream device is not a repeater\n");
+ hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED;
+ goto end;
}
- /* Disabling software DDC before going into part3 to make sure
- * there is no Arbitration between software and hardware for DDC */
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
- DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
- HDMI_DDC_ARBITRATION) | (BIT(4)));
-error:
+ hdcp->ksv_ready = false;
+
+ rc = hdcp_1x_authentication_part2(hdcp);
+ if (rc)
+ goto end;
+
/*
- * Ensure that the state did not change during authentication.
- * If it did, it means that deauthenticate/reauthenticate was
- * called. In that case, this function need not notify HDMI Tx
- * of the result
+ * Disabling software DDC before going into part3 to make sure
+ * there is no Arbitration between software and hardware for DDC
*/
- mutex_lock(hdcp_ctrl->init_data.mutex);
- if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
- if (rc) {
- hdcp_ctrl->hdcp_state = HDCP_STATE_AUTH_FAIL;
- } else {
- hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATED;
- hdcp_ctrl->auth_retries = 0;
- hdcp_1x_cache_topology(hdcp_ctrl);
- hdcp_1x_notify_topology(hdcp_ctrl);
- }
- mutex_unlock(hdcp_ctrl->init_data.mutex);
+ if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI)
+ DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io,
+ HDMI_DDC_ARBITRATION) | (BIT(4)));
+end:
+ if (rc && !hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+
+ hdcp_1x_update_auth_status(hdcp);
- /* Notify HDMI Tx controller of the result */
- pr_debug("%s: Notifying HDMI Tx of auth result\n",
- HDCP_STATE_NAME);
- if (hdcp_ctrl->init_data.notify_status) {
- hdcp_ctrl->init_data.notify_status(
- hdcp_ctrl->init_data.cb_data,
- hdcp_ctrl->hdcp_state);
- }
- } else {
- pr_debug("%s: HDCP state changed during authentication\n",
- HDCP_STATE_NAME);
- mutex_unlock(hdcp_ctrl->init_data.mutex);
- }
return;
-} /* hdcp_1x_auth_work */
+}
int hdcp_1x_authenticate(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
return -EINVAL;
}
- if (HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) {
- pr_debug("%s: already active or activating. returning\n",
- HDCP_STATE_NAME);
- return 0;
- }
+ flush_delayed_work(&hdcp->hdcp_auth_work);
- pr_debug("%s: Queuing work to start HDCP authentication",
- HDCP_STATE_NAME);
+ if (!hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
+ }
if (!hdcp_1x_load_keys(input)) {
- flush_delayed_work(&hdcp_ctrl->hdcp_auth_work);
- queue_delayed_work(hdcp_ctrl->workq,
- &hdcp_ctrl->hdcp_auth_work, HZ/2);
+ queue_delayed_work(hdcp->workq,
+ &hdcp->hdcp_auth_work, HZ/2);
} else {
- flush_work(&hdcp_ctrl->hdcp_int_work);
-
- queue_work(hdcp_ctrl->workq,
- &hdcp_ctrl->hdcp_int_work);
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ hdcp_1x_update_auth_status(hdcp);
}
return 0;
@@ -1284,29 +1365,28 @@ int hdcp_1x_authenticate(void *input)
int hdcp_1x_reauthenticate(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
struct dss_io_data *io;
struct hdcp_reg_set *reg_set;
struct hdcp_int_set *isr;
u32 hdmi_hw_version;
u32 ret = 0, reg;
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
return -EINVAL;
}
- io = hdcp_ctrl->init_data.core_io;
- reg_set = &hdcp_ctrl->reg_set;
- isr = &hdcp_ctrl->int_set;
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
- if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
- pr_debug("%s: invalid state. returning\n",
- HDCP_STATE_NAME);
- return 0;
+ if (!hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
+ pr_err("invalid state\n");
+ return -EINVAL;
}
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ if (hdcp->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));
@@ -1314,7 +1394,7 @@ int hdcp_1x_reauthenticate(void *input)
}
/* Wait to be clean on DDC HW engine */
- hdcp_1x_hw_ddc_clean(hdcp_ctrl);
+ hdcp_1x_hw_ddc_clean(hdcp);
}
/* Disable HDCP interrupts */
@@ -1328,41 +1408,36 @@ int hdcp_1x_reauthenticate(void *input)
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
- if (!hdcp_1x_load_keys(input))
- queue_delayed_work(hdcp_ctrl->workq,
- &hdcp_ctrl->hdcp_auth_work, HZ);
- else
- queue_work(hdcp_ctrl->workq,
- &hdcp_ctrl->hdcp_int_work);
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ hdcp_1x_authenticate(hdcp);
return ret;
} /* hdcp_1x_reauthenticate */
void hdcp_1x_off(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
struct dss_io_data *io;
struct hdcp_reg_set *reg_set;
struct hdcp_int_set *isr;
int rc = 0;
u32 reg;
- if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
return;
}
- io = hdcp_ctrl->init_data.core_io;
- reg_set = &hdcp_ctrl->reg_set;
- isr = &hdcp_ctrl->int_set;
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
- if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
- pr_debug("%s: inactive. returning\n",
- HDCP_STATE_NAME);
+ if (hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ pr_err("invalid state\n");
return;
}
- if (hdcp_ctrl->hdcp_state == HDCP_STATE_AUTHENTICATED)
+ if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED))
hdcp1_set_enc(false);
/*
@@ -1370,27 +1445,25 @@ void hdcp_1x_off(void *input)
* Also, need to set the state to inactive here so that any ongoing
* reauth works will know that the HDCP session has been turned off.
*/
- mutex_lock(hdcp_ctrl->init_data.mutex);
+ mutex_lock(hdcp->init_data.mutex);
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);
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ mutex_unlock(hdcp->init_data.mutex);
+ /* complete any wait pending */
+ complete_all(&hdcp->sink_r0_available);
+ complete_all(&hdcp->r0_checked);
/*
* Cancel any pending auth/reauth attempts.
* If one is ongoing, this will wait for it to finish.
* No more reauthentiaction attempts will be scheduled since we
* set the currect state to inactive.
*/
- rc = cancel_delayed_work(&hdcp_ctrl->hdcp_auth_work);
+ rc = cancel_delayed_work(&hdcp->hdcp_auth_work);
if (rc)
pr_debug("%s: Deleted hdcp auth work\n",
HDCP_STATE_NAME);
- rc = cancel_work_sync(&hdcp_ctrl->hdcp_int_work);
- if (rc)
- pr_debug("%s: Deleted hdcp int work\n",
- HDCP_STATE_NAME);
-
reg = DSS_REG_R(io, reg_set->reset);
DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit);
@@ -1400,34 +1473,34 @@ void hdcp_1x_off(void *input)
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
- hdcp_ctrl->sink_r0_ready = false;
+ hdcp->sink_r0_ready = false;
pr_debug("%s: HDCP: Off\n", HDCP_STATE_NAME);
} /* hdcp_1x_off */
int hdcp_1x_isr(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)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) {
+ if (!hdcp || !hdcp->init_data.core_io) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
- io = hdcp_ctrl->init_data.core_io;
- reg_set = &hdcp_ctrl->reg_set;
- isr = &hdcp_ctrl->int_set;
+ io = hdcp->init_data.core_io;
+ reg_set = &hdcp->reg_set;
+ isr = &hdcp->int_set;
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) {
+ if (hdcp_1x_state(HDCP_STATE_INACTIVE)) {
DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR);
return 0;
}
@@ -1436,10 +1509,10 @@ int hdcp_1x_isr(void *input)
/* AUTH_SUCCESS_INT */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->auth_success_ack));
- pr_debug("%s: AUTH_SUCCESS_INT received\n",
- HDCP_STATE_NAME);
- if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state)
- complete_all(&hdcp_ctrl->r0_checked);
+ pr_debug("%s: AUTH SUCCESS\n", HDCP_STATE_NAME);
+
+ if (hdcp_1x_state(HDCP_STATE_AUTHENTICATING))
+ complete_all(&hdcp->r0_checked);
}
if (hdcp_int_val & isr->auth_fail_int) {
@@ -1448,15 +1521,15 @@ int hdcp_1x_isr(void *input)
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->auth_fail_ack));
- pr_debug("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
+
+ pr_debug("%s: AUTH FAIL, LINK0_STATUS=0x%08x\n",
HDCP_STATE_NAME, link_status);
- if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
- /* Inform HDMI Tx of the failure */
- queue_work(hdcp_ctrl->workq,
- &hdcp_ctrl->hdcp_int_work);
- /* todo: print debug log with auth fail reason */
- } else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
- complete_all(&hdcp_ctrl->r0_checked);
+
+ if (hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) {
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+ hdcp_1x_update_auth_status(hdcp);
+ } else if (hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) {
+ complete_all(&hdcp->r0_checked);
}
/* Clear AUTH_FAIL_INFO as well */
@@ -1498,9 +1571,9 @@ int hdcp_1x_isr(void *input)
error:
return rc;
-} /* hdcp_1x_isr */
+}
-static struct hdcp_1x_ctrl *hdcp_1x_get_ctrl(struct device *dev)
+static struct hdcp_1x *hdcp_1x_get_ctrl(struct device *dev)
{
struct fb_info *fbi;
struct msm_fb_data_type *mfd;
@@ -1538,17 +1611,17 @@ static ssize_t hdcp_1x_sysfs_rda_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
- struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
+ struct hdcp_1x *hdcp = hdcp_1x_get_ctrl(dev);
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
return -EINVAL;
}
- mutex_lock(hdcp_ctrl->init_data.mutex);
- ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp_ctrl->hdcp_state);
- pr_debug("'%d'\n", hdcp_ctrl->hdcp_state);
- mutex_unlock(hdcp_ctrl->init_data.mutex);
+ mutex_lock(hdcp->init_data.mutex);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp->hdcp_state);
+ pr_debug("'%d'\n", hdcp->hdcp_state);
+ mutex_unlock(hdcp->init_data.mutex);
return ret;
} /* hdcp_1x_sysfs_rda_hdcp*/
@@ -1557,27 +1630,27 @@ static ssize_t hdcp_1x_sysfs_rda_tp(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret = 0;
- struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
+ struct hdcp_1x *hdcp = hdcp_1x_get_ctrl(dev);
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
return -EINVAL;
}
- switch (hdcp_ctrl->tp_msgid) {
+ switch (hdcp->tp_msgid) {
case DOWN_CHECK_TOPOLOGY:
case DOWN_REQUEST_TOPOLOGY:
- buf[MSG_ID_IDX] = hdcp_ctrl->tp_msgid;
+ buf[MSG_ID_IDX] = hdcp->tp_msgid;
buf[RET_CODE_IDX] = HDCP_AUTHED;
ret = HEADER_LEN;
- memcpy(buf + HEADER_LEN, &hdcp_ctrl->cached_tp,
+ memcpy(buf + HEADER_LEN, &hdcp->cached_tp,
sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
/* clear the flag once data is read back to user space*/
- hdcp_ctrl->tp_msgid = -1;
+ hdcp->tp_msgid = -1;
break;
default:
ret = -EINVAL;
@@ -1591,9 +1664,9 @@ static ssize_t hdcp_1x_sysfs_wta_tp(struct device *dev,
{
int msgid = 0;
ssize_t ret = count;
- struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
+ struct hdcp_1x *hdcp = hdcp_1x_get_ctrl(dev);
- if (!hdcp_ctrl || !buf) {
+ if (!hdcp || !buf) {
pr_err("invalid input\n");
return -EINVAL;
}
@@ -1603,7 +1676,7 @@ static ssize_t hdcp_1x_sysfs_wta_tp(struct device *dev,
switch (msgid) {
case DOWN_CHECK_TOPOLOGY:
case DOWN_REQUEST_TOPOLOGY:
- hdcp_ctrl->tp_msgid = msgid;
+ hdcp->tp_msgid = msgid;
break;
/* more cases added here */
default:
@@ -1631,65 +1704,59 @@ static struct attribute_group hdcp_1x_fs_attr_group = {
void hdcp_1x_deinit(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
return;
}
- if (hdcp_ctrl->workq)
- destroy_workqueue(hdcp_ctrl->workq);
+ if (hdcp->workq)
+ destroy_workqueue(hdcp->workq);
- sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj,
+ sysfs_remove_group(hdcp->init_data.sysfs_kobj,
&hdcp_1x_fs_attr_group);
- kfree(hdcp_ctrl);
+ kfree(hdcp);
} /* hdcp_1x_deinit */
-static void hdcp_1x_update_client_reg_set(struct hdcp_1x_ctrl *hdcp_ctrl)
+static void hdcp_1x_update_client_reg_set(struct hdcp_1x *hdcp)
{
- if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ if (hdcp->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) {
+ hdcp->reg_set = reg_set;
+ hdcp->sink_addr = sink_addr;
+ hdcp->int_set = isr;
+ } else if (hdcp->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;
+ hdcp->reg_set = reg_set;
+ hdcp->sink_addr = sink_addr;
+ hdcp->int_set = isr;
}
}
static int hdcp_1x_cp_irq(void *input)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ struct hdcp_1x *hdcp = (struct hdcp_1x *)input;
u8 buf = 0;
- int ret = -EINVAL;
+ int ret;
- if (!hdcp_ctrl) {
+ if (!hdcp) {
pr_err("invalid input\n");
goto end;
}
- ret = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.cp_irq_status,
+ ret = hdcp_1x_read(hdcp, &hdcp->sink_addr.cp_irq_status,
&buf, false);
if (IS_ERR_VALUE(ret)) {
pr_err("error reading cp_irq_status\n");
- goto end;
- }
-
- if (!buf) {
- pr_debug("not a hdcp 1.x irq\n");
- ret = -EINVAL;
- goto end;
+ return ret;
}
if ((buf & BIT(2)) || (buf & BIT(3))) {
@@ -1697,34 +1764,39 @@ static int hdcp_1x_cp_irq(void *input)
buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" :
"REAUTHENTICATION_REQUEST");
- hdcp_ctrl->reauth = true;
+ hdcp->reauth = true;
- complete_all(&hdcp_ctrl->sink_rep_ready);
- complete_all(&hdcp_ctrl->sink_r0_available);
+ if (!hdcp_1x_state(HDCP_STATE_INACTIVE))
+ hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL;
+
+ complete_all(&hdcp->sink_r0_available);
+ hdcp_1x_update_auth_status(hdcp);
- queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work);
goto end;
}
if (buf & BIT(1)) {
pr_debug("R0' AVAILABLE\n");
- hdcp_ctrl->sink_r0_ready = true;
- complete_all(&hdcp_ctrl->sink_r0_available);
+ hdcp->sink_r0_ready = true;
+ complete_all(&hdcp->sink_r0_available);
goto end;
}
- if (buf & BIT(0)) {
+ if ((buf & BIT(0))) {
pr_debug("KSVs READY\n");
- complete_all(&hdcp_ctrl->sink_rep_ready);
+
+ hdcp->ksv_ready = true;
goto end;
}
+
+ return -EINVAL;
end:
- return ret;
+ return 0;
}
void *hdcp_1x_init(struct hdcp_init_data *init_data)
{
- struct hdcp_1x_ctrl *hdcp_ctrl = NULL;
+ struct hdcp_1x *hdcp = NULL;
char name[20];
static struct hdcp_ops ops = {
.isr = hdcp_1x_isr,
@@ -1746,23 +1818,23 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
goto error;
}
- hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
- if (!hdcp_ctrl)
+ hdcp = kzalloc(sizeof(*hdcp), GFP_KERNEL);
+ if (!hdcp)
goto error;
- hdcp_ctrl->init_data = *init_data;
- hdcp_ctrl->ops = &ops;
+ hdcp->init_data = *init_data;
+ hdcp->ops = &ops;
snprintf(name, sizeof(name), "hdcp_1x_%d",
- hdcp_ctrl->init_data.client_id);
+ hdcp->init_data.client_id);
- hdcp_ctrl->workq = create_workqueue(name);
- if (!hdcp_ctrl->workq) {
+ hdcp->workq = create_workqueue(name);
+ if (!hdcp->workq) {
pr_err("Error creating workqueue\n");
goto error;
}
- hdcp_1x_update_client_reg_set(hdcp_ctrl);
+ hdcp_1x_update_client_reg_set(hdcp);
if (sysfs_create_group(init_data->sysfs_kobj,
&hdcp_1x_fs_attr_group)) {
@@ -1770,23 +1842,21 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
goto error;
}
- INIT_DELAYED_WORK(&hdcp_ctrl->hdcp_auth_work, hdcp_1x_auth_work);
- INIT_WORK(&hdcp_ctrl->hdcp_int_work, hdcp_1x_int_work);
+ INIT_DELAYED_WORK(&hdcp->hdcp_auth_work, hdcp_1x_auth_work);
- hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
- init_completion(&hdcp_ctrl->r0_checked);
- init_completion(&hdcp_ctrl->sink_r0_available);
- init_completion(&hdcp_ctrl->sink_rep_ready);
+ hdcp->hdcp_state = HDCP_STATE_INACTIVE;
+ init_completion(&hdcp->r0_checked);
+ init_completion(&hdcp->sink_r0_available);
pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
HDCP_STATE_NAME);
error:
- return (void *)hdcp_ctrl;
+ return (void *)hdcp;
} /* hdcp_1x_init */
struct hdcp_ops *hdcp_1x_start(void *input)
{
- return ((struct hdcp_1x_ctrl *)input)->ops;
+ return ((struct hdcp_1x *)input)->ops;
}