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

Commit 89bd4529 authored by Govinda Rajulu Chenna's avatar Govinda Rajulu Chenna Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/dp: implement mst ops in dp sub-modules.



Add new dp_catalog ops to program the mst link configuration,
channel allocation. Add new dp_panel ops to read mst caps
and status from sink device and to update the edid info.

CRs-Fixed: 2192818
Change-Id: I2f3078546bbdc6d446c32f60f1a8c27877c31295
Signed-off-by: default avatarGovinda Rajulu Chenna <gchenna@codeaurora.org>
parent 430b60ef
Loading
Loading
Loading
Loading
+154 −0
Original line number Diff line number Diff line
@@ -1414,6 +1414,155 @@ static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog,
	return ret;
}

static void dp_catalog_ctrl_mst_config(struct dp_catalog_ctrl *ctrl,
		bool enable)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data = NULL;
	u32 reg;

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

	catalog = dp_catalog_get_priv(ctrl);

	io_data = catalog->io.dp_link;

	reg = dp_read(catalog, io_data, DP_MAINLINK_CTRL);
	if (enable)
		reg |= (0x04000100);
	else
		reg &= ~(0x04000100);

	dp_write(catalog, io_data, DP_MAINLINK_CTRL, reg);
	/* make sure mainlink MST configuration is updated */
	wmb();
}

static void dp_catalog_ctrl_trigger_act(struct dp_catalog_ctrl *ctrl)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data = NULL;

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

	catalog = dp_catalog_get_priv(ctrl);

	io_data = catalog->io.dp_link;

	dp_write(catalog, io_data, DP_MST_ACT, 0x1);
	/* make sure ACT signal is performed */
	wmb();
}

static void dp_catalog_ctrl_read_act_complete_sts(struct dp_catalog_ctrl *ctrl,
		bool *sts)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data = NULL;
	u32 reg;

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

	*sts = false;

	catalog = dp_catalog_get_priv(ctrl);

	io_data = catalog->io.dp_link;

	reg = dp_read(catalog, io_data, DP_MST_ACT);

	if (!reg)
		*sts = true;
}

static void dp_catalog_ctrl_channel_alloc(struct dp_catalog_ctrl *ctrl,
			u32 ch, u32 ch_start_slot, u32 tot_slot_cnt)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data = NULL;
	u32 i, slot_reg_1, slot_reg_2, slot;
	u32 reg_off = 0;

	if (!ctrl || ch >= DP_STREAM_MAX) {
		pr_err("invalid input. ch %d\n", ch);
		return;
	}

	if (ch_start_slot > DP_MAX_TIME_SLOTS ||
			(ch_start_slot + tot_slot_cnt > DP_MAX_TIME_SLOTS)) {
		pr_err("invalid slots start %d, tot %d\n",
			ch_start_slot, tot_slot_cnt);
		return;
	}

	catalog = dp_catalog_get_priv(ctrl);

	io_data = catalog->io.dp_link;

	pr_debug("ch %d, start_slot %d, tot_slot %d\n",
			ch, ch_start_slot, tot_slot_cnt);

	if (ch == DP_STREAM_1)
		reg_off = DP_DP1_TIMESLOT_1_32 - DP_DP0_TIMESLOT_1_32;

	slot_reg_1 = dp_read(catalog, io_data, DP_DP0_TIMESLOT_1_32 + reg_off);
	slot_reg_2 = dp_read(catalog, io_data, DP_DP0_TIMESLOT_33_63 + reg_off);

	ch_start_slot = ch_start_slot - 1;
	for (i = 0; i < tot_slot_cnt; i++) {
		if (ch_start_slot < 33) {
			slot_reg_1 |= BIT(ch_start_slot);
		} else {
			slot = ch_start_slot - 33;
			slot_reg_2 |= BIT(slot);
		}
		ch_start_slot++;
	}

	pr_debug("ch:%d slot_reg_1:%d, slot_reg_2:%d\n", ch,
			slot_reg_1, slot_reg_2);

	dp_write(catalog, io_data, DP_DP0_TIMESLOT_1_32 + reg_off, slot_reg_1);
	dp_write(catalog, io_data, DP_DP0_TIMESLOT_33_63 + reg_off, slot_reg_2);
}

static void dp_catalog_ctrl_update_rg(struct dp_catalog_ctrl *ctrl, u32 ch,
		u32 x_int, u32 y_frac_enum)
{
	struct dp_catalog_private *catalog;
	struct dp_io_data *io_data = NULL;
	u32 rg, reg_off = 0;

	if (!ctrl || ch >= DP_STREAM_MAX) {
		pr_err("invalid input. ch %d\n", ch);
		return;
	}

	catalog = dp_catalog_get_priv(ctrl);

	io_data = catalog->io.dp_link;

	rg = y_frac_enum;
	rg |= (x_int << 16);

	pr_debug("ch: %d x_int:%d y_frac_enum:%d rg:%d\n", ch, x_int,
			y_frac_enum, rg);

	if (ch == DP_STREAM_1)
		reg_off = DP_DP1_RG - DP_DP0_RG;

	dp_write(catalog, io_data, DP_DP0_RG + reg_off, rg);
}

/* panel related catalog functions */
static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel)
{
@@ -1902,6 +2051,11 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
		.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,
		.mst_config = dp_catalog_ctrl_mst_config,
		.trigger_act = dp_catalog_ctrl_trigger_act,
		.read_act_complete_sts = dp_catalog_ctrl_read_act_complete_sts,
		.channel_alloc = dp_catalog_ctrl_channel_alloc,
		.update_rg = dp_catalog_ctrl_update_rg,
	};
	struct dp_catalog_audio audio = {
		.init       = dp_catalog_audio_init,
+9 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@
#define DP_INTR_FRAME_END		BIT(6)
#define DP_INTR_CRC_UPDATED		BIT(9)

#define DP_MAX_TIME_SLOTS	64

/* stream id */
enum dp_stream_id {
	DP_STREAM_0,
@@ -112,6 +114,13 @@ struct dp_catalog_ctrl {
	void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
			u32 pattern);
	u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl);
	void (*mst_config)(struct dp_catalog_ctrl *ctrl, bool enable);
	void (*trigger_act)(struct dp_catalog_ctrl *ctrl);
	void (*read_act_complete_sts)(struct dp_catalog_ctrl *ctrl, bool *sts);
	void (*channel_alloc)(struct dp_catalog_ctrl *ctrl,
			u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt);
	void (*update_rg)(struct dp_catalog_ctrl *ctrl, u32 ch, u32 x_int,
			u32 y_frac_enum);
};

#define HEADER_BYTE_2_BIT	 0
+63 −0
Original line number Diff line number Diff line
@@ -1524,6 +1524,66 @@ static int dp_panel_set_stream_id(struct dp_panel *dp_panel,
	return 0;
}

static int dp_panel_read_sink_sts(struct dp_panel *dp_panel, u8 *sts, u32 size)
{
	int rlen, rc = 0;
	struct dp_panel_private *panel;

	if (!dp_panel || !sts || !size) {
		pr_err("invalid input\n");
		rc = -EINVAL;
		return rc;
	}

	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);

	rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT_ESI,
		sts, size);
	if (rlen != size) {
		pr_err("dpcd sink sts fail rlen:%d size:%d\n", rlen, size);
		rc = -EINVAL;
		return rc;
	}

	return 0;
}

static int dp_panel_update_edid(struct dp_panel *dp_panel, struct edid *edid)
{
	dp_panel->edid_ctrl->edid = edid;
	sde_parse_edid(dp_panel->edid_ctrl);
	return _sde_edid_update_modes(dp_panel->connector, dp_panel->edid_ctrl);
}

static bool dp_panel_read_mst_cap(struct dp_panel *dp_panel)
{
	int rlen;
	struct dp_panel_private *panel;
	u8 dpcd;
	bool mst_cap = false;

	if (!dp_panel) {
		pr_err("invalid input\n");
		goto end;
	}

	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);

	rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_MSTM_CAP,
		&dpcd, 1);
	if (rlen < 1) {
		pr_err("dpcd mstm_cap read failed, rlen=%d\n", rlen);
		goto end;
	}

	mst_cap = (mst_cap & DP_MST_CAP)?true:false;

end:
	pr_debug("dp mst-cap: %d\n", mst_cap);

	return mst_cap;
}

struct dp_panel *dp_panel_get(struct dp_panel_in *in)
{
	int rc = 0;
@@ -1572,6 +1632,9 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	dp_panel->setup_hdr = dp_panel_setup_hdr;
	dp_panel->hdr_supported = dp_panel_hdr_supported;
	dp_panel->set_stream_id = dp_panel_set_stream_id;
	dp_panel->read_sink_status = dp_panel_read_sink_sts;
	dp_panel->update_edid = dp_panel_update_edid;
	dp_panel->read_mst_cap = dp_panel_read_mst_cap;

	sde_conn = to_sde_connector(dp_panel->connector);
	sde_conn->drv_panel = dp_panel;
+5 −0
Original line number Diff line number Diff line
@@ -104,8 +104,13 @@ struct dp_panel {
	void (*tpg_config)(struct dp_panel *dp_panel, bool enable);
	int (*spd_config)(struct dp_panel *dp_panel);
	bool (*hdr_supported)(struct dp_panel *dp_panel);

	int (*set_stream_id)(struct dp_panel *dp_panel,
			enum dp_stream_id stream_id);

	int (*read_sink_status)(struct dp_panel *dp_panel, u8 *sts, u32 size);
	int (*update_edid)(struct dp_panel *dp_panel, struct edid *edid);
	bool (*read_mst_cap)(struct dp_panel *dp_panel);
};

/**