diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2016-11-29 15:23:53 -0800 |
|---|---|---|
| committer | Ajay Singh Parmar <aparmar@codeaurora.org> | 2016-11-30 11:07:52 -0800 |
| commit | a5cdf192ad3a1dccbea42e895674b2bad61f25bc (patch) | |
| tree | 3f6f62793081a0d739a18ed4d144694587e60f06 /drivers/video/fbdev | |
| parent | 2be8fc81c3adef891480d3abd19639860d838443 (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.c | 59 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c | 116 |
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); |
