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

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

Merge "drm/msm/dp: fix handling of unsupported IRQ requests"

parents 32fecfad 9c4ed4a1
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__

#include <linux/delay.h>
#include <drm/drm_dp_helper.h>

#include "dp_catalog.h"
#include "dp_reg.h"
@@ -747,6 +748,82 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
	}
}

static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl,
			u32 pattern)
{
	struct dp_catalog_private *catalog;
	u32 value = 0x0;
	void __iomem *base = NULL;

	if (!ctrl) {
		pr_err("invalid input\n");
		return;
	}

	dp_catalog_get_priv(ctrl);

	base = catalog->io->ctrl_io.base;

	dp_write(base + DP_STATE_CTRL, 0x0);

	switch (pattern) {
	case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
		dp_write(base + DP_STATE_CTRL, 0x1);
		break;
	case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
		value &= ~(1 << 16);
		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
		value |= 0xFC;
		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
		dp_write(base + DP_STATE_CTRL, 0x10);
		break;
	case DP_TEST_PHY_PATTERN_PRBS7:
		dp_write(base + DP_STATE_CTRL, 0x20);
		break;
	case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
		dp_write(base + DP_STATE_CTRL, 0x40);
		/* 00111110000011111000001111100000 */
		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0);
		/* 00001111100000111110000011111000 */
		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8);
		/* 1111100000111110 */
		dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E);
		break;
	case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN:
		value = BIT(16);
		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
		value |= 0xFC;
		dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value);
		dp_write(base + DP_MAINLINK_LEVELS, 0x2);
		dp_write(base + DP_STATE_CTRL, 0x10);
		break;
	default:
		pr_debug("No valid test pattern requested: 0x%x\n", pattern);
		return;
	}

	/* Make sure the test pattern is programmed in the hardware */
	wmb();
}

static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl)
{
	struct dp_catalog_private *catalog;
	void __iomem *base = NULL;

	if (!ctrl) {
		pr_err("invalid input\n");
		return 0;
	}

	dp_catalog_get_priv(ctrl);

	base = catalog->io->ctrl_io.base;

	return dp_read(base + DP_MAINLINK_READY);
}

/* panel related catalog functions */
static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
{
@@ -988,6 +1065,8 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io)
		.get_interrupt  = dp_catalog_ctrl_get_interrupt,
		.update_transfer_unit = dp_catalog_ctrl_update_transfer_unit,
		.read_hdcp_status     = dp_catalog_ctrl_read_hdcp_status,
		.send_phy_pattern    = dp_catalog_ctrl_send_phy_pattern,
		.read_phy_pattern = dp_catalog_ctrl_read_phy_pattern,
	};
	struct dp_catalog_audio audio = {
		.init       = dp_catalog_audio_init,
+3 −0
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ struct dp_catalog_ctrl {
	void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
	void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl);
	u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
	void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
			u32 pattern);
	u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl);
};

enum dp_catalog_audio_sdp_type {
+138 −27
Original line number Diff line number Diff line
@@ -36,6 +36,11 @@
#define ST_SEND_VIDEO			BIT(7)
#define ST_PUSH_IDLE			BIT(8)

#define MR_LINK_TRAINING1  0x8
#define MR_LINK_SYMBOL_ERM 0x80
#define MR_LINK_PRBS7 0x100
#define MR_LINK_CUSTOM80 0x200

struct dp_vc_tu_mapping_table {
	u32 vic;
	u8 lanes;
@@ -989,7 +994,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train)

	drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);

	if (ctrl->link->phy_pattern_requested(ctrl->link))
	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
		goto end;

	if (!train)
@@ -1135,18 +1140,14 @@ static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl)
	return false;
}

static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl,
	u32 sink_request)
static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
{
	int ret = 0;
	struct dp_ctrl_private *ctrl;

	if (!dp_ctrl) {
		ret = -EINVAL;
		goto end;
	}
	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
	ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;

	do {
		if (ret == -EAGAIN) {
@@ -1159,8 +1160,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl,
		ctrl->catalog->phy_lane_cfg(ctrl->catalog,
			ctrl->orientation, ctrl->link->link_params.lane_count);

		if (sink_request &
			(DP_LINK_STATUS_UPDATED | DP_TEST_LINK_TRAINING)) {
		/*
		 * Disable and re-enable the mainlink clock since the
		 * link clock might have been adjusted as part of the
@@ -1171,7 +1170,6 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl,
		ret = dp_ctrl_enable_mainlink_clocks(ctrl);
		if (ret)
			continue;
		}

		dp_ctrl_configure_source_params(ctrl);

@@ -1185,10 +1183,111 @@ static int dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl,
		ret = dp_ctrl_setup_main_link(ctrl, true);
	} while (ret == -EAGAIN);

end:
	return ret;
}

static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
{
	int ret = 0;

	if (!ctrl->link->phy_params.phy_test_pattern_sel) {
		pr_debug("no test pattern selected by sink\n");
		return;
	}

	pr_debug("start\n");

	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
	/*
	 * The global reset will need DP link ralated clocks to be
	 * running. Add the global reset just before disabling the
	 * link clocks and core clocks.
	 */
	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
	ctrl->dp_ctrl.off(&ctrl->dp_ctrl);

	ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl);
	if (ret)
		pr_err("failed to enable DP controller\n");

	pr_debug("end\n");
}

static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
{
	bool success = false;
	u32 pattern_sent = 0x0;
	u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;

	pr_debug("request: %s\n",
			dp_link_get_phy_test_pattern(pattern_requested));

	ctrl->catalog->update_vx_px(ctrl->catalog,
			ctrl->link->phy_params.v_level,
			ctrl->link->phy_params.p_level);
	ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
	ctrl->link->send_test_response(ctrl->link);

	pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);

	switch (pattern_sent) {
	case MR_LINK_TRAINING1:
		if (pattern_requested ==
				DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING)
			success = true;
		break;
	case MR_LINK_SYMBOL_ERM:
		if ((pattern_requested ==
				DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT)
			|| (pattern_requested ==
				DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN))
			success = true;
		break;
	case MR_LINK_PRBS7:
		if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7)
			success = true;
		break;
	case MR_LINK_CUSTOM80:
		if (pattern_requested ==
				DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN)
			success = true;
		break;
	default:
		success = false;
		return;
	}

	pr_debug("%s: %s\n", success ? "success" : "failed",
			dp_link_get_phy_test_pattern(pattern_requested));
}

static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
{
	struct dp_ctrl_private *ctrl;
	u32 sink_request = 0x0;

	if (!dp_ctrl) {
		pr_err("invalid input\n");
		return;
	}

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
	sink_request = ctrl->link->sink_request;

	if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
		pr_info("PHY_TEST_PATTERN request\n");
		dp_ctrl_process_phy_test_request(ctrl);
	}

	if (sink_request & DP_LINK_STATUS_UPDATED)
		dp_ctrl_link_maintenance(ctrl);

	if (sink_request & DP_TEST_LINK_TRAINING) {
		ctrl->link->send_test_response(ctrl->link);
		dp_ctrl_link_maintenance(ctrl);
	}
}

static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl)
{
	struct dp_ctrl_private *ctrl;
@@ -1208,6 +1307,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
	struct dp_ctrl_private *ctrl;
	u32 rate = 0;
	u32 link_train_max_retries = 100;
	u32 const phy_cts_pixel_clk_khz = 148500;

	if (!dp_ctrl) {
		rc = -EINVAL;
@@ -1222,9 +1322,17 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
	ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
	ctrl->catalog->hpd_config(ctrl->catalog, true);

	ctrl->link->link_params.bw_code  = drm_dp_link_rate_to_bw_code(rate);
	ctrl->link->link_params.lane_count = ctrl->panel->link_info.num_lanes;
	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
		pr_debug("using phy test link parameters\n");
		if (!ctrl->panel->pinfo.pixel_clk_khz)
			ctrl->pixel_rate = phy_cts_pixel_clk_khz;
	} else {
		ctrl->link->link_params.bw_code =
			drm_dp_link_rate_to_bw_code(rate);
		ctrl->link->link_params.lane_count =
			ctrl->panel->link_info.num_lanes;
		ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz;
	}

	pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n",
		ctrl->link->link_params.bw_code,
@@ -1263,6 +1371,9 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
		dp_ctrl_enable_mainlink_clocks(ctrl);
	}

	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
		dp_ctrl_send_phy_test_pattern(ctrl);

	pr_debug("End-\n");

end:
@@ -1337,12 +1448,12 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
	dp_ctrl->init      = dp_ctrl_host_init;
	dp_ctrl->deinit    = dp_ctrl_host_deinit;
	dp_ctrl->on        = dp_ctrl_on;
	dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request;
	dp_ctrl->off       = dp_ctrl_off;
	dp_ctrl->push_idle = dp_ctrl_push_idle;
	dp_ctrl->abort     = dp_ctrl_abort;
	dp_ctrl->isr       = dp_ctrl_isr;
	dp_ctrl->reset	   = dp_ctrl_reset;
	dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request;

	return dp_ctrl;
error:
+1 −2
Original line number Diff line number Diff line
@@ -28,12 +28,11 @@ struct dp_ctrl {
	void (*deinit)(struct dp_ctrl *dp_ctrl);
	int (*on)(struct dp_ctrl *dp_ctrl);
	void (*off)(struct dp_ctrl *dp_ctrl);
	int (*handle_sink_request)(struct dp_ctrl *dp_ctrl,
		u32 sink_request);
	void (*reset)(struct dp_ctrl *dp_ctrl);
	void (*push_idle)(struct dp_ctrl *dp_ctrl);
	void (*abort)(struct dp_ctrl *dp_ctrl);
	void (*isr)(struct dp_ctrl *dp_ctrl);
	void (*handle_sink_request)(struct dp_ctrl *dp_ctrl);
};

struct dp_ctrl_in {
+5 −27
Original line number Diff line number Diff line
@@ -449,7 +449,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);

	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
		pr_warn("timeout\n");
		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
		return -EINVAL;
	}

@@ -624,20 +624,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	return rc;
}

static void dp_display_link_maintenance(struct dp_display_private *dp)
{
	if (dp->power_on) {
		pr_debug("Set DP ctrl to push idle for link maintenance\n");
		dp->ctrl->push_idle(dp->ctrl);
		dp->ctrl->reset(dp->ctrl);
	} else {
		pr_err("DP not powered on, skip link maintenance\n");
		return;
	}

	dp->ctrl->handle_sink_request(dp->ctrl, dp->link->sink_request);
}

static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
{
	if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
@@ -651,14 +637,7 @@ static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
		return dp_display_process_hpd_high(dp);
	}

	if (dp->link->sink_request & DP_LINK_STATUS_UPDATED)
		dp_display_link_maintenance(dp);

	if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
		drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE,
			&dp->link->test_response, 1);
		dp_display_link_maintenance(dp);
	}
	dp->ctrl->handle_sink_request(dp->ctrl);

	return 0;
}
@@ -689,13 +668,12 @@ static int dp_display_usbpd_attention_cb(struct device *dev)

		rc = dp->link->process_request(dp->link);
		/* check for any test request issued by sink */
		if (!rc) {
		if (!rc)
			dp_display_handle_hpd_irq(dp);

		dp->hpd_irq_on = false;
		goto end;
	}
		dp->hpd_irq_on = false;
	}

	if (!dp->usbpd->hpd_high) {
		dp_display_process_hpd_low(dp);
Loading