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

Commit 1c5a2845 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/sde: update vsync source to dummy before mode-2 entry"

parents b7a50604 aab9b520
Loading
Loading
Loading
Loading
+74 −35
Original line number Diff line number Diff line
@@ -1121,6 +1121,62 @@ static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc,
	return ret;
}

static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
			struct msm_display_info *disp_info, bool is_dummy)
{
	struct sde_vsync_source_cfg vsync_cfg = { 0 };
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct sde_hw_mdp *hw_mdptop;
	struct drm_encoder *drm_enc;
	int i;

	if (!sde_enc || !disp_info) {
		SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n",
					sde_enc != NULL, disp_info != NULL);
		return;
	} else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) {
		SDE_ERROR("invalid num phys enc %d/%d\n",
				sde_enc->num_phys_encs,
				(int) ARRAY_SIZE(sde_enc->hw_pp));
		return;
	}

	drm_enc = &sde_enc->base;
	/* this pointers are checked in virt_enable_helper */
	priv = drm_enc->dev->dev_private;

	sde_kms = to_sde_kms(priv->kms);
	if (!sde_kms) {
		SDE_ERROR("invalid sde_kms\n");
		return;
	}

	hw_mdptop = sde_kms->hw_mdp;
	if (!hw_mdptop) {
		SDE_ERROR("invalid mdptop\n");
		return;
	}

	if (hw_mdptop->ops.setup_vsync_source &&
			disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
		for (i = 0; i < sde_enc->num_phys_encs; i++)
			vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;

		vsync_cfg.pp_count = sde_enc->num_phys_encs;
		vsync_cfg.frame_rate = sde_enc->disp_info.frame_rate;
		if (is_dummy)
			vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_1;
		else if (disp_info->is_te_using_watchdog_timer)
			vsync_cfg.vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0;
		else
			vsync_cfg.vsync_source = SDE_VSYNC0_SOURCE_GPIO;
		vsync_cfg.is_dummy = is_dummy;

		hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg);
	}
}

static int sde_encoder_update_rsc_client(
		struct drm_encoder *drm_enc,
		struct sde_encoder_rsc_config *config, bool enable)
@@ -1237,6 +1293,9 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
		rsc_cfg.inline_rotate_prefill =
				sde_crtc_get_inline_prefill(drm_enc->crtc);

		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
									false);

		/* enable RSC */
		sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);

@@ -1245,6 +1304,14 @@ static void _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
		/* disable RSC */
		sde_encoder_update_rsc_client(drm_enc, NULL, false);

		/**
		 * this call is for hardware workaround on sdm845 and should
		 * not be removed without considering the design changes for
		 * sde rsc + command mode concurrency. It may lead to pp
		 * timeout due to vsync from panel for command mode panel.
		 */
		_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
									true);
		/* disable all the irq */
		for (i = 0; i < sde_enc->num_phys_encs; i++) {
			struct sde_encoder_phys *phys =
@@ -1604,33 +1671,22 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
	struct sde_encoder_virt *sde_enc = NULL;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct sde_hw_mdp *hw_mdptop;
	int i = 0;
	struct sde_watchdog_te_status te_cfg = { 0 };

	if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) {
		SDE_ERROR("invalid parameters\n");
		return;
	}
	priv = drm_enc->dev->dev_private;

	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!sde_enc || !sde_enc->cur_master) {
		SDE_ERROR("invalid sde encoder/master\n");
		return;
	}

	priv = drm_enc->dev->dev_private;
	sde_kms = to_sde_kms(priv->kms);
	hw_mdptop = sde_kms->hw_mdp;

	if (!hw_mdptop) {
		SDE_ERROR("invalid mdptop\n");
	if (!sde_kms) {
		SDE_ERROR("invalid sde_kms\n");
		return;
	}

	sde_kms = to_sde_kms(priv->kms);
	if (!sde_kms) {
		SDE_ERROR("invalid sde_kms\n");
	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!sde_enc || !sde_enc->cur_master) {
		SDE_ERROR("invalid sde encoder/master\n");
		return;
	}

@@ -1640,24 +1696,7 @@ static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc)
				sde_enc->cur_master->hw_mdptop,
				sde_kms->catalog);

	if (sde_enc->num_phys_encs > ARRAY_SIZE(te_cfg.ppnumber) ||
			sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) {
		SDE_ERROR("invalid num phys enc %d/%d/%d\n",
				sde_enc->num_phys_encs,
				(int) ARRAY_SIZE(te_cfg.ppnumber),
				(int) ARRAY_SIZE(sde_enc->hw_pp));
		return;
	}

	if (hw_mdptop->ops.setup_vsync_sel) {
		for (i = 0; i < sde_enc->num_phys_encs; i++)
			te_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx;

		te_cfg.pp_count = sde_enc->num_phys_encs;
		te_cfg.frame_rate = sde_enc->disp_info.frame_rate;
		hw_mdptop->ops.setup_vsync_sel(hw_mdptop, &te_cfg,
				sde_enc->disp_info.is_te_using_watchdog_timer);
	}
	_sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false);

	memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi));
	memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi));
+13 −0
Original line number Diff line number Diff line
@@ -82,6 +82,19 @@ enum sde_format_flags {
#define SDE_BLEND_BG_INV_MOD_ALPHA	(1 << 12)
#define SDE_BLEND_BG_TRANSP_EN		(1 << 13)

#define SDE_VSYNC0_SOURCE_GPIO		0
#define SDE_VSYNC1_SOURCE_GPIO		1
#define SDE_VSYNC2_SOURCE_GPIO		2
#define SDE_VSYNC_SOURCE_INTF_0		3
#define SDE_VSYNC_SOURCE_INTF_1		4
#define SDE_VSYNC_SOURCE_INTF_2		5
#define SDE_VSYNC_SOURCE_INTF_3		6
#define SDE_VSYNC_SOURCE_WD_TIMER_4	11
#define SDE_VSYNC_SOURCE_WD_TIMER_3	12
#define SDE_VSYNC_SOURCE_WD_TIMER_2	13
#define SDE_VSYNC_SOURCE_WD_TIMER_1	14
#define SDE_VSYNC_SOURCE_WD_TIMER_0	15

enum sde_hw_blk_type {
	SDE_HW_BLK_TOP = 0,
	SDE_HW_BLK_SSPP,
+67 −19
Original line number Diff line number Diff line
@@ -38,6 +38,18 @@
#define MDP_WD_TIMER_0_CTL                0x380
#define MDP_WD_TIMER_0_CTL2               0x384
#define MDP_WD_TIMER_0_LOAD_VALUE         0x388
#define MDP_WD_TIMER_1_CTL                0x390
#define MDP_WD_TIMER_1_CTL2               0x394
#define MDP_WD_TIMER_1_LOAD_VALUE         0x398
#define MDP_WD_TIMER_2_CTL                0x420
#define MDP_WD_TIMER_2_CTL2               0x424
#define MDP_WD_TIMER_2_LOAD_VALUE         0x428
#define MDP_WD_TIMER_3_CTL                0x430
#define MDP_WD_TIMER_3_CTL2               0x434
#define MDP_WD_TIMER_3_LOAD_VALUE         0x438
#define MDP_WD_TIMER_4_CTL                0x440
#define MDP_WD_TIMER_4_CTL2               0x444
#define MDP_WD_TIMER_4_LOAD_VALUE         0x448

#define MDP_TICK_COUNT                    16
#define XO_CLK_RATE                       19200
@@ -204,38 +216,74 @@ static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
	status->wb[WB_3] = 0;
}

static void sde_hw_setup_vsync_sel(struct sde_hw_mdp *mdp,
		struct sde_watchdog_te_status *cfg, bool watchdog_te)
static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp,
		struct sde_vsync_source_cfg *cfg)
{
	struct sde_hw_blk_reg_map *c = &mdp->hw;
	u32 reg = 0;
	int i = 0;
	u32 pp_offset[] = {0xC, 0x8, 0x4, 0x13};
	struct sde_hw_blk_reg_map *c;
	u32 reg, wd_load_value, wd_ctl, wd_ctl2, i;
	static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18};

	if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber)))
		return;

	c = &mdp->hw;
	reg = SDE_REG_READ(c, MDP_VSYNC_SEL);
	for (i = 0; i < cfg->pp_count; i++) {
		int pp_idx = cfg->ppnumber[i] - PINGPONG_0;
		if (pp_idx >= ARRAY_SIZE(pp_offset))
			continue;

		if (watchdog_te)
			reg |= 0xF << pp_offset[pp_idx];
		else
			reg &= ~(0xF << pp_offset[pp_idx]);
		reg &= ~(0xf << pp_offset[pp_idx]);
		reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx];
	}

	SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg);

	if (watchdog_te) {
		SDE_REG_WRITE(c, MDP_WD_TIMER_0_LOAD_VALUE,
	if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 &&
			cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) {
		switch (cfg->vsync_source) {
		case SDE_VSYNC_SOURCE_WD_TIMER_4:
			wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE;
			wd_ctl = MDP_WD_TIMER_4_CTL;
			wd_ctl2 = MDP_WD_TIMER_4_CTL2;
			break;
		case SDE_VSYNC_SOURCE_WD_TIMER_3:
			wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE;
			wd_ctl = MDP_WD_TIMER_3_CTL;
			wd_ctl2 = MDP_WD_TIMER_3_CTL2;
			break;
		case SDE_VSYNC_SOURCE_WD_TIMER_2:
			wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE;
			wd_ctl = MDP_WD_TIMER_2_CTL;
			wd_ctl2 = MDP_WD_TIMER_2_CTL2;
			break;
		case SDE_VSYNC_SOURCE_WD_TIMER_1:
			wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE;
			wd_ctl = MDP_WD_TIMER_1_CTL;
			wd_ctl2 = MDP_WD_TIMER_1_CTL2;
			break;
		case SDE_VSYNC_SOURCE_WD_TIMER_0:
		default:
			wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE;
			wd_ctl = MDP_WD_TIMER_0_CTL;
			wd_ctl2 = MDP_WD_TIMER_0_CTL2;
			break;
		}

		if (cfg->is_dummy) {
			SDE_REG_WRITE(c, wd_ctl2, 0x0);
		} else {
			SDE_REG_WRITE(c, wd_load_value,
				CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));

		SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL, BIT(0)); /* clear timer */
		reg = SDE_REG_READ(c, MDP_WD_TIMER_0_CTL2);
			SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
			reg = SDE_REG_READ(c, wd_ctl2);
			reg |= BIT(8);		/* enable heartbeat timer */
			reg |= BIT(0);		/* enable WD timer */
		SDE_REG_WRITE(c, MDP_WD_TIMER_0_CTL2, reg);
			SDE_REG_WRITE(c, wd_ctl2, reg);
		}

		/* make sure that timers are enabled/disabled for vsync state */
		wmb();
	}
}

@@ -308,7 +356,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
	ops->setup_cdm_output = sde_hw_setup_cdm_output;
	ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
	ops->get_danger_status = sde_hw_get_danger_status;
	ops->setup_vsync_sel = sde_hw_setup_vsync_sel;
	ops->setup_vsync_source = sde_hw_setup_vsync_source;
	ops->get_safe_status = sde_hw_get_safe_status;
	ops->setup_dce = sde_hw_setup_dce;
	ops->reset_ubwc = sde_hw_reset_ubwc;
+12 −7
Original line number Diff line number Diff line
@@ -78,15 +78,21 @@ struct sde_danger_safe_status {
};

/**
 * struct sde_watchdog_te_status - configure watchdog timer to generate TE
 * struct sde_vsync_source_cfg - configure vsync source and configure the
 *                                    watchdog timers if required.
 * @pp_count: number of ping pongs active
 * @frame_rate: Display frame rate
 * @ppnumber: ping pong index array
 * @vsync_source: vsync source selection
 * @is_dummy: a dummy source of vsync selection. It must not be selected for
 *           any case other than sde rsc idle request.
 */
struct sde_watchdog_te_status {
struct sde_vsync_source_cfg {
	u32 pp_count;
	u32 frame_rate;
	u32 ppnumber[PINGPONG_MAX];
	u32 vsync_source;
	bool is_dummy;
};

/**
@@ -155,13 +161,12 @@ struct sde_hw_mdp_ops {
			struct sde_danger_safe_status *status);

	/**
	 * setup_vsync_sel - get vsync configuration details
	 * setup_vsync_source - setup vsync source configuration details
	 * @mdp: mdp top context driver
	 * @cfg: watchdog timer configuration
	 * @watchdog_te: watchdog timer enable
	 * @cfg: vsync source selection configuration
	 */
	void (*setup_vsync_sel)(struct sde_hw_mdp *mdp,
			struct sde_watchdog_te_status *cfg, bool watchdog_te);
	void (*setup_vsync_source)(struct sde_hw_mdp *mdp,
				struct sde_vsync_source_cfg *cfg);

	/**
	 * get_safe_status - get safe status