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

Commit 973d168d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'drm-intel-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel:
  drm/i915: Disable FBC on Ironlake to save 1W
  drm/i915: Take advantage of auto-polling CRT hotplug detection on PCH hardware
  drm/i915/crt: Introduce struct intel_crt
  drm/i915: Do not hold mutex when faulting in user addresses
  drm: radeon: fix error value sign
  drm/radeon/kms: fix and unify tiled buffer alignment checking for r6xx/7xx
  drm/i915: Retire any pending operations on the old scanout when switching
  drm/i915: Fix I2C adapter registration
parents 764bc569 16c59ef3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -150,7 +150,8 @@ static const struct intel_device_info intel_ironlake_d_info = {

static const struct intel_device_info intel_ironlake_m_info = {
	.gen = 5, .is_mobile = 1,
	.need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
	.need_gfx_hws = 1, .has_rc6 = 1, .has_hotplug = 1,
	.has_fbc = 0, /* disabled due to buggy hardware */
	.has_bsd_ring = 1,
};

+2 −0
Original line number Diff line number Diff line
@@ -1045,6 +1045,8 @@ void i915_gem_clflush_object(struct drm_gem_object *obj);
int i915_gem_object_set_domain(struct drm_gem_object *obj,
			       uint32_t read_domains,
			       uint32_t write_domain);
int i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
			      bool interruptible);
int i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+41 −36
Original line number Diff line number Diff line
@@ -547,6 +547,19 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
	struct drm_i915_gem_object *obj_priv;
	int ret = 0;

	if (args->size == 0)
		return 0;

	if (!access_ok(VERIFY_WRITE,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size))
		return -EFAULT;

	ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
				       args->size);
	if (ret)
		return -EFAULT;

	ret = i915_mutex_lock_interruptible(dev);
	if (ret)
		return ret;
@@ -564,23 +577,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
		goto out;
	}

	if (args->size == 0)
		goto out;

	if (!access_ok(VERIFY_WRITE,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size)) {
		ret = -EFAULT;
		goto out;
	}

	ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
				       args->size);
	if (ret) {
		ret = -EFAULT;
		goto out;
	}

	ret = i915_gem_object_get_pages_or_evict(obj);
	if (ret)
		goto out;
@@ -981,7 +977,20 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
	struct drm_i915_gem_pwrite *args = data;
	struct drm_gem_object *obj;
	struct drm_i915_gem_object *obj_priv;
	int ret = 0;
	int ret;

	if (args->size == 0)
		return 0;

	if (!access_ok(VERIFY_READ,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size))
		return -EFAULT;

	ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
				      args->size);
	if (ret)
		return -EFAULT;

	ret = i915_mutex_lock_interruptible(dev);
	if (ret)
@@ -994,30 +1003,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
	}
	obj_priv = to_intel_bo(obj);


	/* Bounds check destination. */
	if (args->offset > obj->size || args->size > obj->size - args->offset) {
		ret = -EINVAL;
		goto out;
	}

	if (args->size == 0)
		goto out;

	if (!access_ok(VERIFY_READ,
		       (char __user *)(uintptr_t)args->data_ptr,
		       args->size)) {
		ret = -EFAULT;
		goto out;
	}

	ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
				      args->size);
	if (ret) {
		ret = -EFAULT;
		goto out;
	}

	/* We can only do the GTT pwrite on untiled buffers, as otherwise
	 * it would end up going through the fenced access, and we'll get
	 * different detiling behavior between reading and writing.
@@ -2907,6 +2898,20 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
	return 0;
}

int
i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
			  bool interruptible)
{
	if (!obj->active)
		return 0;

	if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
		i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
				    0, obj->base.write_domain);

	return i915_gem_object_wait_rendering(&obj->base, interruptible);
}

/**
 * Moves a single object to the CPU read, and possibly write domain.
 *
+94 −65
Original line number Diff line number Diff line
@@ -34,6 +34,25 @@
#include "i915_drm.h"
#include "i915_drv.h"

/* Here's the desired hotplug mode */
#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 |		\
			   ADPA_CRT_HOTPLUG_WARMUP_10MS |		\
			   ADPA_CRT_HOTPLUG_SAMPLE_4S |			\
			   ADPA_CRT_HOTPLUG_VOLTAGE_50 |		\
			   ADPA_CRT_HOTPLUG_VOLREF_325MV |		\
			   ADPA_CRT_HOTPLUG_ENABLE)

struct intel_crt {
	struct intel_encoder base;
	bool force_hotplug_required;
};

static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
{
	return container_of(intel_attached_encoder(connector),
			    struct intel_crt, base);
}

static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
{
	struct drm_device *dev = encoder->dev;
@@ -129,7 +148,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
	}

	adpa = 0;
	adpa = ADPA_HOTPLUG_BITS;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -157,33 +176,25 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
{
	struct drm_device *dev = connector->dev;
	struct intel_crt *crt = intel_attached_crt(connector);
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 adpa, temp;
	u32 adpa;
	bool ret;
	bool turn_off_dac = false;

	temp = adpa = I915_READ(PCH_ADPA);
	/* The first time through, trigger an explicit detection cycle */
	if (crt->force_hotplug_required) {
		bool turn_off_dac = HAS_PCH_SPLIT(dev);
		u32 save_adpa;

	if (HAS_PCH_SPLIT(dev))
		turn_off_dac = true;
		crt->force_hotplug_required = 0;

	adpa &= ~ADPA_CRT_HOTPLUG_MASK;
		save_adpa = adpa = I915_READ(PCH_ADPA);
		DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);

		adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
		if (turn_off_dac)
			adpa &= ~ADPA_DAC_ENABLE;

	/* disable HPD first */
	I915_WRITE(PCH_ADPA, adpa);
	(void)I915_READ(PCH_ADPA);

	adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
			ADPA_CRT_HOTPLUG_WARMUP_10MS |
			ADPA_CRT_HOTPLUG_SAMPLE_4S |
			ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
			ADPA_CRT_HOTPLUG_VOLREF_325MV |
			ADPA_CRT_HOTPLUG_ENABLE |
			ADPA_CRT_HOTPLUG_FORCE_TRIGGER);

	DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
		I915_WRITE(PCH_ADPA, adpa);

		if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
@@ -191,19 +202,18 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");

		if (turn_off_dac) {
		/* Make sure hotplug is enabled */
		I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
		(void)I915_READ(PCH_ADPA);
			I915_WRITE(PCH_ADPA, save_adpa);
			POSTING_READ(PCH_ADPA);
		}
	}

	/* Check the status to see if both blue and green are on now */
	adpa = I915_READ(PCH_ADPA);
	adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
	if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
		(adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
	if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
		ret = true;
	else
		ret = false;
	DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);

	return ret;
}
@@ -277,13 +287,12 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
	return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
}

static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
static bool intel_crt_detect_ddc(struct intel_crt *crt)
{
	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
	struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;

	/* CRT should always be at 0, but check anyway */
	if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
	if (crt->base.type != INTEL_OUTPUT_ANALOG)
		return false;

	if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
@@ -291,7 +300,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
		return true;
	}

	if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
	if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
		DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
		return true;
	}
@@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
}

static enum drm_connector_status
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
{
	struct drm_encoder *encoder = &intel_encoder->base;
	struct drm_encoder *encoder = &crt->base.base;
	struct drm_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -434,7 +443,7 @@ static enum drm_connector_status
intel_crt_detect(struct drm_connector *connector, bool force)
{
	struct drm_device *dev = connector->dev;
	struct intel_encoder *encoder = intel_attached_encoder(connector);
	struct intel_crt *crt = intel_attached_crt(connector);
	struct drm_crtc *crtc;
	int dpms_mode;
	enum drm_connector_status status;
@@ -443,28 +452,31 @@ intel_crt_detect(struct drm_connector *connector, bool force)
		if (intel_crt_detect_hotplug(connector)) {
			DRM_DEBUG_KMS("CRT detected via hotplug\n");
			return connector_status_connected;
		} else
		} else {
			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
			return connector_status_disconnected;
		}
	}

	if (intel_crt_detect_ddc(&encoder->base))
	if (intel_crt_detect_ddc(crt))
		return connector_status_connected;

	if (!force)
		return connector->status;

	/* for pre-945g platforms use load detect */
	if (encoder->base.crtc && encoder->base.crtc->enabled) {
		status = intel_crt_load_detect(encoder->base.crtc, encoder);
	crtc = crt->base.base.crtc;
	if (crtc && crtc->enabled) {
		status = intel_crt_load_detect(crtc, crt);
	} else {
		crtc = intel_get_load_detect_pipe(encoder, connector,
		crtc = intel_get_load_detect_pipe(&crt->base, connector,
						  NULL, &dpms_mode);
		if (crtc) {
			if (intel_crt_detect_ddc(&encoder->base))
			if (intel_crt_detect_ddc(crt))
				status = connector_status_connected;
			else
				status = intel_crt_load_detect(crtc, encoder);
			intel_release_load_detect_pipe(encoder,
				status = intel_crt_load_detect(crtc, crt);
			intel_release_load_detect_pipe(&crt->base,
						       connector, dpms_mode);
		} else
			status = connector_status_unknown;
@@ -536,17 +548,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
void intel_crt_init(struct drm_device *dev)
{
	struct drm_connector *connector;
	struct intel_encoder *intel_encoder;
	struct intel_crt *crt;
	struct intel_connector *intel_connector;
	struct drm_i915_private *dev_priv = dev->dev_private;

	intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
	if (!intel_encoder)
	crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
	if (!crt)
		return;

	intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
	if (!intel_connector) {
		kfree(intel_encoder);
		kfree(crt);
		return;
	}

@@ -554,20 +566,20 @@ void intel_crt_init(struct drm_device *dev)
	drm_connector_init(dev, &intel_connector->base,
			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);

	drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
	drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
			 DRM_MODE_ENCODER_DAC);

	intel_connector_attach_encoder(intel_connector, intel_encoder);
	intel_connector_attach_encoder(intel_connector, &crt->base);

	intel_encoder->type = INTEL_OUTPUT_ANALOG;
	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
				   (1 << INTEL_ANALOG_CLONE_BIT) |
				   (1 << INTEL_SDVO_LVDS_CLONE_BIT);
	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
	crt->base.type = INTEL_OUTPUT_ANALOG;
	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
				1 << INTEL_ANALOG_CLONE_BIT |
				1 << INTEL_SDVO_LVDS_CLONE_BIT);
	crt->base.crtc_mask = (1 << 0) | (1 << 1);
	connector->interlace_allowed = 1;
	connector->doublescan_allowed = 0;

	drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
	drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);

	drm_sysfs_connector_add(connector);
@@ -577,5 +589,22 @@ void intel_crt_init(struct drm_device *dev)
	else
		connector->polled = DRM_CONNECTOR_POLL_CONNECT;

	/*
	 * Configure the automatic hotplug detection stuff
	 */
	crt->force_hotplug_required = 0;
	if (HAS_PCH_SPLIT(dev)) {
		u32 adpa;

		adpa = I915_READ(PCH_ADPA);
		adpa &= ~ADPA_CRT_HOTPLUG_MASK;
		adpa |= ADPA_HOTPLUG_BITS;
		I915_WRITE(PCH_ADPA, adpa);
		POSTING_READ(PCH_ADPA);

		DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
		crt->force_hotplug_required = 1;
	}

	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
+12 −0
Original line number Diff line number Diff line
@@ -1611,6 +1611,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,

		wait_event(dev_priv->pending_flip_queue,
			   atomic_read(&obj_priv->pending_flip) == 0);

		/* Big Hammer, we also need to ensure that any pending
		 * MI_WAIT_FOR_EVENT inside a user batch buffer on the
		 * current scanout is retired before unpinning the old
		 * framebuffer.
		 */
		ret = i915_gem_object_flush_gpu(obj_priv, false);
		if (ret) {
			i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
			mutex_unlock(&dev->struct_mutex);
			return ret;
		}
	}

	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
Loading