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

Commit 8201f1e8 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'exynos-drm-fixes' of...

Merge branch 'exynos-drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-fixes

   Just several fixups,
   - fix page fault and vblank timeout issues due to delayed vblank handling.
   - fix panel driver probing to fail without te-gpios property.
   - fix potential security hole by using "%pK" format.
   - fix wrong if statement condition.

   And one cleanup which removes Exynos4415 SoC support which is not supported
   anymore.

* 'exynos-drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos:
  drm/exynos/dsi: make te-gpios optional
  drm/exynos: Print kernel pointers in a restricted form
  drm/exynos/decon5433: fix software trigger mask
  drm/exynos/fimd: signal frame done interrupt at front porch
  drm/exynos/decon5433: signal frame done interrupt at front porch
  drm/exynos/decon5433: fix vblank event handling
  drm/exynos: move crtc event handling to drivers callbacks
  drm/exynos: Remove support for Exynos4415 (SoC not supported anymore)
  drm/exynos/decon5433: & vs | typo
parents d08997cb 22e098da
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@ Required properties:
  - compatible: value should be one of the following
		"samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */
		"samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */
		"samsung,exynos4415-mipi-dsi" /* for Exynos4415 SoC */
		"samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */
		"samsung,exynos5422-mipi-dsi" /* for Exynos5422/5800 SoCs */
		"samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */
+0 −1
Original line number Diff line number Diff line
@@ -11,7 +11,6 @@ Required properties:
		"samsung,s5pv210-fimd"; /* for S5PV210 SoC */
		"samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */
		"samsung,exynos4210-fimd"; /* for Exynos4 SoCs */
		"samsung,exynos4415-fimd"; /* for Exynos4415 SoC */
		"samsung,exynos5250-fimd"; /* for Exynos5250 SoCs */
		"samsung,exynos5420-fimd"; /* for Exynos5420/5422/5800 SoCs */

+82 −5
Original line number Diff line number Diff line
@@ -68,6 +68,8 @@ struct decon_context {
	unsigned long			flags;
	unsigned long			out_type;
	int				first_win;
	spinlock_t			vblank_lock;
	u32				frame_id;
};

static const uint32_t decon_formats[] = {
@@ -103,7 +105,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
		if (ctx->out_type & IFTYPE_I80)
			val |= VIDINTCON0_FRAMEDONE;
		else
			val |= VIDINTCON0_INTFRMEN;
			val |= VIDINTCON0_INTFRMEN | VIDINTCON0_FRAMESEL_FP;

		writel(val, ctx->addr + DECON_VIDINTCON0);
	}
@@ -122,14 +124,56 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
		writel(0, ctx->addr + DECON_VIDINTCON0);
}

/* return number of starts/ends of frame transmissions since reset */
static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
{
	u32 frm, pfrm, status, cnt = 2;

	/* To get consistent result repeat read until frame id is stable.
	 * Usually the loop will be executed once, in rare cases when the loop
	 * is executed at frame change time 2nd pass will be needed.
	 */
	frm = readl(ctx->addr + DECON_CRFMID);
	do {
		status = readl(ctx->addr + DECON_VIDCON1);
		pfrm = frm;
		frm = readl(ctx->addr + DECON_CRFMID);
	} while (frm != pfrm && --cnt);

	/* CRFMID is incremented on BPORCH in case of I80 and on VSYNC in case
	 * of RGB, it should be taken into account.
	 */
	if (!frm)
		return 0;

	switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) {
	case VIDCON1_VSTATUS_VS:
		if (!(ctx->out_type & IFTYPE_I80))
			--frm;
		break;
	case VIDCON1_VSTATUS_BP:
		--frm;
		break;
	case VIDCON1_I80_ACTIVE:
	case VIDCON1_VSTATUS_AC:
		if (end)
			--frm;
		break;
	default:
		break;
	}

	return frm;
}

static void decon_setup_trigger(struct decon_context *ctx)
{
	if (!(ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)))
		return;

	if (!(ctx->out_type & I80_HW_TRG)) {
		writel(TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN
		       | TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN,
		writel(TRIGCON_TRIGEN_PER_F | TRIGCON_TRIGEN_F |
		       TRIGCON_TE_AUTO_MASK | TRIGCON_SWTRIGEN,
		       ctx->addr + DECON_TRIGCON);
		return;
	}
@@ -365,11 +409,14 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
{
	struct decon_context *ctx = crtc->ctx;
	unsigned long flags;
	int i;

	if (test_bit(BIT_SUSPENDED, &ctx->flags))
		return;

	spin_lock_irqsave(&ctx->vblank_lock, flags);

	for (i = ctx->first_win; i < WINDOWS_NR; i++)
		decon_shadow_protect_win(ctx, i, false);

@@ -378,11 +425,18 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)

	if (ctx->out_type & IFTYPE_I80)
		set_bit(BIT_WIN_UPDATED, &ctx->flags);

	ctx->frame_id = decon_get_frame_count(ctx, true);

	exynos_crtc_handle_event(crtc);

	spin_unlock_irqrestore(&ctx->vblank_lock, flags);
}

static void decon_swreset(struct decon_context *ctx)
{
	unsigned int tries;
	unsigned long flags;

	writel(0, ctx->addr + DECON_VIDCON0);
	for (tries = 2000; tries; --tries) {
@@ -400,6 +454,10 @@ static void decon_swreset(struct decon_context *ctx)

	WARN(tries == 0, "failed to software reset DECON\n");

	spin_lock_irqsave(&ctx->vblank_lock, flags);
	ctx->frame_id = 0;
	spin_unlock_irqrestore(&ctx->vblank_lock, flags);

	if (!(ctx->out_type & IFTYPE_HDMI))
		return;

@@ -578,6 +636,24 @@ static const struct component_ops decon_component_ops = {
	.unbind = decon_unbind,
};

static void decon_handle_vblank(struct decon_context *ctx)
{
	u32 frm;

	spin_lock(&ctx->vblank_lock);

	frm = decon_get_frame_count(ctx, true);

	if (frm != ctx->frame_id) {
		/* handle only if incremented, take care of wrap-around */
		if ((s32)(frm - ctx->frame_id) > 0)
			drm_crtc_handle_vblank(&ctx->crtc->base);
		ctx->frame_id = frm;
	}

	spin_unlock(&ctx->vblank_lock);
}

static irqreturn_t decon_irq_handler(int irq, void *dev_id)
{
	struct decon_context *ctx = dev_id;
@@ -598,7 +674,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
			    (VIDOUT_INTERLACE_EN_F | VIDOUT_INTERLACE_FIELD_F))
				return IRQ_HANDLED;
		}
		drm_crtc_handle_vblank(&ctx->crtc->base);
		decon_handle_vblank(ctx);
	}

out:
@@ -671,6 +747,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
	__set_bit(BIT_SUSPENDED, &ctx->flags);
	ctx->dev = dev;
	ctx->out_type = (unsigned long)of_device_get_match_data(dev);
	spin_lock_init(&ctx->vblank_lock);

	if (ctx->out_type & IFTYPE_HDMI) {
		ctx->first_win = 1;
@@ -678,7 +755,7 @@ static int exynos5433_decon_probe(struct platform_device *pdev)
		ctx->out_type |= IFTYPE_I80;
	}

	if (ctx->out_type | I80_HW_TRG) {
	if (ctx->out_type & I80_HW_TRG) {
		ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
							"samsung,disp-sysreg");
		if (IS_ERR(ctx->sysreg)) {
+1 −0
Original line number Diff line number Diff line
@@ -526,6 +526,7 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc)

	for (i = 0; i < WINDOWS_NR; i++)
		decon_shadow_protect_win(ctx, i, false);
	exynos_crtc_handle_event(crtc);
}

static void decon_init(struct decon_context *ctx)
+16 −13
Original line number Diff line number Diff line
@@ -85,16 +85,28 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,
				     struct drm_crtc_state *old_crtc_state)
{
	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
	struct drm_pending_vblank_event *event;
	unsigned long flags;

	if (exynos_crtc->ops->atomic_flush)
		exynos_crtc->ops->atomic_flush(exynos_crtc);
}

static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
	.enable		= exynos_drm_crtc_enable,
	.disable	= exynos_drm_crtc_disable,
	.mode_set_nofb	= exynos_drm_crtc_mode_set_nofb,
	.atomic_check	= exynos_crtc_atomic_check,
	.atomic_begin	= exynos_crtc_atomic_begin,
	.atomic_flush	= exynos_crtc_atomic_flush,
};

void exynos_crtc_handle_event(struct exynos_drm_crtc *exynos_crtc)
{
	struct drm_crtc *crtc = &exynos_crtc->base;
	struct drm_pending_vblank_event *event = crtc->state->event;
	unsigned long flags;

	event = crtc->state->event;
	if (event) {
		crtc->state->event = NULL;

		spin_lock_irqsave(&crtc->dev->event_lock, flags);
		if (drm_crtc_vblank_get(crtc) == 0)
			drm_crtc_arm_vblank_event(crtc, event);
@@ -105,15 +117,6 @@ static void exynos_crtc_atomic_flush(struct drm_crtc *crtc,

}

static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
	.enable		= exynos_drm_crtc_enable,
	.disable	= exynos_drm_crtc_disable,
	.mode_set_nofb	= exynos_drm_crtc_mode_set_nofb,
	.atomic_check	= exynos_crtc_atomic_check,
	.atomic_begin	= exynos_crtc_atomic_begin,
	.atomic_flush	= exynos_crtc_atomic_flush,
};

static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
{
	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
Loading