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

Commit 2c07d5a8 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-vc4-next-2016-08-29' of https://github.com/anholt/linux into drm-next

This pull request brings in interlaced vblank timing and a 3D
rendering memory/CPU overhead reduction.

* tag 'drm-vc4-next-2016-08-29' of https://github.com/anholt/linux:
  drm/vc4: Don't force new binner overflow allocation per draw.
  drm/vc4: Enable/Disable vblanks properly in crtc en/disable.
  drm/vc4: Enable precise vblank timestamping for interlaced modes.
  drm/vc4: Reject doublescan modes.
  drm/vc4: Fix handling of interlaced video modes.
  drm/vc4: Disallow interlaced modes on DPI.
parents 2b2fd56d 67f13690
Loading
Loading
Loading
Loading
+39 −13
Original line number Diff line number Diff line
@@ -163,14 +163,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
	int vblank_lines;
	int ret = 0;

	/*
	 * XXX Doesn't work well in interlaced mode yet, partially due
	 * to problems in vc4 kms or drm core interlaced mode handling,
	 * so disable for now in interlaced mode.
	 */
	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
		return ret;

	/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */

	/* Get optional system timestamp before query. */
@@ -191,11 +183,16 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,

	/* Vertical position of hvs composed scanline. */
	*vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);

	/* No hpos info available. */
	if (hpos)
	*hpos = 0;

	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
		*vpos /= 2;

		/* Use hpos to correct for field offset in interlaced mode. */
		if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
			*hpos += mode->crtc_htotal / 2;
	}

	/* This is the offset we need for translating hvs -> pv scanout pos. */
	fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;

@@ -217,8 +214,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
		 * position of the PV.
		 */
		*vpos -= fifo_lines + 1;
		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
			*vpos /= 2;

		ret |= DRM_SCANOUTPOS_ACCURATE;
		return ret;
@@ -480,6 +475,9 @@ static void vc4_crtc_disable(struct drm_crtc *crtc)
	int ret;
	require_hvs_enabled(dev);

	/* Disable vblank irq handling before crtc is disabled. */
	drm_crtc_vblank_off(crtc);

	CRTC_WRITE(PV_V_CONTROL,
		   CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
	ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
@@ -530,6 +528,33 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
	/* Turn on the pixel valve, which will emit the vstart signal. */
	CRTC_WRITE(PV_V_CONTROL,
		   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);

	/* Enable vblank irq handling after crtc is started. */
	drm_crtc_vblank_on(crtc);
}

static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
				const struct drm_display_mode *mode,
				struct drm_display_mode *adjusted_mode)
{
	/* Do not allow doublescan modes from user space */
	if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
		DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
			      crtc->base.id);
		return false;
	}

	/*
	 * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
	 * coming from user space. We don't want this, as it screws up
	 * vblank timestamping, so fix it up.
	 */
	drm_mode_set_crtcinfo(adjusted_mode, 0);

	DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
	drm_mode_debug_printmodeline(adjusted_mode);

	return true;
}

static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -819,6 +844,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
	.mode_set_nofb = vc4_crtc_mode_set_nofb,
	.disable = vc4_crtc_disable,
	.enable = vc4_crtc_enable,
	.mode_fixup = vc4_crtc_mode_fixup,
	.atomic_check = vc4_crtc_atomic_check,
	.atomic_flush = vc4_crtc_atomic_flush,
};
+11 −0
Original line number Diff line number Diff line
@@ -340,9 +340,20 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder)
	}
}

static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder,
				       const struct drm_display_mode *mode,
				       struct drm_display_mode *adjusted_mode)
{
	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
		return false;

	return true;
}

static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = {
	.disable = vc4_dpi_encoder_disable,
	.enable = vc4_dpi_encoder_enable,
	.mode_fixup = vc4_dpi_encoder_mode_fixup,
};

static const struct of_device_id vc4_dpi_dt_match[] = {
+0 −4
Original line number Diff line number Diff line
@@ -419,10 +419,6 @@ vc4_submit_next_bin_job(struct drm_device *dev)

	vc4_flush_caches(dev);

	/* Disable the binner's pre-loaded overflow memory address */
	V3D_WRITE(V3D_BPOA, 0);
	V3D_WRITE(V3D_BPOS, 0);

	/* Either put the job in the binner if it uses the binner, or
	 * immediately move it to the to-be-rendered queue.
	 */
+27 −2
Original line number Diff line number Diff line
@@ -208,10 +208,35 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
	return ret;
}

/*
 * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
 * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
 * screws up vblank timestamping for interlaced modes, so fix it up.
 */
static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
					  uint32_t maxX, uint32_t maxY)
{
	struct drm_display_mode *mode;
	int count;

	count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
	if (count == 0)
		return 0;

	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
		      connector->base.id, connector->name);
	list_for_each_entry(mode, &connector->modes, head) {
		drm_mode_set_crtcinfo(mode, 0);
		drm_mode_debug_printmodeline(mode);
	}

	return count;
}

static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
	.dpms = drm_atomic_helper_connector_dpms,
	.detect = vc4_hdmi_connector_detect,
	.fill_modes = drm_helper_probe_single_connector_modes,
	.fill_modes = vc4_hdmi_connector_probe_modes,
	.destroy = vc4_hdmi_connector_destroy,
	.reset = drm_atomic_helper_connector_reset,
	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -246,7 +271,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
	connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
			     DRM_CONNECTOR_POLL_DISCONNECT);

	connector->interlace_allowed = 0;
	connector->interlace_allowed = 1;
	connector->doublescan_allowed = 0;

	drm_mode_connector_attach_encoder(connector, encoder);