summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorAjay Singh Parmar <aparmar@codeaurora.org>2016-11-29 15:23:53 -0800
committerAjay Singh Parmar <aparmar@codeaurora.org>2016-11-30 11:07:52 -0800
commita5cdf192ad3a1dccbea42e895674b2bad61f25bc (patch)
tree3f6f62793081a0d739a18ed4d144694587e60f06 /drivers/video/fbdev
parent2be8fc81c3adef891480d3abd19639860d838443 (diff)
msm: mdss: dp: hdcp 2.2: add support for interrupt handling
Enable the interrupts required by hdcp 2.2 to update the hdcp 2.2 state machine as per hardware status. Change-Id: Ib551b1fe8641203b66a31e745d5091641b4d0ae2 Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c59
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c116
2 files changed, 154 insertions, 21 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 840df3741b21..84ca19668d06 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1286,12 +1286,8 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
link_training:
dp_drv->power_on = true;
- if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) {
- mutex_unlock(&dp_drv->train_mutex);
-
- mdss_dp_link_retraining(dp_drv);
- return 0;
- }
+ while (-EAGAIN == mdss_dp_train_main_link(dp_drv))
+ pr_debug("MAIN LINK TRAINING RETRY\n");
dp_drv->cont_splash = 0;
@@ -1622,13 +1618,27 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work)
struct mdss_dp_drv_pdata *dp;
struct delayed_work *dw = to_delayed_work(work);
struct hdcp_ops *ops;
+ unsigned char *base;
int rc = 0;
+ u32 hdcp_auth_state;
dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work);
+ base = dp->base;
+
+ hdcp_auth_state = (dp_read(base + DP_HDCP_STATUS) >> 20) & 0x3;
+
+ pr_debug("hdcp auth state %d\n", hdcp_auth_state);
ops = dp->hdcp.ops;
switch (dp->hdcp_status) {
+ case HDCP_STATE_AUTHENTICATING:
+ pr_debug("start authenticaton\n");
+
+ if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
+ rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+
+ break;
case HDCP_STATE_AUTHENTICATED:
pr_debug("hdcp authenticated\n");
dp->hdcp.auth_state = true;
@@ -1636,7 +1646,7 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work)
case HDCP_STATE_AUTH_FAIL:
dp->hdcp.auth_state = false;
- if (dp->power_on) {
+ if (dp->alt_mode.dp_status.hpd_high && dp->power_on) {
pr_debug("Reauthenticating\n");
if (ops && ops->reauthenticate) {
rc = ops->reauthenticate(dp->hdcp.data);
@@ -1664,7 +1674,8 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)
dp->hdcp_status = status;
- queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
+ if (dp->alt_mode.dp_status.hpd_high)
+ queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
}
static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata)
@@ -1927,20 +1938,28 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dp_on(pdata);
break;
case MDSS_EVENT_PANEL_ON:
+ mdss_dp_ack_state(dp, true);
+
mdss_dp_update_hdcp_info(dp);
- if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
- rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+ if (dp_is_hdcp_enabled(dp)) {
+ cancel_delayed_work(&dp->hdcp_cb_work);
- mdss_dp_ack_state(dp, true);
+ dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+ queue_delayed_work(dp->workq,
+ &dp->hdcp_cb_work, HZ / 2);
+ }
break;
case MDSS_EVENT_PANEL_OFF:
rc = mdss_dp_off(pdata);
break;
case MDSS_EVENT_BLANK:
- if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
- flush_delayed_work(&dp->hdcp_cb_work);
- dp->hdcp.ops->off(dp->hdcp.data);
+ if (dp_is_hdcp_enabled(dp)) {
+ dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+ cancel_delayed_work(&dp->hdcp_cb_work);
+ if (dp->hdcp.ops->off)
+ dp->hdcp.ops->off(dp->hdcp.data);
}
mdss_dp_mainlink_push_idle(pdata);
@@ -2189,9 +2208,6 @@ irqreturn_t dp_isr(int irq, void *ptr)
isr1 &= ~mask1; /* remove masks bit */
- pr_debug("isr=%x mask=%x isr2=%x\n",
- isr1, mask1, isr2);
-
ack = isr1 & EDP_INTR_STATUS1;
ack <<= 1; /* ack bits */
ack |= mask1;
@@ -2601,8 +2617,7 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
if (dp_drv->alt_mode.dp_status.hpd_irq) {
pr_debug("Attention: hpd_irq high\n");
- if (dp_drv->power_on && dp_drv->hdcp.ops &&
- dp_drv->hdcp.ops->cp_irq) {
+ if (dp_drv->hdcp.ops && dp_drv->hdcp.ops->cp_irq) {
if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data))
return;
}
@@ -2616,6 +2631,12 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
if (!dp_drv->alt_mode.dp_status.hpd_high) {
pr_debug("Attention: HPD low\n");
+
+ if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->off) {
+ cancel_delayed_work(&dp_drv->hdcp_cb_work);
+ dp_drv->hdcp.ops->off(dp_drv->hdcp.data);
+ }
+
mdss_dp_update_cable_status(dp_drv, false);
mdss_dp_notify_clients(dp_drv, false);
pr_debug("Attention: Notified clients\n");
diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
index 695331babf55..73b9ad65482f 100644
--- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
@@ -23,6 +23,8 @@
#include "mdss_hdcp.h"
#include "mdss_dp_util.h"
+struct dp_hdcp2p2_ctrl;
+
enum dp_hdcp2p2_sink_status {
SINK_DISCONNECTED,
SINK_CONNECTED
@@ -33,9 +35,21 @@ enum dp_auth_status {
DP_HDCP_AUTH_STATUS_SUCCESS
};
+struct dp_hdcp2p2_int_set {
+ u32 interrupt;
+ char *name;
+ void (*func)(struct dp_hdcp2p2_ctrl *ctrl);
+};
+
+struct dp_hdcp2p2_interrupts {
+ u32 reg;
+ struct dp_hdcp2p2_int_set *int_set;
+};
+
struct dp_hdcp2p2_ctrl {
atomic_t auth_state;
enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
+ struct dp_hdcp2p2_interrupts *intr;
struct hdcp_init_data init_data;
struct mutex mutex; /* mutex to protect access to ctrl */
struct mutex msg_lock; /* mutex to protect access to msg buffer */
@@ -172,7 +186,10 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
queue_kthread_work(&ctrl->worker, &ctrl->status);
break;
case HDMI_HDCP_WKUP_CMD_LINK_POLL:
- ctrl->polling = true;
+ if (ctrl->cp_irq_done)
+ queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
+ else
+ ctrl->polling = true;
break;
case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
queue_kthread_work(&ctrl->worker, &ctrl->auth);
@@ -211,6 +228,31 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
}
+static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
+{
+ unsigned char *base = ctrl->init_data.core_io->base;
+ struct dp_hdcp2p2_interrupts *intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+ u32 interrupts = 0;
+
+ while (int_set && int_set->interrupt) {
+ interrupts |= int_set->interrupt;
+ int_set++;
+ }
+
+ if (enable)
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) | interrupts);
+ else
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) & ~interrupts);
+
+ intr++;
+ }
+}
+
static void dp_hdcp2p2_off(void *input)
{
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
@@ -221,6 +263,13 @@ static void dp_hdcp2p2_off(void *input)
return;
}
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
dp_hdcp2p2_reset(ctrl);
flush_kthread_worker(&ctrl->worker);
@@ -237,6 +286,8 @@ static int dp_hdcp2p2_authenticate(void *input)
flush_kthread_worker(&ctrl->worker);
+ dp_hdcp2p2_set_interrupts(ctrl, true);
+
ctrl->sink_status = SINK_CONNECTED;
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
@@ -317,6 +368,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
return;
}
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
/* notify DP about HDCP failure */
ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTH_FAIL);
@@ -640,6 +693,8 @@ static int dp_hdcp2p2_cp_irq(void *input)
goto error;
}
+ pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status);
+
if (!ctrl->sink_rx_status) {
pr_debug("not a hdcp 2.2 irq\n");
rc = -EINVAL;
@@ -653,6 +708,46 @@ error:
return rc;
}
+static int dp_hdcp2p2_isr(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ struct dp_hdcp2p2_interrupts *intr;
+ u32 hdcp_int_val;
+
+ if (!ctrl || !ctrl->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = ctrl->init_data.core_io;
+ intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+
+ hdcp_int_val = dp_read(io->base + intr->reg);
+
+ while (int_set && int_set->interrupt) {
+ if (hdcp_int_val & (int_set->interrupt >> 2)) {
+ pr_debug("%s\n", int_set->name);
+
+ if (int_set->func)
+ int_set->func(ctrl);
+
+ dp_write(io->base + intr->reg, hdcp_int_val |
+ (int_set->interrupt >> 1));
+ }
+ int_set++;
+ }
+ intr++;
+ }
+end:
+ return rc;
+}
+
void dp_hdcp2p2_deinit(void *input)
{
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
@@ -684,6 +779,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
int rc;
struct dp_hdcp2p2_ctrl *ctrl;
static struct hdcp_ops ops = {
+ .isr = dp_hdcp2p2_isr,
.reauthenticate = dp_hdcp2p2_reauthenticate,
.authenticate = dp_hdcp2p2_authenticate,
.feature_supported = dp_hdcp2p2_feature_supported,
@@ -694,7 +790,22 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
static struct hdcp_client_ops client_ops = {
.wakeup = dp_hdcp2p2_wakeup,
};
-
+ static struct dp_hdcp2p2_int_set int_set1[] = {
+ {BIT(17), "authentication successful", 0},
+ {BIT(20), "authentication failed", 0},
+ {BIT(24), "encryption enabled", 0},
+ {BIT(27), "encryption disabled", 0},
+ {0},
+ };
+ static struct dp_hdcp2p2_int_set int_set2[] = {
+ {BIT(2), "key fifo underflow", 0},
+ {0},
+ };
+ static struct dp_hdcp2p2_interrupts intr[] = {
+ {DP_INTR_STATUS2, int_set1},
+ {DP_INTR_STATUS3, int_set2},
+ {0}
+ };
static struct hdcp_txmtr_ops txmtr_ops;
struct hdcp_register_data register_data = {0};
@@ -719,6 +830,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
}
ctrl->sink_status = SINK_DISCONNECTED;
+ ctrl->intr = intr;
atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);