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

Commit 3f64ce5c 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: add mst bandwidth alloc/dealloc implementation" into dev/msm-4.14-display

parents b585ce05 5e8037d9
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -1573,6 +1573,57 @@ static void dp_catalog_ctrl_channel_alloc(struct dp_catalog_ctrl *ctrl,
	dp_write(catalog, io_data, DP_DP0_TIMESLOT_33_63 + reg_off, slot_reg_2);
}

static void dp_catalog_ctrl_channel_dealloc(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("dealloc 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("dealloc 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)
{
@@ -2111,6 +2162,7 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
		.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,
		.channel_dealloc = dp_catalog_ctrl_channel_dealloc,
	};
	struct dp_catalog_audio audio = {
		.init       = dp_catalog_audio_init,
+2 −0
Original line number Diff line number Diff line
@@ -125,6 +125,8 @@ struct dp_catalog_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);
	void (*channel_dealloc)(struct dp_catalog_ctrl *ctrl,
			u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt);
};

#define HEADER_BYTE_2_BIT	 0
+117 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <drm/drm_fixed.h>

#include "dp_ctrl.h"

@@ -843,6 +844,81 @@ static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl)
	ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
}

static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl,
		struct dp_panel *panel, u32 *p_x_int, u32 *p_y_frac_enum)
{
	u64 min_slot_cnt, max_slot_cnt;
	u64 raw_target_sc, target_sc_fixp;
	u64 ts_denom, ts_enum, ts_int;
	u64 pclk = panel->pinfo.pixel_clk_khz;
	u64 lclk = panel->link_info.rate;
	u64 lanes = panel->link_info.num_lanes;
	u64 bpp = panel->pinfo.bpp;
	u64 pbn = panel->pbn;
	u64 numerator, denominator, temp, temp1, temp2;
	u32 x_int = 0, y_frac_enum = 0;
	u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp;

	/* min_slot_cnt */
	numerator = pclk * bpp * 64 * 1000;
	denominator = lclk * lanes * 8 * 1000;
	min_slot_cnt = drm_fixp_from_fraction(numerator, denominator);

	/* max_slot_cnt */
	numerator = pbn * 54 * 1000;
	denominator = lclk * lanes;
	max_slot_cnt = drm_fixp_from_fraction(numerator, denominator);

	/* raw_target_sc */
	numerator = max_slot_cnt + min_slot_cnt;
	denominator = drm_fixp_from_fraction(2, 1);
	raw_target_sc = drm_fixp_div(numerator, denominator);

	/* target_sc */
	temp = drm_fixp_from_fraction(256 * lanes, 1);
	numerator = drm_fixp_mul(raw_target_sc, temp);
	denominator = drm_fixp_from_fraction(256 * lanes, 1);
	target_sc_fixp = drm_fixp_div(numerator, denominator);

	ts_enum = 256 * lanes;
	ts_denom = drm_fixp_from_fraction(256 * lanes, 1);
	ts_int = drm_fixp2int(target_sc_fixp);

	temp = drm_fixp2int_ceil(raw_target_sc);
	if (temp != ts_int) {
		temp = drm_fixp_from_fraction(ts_int, 1);
		temp1 = raw_target_sc - temp;
		temp2 = drm_fixp_mul(temp1, ts_denom);
		ts_enum = drm_fixp2int(temp2);
	}

	/* target_strm_sym */
	ts_int_fixp = drm_fixp_from_fraction(ts_int, 1);
	ts_frac_fixp = drm_fixp_from_fraction(ts_enum, drm_fixp2int(ts_denom));
	temp = ts_int_fixp + ts_frac_fixp;
	temp1 = drm_fixp_from_fraction(lanes, 1);
	target_strm_sym = drm_fixp_mul(temp, temp1);

	/* x_int */
	x_int = drm_fixp2int(target_strm_sym);

	/* y_enum_frac */
	temp = drm_fixp_from_fraction(x_int, 1);
	temp1 = target_strm_sym - temp;
	temp2 = drm_fixp_from_fraction(256, 1);
	y_frac_enum_fixp = drm_fixp_mul(temp1, temp2);

	temp1 = drm_fixp2int(y_frac_enum_fixp);
	temp2 = drm_fixp2int_ceil(y_frac_enum_fixp);

	y_frac_enum = (u32)((temp1 == temp2) ? temp1 : temp1 + 1);

	*p_x_int = x_int;
	*p_y_frac_enum = y_frac_enum;

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

static int dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
		struct dp_panel *panel)
{
@@ -862,9 +938,7 @@ static int dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
	lanes = ctrl->link->link_params.lane_count;
	bw_code = ctrl->link->link_params.bw_code;

	x_int = (u32)(lanes * panel->channel_total_slots);
	y_frac_enum = (u32)(256 * ((lanes * lanes *
				panel->channel_total_slots) - x_int));
	dp_ctrl_mst_calculate_rg(ctrl, panel, &x_int, &y_frac_enum);

	ctrl->catalog->update_rg(ctrl->catalog, panel->stream_id,
			x_int, y_frac_enum);
@@ -932,6 +1006,45 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
	return rc;
}

static void dp_ctrl_mst_stream_pre_off(struct dp_ctrl *dp_ctrl,
		struct dp_panel *panel)
{
	struct dp_ctrl_private *ctrl;
	bool act_complete;

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

	if (!ctrl->mst_mode)
		return;

	ctrl->catalog->channel_dealloc(ctrl->catalog,
				panel->stream_id,
				panel->channel_start_slot,
				panel->channel_total_slots);

	ctrl->catalog->trigger_act(ctrl->catalog);
	msleep(20); /* needs 1 frame time */
	ctrl->catalog->read_act_complete_sts(ctrl->catalog, &act_complete);

	if (!act_complete)
		pr_err("mst stream_off act trigger complete failed\n");
	else
		DP_MST_DEBUG("mst stream_off ACT trigger complete SUCCESS\n");
}

static void dp_ctrl_stream_pre_off(struct dp_ctrl *dp_ctrl,
		struct dp_panel *panel)
{
	if (!dp_ctrl || !panel) {
		pr_err("invalid input\n");
		return;
	}

	dp_ctrl_push_idle(dp_ctrl, panel->stream_id);

	dp_ctrl_mst_stream_pre_off(dp_ctrl, panel);
}

static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
{
	struct dp_ctrl_private *ctrl;
@@ -1107,6 +1220,7 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
	dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request;
	dp_ctrl->stream_on = dp_ctrl_stream_on;
	dp_ctrl->stream_off = dp_ctrl_stream_off;
	dp_ctrl->stream_pre_off = dp_ctrl_stream_pre_off;

	return dp_ctrl;
error:
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct dp_ctrl {
	int (*link_maintenance)(struct dp_ctrl *dp_ctrl);
	int (*stream_on)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
	void (*stream_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
	void (*stream_pre_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
};

struct dp_ctrl_in {
+80 −22
Original line number Diff line number Diff line
@@ -798,12 +798,17 @@ static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
	int idx;
	struct dp_panel *dp_panel;

	mutex_lock(&dp->session_lock);

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;

		dp_panel = dp->active_panels[idx];

		dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);
		dp->ctrl->stream_off(dp->ctrl, dp_panel);

		mutex_lock(&dp_panel->audio->ops_lock);

		if (dp_panel->audio_supported)
@@ -818,11 +823,15 @@ static void dp_display_handle_maintenance_req(struct dp_display_private *dp)

		dp_panel = dp->active_panels[idx];

		dp->ctrl->stream_on(dp->ctrl, dp_panel);

		if (dp_panel->audio_supported)
			dp_panel->audio->on(dp_panel->audio);

		mutex_unlock(&dp_panel->audio->ops_lock);
	}

	mutex_unlock(&dp->session_lock);
}

static void dp_display_mst_attention(struct dp_display_private *dp)
@@ -1048,6 +1057,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
	panel_in.catalog = &dp->catalog->panel;
	panel_in.link = dp->link;
	panel_in.connector = dp->dp_display.base_connector;
	panel_in.base_panel = NULL;

	dp->panel = dp_panel_get(&panel_in);
	if (IS_ERR(dp->panel)) {
@@ -1198,14 +1208,45 @@ static int dp_display_set_mode(struct dp_display *dp_display, void *panel,
	return 0;
}

static int dp_display_prepare(struct dp_display *dp, void *panel)
static int dp_display_prepare(struct dp_display *dp_display, void *panel)
{
	struct dp_display_private *dp;
	struct dp_panel *dp_panel;

	if (!dp_display || !panel) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	dp_panel = panel;
	if (!dp_panel->connector) {
		pr_err("invalid connector input\n");
		return -EINVAL;
	}

	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->session_lock);

	if (atomic_read(&dp->aborted))
		goto end;

	dp->aux->init(dp->aux, dp->parser->aux_cfg);

	if (dp->debug->psm_enabled) {
		dp->link->psm_config(dp->link, &dp->panel->link_info, false);
		dp->debug->psm_enabled = false;
	}

end:
	mutex_unlock(&dp->session_lock);

	return 0;
}

static int dp_display_set_stream_info(struct dp_display *dp_display,
			void *panel, u32 ch_id, u32 ch_start_slot,
			u32 ch_tot_slots)
			u32 ch_tot_slots, u32 pbn)
{
	int rc = 0;
	struct dp_panel *dp_panel;
@@ -1217,7 +1258,7 @@ static int dp_display_set_stream_info(struct dp_display *dp_display,

	dp_panel = panel;
	dp_panel->set_stream_info(dp_panel, ch_id,
			ch_start_slot, ch_tot_slots);
			ch_start_slot, ch_tot_slots, pbn);

	return rc;
}
@@ -1266,13 +1307,6 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel)
		goto end;
	}

	dp->aux->init(dp->aux, dp->parser->aux_cfg);

	if (dp->debug->psm_enabled) {
		dp->link->psm_config(dp->link, &dp->panel->link_info, false);
		dp->debug->psm_enabled = false;
	}

	rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active);
	if (rc)
		goto end;
@@ -1355,9 +1389,8 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel)
static int dp_display_stream_pre_disable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	dp->ctrl->push_idle(dp->ctrl, dp_panel->stream_id);

	dp_panel->audio->deregister_ext_disp(dp_panel->audio);
	dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);

	return 0;
}
@@ -1390,17 +1423,17 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
			dp->hdcp.ops->off(dp->hdcp.data);
	}

	if (dp->usbpd->hpd_high && !dp_display_is_sink_count_zero(dp) &&
			dp->usbpd->alt_mode_cfg_done) {
	if (dp_panel->audio_supported)
		dp_panel->audio->off(dp_panel->audio);

	rc = dp_display_stream_pre_disable(dp, dp_panel);

	if (dp->usbpd->hpd_high && !dp_display_is_sink_count_zero(dp) &&
			dp->usbpd->alt_mode_cfg_done && !dp->mst.mst_active) {
		dp->link->psm_config(dp->link, &dp->panel->link_info, true);
		dp->debug->psm_enabled = true;
	}

	rc = dp_display_stream_pre_disable(dp, dp_panel);

end:
	mutex_unlock(&dp->session_lock);
	return 0;
@@ -1455,10 +1488,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel)
		dp->dp_display.is_sst_connected = false;
	}

	dp->aux->deinit(dp->aux);
	dp->power_on = false;
	dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
	complete_all(&dp->notification_comp);
end:
	mutex_unlock(&dp->session_lock);
	return 0;
@@ -1509,8 +1539,35 @@ static struct dp_debug *dp_get_debug(struct dp_display *dp_display)
	return dp->debug;
}

static int dp_display_unprepare(struct dp_display *dp, void *panel)
static int dp_display_unprepare(struct dp_display *dp_display, void *panel)
{
	struct dp_display_private *dp;

	if (!dp_display || !panel) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->session_lock);

	if (dp->active_stream_cnt)
		goto end;

	if (atomic_read(&dp->aborted))
		goto end;

	if (!dp->mst.mst_active) {
		dp->aux->deinit(dp->aux);
		dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
	}

	complete_all(&dp->notification_comp);

end:
	mutex_unlock(&dp->session_lock);

	return 0;
}

@@ -1739,6 +1796,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,
	panel_in.catalog = &dp->catalog->panel;
	panel_in.link = dp->link;
	panel_in.connector = connector;
	panel_in.base_panel = dp->panel;

	dp_panel = dp_panel_get(&panel_in);
	if (IS_ERR(dp_panel)) {
Loading