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

Commit 24d0c1f9 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: handle fast attention events"

parents 23bb5f21 44b187a8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -468,9 +468,10 @@
		reg =	<0xc990000 0xa84>,
			<0xc011000 0x910>,
			<0x1fcb200 0x050>,
			<0xc8c2200 0x1a0>,
			<0x780000 0x621c>,
			<0xc9e1000 0x02c>;
		reg-names = "dp_ctrl", "dp_phy", "tcsr_regs",
		reg-names = "dp_ctrl", "dp_phy", "tcsr_regs", "dp_mmss_cc",
				"qfprom_physical","hdcp_physical";

		clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>,
+56 −3
Original line number Diff line number Diff line
@@ -255,6 +255,15 @@ struct __attribute__ ((__packed__)) hdcp_version_rsp {
	uint32_t appversion;
};

struct __attribute__ ((__packed__)) hdcp_verify_key_req {
	uint32_t commandid;
};

struct __attribute__ ((__packed__)) hdcp_verify_key_rsp {
	uint32_t status;
	uint32_t commandId;
};

struct __attribute__ ((__packed__)) hdcp_lib_init_req_v1 {
	uint32_t commandid;
};
@@ -794,6 +803,48 @@ exit:
	return rc;
}

static int hdcp_lib_verify_keys(struct hdcp_lib_handle *handle)
{
	int rc = -EINVAL;
	struct hdcp_verify_key_req *req_buf;
	struct hdcp_verify_key_rsp *rsp_buf;

	if (!handle) {
		pr_err("invalid input\n");
		goto exit;
	}

	if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
		pr_err("app not loaded\n");
		goto exit;
	}

	req_buf = (struct hdcp_verify_key_req *)handle->qseecom_handle->sbuf;
	req_buf->commandid = HDCP_TXMTR_VERIFY_KEY;

	rsp_buf = (struct hdcp_verify_key_rsp *)
	    (handle->qseecom_handle->sbuf +
	     QSEECOM_ALIGN(sizeof(struct hdcp_verify_key_req)));

	rc = qseecom_send_command(handle->qseecom_handle,
				  req_buf,
				  QSEECOM_ALIGN(sizeof
						(struct hdcp_verify_key_req)),
				  rsp_buf,
				  QSEECOM_ALIGN(sizeof
						(struct hdcp_verify_key_rsp)));

	if (rc < 0) {
		pr_err("qseecom cmd failed err = %d\n", rc);
		goto exit;
	}

	return rsp_buf->status;
exit:
	return rc;
}


static int hdcp_app_init_legacy(struct hdcp_lib_handle *handle)
{
	int rc = 0;
@@ -1456,11 +1507,13 @@ static bool hdcp_lib_client_feature_supported(void *phdcpcontext)

	rc = hdcp_lib_library_load(handle);
	if (!rc) {
		if (!hdcp_lib_verify_keys(handle)) {
			pr_debug("HDCP2p2 supported\n");
			handle->feature_supported = true;
		hdcp_lib_library_unload(handle);
			supported = true;
		}
		hdcp_lib_library_unload(handle);
	}
exit:
	return supported;
}
+103 −41
Original line number Diff line number Diff line
@@ -45,6 +45,11 @@
#define VDDA_UA_ON_LOAD		100000	/* uA units */
#define VDDA_UA_OFF_LOAD	100		/* uA units */

struct mdss_dp_attention_node {
	u32 vdo;
	struct list_head list;
};

#define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3
static u32 supported_modes[] = {
	HDMI_VFRMT_640x480p60_4_3,
@@ -60,6 +65,7 @@ static u32 supported_modes[] = {
static int mdss_dp_off_irq(struct mdss_dp_drv_pdata *dp_drv);
static void mdss_dp_mainlink_push_idle(struct mdss_panel_data *pdata);
static inline void mdss_dp_link_retraining(struct mdss_dp_drv_pdata *dp);
static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp_drv);

static void mdss_dp_put_dt_clk_data(struct device *dev,
	struct dss_module_power *module_power)
@@ -1133,7 +1139,7 @@ static void mdss_dp_configure_source_params(struct mdss_dp_drv_pdata *dp,
	mdss_dp_fill_link_cfg(dp);
	mdss_dp_mainlink_ctrl(&dp->ctrl_io, true);
	mdss_dp_config_ctrl(dp);
	mdss_dp_sw_mvid_nvid(&dp->ctrl_io);
	mdss_dp_sw_config_msa(&dp->ctrl_io, dp->link_rate, &dp->dp_cc_io);
	mdss_dp_timing_cfg(&dp->ctrl_io, &dp->panel_data.panel_info);
}

@@ -1290,7 +1296,6 @@ link_training:
	dp_drv->cont_splash = 0;

	dp_drv->power_on = true;
	mdss_dp_ack_state(dp_drv, true);
	pr_debug("End-\n");

exit:
@@ -1559,6 +1564,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
		goto edid_error;
	}

	mdss_dp_update_cable_status(dp_drv, true);
	mdss_dp_notify_clients(dp_drv, true);
	dp_drv->dp_initialized = true;

@@ -1883,8 +1889,13 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp)
	}

	/* update internal data about hdcp */
	if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) {
		dp->hdcp.data = fd;
		dp->hdcp.ops = ops;
	} else {
		dp->hdcp.data = NULL;
		dp->hdcp.ops = NULL;
	}
}

static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv)
@@ -1920,6 +1931,8 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,

		if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
			rc = dp->hdcp.ops->authenticate(dp->hdcp.data);

		mdss_dp_ack_state(dp, true);
		break;
	case MDSS_EVENT_PANEL_OFF:
		rc = mdss_dp_off(pdata);
@@ -2041,6 +2054,12 @@ static int mdss_retrieve_dp_ctrl_resources(struct platform_device *pdev,
		return rc;
	}

	if (msm_dss_ioremap_byname(pdev, &dp_drv->dp_cc_io, "dp_mmss_cc")) {
		pr_err("%d unable to remap dp MMSS_CC resources\n",
				__LINE__);
		return rc;
	}

	if (msm_dss_ioremap_byname(pdev, &dp_drv->qfprom_io,
					"qfprom_physical"))
		pr_warn("unable to remap dp qfprom resources\n");
@@ -2117,6 +2136,9 @@ static void mdss_dp_event_work(struct work_struct *work)
	case EV_IDLE_PATTERNS_SENT:
		mdss_dp_idle_patterns_sent(dp);
		break;
	case EV_USBPD_ATTENTION:
		mdss_dp_handle_attention(dp);
		break;
	case EV_USBPD_DISCOVER_MODES:
		usbpd_send_svdm(dp->pd, USB_C_DP_SID, USBPD_SVDM_DISCOVER_MODES,
			SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0);
@@ -2225,6 +2247,7 @@ static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp)

	INIT_WORK(&dp->work, mdss_dp_event_work);
	INIT_DELAYED_WORK(&dp->hdcp_cb_work, mdss_dp_hdcp_cb_work);
	INIT_LIST_HEAD(&dp->attention_head);
	return 0;
}

@@ -2508,6 +2531,7 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
				const u32 *vdos, int num_vdos)
{
	struct mdss_dp_drv_pdata *dp_drv;
	struct mdss_dp_attention_node *node;

	dp_drv = container_of(hdlr, struct mdss_dp_drv_pdata, svid_handler);
	if (!dp_drv->pd) {
@@ -2535,9 +2559,39 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
		dp_send_events(dp_drv, EV_USBPD_DP_STATUS);
		break;
	case USBPD_SVDM_ATTENTION:
		node = kzalloc(sizeof(*node), GFP_KERNEL);
		node->vdo = *vdos;

		mutex_lock(&dp_drv->attention_lock);
		list_add_tail(&node->list, &dp_drv->attention_head);
		mutex_unlock(&dp_drv->attention_lock);

		dp_send_events(dp_drv, EV_USBPD_ATTENTION);
		break;
	case DP_VDM_STATUS:
		dp_drv->alt_mode.dp_status.response = *vdos;
		mdss_dp_usbpd_ext_dp_status(&dp_drv->alt_mode.dp_status);

		if (!(dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)) {
			dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
			dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
		}
		break;
	case DP_VDM_CONFIGURE:
		dp_drv->alt_mode.current_state |= DP_CONFIGURE_DONE;
		pr_debug("Configure: config USBPD to DP done\n");

		if (dp_drv->alt_mode.dp_status.hpd_high)
			mdss_dp_host_init(&dp_drv->panel_data);
		break;
	default:
		pr_err("unknown cmd: %d\n", cmd);
		break;
	}
}

static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
{
	dp_drv->hpd_irq_toggled = dp_drv->hpd_irq_on !=
		dp_drv->alt_mode.dp_status.hpd_irq;

@@ -2549,10 +2603,10 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
			dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data);

		if (!mdss_dp_process_hpd_irq_high(dp_drv))
				break;
			return;
	} else if (dp_drv->hpd_irq_toggled) {
		if (!mdss_dp_process_hpd_irq_low(dp_drv))
				break;
			return;
	}

	if (!dp_drv->alt_mode.dp_status.hpd_high) {
@@ -2560,7 +2614,7 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
		mdss_dp_update_cable_status(dp_drv, false);
		mdss_dp_notify_clients(dp_drv, false);
		pr_debug("Attention: Notified clients\n");
			break;
		return;
	}

	pr_debug("Attention: HPD high\n");
@@ -2574,27 +2628,34 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
	else
		dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);

		break;
	case DP_VDM_STATUS:
		dp_drv->alt_mode.dp_status.response = *vdos;
		mdss_dp_usbpd_ext_dp_status(&dp_drv->alt_mode.dp_status);

		if (!(dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)) {
			dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
			dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
	pr_debug("exit\n");
}
		break;
	case DP_VDM_CONFIGURE:
		dp_drv->alt_mode.current_state |= DP_CONFIGURE_DONE;
		pr_debug("Configure: config USBPD to DP done\n");

		if (dp_drv->alt_mode.dp_status.hpd_high)
			mdss_dp_host_init(&dp_drv->panel_data);
		break;
	default:
		pr_err("unknown cmd: %d\n", cmd);
		break;
	}
static void mdss_dp_handle_attention(struct mdss_dp_drv_pdata *dp)
{
	int i = 0;

	while (!list_empty_careful(&dp->attention_head)) {
		struct mdss_dp_attention_node *node;
		u32 vdo;

		pr_debug("processing item %d in the list\n", ++i);

		mutex_lock(&dp->attention_lock);
		node = list_first_entry(&dp->attention_head,
				struct mdss_dp_attention_node, list);

		vdo = node->vdo;
		list_del(&node->list);
		mutex_unlock(&dp->attention_lock);

		kzfree(node);

		dp->alt_mode.dp_status.response = vdo;
		mdss_dp_usbpd_ext_dp_status(&dp->alt_mode.dp_status);
		mdss_dp_process_attention(dp);
	};

}

static int mdss_dp_usbpd_setup(struct mdss_dp_drv_pdata *dp_drv)
@@ -2670,6 +2731,7 @@ static int mdss_dp_probe(struct platform_device *pdev)
	dp_drv->mask2 = EDP_INTR_MASK2;
	mutex_init(&dp_drv->emutex);
	mutex_init(&dp_drv->pd_msg_mutex);
	mutex_init(&dp_drv->attention_lock);
	mutex_init(&dp_drv->hdcp_mutex);
	spin_lock_init(&dp_drv->lock);

+5 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ struct dp_alt_mode {
#define EV_USBPD_DP_CONFIGURE		BIT(10)
#define EV_USBPD_CC_PIN_POLARITY	BIT(11)
#define EV_USBPD_EXIT_MODE		BIT(12)
#define EV_USBPD_ATTENTION		BIT(13)

/* dp state ctrl */
#define ST_TRAIN_PATTERN_1		BIT(0)
@@ -406,6 +407,7 @@ struct mdss_dp_drv_pdata {
	struct dss_io_data ctrl_io;
	struct dss_io_data phy_io;
	struct dss_io_data tcsr_reg_io;
	struct dss_io_data dp_cc_io;
	struct dss_io_data qfprom_io;
	struct dss_io_data hdcp_io;
	int base_size;
@@ -454,6 +456,7 @@ struct mdss_dp_drv_pdata {
	struct mutex aux_mutex;
	struct mutex train_mutex;
	struct mutex pd_msg_mutex;
	struct mutex attention_lock;
	struct mutex hdcp_mutex;
	bool cable_connected;
	u32 s3d_mode;
@@ -497,6 +500,8 @@ struct mdss_dp_drv_pdata {

	struct dpcd_test_request test_data;
	struct dpcd_sink_count sink_count;

	struct list_head attention_head;
};

enum dp_lane_count {
+2 −0
Original line number Diff line number Diff line
@@ -1647,6 +1647,8 @@ int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp)
clear:
	dp_clear_training_pattern(dp);
	if (ret != -EINVAL) {
		mdss_dp_config_misc_settings(&dp->ctrl_io,
				&dp->panel_data.panel_info);
		mdss_dp_setup_tr_unit(&dp->ctrl_io, dp->link_rate,
					dp->lane_cnt, dp->vic);
		mdss_dp_state_ctrl(&dp->ctrl_io, ST_SEND_VIDEO);
Loading