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 Original line 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 = {
static const struct intel_device_info intel_ironlake_m_info = {
	.gen = 5, .is_mobile = 1,
	.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,
	.has_bsd_ring = 1,
};
};


+2 −0
Original line number Original line 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,
int i915_gem_object_set_domain(struct drm_gem_object *obj,
			       uint32_t read_domains,
			       uint32_t read_domains,
			       uint32_t write_domain);
			       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);
int i915_gem_init_ringbuffer(struct drm_device *dev);
void i915_gem_cleanup_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,
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+41 −36
Original line number Original line 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;
	struct drm_i915_gem_object *obj_priv;
	int ret = 0;
	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);
	ret = i915_mutex_lock_interruptible(dev);
	if (ret)
	if (ret)
		return ret;
		return ret;
@@ -564,23 +577,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
		goto out;
		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);
	ret = i915_gem_object_get_pages_or_evict(obj);
	if (ret)
	if (ret)
		goto out;
		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_i915_gem_pwrite *args = data;
	struct drm_gem_object *obj;
	struct drm_gem_object *obj;
	struct drm_i915_gem_object *obj_priv;
	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);
	ret = i915_mutex_lock_interruptible(dev);
	if (ret)
	if (ret)
@@ -994,30 +1003,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
	}
	}
	obj_priv = to_intel_bo(obj);
	obj_priv = to_intel_bo(obj);



	/* Bounds check destination. */
	/* Bounds check destination. */
	if (args->offset > obj->size || args->size > obj->size - args->offset) {
	if (args->offset > obj->size || args->size > obj->size - args->offset) {
		ret = -EINVAL;
		ret = -EINVAL;
		goto out;
		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
	/* 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
	 * it would end up going through the fenced access, and we'll get
	 * different detiling behavior between reading and writing.
	 * 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;
	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.
 * Moves a single object to the CPU read, and possibly write domain.
 *
 *
+94 −65
Original line number Original line Diff line number Diff line
@@ -34,6 +34,25 @@
#include "i915_drm.h"
#include "i915_drm.h"
#include "i915_drv.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)
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
{
{
	struct drm_device *dev = encoder->dev;
	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);
			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
	}
	}


	adpa = 0;
	adpa = ADPA_HOTPLUG_BITS;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
	if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
		adpa |= ADPA_HSYNC_ACTIVE_HIGH;
	if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
	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)
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
{
{
	struct drm_device *dev = connector->dev;
	struct drm_device *dev = connector->dev;
	struct intel_crt *crt = intel_attached_crt(connector);
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 adpa, temp;
	u32 adpa;
	bool ret;
	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))
		crt->force_hotplug_required = 0;
		turn_off_dac = true;


	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)
		if (turn_off_dac)
			adpa &= ~ADPA_DAC_ENABLE;
			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);
		I915_WRITE(PCH_ADPA, adpa);


		if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
		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");
			DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");


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


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


	return 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;
	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 = crt->base.base.dev->dev_private;
	struct drm_i915_private *dev_priv = encoder->dev->dev_private;


	/* CRT should always be at 0, but check anyway */
	/* 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;
		return false;


	if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
	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;
		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");
		DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
		return true;
		return true;
	}
	}
@@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
}
}


static enum drm_connector_status
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_device *dev = encoder->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	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)
intel_crt_detect(struct drm_connector *connector, bool force)
{
{
	struct drm_device *dev = connector->dev;
	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;
	struct drm_crtc *crtc;
	int dpms_mode;
	int dpms_mode;
	enum drm_connector_status status;
	enum drm_connector_status status;
@@ -443,28 +452,31 @@ intel_crt_detect(struct drm_connector *connector, bool force)
		if (intel_crt_detect_hotplug(connector)) {
		if (intel_crt_detect_hotplug(connector)) {
			DRM_DEBUG_KMS("CRT detected via hotplug\n");
			DRM_DEBUG_KMS("CRT detected via hotplug\n");
			return connector_status_connected;
			return connector_status_connected;
		} else
		} else {
			DRM_DEBUG_KMS("CRT not detected via hotplug\n");
			return connector_status_disconnected;
			return connector_status_disconnected;
		}
		}
	}


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


	if (!force)
	if (!force)
		return connector->status;
		return connector->status;


	/* for pre-945g platforms use load detect */
	/* for pre-945g platforms use load detect */
	if (encoder->base.crtc && encoder->base.crtc->enabled) {
	crtc = crt->base.base.crtc;
		status = intel_crt_load_detect(encoder->base.crtc, encoder);
	if (crtc && crtc->enabled) {
		status = intel_crt_load_detect(crtc, crt);
	} else {
	} else {
		crtc = intel_get_load_detect_pipe(encoder, connector,
		crtc = intel_get_load_detect_pipe(&crt->base, connector,
						  NULL, &dpms_mode);
						  NULL, &dpms_mode);
		if (crtc) {
		if (crtc) {
			if (intel_crt_detect_ddc(&encoder->base))
			if (intel_crt_detect_ddc(crt))
				status = connector_status_connected;
				status = connector_status_connected;
			else
			else
				status = intel_crt_load_detect(crtc, encoder);
				status = intel_crt_load_detect(crtc, crt);
			intel_release_load_detect_pipe(encoder,
			intel_release_load_detect_pipe(&crt->base,
						       connector, dpms_mode);
						       connector, dpms_mode);
		} else
		} else
			status = connector_status_unknown;
			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)
void intel_crt_init(struct drm_device *dev)
{
{
	struct drm_connector *connector;
	struct drm_connector *connector;
	struct intel_encoder *intel_encoder;
	struct intel_crt *crt;
	struct intel_connector *intel_connector;
	struct intel_connector *intel_connector;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_private *dev_priv = dev->dev_private;


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


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


@@ -554,20 +566,20 @@ void intel_crt_init(struct drm_device *dev)
	drm_connector_init(dev, &intel_connector->base,
	drm_connector_init(dev, &intel_connector->base,
			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
			   &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);
			 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;
	crt->base.type = INTEL_OUTPUT_ANALOG;
	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
	crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
				   (1 << INTEL_ANALOG_CLONE_BIT) |
				1 << INTEL_ANALOG_CLONE_BIT |
				   (1 << INTEL_SDVO_LVDS_CLONE_BIT);
				1 << INTEL_SDVO_LVDS_CLONE_BIT);
	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
	crt->base.crtc_mask = (1 << 0) | (1 << 1);
	connector->interlace_allowed = 1;
	connector->interlace_allowed = 1;
	connector->doublescan_allowed = 0;
	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_connector_helper_add(connector, &intel_crt_connector_helper_funcs);


	drm_sysfs_connector_add(connector);
	drm_sysfs_connector_add(connector);
@@ -577,5 +589,22 @@ void intel_crt_init(struct drm_device *dev)
	else
	else
		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
		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;
	dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
}
+12 −0
Original line number Original line 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,
		wait_event(dev_priv->pending_flip_queue,
			   atomic_read(&obj_priv->pending_flip) == 0);
			   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,
	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
Loading