f2fe333
Bugzilla: N/A
f2fe333
Upstream-status: Queued for 3.13
f2fe333
f2fe333
From db8edc33193879f39c1b52521e20f4d6eb4e9858 Mon Sep 17 00:00:00 2001
f2fe333
From: Dave Airlie <airlied@redhat.com>
f2fe333
Date: Fri, 08 Nov 2013 06:36:45 +0000
f2fe333
Subject: drm/qxl: backport fixes for Fedora
f2fe333
f2fe333
This pulls these changes from drm-next back into Fedora.
f2fe333
f2fe333
drm/qxl: prefer the monitor config resolution (b080742393e2c1)
f2fe333
drm/qxl: remove unnecessary check (a40a60d912a101e8dfb08ee1)
f2fe333
drm/qxl: fix disabling extra monitors from client (5cab51cb3381157)
f2fe333
qxl: avoid an oops in the deferred io code. (cc87509d87696d7cd39)
f2fe333
drm/qxl: support 64bit surface bar (35541782dcc1e502)
f2fe333
qxl: add a connector property to denote hotplug should rescan modes. (4695b03970df37)
f2fe333
f2fe333
Signed-off-by: Dave Airlie <airlied@redhat.com>
f2fe333
---
f2fe333
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
f2fe333
index 835caba..1d975eb 100644
f2fe333
--- a/drivers/gpu/drm/qxl/qxl_display.c
f2fe333
+++ b/drivers/gpu/drm/qxl/qxl_display.c
f2fe333
@@ -110,7 +110,9 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
f2fe333
 	drm_helper_hpd_irq_event(qdev->ddev);
f2fe333
 }
f2fe333
 
f2fe333
-static int qxl_add_monitors_config_modes(struct drm_connector *connector)
f2fe333
+static int qxl_add_monitors_config_modes(struct drm_connector *connector,
f2fe333
+                                         unsigned *pwidth,
f2fe333
+                                         unsigned *pheight)
f2fe333
 {
f2fe333
 	struct drm_device *dev = connector->dev;
f2fe333
 	struct qxl_device *qdev = dev->dev_private;
f2fe333
@@ -126,11 +128,15 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector)
f2fe333
 	mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,
f2fe333
 			    false);
f2fe333
 	mode->type |= DRM_MODE_TYPE_PREFERRED;
f2fe333
+	*pwidth = head->width;
f2fe333
+	*pheight = head->height;
f2fe333
 	drm_mode_probed_add(connector, mode);
f2fe333
 	return 1;
f2fe333
 }
f2fe333
 
f2fe333
-static int qxl_add_common_modes(struct drm_connector *connector)
f2fe333
+static int qxl_add_common_modes(struct drm_connector *connector,
f2fe333
+                                unsigned pwidth,
f2fe333
+                                unsigned pheight)
f2fe333
 {
f2fe333
 	struct drm_device *dev = connector->dev;
f2fe333
 	struct drm_display_mode *mode = NULL;
f2fe333
@@ -159,12 +165,9 @@ static int qxl_add_common_modes(struct drm_connector *connector)
f2fe333
 	};
f2fe333
 
f2fe333
 	for (i = 0; i < ARRAY_SIZE(common_modes); i++) {
f2fe333
-		if (common_modes[i].w < 320 || common_modes[i].h < 200)
f2fe333
-			continue;
f2fe333
-
f2fe333
 		mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h,
f2fe333
 				    60, false, false, false);
f2fe333
-		if (common_modes[i].w == 1024 && common_modes[i].h == 768)
f2fe333
+		if (common_modes[i].w == pwidth && common_modes[i].h == pheight)
f2fe333
 			mode->type |= DRM_MODE_TYPE_PREFERRED;
f2fe333
 		drm_mode_probed_add(connector, mode);
f2fe333
 	}
f2fe333
@@ -720,16 +723,18 @@ static int qxl_conn_get_modes(struct drm_connector *connector)
f2fe333
 {
f2fe333
 	int ret = 0;
f2fe333
 	struct qxl_device *qdev = connector->dev->dev_private;
f2fe333
+	unsigned pwidth = 1024;
f2fe333
+	unsigned pheight = 768;
f2fe333
 
f2fe333
 	DRM_DEBUG_KMS("monitors_config=%p\n", qdev->monitors_config);
f2fe333
 	/* TODO: what should we do here? only show the configured modes for the
f2fe333
 	 * device, or allow the full list, or both? */
f2fe333
 	if (qdev->monitors_config && qdev->monitors_config->count) {
f2fe333
-		ret = qxl_add_monitors_config_modes(connector);
f2fe333
+		ret = qxl_add_monitors_config_modes(connector, &pwidth, &pheight);
f2fe333
 		if (ret < 0)
f2fe333
 			return ret;
f2fe333
 	}
f2fe333
-	ret += qxl_add_common_modes(connector);
f2fe333
+	ret += qxl_add_common_modes(connector, pwidth, pheight);
f2fe333
 	return ret;
f2fe333
 }
f2fe333
 
f2fe333
@@ -793,7 +798,10 @@ static enum drm_connector_status qxl_conn_detect(
f2fe333
 		     qdev->client_monitors_config->count > output->index &&
f2fe333
 		     qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]));
f2fe333
 
f2fe333
-	DRM_DEBUG("\n");
f2fe333
+	DRM_DEBUG("#%d connected: %d\n", output->index, connected);
f2fe333
+	if (!connected)
f2fe333
+		qxl_monitors_config_set(qdev, output->index, 0, 0, 0, 0, 0);
f2fe333
+
f2fe333
 	return connected ? connector_status_connected
f2fe333
 			 : connector_status_disconnected;
f2fe333
 }
f2fe333
@@ -835,8 +843,21 @@ static const struct drm_encoder_funcs qxl_enc_funcs = {
f2fe333
 	.destroy = qxl_enc_destroy,
f2fe333
 };
f2fe333
 
f2fe333
+static int qxl_mode_create_hotplug_mode_update_property(struct qxl_device *qdev)
f2fe333
+{
f2fe333
+	if (qdev->hotplug_mode_update_property)
f2fe333
+		return 0;
f2fe333
+
f2fe333
+	qdev->hotplug_mode_update_property =
f2fe333
+		drm_property_create_range(qdev->ddev, DRM_MODE_PROP_IMMUTABLE,
f2fe333
+					  "hotplug_mode_update", 0, 1);
f2fe333
+
f2fe333
+	return 0;
f2fe333
+}
f2fe333
+
f2fe333
 static int qdev_output_init(struct drm_device *dev, int num_output)
f2fe333
 {
f2fe333
+	struct qxl_device *qdev = dev->dev_private;
f2fe333
 	struct qxl_output *qxl_output;
f2fe333
 	struct drm_connector *connector;
f2fe333
 	struct drm_encoder *encoder;
f2fe333
@@ -863,6 +884,8 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
f2fe333
 	drm_encoder_helper_add(encoder, &qxl_enc_helper_funcs);
f2fe333
 	drm_connector_helper_add(connector, &qxl_connector_helper_funcs);
f2fe333
 
f2fe333
+	drm_object_attach_property(&connector->base,
f2fe333
+				   qdev->hotplug_mode_update_property, 0);
f2fe333
 	drm_sysfs_connector_add(connector);
f2fe333
 	return 0;
f2fe333
 }
f2fe333
@@ -975,6 +998,9 @@ int qxl_modeset_init(struct qxl_device *qdev)
f2fe333
 	qdev->ddev->mode_config.max_height = 8192;
f2fe333
 
f2fe333
 	qdev->ddev->mode_config.fb_base = qdev->vram_base;
f2fe333
+
f2fe333
+	qxl_mode_create_hotplug_mode_update_property(qdev);
f2fe333
+
f2fe333
 	for (i = 0 ; i < qxl_num_crtc; ++i) {
f2fe333
 		qdev_crtc_init(qdev->ddev, i);
f2fe333
 		qdev_output_init(qdev->ddev, i);
f2fe333
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
f2fe333
index 7e96f4f..18c599d 100644
f2fe333
--- a/drivers/gpu/drm/qxl/qxl_drv.h
f2fe333
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
f2fe333
@@ -323,6 +323,8 @@ struct qxl_device {
f2fe333
 	struct work_struct gc_work;
f2fe333
 
f2fe333
 	struct work_struct fb_work;
f2fe333
+
f2fe333
+	struct drm_property *hotplug_mode_update_property;
f2fe333
 };
f2fe333
 
f2fe333
 /* forward declaration for QXL_INFO_IO */
f2fe333
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
f2fe333
index 88722f2..f437b30 100644
f2fe333
--- a/drivers/gpu/drm/qxl/qxl_fb.c
f2fe333
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
f2fe333
@@ -108,7 +108,7 @@ static void qxl_fb_dirty_flush(struct fb_info *info)
f2fe333
 	u32 x1, x2, y1, y2;
f2fe333
 
f2fe333
 	/* TODO: hard coding 32 bpp */
f2fe333
-	int stride = qfbdev->qfb.base.pitches[0] * 4;
f2fe333
+	int stride = qfbdev->qfb.base.pitches[0];
f2fe333
 
f2fe333
 	x1 = qfbdev->dirty.x1;
f2fe333
 	x2 = qfbdev->dirty.x2;
f2fe333
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
f2fe333
index 9e8da9e..e0ddd5b 100644
f2fe333
--- a/drivers/gpu/drm/qxl/qxl_kms.c
f2fe333
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
f2fe333
@@ -120,7 +120,7 @@ int qxl_device_init(struct qxl_device *qdev,
f2fe333
 		    struct pci_dev *pdev,
f2fe333
 		    unsigned long flags)
f2fe333
 {
f2fe333
-	int r;
f2fe333
+	int r, sb;
f2fe333
 
f2fe333
 	qdev->dev = &pdev->dev;
f2fe333
 	qdev->ddev = ddev;
f2fe333
@@ -136,21 +136,39 @@ int qxl_device_init(struct qxl_device *qdev,
f2fe333
 	qdev->rom_base = pci_resource_start(pdev, 2);
f2fe333
 	qdev->rom_size = pci_resource_len(pdev, 2);
f2fe333
 	qdev->vram_base = pci_resource_start(pdev, 0);
f2fe333
-	qdev->surfaceram_base = pci_resource_start(pdev, 1);
f2fe333
-	qdev->surfaceram_size = pci_resource_len(pdev, 1);
f2fe333
 	qdev->io_base = pci_resource_start(pdev, 3);
f2fe333
 
f2fe333
 	qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0));
f2fe333
-	qdev->surface_mapping = io_mapping_create_wc(qdev->surfaceram_base, qdev->surfaceram_size);
f2fe333
-	DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk)\n",
f2fe333
+
f2fe333
+	if (pci_resource_len(pdev, 4) > 0) {
f2fe333
+		/* 64bit surface bar present */
f2fe333
+		sb = 4;
f2fe333
+		qdev->surfaceram_base = pci_resource_start(pdev, sb);
f2fe333
+		qdev->surfaceram_size = pci_resource_len(pdev, sb);
f2fe333
+		qdev->surface_mapping =
f2fe333
+			io_mapping_create_wc(qdev->surfaceram_base,
f2fe333
+					     qdev->surfaceram_size);
f2fe333
+	}
f2fe333
+	if (qdev->surface_mapping == NULL) {
f2fe333
+		/* 64bit surface bar not present (or mapping failed) */
f2fe333
+		sb = 1;
f2fe333
+		qdev->surfaceram_base = pci_resource_start(pdev, sb);
f2fe333
+		qdev->surfaceram_size = pci_resource_len(pdev, sb);
f2fe333
+		qdev->surface_mapping =
f2fe333
+			io_mapping_create_wc(qdev->surfaceram_base,
f2fe333
+					     qdev->surfaceram_size);
f2fe333
+	}
f2fe333
+
f2fe333
+	DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk, %s)\n",
f2fe333
 		 (unsigned long long)qdev->vram_base,
f2fe333
 		 (unsigned long long)pci_resource_end(pdev, 0),
f2fe333
 		 (int)pci_resource_len(pdev, 0) / 1024 / 1024,
f2fe333
 		 (int)pci_resource_len(pdev, 0) / 1024,
f2fe333
 		 (unsigned long long)qdev->surfaceram_base,
f2fe333
-		 (unsigned long long)pci_resource_end(pdev, 1),
f2fe333
+		 (unsigned long long)pci_resource_end(pdev, sb),
f2fe333
 		 (int)qdev->surfaceram_size / 1024 / 1024,
f2fe333
-		 (int)qdev->surfaceram_size / 1024);
f2fe333
+		 (int)qdev->surfaceram_size / 1024,
f2fe333
+		 (sb == 4) ? "64bit" : "32bit");
f2fe333
 
f2fe333
 	qdev->rom = ioremap(qdev->rom_base, qdev->rom_size);
f2fe333
 	if (!qdev->rom) {
f2fe333
--
f2fe333
cgit v0.9.0.2-2-gbebe