diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-08-16 16:35:08 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-08-16 16:35:07 -0700 |
commit | 0391265ec07bbd6b2854e8bf1004b803c1359ff9 (patch) | |
tree | 18d512ee4e78637bcfb09b52f05421abe4f7e5a3 /drivers/video | |
parent | 13dc7954bfe3ffb1eb51e1496250dab730601c6d (diff) | |
parent | 85b28aea37afddbf6893e47a22c2f24c9a39c2ea (diff) |
Merge "msm: mdss: add support for hdcp 1.x interrupt handler"
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dp.h | 9 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dp_aux.c | 13 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dp_util.h | 38 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_hdcp.c | 1006 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_hdcp.h | 10 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 1 |
6 files changed, 642 insertions, 435 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index a8bb2ab5d343..4a80c25dd157 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -106,15 +106,6 @@ #define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2) -struct edp_cmd { - char read; /* 1 == read, 0 == write */ - char i2c; /* 1 == i2c cmd, 0 == native cmd */ - u32 addr; /* 20 bits */ - char *datap; - int len; /* len to be tx OR len to be rx for read */ - char next; /* next command */ -}; - struct edp_buf { char *start; /* buffer start addr */ char *end; /* buffer end addr */ diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index dfba02871649..7e9510cf08c7 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -228,6 +228,11 @@ static int dp_aux_write_cmds(struct mdss_dp_drv_pdata *ep, return ret; } +int dp_aux_write(void *ep, struct edp_cmd *cmd) +{ + return dp_aux_write_cmds(ep, cmd); +} + static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep, struct edp_cmd *cmds) { @@ -275,12 +280,20 @@ static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep, else ret = ep->aux_error_num; + if (cmds->out_buf) + memcpy(cmds->out_buf, rp->data, cmds->len); + ep->aux_cmd_busy = 0; mutex_unlock(&ep->aux_mutex); return ret; } +int dp_aux_read(void *ep, struct edp_cmd *cmds) +{ + return dp_aux_read_cmds(ep, cmds); +} + void dp_aux_native_handler(struct mdss_dp_drv_pdata *ep, u32 isr) { diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index 2079dba2a357..a2649b8c1611 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -88,6 +88,32 @@ #define TCSR_USB3_DP_PHYMODE 0x48 #define EDID_START_ADDRESS 0x50 +/* DP HDCP 1.3 registers */ +#define DP_HDCP_CTRL (0x0A0) +#define DP_HDCP_STATUS (0x0A4) +#define DP_HDCP_SW_UPPER_AKSV (0x298) +#define DP_HDCP_SW_LOWER_AKSV (0x29C) +#define DP_HDCP_ENTROPY_CTRL0 (0x750) +#define DP_HDCP_ENTROPY_CTRL1 (0x75C) +#define DP_HDCP_SHA_STATUS (0x0C8) +#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0) +#define DP_HDCP_RCVPORT_DATA3 (0x2A4) +#define DP_HDCP_RCVPORT_DATA4 (0x2A8) +#define DP_HDCP_RCVPORT_DATA5 (0x0C0) +#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_RCVPORT_DATA0 (0x004) +#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_DATA8 (0x010) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018) +#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; @@ -95,6 +121,18 @@ struct lane_mapping { char lane3; }; +struct edp_cmd { + char read; /* 1 == read, 0 == write */ + char i2c; /* 1 == i2c cmd, 0 == native cmd */ + u32 addr; /* 20 bits */ + char *datap; + char *out_buf; + int len; /* len to be tx OR len to be rx for read */ + char next; /* next command */ +}; + +int dp_aux_read(void *ep, struct edp_cmd *cmds); +int dp_aux_write(void *ep, struct edp_cmd *cmd); void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data); u32 mdss_dp_get_ctrl_hw_version(struct dss_io_data *ctrl_io); u32 mdss_dp_get_phy_hw_version(struct dss_io_data *phy_io); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c index 6256c9a99877..dad089e74934 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c @@ -15,9 +15,11 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/iopoll.h> #include <soc/qcom/scm.h> #include <linux/hdcp_qseecom.h> #include "mdss_hdmi_hdcp.h" +#include "mdss_dp_util.h" #include "video/msm_hdmi_hdcp_mgr.h" #define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state)) @@ -36,15 +38,188 @@ #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 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) + +#define reg_set_data(x) \ + (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \ + reg_set->data##x) + +struct hdcp_sink_addr { + char *name; + u32 addr; + u32 len; +}; struct hdmi_hdcp_reg_data { u32 reg_id; - u32 off; - char *name; - u32 reg_val; + struct hdcp_sink_addr *sink; +}; + +struct hdcp_sink_addr_map { + /* addresses to read from sink */ + struct hdcp_sink_addr bcaps; + struct hdcp_sink_addr bksv; + struct hdcp_sink_addr r0; + struct hdcp_sink_addr bstatus; + struct hdcp_sink_addr ksv_fifo; + struct hdcp_sink_addr v_h0; + struct hdcp_sink_addr v_h1; + struct hdcp_sink_addr v_h2; + struct hdcp_sink_addr v_h3; + struct hdcp_sink_addr v_h4; + + /* addresses to write to sink */ + struct hdcp_sink_addr an; + struct hdcp_sink_addr aksv; + 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; + u32 r0_offset; + u32 v_offset; + u32 ctrl; + u32 aksv_lsb; + u32 aksv_msb; + u32 entropy_ctrl0; + u32 entropy_ctrl1; + u32 sha_ctrl; + u32 sec_sha_ctrl; + u32 sha_status; + + u32 data0; + u32 data1; + u32 data2_0; + u32 data3; + u32 data4; + u32 data5; + u32 data6; + u32 data7; + u32 data8; + u32 data9; + u32 data10; + u32 data11; + u32 data12; + + u32 sec_data0; + u32 sec_data1; + u32 sec_data7; + u32 sec_data8; + u32 sec_data9; + u32 sec_data10; + u32 sec_data11; + u32 sec_data12; + + u32 reset; }; +#define HDCP_REG_SET_CLIENT_HDMI \ + {HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \ + HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \ + HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \ + HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \ + HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \ + HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \ + HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \ + HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \ + HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \ + HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \ + 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, \ + HDMI_HDCP_RESET} + +#define HDCP_REG_SET_CLIENT_DP \ + {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ + DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \ + DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \ + 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \ + DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \ + DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \ + 0, 0, 0, 0, 0, 0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \ + 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, 0} + +#define HDCP_HDMI_SINK_ADDR_MAP \ + {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \ + {"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \ + {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \ + {"v_h4", 0x30, 4}, {"an", 0x16, 8}, {"aksv", 0x10, 5}, \ + {"repater", 0x00, 0} } + +#define HDCP_DP_SINK_ADDR_MAP \ + {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \ + {"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \ + {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \ + {"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; u32 tp_msgid; @@ -57,7 +232,9 @@ struct hdmi_hdcp_ctrl { struct completion r0_checked; struct hdmi_hdcp_init_data init_data; struct hdmi_hdcp_ops *ops; - bool hdmi_tx_ver_4; + struct hdcp_reg_set reg_set; + struct hdcp_int_set int_set; + struct hdcp_sink_addr_map sink_addr; }; const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state) @@ -256,6 +433,7 @@ static int hdmi_hdcp_load_keys(void *input) struct dss_io_data *io; struct dss_io_data *qfprom_io; struct hdmi_hdcp_ctrl *hdcp_ctrl = input; + struct hdcp_reg_set *reg_set; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { @@ -274,6 +452,7 @@ static int hdmi_hdcp_load_keys(void *input) io = hdcp_ctrl->init_data.core_io; qfprom_io = hdcp_ctrl->init_data.qfprom_io; + reg_set = &hdcp_ctrl->reg_set; /* On compatible hardware, use SW keys */ reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION); @@ -297,7 +476,7 @@ static int hdmi_hdcp_load_keys(void *input) ksv_lsb_addr = HDCP_KSV_LSB; ksv_msb_addr = HDCP_KSV_MSB; - if (hdcp_ctrl->hdmi_tx_ver_4) { + if (hdcp_ctrl->init_data.sec_access) { ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET; ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET; } @@ -322,27 +501,121 @@ static int hdmi_hdcp_load_keys(void *input) goto end; } - DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, aksv_lsb); - DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, aksv_msb); + DSS_REG_W(io, reg_set->aksv_lsb, aksv_lsb); + DSS_REG_W(io, reg_set->aksv_msb, aksv_msb); /* Setup seed values for random number An */ - DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF); - DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE); - - /* Disable the RngCipher state */ - DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL, - DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2))); + DSS_REG_W(io, reg_set->entropy_ctrl0, 0xB1FFB0FF); + DSS_REG_W(io, reg_set->entropy_ctrl1, 0xF00DFACE); /* make sure hw is programmed */ wmb(); - DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0)); + /* enable hdcp engine */ + DSS_REG_W(io, reg_set->ctrl, 0x1); hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING; end: return rc; } +static int hdmi_hdcp_read(struct hdmi_hdcp_ctrl *hdcp_ctrl, + struct hdcp_sink_addr *sink, + u8 *buf, bool realign) +{ + u32 rc = 0; + struct hdmi_tx_ddc_data ddc_data; + + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + reset_hdcp_ddc_failures(hdcp_ctrl); + + memset(&ddc_data, 0, sizeof(ddc_data)); + ddc_data.dev_addr = 0x74; + ddc_data.offset = sink->addr; + ddc_data.data_buf = buf; + ddc_data.data_len = sink->len; + ddc_data.request_len = sink->len; + ddc_data.retry = 5; + ddc_data.what = sink->name; + ddc_data.retry_align = realign; + + hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; + + rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, sink->name); + } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && + hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + struct edp_cmd cmd = {0}; + + cmd.read = 1; + cmd.addr = sink->addr; + cmd.out_buf = buf; + cmd.len = sink->len; + + rc = dp_aux_read(hdcp_ctrl->init_data.dp_data, &cmd); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, sink->name); + } + + return rc; +} + +static int hdmi_hdcp_write(struct hdmi_hdcp_ctrl *hdcp_ctrl, + u32 offset, u32 len, u8 *buf, char *name) +{ + int rc = 0; + struct hdmi_tx_ddc_data ddc_data; + + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + memset(&ddc_data, 0, sizeof(ddc_data)); + + ddc_data.dev_addr = 0x74; + ddc_data.offset = offset; + ddc_data.data_buf = buf; + ddc_data.data_len = len; + ddc_data.what = name; + hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; + + rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); + if (rc) + DEV_ERR("%s: %s: %s write failed\n", __func__, + HDCP_STATE_NAME, name); + } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && + hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + struct edp_cmd cmd = {0}; + + cmd.addr = offset; + cmd.len = len; + cmd.datap = buf; + + rc = dp_aux_write(hdcp_ctrl->init_data.dp_data, &cmd); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, name); + } + + return rc; +} + +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; + + 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) { int rc; @@ -353,13 +626,12 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) bool is_match; 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; - struct hdmi_tx_ddc_data ddc_data; - u32 link0_status, an_ready, keys_state; + u32 link0_status; u8 buf[0xFF]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; u32 ret = 0; @@ -376,6 +648,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) 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; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { DEV_ERR("%s: %s: invalid state. returning\n", __func__, @@ -384,32 +657,14 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) goto error; } - /* Clear any DDC failures from previous tries */ - reset_hdcp_ddc_failures(hdcp_ctrl); - - /* - * Read BCAPS - * We need to first try to read an HDCP register on the sink to see if - * the sink is ready for HDCP authentication - */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x40; - ddc_data.data_buf = &bcaps; - ddc_data.data_len = 1; - ddc_data.request_len = 1; - ddc_data.retry = 5; - ddc_data.what = "Bcaps"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BCAPS read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, + &bcaps, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bcaps\n", __func__); goto error; } - DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps); + + hdmi_hdcp_enable_interrupts(hdcp_ctrl); /* receiver (0), repeater (1) */ hdcp_ctrl->current_tp.ds_type = @@ -419,7 +674,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12; + scm_buf[0].addr = phy_addr + reg_set->data12; scm_buf[0].val = bcaps; ret = hdcp_scm_call(scm_buf, &resp); @@ -429,30 +684,19 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, - bcaps); + } else if (hdcp_ctrl->init_data.sec_access) { + DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps); + DSS_REG_W(io, reg_set->data12, bcaps); } /* Wait for HDCP keys to be checked and validated */ - timeout_count = 100; - keys_state = (link0_status >> 28) & 0x7; - while ((keys_state != HDCP_KEYS_STATE_VALID) && - --timeout_count) { - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - keys_state = (link0_status >> 28) & 0x7; - DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x", - __func__, HDCP_STATE_NAME, timeout_count, - keys_state, link0_status); - msleep(20); - } - - if (!timeout_count) { - DEV_ERR("%s: %s: Invalid Keys State: %d\n", __func__, - HDCP_STATE_NAME, keys_state); - rc = -EINVAL; + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + ((link0_status >> reg_set->keys_offset) & 0x7) + == HDCP_KEYS_STATE_VALID, + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: key not ready\n", __func__); goto error; } @@ -460,39 +704,39 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) * 1.1_Features turned off by default. * No need to write AInfo since 1.1_Features is disabled. */ - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA4, 0); + DSS_REG_W(io, reg_set->data4, 0); /* Wait for An0 and An1 bit to be ready */ - timeout_count = 100; - do { - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - an_ready = (link0_status & BIT(8)) && (link0_status & BIT(9)); - if (!an_ready) { - DEV_DBG("%s: %s: An not ready(%d). l0_status=0x%08x\n", - __func__, HDCP_STATE_NAME, timeout_count, - link0_status); - msleep(20); - } - } while (!an_ready && --timeout_count); - - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: timedout, An0=%ld, An1=%ld\n", __func__, - HDCP_STATE_NAME, (link0_status & BIT(8)) >> 8, - (link0_status & BIT(9)) >> 9); + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + (link0_status & (BIT(8) | BIT(9))), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: An not ready\n", __func__); goto error; } /* As per hardware recommendations, wait before reading An */ msleep(20); - /* Read An0 and An1 */ - link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5); - link0_an_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA6); + /* + * 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) { + udelay(1); + link0_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) { + udelay(1); + link0_an_0 = DSS_REG_R(io, reg_set->data6); + } /* Read AKSV */ - link0_aksv_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA3); - link0_aksv_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA4); + link0_aksv_0 = DSS_REG_R(io, reg_set->data3); + link0_aksv_1 = DSS_REG_R(io, reg_set->data4); /* Copy An and AKSV to byte arrays for transmission */ aksv[0] = link0_aksv_0 & 0xFF; @@ -510,55 +754,21 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) an[6] = (link0_an_1 >> 16) & 0xFF; an[7] = (link0_an_1 >> 24) & 0xFF; - /* Write An to offset 0x18 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x18; - ddc_data.data_buf = an; - ddc_data.data_len = 8; - ddc_data.what = "An"; - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: An write failed\n", __func__, HDCP_STATE_NAME); + rc = hdmi_hdcp_write(hdcp_ctrl, 0x18, 8, an, "an"); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error writing an to sink\n", __func__); goto error; } - /* Write AKSV to offset 0x10 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x10; - ddc_data.data_buf = aksv; - ddc_data.data_len = 5; - ddc_data.what = "Aksv"; - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: AKSV write failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_write(hdcp_ctrl, 0x10, 5, aksv, "aksv"); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error writing aksv to sink\n", __func__); goto error; } - DEV_DBG("%s: %s: Link0-AKSV=%02x%08x\n", __func__, - HDCP_STATE_NAME, link0_aksv_1 & 0xFF, link0_aksv_0); - - /* Read BKSV at offset 0x00 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x00; - ddc_data.data_buf = bksv; - ddc_data.data_len = 5; - ddc_data.request_len = 5; - ddc_data.retry = 5; - ddc_data.what = "Bksv"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BKSV read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bksv from sink\n", __func__); goto error; } @@ -584,9 +794,9 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA0; + scm_buf[0].addr = phy_addr + reg_set->data0; scm_buf[0].val = link0_bksv_0; - scm_buf[1].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA1; + scm_buf[1].addr = phy_addr + reg_set->data1; scm_buf[1].val = link0_bksv_1; ret = hdcp_scm_call(scm_buf, &resp); @@ -597,52 +807,45 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, - link0_bksv_0); - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, - link0_bksv_1); + } else if (hdcp_ctrl->init_data.sec_access) { + DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); + DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA0, link0_bksv_0); - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA1, link0_bksv_1); + DSS_REG_W(io, reg_set->data0, link0_bksv_0); + DSS_REG_W(io, reg_set->data1, link0_bksv_1); } - /* Enable HDCP interrupts and ack/clear any stale interrupts */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0xE6); - /* * HDCP Compliace Test case 1A-01: * Wait here at least 100ms before reading R0' */ msleep(125); - /* Read R0' at offset 0x08 */ + /* Wait for HDCP R0 computation to be completed */ + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + link0_status & BIT(reg_set->r0_offset), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: R0 not ready\n", __func__); + goto error; + } + memset(buf, 0, sizeof(buf)); - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x08; - ddc_data.data_buf = buf; - ddc_data.data_len = 2; - ddc_data.request_len = 2; - ddc_data.retry = 5; - ddc_data.what = "R0'"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: R0' read failed\n", __func__, HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading R0' from sink\n", __func__); goto error; } + DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME, buf[1], buf[0]); /* Write R0' to HDCP registers and check to see if it is a match */ reinit_completion(&hdcp_ctrl->r0_checked); - DSS_REG_W(io, HDMI_HDCP_RCVPORT_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( &hdcp_ctrl->r0_checked, HZ*2); - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); + link0_status = DSS_REG_R(io, reg_set->status); is_match = link0_status & BIT(12); if (!is_match) { DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__, @@ -663,166 +866,108 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) } error: - if (rc) { + if (rc) DEV_ERR("%s: %s: Authentication Part I failed\n", __func__, hdcp_ctrl ? HDCP_STATE_NAME : "???"); - } else { - /* Enable HDCP Encryption */ - DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0) | BIT(8)); + else DEV_INFO("%s: %s: Authentication Part I successful\n", __func__, HDCP_STATE_NAME); - } return rc; } /* hdmi_hdcp_authentication_part1 */ -#define READ_WRITE_V_H(io, off, name, reg, wr) \ -do { \ - ddc_data.offset = (off); \ - memset(what, 0, sizeof(what)); \ - snprintf(what, sizeof(what), (name)); \ - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; \ - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); \ - if (rc) { \ - DEV_ERR("%s: %s: Read %s failed\n", __func__, HDCP_STATE_NAME, \ - what); \ - goto error; \ - } \ - DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", \ - __func__, HDCP_STATE_NAME, what, buf[0], buf[1], \ - buf[2], buf[3]); \ - if (wr) { \ - DSS_REG_W((io), (reg), \ - (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); \ - } \ -} while (0); +static int hdmi_hdcp_set_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl, + struct hdmi_hdcp_reg_data *rd, u8 *buf) +{ + int rc; + struct dss_io_data *io; + + if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access) + io = hdcp_ctrl->init_data.hdcp_io; + else + io = hdcp_ctrl->init_data.core_io; + + rc = hdmi_hdcp_read(hdcp_ctrl, rd->sink, buf, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name); + 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) + DSS_REG_W(io, rd->reg_id, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); +end: + return rc; +} static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl) { - char what[20]; int rc = 0; u8 buf[4]; - struct hdmi_tx_ddc_data ddc_data; - struct dss_io_data *io; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - + struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set; struct hdmi_hdcp_reg_data reg_data[] = { - {HDMI_HDCP_RCVPORT_DATA7, 0x20, "V' H0"}, - {HDMI_HDCP_RCVPORT_DATA8, 0x24, "V' H1"}, - {HDMI_HDCP_RCVPORT_DATA9, 0x28, "V' H2"}, - {HDMI_HDCP_RCVPORT_DATA10, 0x2C, "V' H3"}, - {HDMI_HDCP_RCVPORT_DATA11, 0x30, "V' H4"}, + {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0}, + {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1}, + {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2}, + {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3}, + {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4}, }; - u32 size = sizeof(reg_data)/sizeof(reg_data[0]); - u32 iter = 0; - u32 ret = 0; - u32 resp = 0; - - if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; - } + u32 size = ARRAY_SIZE(reg_data); + u32 iter = 0, ret = 0, resp = 0; phy_addr = hdcp_ctrl->init_data.phy_addr; - io = hdcp_ctrl->init_data.core_io; - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.data_buf = buf; - ddc_data.data_len = 4; - ddc_data.request_len = 4; - ddc_data.retry = 5; - ddc_data.what = what; - - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); + memset(scm_buf, 0x00, sizeof(scm_buf)); - for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) { - struct hdmi_hdcp_reg_data *rd = reg_data + iter; + for (iter = 0; iter < size; iter++) { + struct hdmi_hdcp_reg_data *rd = reg_data + iter; - READ_WRITE_V_H(io, rd->off, rd->name, 0, false); + memset(buf, 0, sizeof(buf)); + hdmi_hdcp_set_v_h(hdcp_ctrl, rd, buf); - rd->reg_val = buf[3] << 24 | buf[2] << 16 | + if (hdcp_ctrl->tz_hdcp) { + u32 reg_val = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]; scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id; - scm_buf[iter].val = reg_data[iter].reg_val; - } + scm_buf[iter].val = reg_val; - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; + ret = hdcp_scm_call(scm_buf, &resp); + if (ret || resp) { + DEV_ERR("%s: scm err: ret=%d, resp=%d\n", + __func__, ret, resp); + rc = -EINVAL; + goto error; + } } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io; - - /* Read V'.HO 4 Byte at offset 0x20 */ - READ_WRITE_V_H(hdcp_io, 0x20, "V' H0", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true); - - /* Read V'.H1 4 Byte at offset 0x24 */ - READ_WRITE_V_H(hdcp_io, 0x24, "V' H1", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true); - - /* Read V'.H2 4 Byte at offset 0x28 */ - READ_WRITE_V_H(hdcp_io, 0x28, "V' H2", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true); - - /* Read V'.H3 4 Byte at offset 0x2C */ - READ_WRITE_V_H(hdcp_io, 0x2C, "V' H3", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true); - - /* Read V'.H4 4 Byte at offset 0x30 */ - READ_WRITE_V_H(hdcp_io, 0x30, "V' H4", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true); - } else { - /* Read V'.HO 4 Byte at offset 0x20 */ - READ_WRITE_V_H(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7, - true); - - /* Read V'.H1 4 Byte at offset 0x24 */ - READ_WRITE_V_H(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8, - true); - - /* Read V'.H2 4 Byte at offset 0x28 */ - READ_WRITE_V_H(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9, - true); - - /* Read V'.H3 4 Byte at offset 0x2C */ - READ_WRITE_V_H(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10, - true); - - /* Read V'.H4 4 Byte at offset 0x30 */ - READ_WRITE_V_H(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11, - true); } - error: return rc; } static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) { - int rc, cnt, i; - struct hdmi_tx_ddc_data ddc_data; + int rc, i; u32 timeout_count, down_stream_devices = 0; u32 repeater_cascade_depth = 0; u8 buf[0xFF]; u8 *ksv_fifo = NULL; - u8 bcaps; - u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0; - u32 link0_status; + 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; struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; u32 ret = 0; u32 resp = 0; + u32 ksv_read_retry = 20; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { DEV_ERR("%s: invalid input\n", __func__); @@ -831,6 +976,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) } phy_addr = hdcp_ctrl->init_data.phy_addr; + reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { DEV_DBG("%s: %s: invalid state. returning\n", __func__, @@ -844,8 +990,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) io = hdcp_ctrl->init_data.core_io; memset(buf, 0, sizeof(buf)); - memset(ksv_fifo, 0, - sizeof(hdcp_ctrl->current_tp.ksv_list)); + memset(ksv_fifo, 0, sizeof(hdcp_ctrl->current_tp.ksv_list)); /* * Wait until READY bit is set in BCAPS, as per HDCP specifications @@ -853,48 +998,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) */ timeout_count = 50; do { - timeout_count--; - /* Read BCAPS at offset 0x40 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x40; - ddc_data.data_buf = &bcaps; - ddc_data.data_len = 1; - ddc_data.request_len = 1; - ddc_data.retry = 5; - ddc_data.what = "Bcaps"; - ddc_data.retry_align = true; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BCAPS read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_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); - } while (!(bcaps & BIT(5)) && timeout_count); - - /* Read BSTATUS at offset 0x41 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x41; - ddc_data.data_buf = buf; - ddc_data.data_len = 2; - ddc_data.request_len = 2; - ddc_data.retry = 5; - ddc_data.what = "Bstatuss"; - ddc_data.retry_align = true; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BSTATUS read failed\n", __func__, - HDCP_STATE_NAME); + } while (!(bcaps & BIT(5)) && --timeout_count); + + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus, + buf, true); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bstatus\n", __func__); goto error; } + bstatus = buf[1]; bstatus = (bstatus << 8) | buf[0]; @@ -902,7 +1021,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) memset(scm_buf, 0x00, sizeof(scm_buf)); /* Write BSTATUS and BCAPS to HDCP registers */ - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12; + scm_buf[0].addr = phy_addr + reg_set->data12; scm_buf[0].val = bcaps | (bstatus << 8); ret = hdcp_scm_call(scm_buf, &resp); @@ -912,12 +1031,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, - bcaps | (bstatus << 8)); + reg_set->sec_data12, + bcaps | (bstatus << 8)); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps | (bstatus << 8)); + DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8)); } down_stream_devices = bstatus & 0x7F; @@ -972,37 +1091,28 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) * HDCP Repeaters (REPEATER == 0). */ ksv_bytes = 5 * down_stream_devices; - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x43; - ddc_data.data_buf = ksv_fifo; - ddc_data.data_len = ksv_bytes; - ddc_data.request_len = ksv_bytes; - ddc_data.retry = 5; - ddc_data.what = "KSV FIFO"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - cnt = 0; + hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes; + do { - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: KSV FIFO read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo, + ksv_fifo, false); + if (IS_ERR_VALUE(rc)) { + DEV_DBG("%s: could not read ksv fifo (%d)\n", + __func__, 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 { - break; + } - cnt++; - } while (cnt != 20); + } while (rc && --ksv_read_retry); - if (cnt == 20) + if (rc) { + DEV_ERR("%s: error reading ksv_fifo\n", __func__); goto error; + } rc = hdmi_hdcp_transfer_v_h(hdcp_ctrl); if (rc) @@ -1019,9 +1129,9 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_CTRL; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = HDCP_REG_ENABLE; - scm_buf[1].addr = phy_addr + HDMI_HDCP_SHA_CTRL; + scm_buf[1].addr = phy_addr + reg_set->sha_ctrl; scm_buf[1].val = HDCP_REG_DISABLE; ret = hdcp_scm_call(scm_buf, &resp); @@ -1031,16 +1141,16 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, + reg_set->sec_sha_ctrl, HDCP_REG_ENABLE); DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, + reg_set->sec_sha_ctrl, HDCP_REG_DISABLE); } else { - DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_ENABLE); - DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_DISABLE); + DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE); + DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE); } for (i = 0; i < ksv_bytes - 1; i++) { @@ -1048,7 +1158,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = ksv_fifo[i] << 16; ret = hdcp_scm_call(scm_buf, &resp); @@ -1058,12 +1168,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, + reg_set->sec_sha_ctrl, ksv_fifo[i] << 16); } else { - DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, ksv_fifo[i] << 16); + DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16); } /* @@ -1071,31 +1181,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) * HDCP_SHA_BLOCK_DONE before writing any further */ if (i && !((i + 1) % 64)) { - timeout_count = 100; - while (!(DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) & BIT(0)) - && (--timeout_count)) { - DEV_DBG("%s: %s: Wrote 64 bytes KSV FIFO\n", - __func__, HDCP_STATE_NAME); - DEV_DBG("%s: %s: HDCP_SHA_STATUS=%08x\n", - __func__, HDCP_STATE_NAME, - DSS_REG_R(io, HDMI_HDCP_SHA_STATUS)); - msleep(20); - } - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: Write KSV FIFO timedout", - __func__, HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->sha_status, + sha_status, sha_status & BIT(0), + HDCP_POLL_SLEEP_US, + HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: block not done\n", __func__); goto error; } } - } /* Write l to DONE bit[0] */ if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1; ret = hdcp_scm_call(scm_buf, &resp); @@ -1105,43 +1206,32 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, + reg_set->sec_sha_ctrl, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); } else { - DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, + DSS_REG_W_ND(io, reg_set->sha_ctrl, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); } /* Now wait for HDCP_SHA_COMP_DONE */ - timeout_count = 100; - while ((0x10 != (DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) - & 0xFFFFFF10)) && --timeout_count) - msleep(20); - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: SHA computation timedout", __func__, - HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, + sha_status & BIT(4), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: comp not done\n", __func__); goto error; } /* Wait for V_MATCHES */ - timeout_count = 100; - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - while (((link0_status & BIT(20)) != BIT(20)) && --timeout_count) { - DEV_DBG("%s: %s: Waiting for V_MATCHES(%d). l0_status=0x%08x\n", - __func__, HDCP_STATE_NAME, timeout_count, link0_status); - msleep(20); - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - } - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: HDCP V Match timedout", __func__, - HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->status, status, + status & BIT(reg_set->v_offset), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: V not ready\n", __func__); goto error; } - error: if (rc) DEV_ERR("%s: %s: Authentication Part II failed\n", __func__, @@ -1236,7 +1326,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work) io = hdcp_ctrl->init_data.core_io; /* Enabling Software DDC */ - DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io, + 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))); rc = hdmi_hdcp_authentication_part1(hdcp_ctrl); @@ -1258,7 +1349,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work) } /* Disabling software DDC before going into part3 to make sure * there is no Arbitration between software and hardware for DDC */ - DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io, + 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: @@ -1314,12 +1406,17 @@ int hdmi_hdcp_authenticate(void *input) DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__, HDCP_STATE_NAME); - if (!hdmi_hdcp_load_keys(input)) + if (!hdmi_hdcp_load_keys(input)) { + flush_delayed_work(&hdcp_ctrl->hdcp_auth_work); + queue_delayed_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_auth_work, HZ/2); - else + } else { + flush_work(&hdcp_ctrl->hdcp_int_work); + queue_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_int_work); + } return 0; } /* hdmi_hdcp_authenticate */ @@ -1328,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; @@ -1337,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__, @@ -1344,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, HDMI_HDCP_RESET, BIT(0)); + DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); - /* 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, @@ -1375,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) { @@ -1383,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__, @@ -1396,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); @@ -1415,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 */ @@ -1429,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__); @@ -1437,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) { @@ -1471,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 */ @@ -1605,6 +1741,27 @@ void hdmi_hdcp_deinit(void *input) kfree(hdcp_ctrl); } /* hdmi_hdcp_deinit */ +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; + } +} + void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) { struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL; @@ -1624,9 +1781,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) goto error; } - if (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4 - && !init_data->hdcp_io) { - DEV_ERR("%s: hdcp_io required for HDMI Tx Ver 4\n", __func__); + if (init_data->sec_access && !init_data->hdcp_io) { + DEV_ERR("%s: hdcp_io required\n", __func__); goto error; } @@ -1638,8 +1794,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) hdcp_ctrl->init_data = *init_data; hdcp_ctrl->ops = &ops; - hdcp_ctrl->hdmi_tx_ver_4 = - (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4); + + hdmi_hdcp_update_client_reg_set(hdcp_ctrl); if (sysfs_create_group(init_data->sysfs_kobj, &hdmi_hdcp_fs_attr_group)) { @@ -1653,7 +1809,7 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE; init_completion(&hdcp_ctrl->r0_checked); - if (!hdcp_ctrl->hdmi_tx_ver_4) { + if (!hdcp_ctrl->init_data.sec_access) { ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP); if (ret <= 0) { DEV_ERR("%s: secure hdcp service unavailable, ret = %d", diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h index 7dda3ff5c67d..4f2bdc4bfd3d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,11 @@ #include <video/msm_hdmi_modes.h> #include <soc/qcom/scm.h> +enum hdcp_client_id { + HDCP_CLIENT_HDMI, + HDCP_CLIENT_DP, +}; + enum hdmi_hdcp_state { HDCP_STATE_INACTIVE, HDCP_STATE_AUTHENTICATING, @@ -37,10 +42,13 @@ struct hdmi_hdcp_init_data { void *cb_data; void (*notify_status)(void *cb_data, enum hdmi_hdcp_state status); struct hdmi_tx_ddc_ctrl *ddc_ctrl; + void *dp_data; u32 phy_addr; u32 hdmi_tx_ver; struct msm_hdmi_mode_timing_info *timing; bool tethered; + bool sec_access; + enum hdcp_client_id client_id; }; struct hdmi_hdcp_ops { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index cd3017219005..050c4a4cecdf 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1801,6 +1801,7 @@ static int hdmi_tx_init_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl) hdcp_init_data.notify_status = hdmi_tx_hdcp_cb; hdcp_init_data.cb_data = (void *)hdmi_ctrl; hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version; + hdcp_init_data.sec_access = true; hdcp_init_data.timing = &hdmi_ctrl->timing; if (hdmi_ctrl->hdcp14_present) { |