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

Commit 5259c522 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-intel-next' of git://people.freedesktop.org/~danvet/drm-intel into drm-next

New feature pile for 3.12! Highlights:
- Stereo/3d support for hdmi from Damien, both the drm core bits and
  the i915 integration.
- Manual boost/deboost logic for gpu turbo (Chris)
- Fixed up clock readout support for vlv (Chris).
- Tons of little fixes and improvements for vlv in general (Chon Minng
  Lee and Jesse Barnes).
- Power well support for the legacy vga plane (Ville).
- DP impromevents from Jani.
- Improvements to the Haswell modeset sequence (Ville+Paulo).
- Haswell DDI improvements, using the VBT for some tuning values and
  to check the configuration (Paulo).
- Tons of other small improvements and fixups.

* 'drm-intel-next' of git://people.freedesktop.org/~danvet/drm-intel: (92 commits)
  drm/i915: Use adjusted_mode in the fastboot hack to disable pfit
  drm/i915: Add a more detailed comment about the set_base() fastboot hack
  drm/i915/vlv: Turn off power gate for BIOS-less system.
  drm/i915/vlv: reset DPIO on load and resume v2
  drm/i915: Simplify PSR debugfs
  drm/i915: Tweak RPS thresholds to more aggressively downclock
  drm/i915: Boost RPS frequency for CPU stalls
  drm/i915: Fix __wait_seqno to use true infinite timeouts
  drm/i915: Add some missing steps to i915_driver_load error path
  drm/i915: Clean up the ring scaling calculations
  drm/i915: Don't populate pipe_src_{w,h} multiple times
  drm/i915: implement the Haswell mode set sequence workaround
  drm/i915: Disable/enable planes as the first/last thing during modeset on HSW
  i915/vlv: untangle integrated clock source handling v4
  drm/i915: fix typo s/PatherPoint/PantherPoint/
  drm/i915: Make intel_resume_power_well() static
  drm/i915: destroy connector sysfs files earlier
  drm/i915/dp: do not write DP_TRAINING_PATTERN_SET all the time
  drm/i915/dp: retry i2c-over-aux seven times on AUX DEFER
  drm/i915/vlv: reduce GT FIFO error info to a debug message
  ...
parents 6aba5b6c 967ad7f1
Loading
Loading
Loading
Loading
+66 −34
Original line number Diff line number Diff line
@@ -1319,6 +1319,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
	if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
		return -ERANGE;

	if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
		return -EINVAL;

	out->clock = in->clock;
	out->hdisplay = in->hdisplay;
	out->hsync_start = in->hsync_start;
@@ -1581,6 +1584,19 @@ int drm_mode_getcrtc(struct drm_device *dev,
	return ret;
}

static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
					 const struct drm_file *file_priv)
{
	/*
	 * If user-space hasn't configured the driver to expose the stereo 3D
	 * modes, don't expose them.
	 */
	if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
		return false;

	return true;
}

/**
 * drm_mode_getconnector - get connector configuration
 * @dev: drm device for the ioctl
@@ -1646,6 +1662,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,

	/* delayed so we get modes regardless of pre-fill_modes state */
	list_for_each_entry(mode, &connector->modes, head)
		if (drm_mode_expose_to_userspace(mode, file_priv))
			mode_count++;

	out_resp->connector_id = connector->base.id;
@@ -1668,6 +1685,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
		copied = 0;
		mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
		list_for_each_entry(mode, &connector->modes, head) {
			if (!drm_mode_expose_to_userspace(mode, file_priv))
				continue;

			drm_crtc_convert_to_umode(&u_mode, mode);
			if (copy_to_user(mode_ptr + copied,
					 &u_mode, sizeof(u_mode))) {
@@ -2042,6 +2062,45 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
}
EXPORT_SYMBOL(drm_mode_set_config_internal);

/*
 * Checks that the framebuffer is big enough for the CRTC viewport
 * (x, y, hdisplay, vdisplay)
 */
static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
				   int x, int y,
				   const struct drm_display_mode *mode,
				   const struct drm_framebuffer *fb)

{
	int hdisplay, vdisplay;

	hdisplay = mode->hdisplay;
	vdisplay = mode->vdisplay;

	if (drm_mode_is_stereo(mode)) {
		struct drm_display_mode adjusted = *mode;

		drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
		hdisplay = adjusted.crtc_hdisplay;
		vdisplay = adjusted.crtc_vdisplay;
	}

	if (crtc->invert_dimensions)
		swap(hdisplay, vdisplay);

	if (hdisplay > fb->width ||
	    vdisplay > fb->height ||
	    x > fb->width - hdisplay ||
	    y > fb->height - vdisplay) {
		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
			      fb->width, fb->height, hdisplay, vdisplay, x, y,
			      crtc->invert_dimensions ? " (inverted)" : "");
		return -ENOSPC;
	}

	return 0;
}

/**
 * drm_mode_setcrtc - set CRTC configuration
 * @dev: drm device for the ioctl
@@ -2089,7 +2148,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
	DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);

	if (crtc_req->mode_valid) {
		int hdisplay, vdisplay;
		/* If we have a mode we need a framebuffer. */
		/* If we pass -1, set the mode with the currently bound fb */
		if (crtc_req->fb_id == -1) {
@@ -2125,23 +2183,11 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,

		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);

		hdisplay = mode->hdisplay;
		vdisplay = mode->vdisplay;

		if (crtc->invert_dimensions)
			swap(hdisplay, vdisplay);

		if (hdisplay > fb->width ||
		    vdisplay > fb->height ||
		    crtc_req->x > fb->width - hdisplay ||
		    crtc_req->y > fb->height - vdisplay) {
			DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
				      fb->width, fb->height,
				      hdisplay, vdisplay, crtc_req->x, crtc_req->y,
				      crtc->invert_dimensions ? " (inverted)" : "");
			ret = -ENOSPC;
		ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
					      mode, fb);
		if (ret)
			goto out;
		}

	}

	if (crtc_req->count_connectors == 0 && mode) {
@@ -3558,7 +3604,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
	struct drm_pending_vblank_event *e = NULL;
	unsigned long flags;
	int hdisplay, vdisplay;
	int ret = -EINVAL;

	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -3590,22 +3635,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
	if (!fb)
		goto out;

	hdisplay = crtc->mode.hdisplay;
	vdisplay = crtc->mode.vdisplay;

	if (crtc->invert_dimensions)
		swap(hdisplay, vdisplay);

	if (hdisplay > fb->width ||
	    vdisplay > fb->height ||
	    crtc->x > fb->width - hdisplay ||
	    crtc->y > fb->height - vdisplay) {
		DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n",
			      fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y,
			      crtc->invert_dimensions ? " (inverted)" : "");
		ret = -ENOSPC;
	ret = drm_crtc_check_viewport(crtc, crtc->x, crtc->y, &crtc->mode, fb);
	if (ret)
		goto out;
	}

	if (crtc->fb->pixel_format != fb->pixel_format) {
		DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
+7 −1
Original line number Diff line number Diff line
@@ -76,7 +76,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
{
	struct drm_display_mode *mode;

	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
	if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
		      DRM_MODE_FLAG_3D_MASK))
		return;

	list_for_each_entry(mode, &connector->modes, head) {
@@ -86,6 +87,9 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
		if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
				!(flags & DRM_MODE_FLAG_DBLSCAN))
			mode->status = MODE_NO_DBLESCAN;
		if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
				!(flags & DRM_MODE_FLAG_3D_MASK))
			mode->status = MODE_NO_STEREO;
	}

	return;
@@ -175,6 +179,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
		mode_flags |= DRM_MODE_FLAG_INTERLACE;
	if (connector->doublescan_allowed)
		mode_flags |= DRM_MODE_FLAG_DBLSCAN;
	if (connector->stereo_allowed)
		mode_flags |= DRM_MODE_FLAG_3D_MASK;
	drm_mode_validate_flag(connector, mode_flags);

	list_for_each_entry(mode, &connector->modes, head) {
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
	DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED),
	DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW),
	DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0),
	DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),

	DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+150 −26
Original line number Diff line number Diff line
@@ -2416,7 +2416,7 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)

		if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
		     KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
		    drm_mode_equal_no_clocks(to_match, cea_mode))
		    drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode))
			return mode + 1;
	}
	return 0;
@@ -2465,7 +2465,7 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)

		if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
		     KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
		    drm_mode_equal_no_clocks(to_match, hdmi_mode))
		    drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode))
			return mode + 1;
	}
	return 0;
@@ -2519,6 +2519,9 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
		if (!newmode)
			continue;

		/* Carry over the stereo flags */
		newmode->flags |= mode->flags & DRM_MODE_FLAG_3D_MASK;

		/*
		 * The current mode could be either variant. Make
		 * sure to pick the "other" clock for the new mode.
@@ -2565,18 +2568,102 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
	return modes;
}

struct stereo_mandatory_mode {
	int width, height, vrefresh;
	unsigned int flags;
};

static const struct stereo_mandatory_mode stereo_mandatory_modes[] = {
	{ 1920, 1080, 24, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM },
	{ 1920, 1080, 24, DRM_MODE_FLAG_3D_FRAME_PACKING },
	{ 1920, 1080, 50,
	  DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
	{ 1920, 1080, 60,
	  DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
	{ 1280, 720,  50, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM },
	{ 1280, 720,  50, DRM_MODE_FLAG_3D_FRAME_PACKING },
	{ 1280, 720,  60, DRM_MODE_FLAG_3D_TOP_AND_BOTTOM },
	{ 1280, 720,  60, DRM_MODE_FLAG_3D_FRAME_PACKING }
};

static bool
stereo_match_mandatory(const struct drm_display_mode *mode,
		       const struct stereo_mandatory_mode *stereo_mode)
{
	unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;

	return mode->hdisplay == stereo_mode->width &&
	       mode->vdisplay == stereo_mode->height &&
	       interlaced == (stereo_mode->flags & DRM_MODE_FLAG_INTERLACE) &&
	       drm_mode_vrefresh(mode) == stereo_mode->vrefresh;
}

static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector)
{
	struct drm_device *dev = connector->dev;
	const struct drm_display_mode *mode;
	struct list_head stereo_modes;
	int modes = 0, i;

	INIT_LIST_HEAD(&stereo_modes);

	list_for_each_entry(mode, &connector->probed_modes, head) {
		for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++) {
			const struct stereo_mandatory_mode *mandatory;
			struct drm_display_mode *new_mode;

			if (!stereo_match_mandatory(mode,
						    &stereo_mandatory_modes[i]))
				continue;

			mandatory = &stereo_mandatory_modes[i];
			new_mode = drm_mode_duplicate(dev, mode);
			if (!new_mode)
				continue;

			new_mode->flags |= mandatory->flags;
			list_add_tail(&new_mode->head, &stereo_modes);
			modes++;
		}
	}

	list_splice_tail(&stereo_modes, &connector->probed_modes);

	return modes;
}

static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
{
	struct drm_device *dev = connector->dev;
	struct drm_display_mode *newmode;

	vic--; /* VICs start at 1 */
	if (vic >= ARRAY_SIZE(edid_4k_modes)) {
		DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
		return 0;
	}

	newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]);
	if (!newmode)
		return 0;

	drm_mode_probed_add(connector, newmode);

	return 1;
}

/*
 * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
 * @connector: connector corresponding to the HDMI sink
 * @db: start of the CEA vendor specific block
 * @len: length of the CEA block payload, ie. one can access up to db[len]
 *
 * Parses the HDMI VSDB looking for modes to add to @connector.
 * Parses the HDMI VSDB looking for modes to add to @connector. This function
 * also adds the stereo 3d modes when applicable.
 */
static int
do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
{
	struct drm_device *dev = connector->dev;
	int modes = 0, offset = 0, i;
	u8 vic_len;

@@ -2597,30 +2684,22 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)

	/* the declared length is not long enough for the 2 first bytes
	 * of additional video format capabilities */
	offset += 2;
	if (len < (8 + offset))
	if (len < (8 + offset + 2))
		goto out;

	/* 3D_Present */
	offset++;
	if (db[8 + offset] & (1 << 7))
		modes += add_hdmi_mandatory_stereo_modes(connector);

	offset++;
	vic_len = db[8 + offset] >> 5;

	for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
		struct drm_display_mode *newmode;
		u8 vic;

		vic = db[9 + offset + i];

		vic--; /* VICs start at 1 */
		if (vic >= ARRAY_SIZE(edid_4k_modes)) {
			DRM_ERROR("Unknown HDMI VIC: %d\n", vic);
			continue;
		}

		newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]);
		if (!newmode)
			continue;

		drm_mode_probed_add(connector, newmode);
		modes++;
		modes += add_hdmi_mode(connector, vic);
	}

out:
@@ -2680,8 +2759,8 @@ static int
add_cea_modes(struct drm_connector *connector, struct edid *edid)
{
	const u8 *cea = drm_find_cea_extension(edid);
	const u8 *db;
	u8 dbl;
	const u8 *db, *hdmi = NULL;
	u8 dbl, hdmi_len;
	int modes = 0;

	if (cea && cea_revision(cea) >= 3) {
@@ -2696,11 +2775,20 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)

			if (cea_db_tag(db) == VIDEO_BLOCK)
				modes += do_cea_modes(connector, db + 1, dbl);
			else if (cea_db_is_hdmi_vsdb(db))
				modes += do_hdmi_vsdb_modes(connector, db, dbl);
			else if (cea_db_is_hdmi_vsdb(db)) {
				hdmi = db;
				hdmi_len = dbl;
			}
		}
	}

	/*
	 * We parse the HDMI VSDB after having added the cea modes as we will
	 * be patching their flags when the sink supports stereo 3D.
	 */
	if (hdmi)
		modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len);

	return modes;
}

@@ -3333,6 +3421,33 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
}
EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);

static enum hdmi_3d_structure
s3d_structure_from_display_mode(const struct drm_display_mode *mode)
{
	u32 layout = mode->flags & DRM_MODE_FLAG_3D_MASK;

	switch (layout) {
	case DRM_MODE_FLAG_3D_FRAME_PACKING:
		return HDMI_3D_STRUCTURE_FRAME_PACKING;
	case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE:
		return HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE;
	case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE:
		return HDMI_3D_STRUCTURE_LINE_ALTERNATIVE;
	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL:
		return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL;
	case DRM_MODE_FLAG_3D_L_DEPTH:
		return HDMI_3D_STRUCTURE_L_DEPTH;
	case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH:
		return HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH;
	case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
		return HDMI_3D_STRUCTURE_TOP_AND_BOTTOM;
	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
		return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF;
	default:
		return HDMI_3D_STRUCTURE_INVALID;
	}
}

/**
 * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with
 * data from a DRM display mode
@@ -3350,20 +3465,29 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
					    const struct drm_display_mode *mode)
{
	int err;
	u32 s3d_flags;
	u8 vic;

	if (!frame || !mode)
		return -EINVAL;

	vic = drm_match_hdmi_mode(mode);
	if (!vic)
	s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK;

	if (!vic && !s3d_flags)
		return -EINVAL;

	if (vic && s3d_flags)
		return -EINVAL;

	err = hdmi_vendor_infoframe_init(frame);
	if (err < 0)
		return err;

	if (vic)
		frame->vic = vic;
	else
		frame->s3d_struct = s3d_structure_from_display_mode(mode);

	return 0;
}
+21 −0
Original line number Diff line number Diff line
@@ -302,6 +302,27 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
	return 0;
}

/**
 * Set device/driver capabilities
 */
int
drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	struct drm_set_client_cap *req = data;

	switch (req->capability) {
	case DRM_CLIENT_CAP_STEREO_3D:
		if (req->value > 1)
			return -EINVAL;
		file_priv->stereo_allowed = req->value;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/**
 * Setversion ioctl.
 *
Loading