Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d27592c authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: dp: hdcp 2.2: add support for interrupt handling"

parents d3191bd9 a5cdf192
Loading
Loading
Loading
Loading
+40 −19
Original line number Diff line number Diff line
@@ -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,6 +1674,7 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)

	dp->hdcp_status = status;

	if (dp->alt_mode.dp_status.hpd_high)
		queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
}

@@ -1927,19 +1938,27 @@ 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);
		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);
		}

@@ -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");
+114 −2
Original line number Diff line number Diff line
@@ -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,6 +186,9 @@ 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:
		if (ctrl->cp_irq_done)
			queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
		else
			ctrl->polling = true;
		break;
	case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
@@ -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);