public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
* tile group support (v2)
@ 2014-10-22  2:32 Dave Airlie
  2014-10-22  2:32 ` [PATCH 1/6] drm/displayid: add displayid defines and edid extension (v2) Dave Airlie
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

This is just a second round of the previous series, cleaned up the
problems pointed out (except property hotplug - bigger problem),

Dave.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/6] drm/displayid: add displayid defines and edid extension (v2)
  2014-10-22  2:32 tile group support (v2) Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  2014-10-22  2:32 ` [PATCH 2/6] drm: add tile_group support. (v2) Dave Airlie
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

These are just taken from the DisplayID v1.3 spec, and the
DDC spec.

v2: use __packed (Jani)

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 include/drm/drm_displayid.h | 76 +++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_edid.h      |  2 ++
 2 files changed, 78 insertions(+)
 create mode 100644 include/drm/drm_displayid.h

diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
new file mode 100644
index 0000000..623b4e9
--- /dev/null
+++ b/include/drm/drm_displayid.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef DRM_DISPLAYID_H
+#define DRM_DISPLAYID_H
+
+#define DATA_BLOCK_PRODUCT_ID 0x00
+#define DATA_BLOCK_DISPLAY_PARAMETERS 0x01
+#define DATA_BLOCK_COLOR_CHARACTERISTICS 0x02
+#define DATA_BLOCK_TYPE_1_DETAILED_TIMING 0x03
+#define DATA_BLOCK_TYPE_2_DETAILED_TIMING 0x04
+#define DATA_BLOCK_TYPE_3_SHORT_TIMING 0x05
+#define DATA_BLOCK_TYPE_4_DMT_TIMING 0x06
+#define DATA_BLOCK_VESA_TIMING 0x07
+#define DATA_BLOCK_CEA_TIMING 0x08
+#define DATA_BLOCK_VIDEO_TIMING_RANGE 0x09
+#define DATA_BLOCK_PRODUCT_SERIAL_NUMBER 0x0a
+#define DATA_BLOCK_GP_ASCII_STRING 0x0b
+#define DATA_BLOCK_DISPLAY_DEVICE_DATA 0x0c
+#define DATA_BLOCK_INTERFACE_POWER_SEQUENCING 0x0d
+#define DATA_BLOCK_TRANSFER_CHARACTERISTICS 0x0e
+#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
+#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
+#define DATA_BLOCK_TILED_DISPLAY 0x12
+
+#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
+
+#define PRODUCT_TYPE_EXTENSION 0
+#define PRODUCT_TYPE_TEST 1
+#define PRODUCT_TYPE_PANEL 2
+#define PRODUCT_TYPE_MONITOR 3
+#define PRODUCT_TYPE_TV 4
+#define PRODUCT_TYPE_REPEATER 5
+#define PRODUCT_TYPE_DIRECT_DRIVE 6
+
+struct displayid_hdr {
+	u8 rev;
+	u8 bytes;
+	u8 prod_id;
+	u8 ext_count;
+} __packed;
+
+struct displayid_block {
+	u8 tag;
+	u8 rev;
+	u8 num_bytes;
+} __packed;
+
+struct displayid_tiled_block {
+	struct displayid_block base;
+	u8 tile_cap;
+	u8 topo[3];
+	u8 tile_size[4];
+	u8 tile_pixel_bezel[5];
+	u8 topology_id[8];
+} __packed;
+
+#endif
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index b96031d..3e87f5a 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -27,12 +27,14 @@
 
 #define EDID_LENGTH 128
 #define DDC_ADDR 0x50
+#define DDC_ADDR2 0x52 /* E-DDC 1.2 - where DisplayID can hide */
 
 #define CEA_EXT	    0x02
 #define VTB_EXT	    0x10
 #define DI_EXT	    0x40
 #define LS_EXT	    0x50
 #define MI_EXT	    0x60
+#define DISPLAYID_EXT 0x70
 
 struct est_timings {
 	u8 t1;
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/6] drm: add tile_group support. (v2)
  2014-10-22  2:32 tile group support (v2) Dave Airlie
  2014-10-22  2:32 ` [PATCH 1/6] drm/displayid: add displayid defines and edid extension (v2) Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  2014-10-22  8:15   ` Daniel Vetter
  2014-10-28  6:54   ` Dave Airlie
  2014-10-22  2:32 ` [PATCH 3/6] drm/mst: cached EDID for logical ports Dave Airlie
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

A tile group is an identifier shared by a single monitor,
DisplayID topology has 8 bytes we can use for this, just
use those for now until something else comes up in the
future. We assign these to an idr and use the idr to
tell userspace what connectors are in the same tile group.

DisplayID v1.3 says the serial number must be unique for
displays from the same manufacturer.

v2:
destroy idr (dvdhrm)
add docbook (danvet)
airlied:- not sure how to make docbook add fns to tile group section.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 Documentation/DocBook/drm.tmpl |  4 ++
 drivers/gpu/drm/drm_crtc.c     | 99 ++++++++++++++++++++++++++++++++++++++++++
 include/drm/drm_crtc.h         | 16 +++++++
 3 files changed, 119 insertions(+)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 0a5cbbb..5ea6289 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2374,6 +2374,10 @@ void intel_crt_init(struct drm_device *dev)
       <title id="drm-kms-planehelpers">Plane Helper Reference</title>
 !Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
     </sect2>
+    <sect2>
+	  <title>Tile group</title>
+!Pdrivers/gpu/drm/drm_crtc.c Tile group
+    </sect2>
   </sect1>
 
   <!-- Internals: kms properties -->
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 363301c..7f45fdc 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -5047,6 +5047,7 @@ void drm_mode_config_init(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
 	INIT_LIST_HEAD(&dev->mode_config.plane_list);
 	idr_init(&dev->mode_config.crtc_idr);
+	idr_init(&dev->mode_config.tile_idr);
 
 	drm_modeset_lock_all(dev);
 	drm_mode_create_standard_connector_properties(dev);
@@ -5134,6 +5135,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		crtc->funcs->destroy(crtc);
 	}
 
+	idr_destroy(&dev->mode_config.tile_idr);
 	idr_destroy(&dev->mode_config.crtc_idr);
 	drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
 }
@@ -5156,3 +5158,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
 					   supported_rotations);
 }
 EXPORT_SYMBOL(drm_mode_create_rotation_property);
+
+/**
+ * DOC: Tile group
+ *
+ * Tile groups are used to represent tiled monitors with a unique
+ * integer identifier. Tiled monitors using DisplayID v1.3 have
+ * a unique 8-byte handle, we store this in a tile group, so we
+ * have a common identifier for all tiles in a monitor group.
+ */
+static void drm_tile_group_free(struct kref *kref)
+{
+	struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
+	struct drm_device *dev = tg->dev;
+	mutex_lock(&dev->mode_config.idr_mutex);
+	idr_remove(&dev->mode_config.tile_idr, tg->id);
+	mutex_lock(&dev->mode_config.idr_mutex);
+	kfree(tg);
+}
+
+/**
+ * drm_mode_put_tile_group - drop a reference to a tile group.
+ * @dev: DRM device
+ * @tg: tile group to drop reference to.
+ *
+ * drop reference to tile group and free if 0.
+ */
+void drm_mode_put_tile_group(struct drm_device *dev,
+			     struct drm_tile_group *tg)
+{
+	kref_put(&tg->refcount, drm_tile_group_free);
+}
+
+/**
+ * drm_mode_get_tile_group - get a reference to an existing tile group
+ * @dev: DRM device
+ * @topology: 8-bytes unique per monitor.
+ *
+ * Use the unique bytes to get a reference to an existing tile group.
+ *
+ * RETURNS:
+ * tile group or NULL if not found.
+ */
+struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
+					       char topology[8])
+{
+	struct drm_tile_group *tg;
+	int id;
+	mutex_lock(&dev->mode_config.idr_mutex);
+	idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
+		if (!memcmp(tg->group_data, topology, 8)) {
+			if (!kref_get_unless_zero(&tg->refcount))
+				tg = NULL;
+			mutex_unlock(&dev->mode_config.idr_mutex);
+			return tg;
+		}
+	}
+	mutex_unlock(&dev->mode_config.idr_mutex);
+	return NULL;
+}
+
+/**
+ * drm_mode_create_tile_group - create a tile group from a displayid description
+ * @dev: DRM device
+ * @topology: 8-bytes unique per monitor.
+ *
+ * Create a tile group for the unique monitor, and get a unique
+ * identifier for the tile group.
+ *
+ * RETURNS:
+ * new tile group or error.
+ */
+struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
+						  char topology[8])
+{
+	struct drm_tile_group *tg;
+	int ret;
+
+	tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+	if (!tg)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&tg->refcount);
+	memcpy(tg->group_data, topology, 8);
+	tg->dev = dev;
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
+	if (ret >= 0) {
+		tg->id = ret;
+	} else {
+		kfree(tg);
+		tg = ERR_PTR(ret);
+	}
+
+	mutex_unlock(&dev->mode_config.idr_mutex);
+	return tg;
+}
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index f1105d0..afaec4b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -136,6 +136,14 @@ struct drm_display_info {
 	u8 cea_rev;
 };
 
+/* data corresponds to displayid vend/prod/serial */
+struct drm_tile_group {
+	struct kref refcount;
+	struct drm_device *dev;
+	int id;
+	u8 group_data[8];
+};
+
 struct drm_framebuffer_funcs {
 	/* note: use drm_framebuffer_remove() */
 	void (*destroy)(struct drm_framebuffer *framebuffer);
@@ -770,6 +778,7 @@ struct drm_mode_config {
 	struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */
 	struct mutex idr_mutex; /* for IDR management */
 	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
+	struct idr tile_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
 	/* this is limited to one for now */
 
 
@@ -1106,6 +1115,13 @@ extern void drm_set_preferred_mode(struct drm_connector *connector,
 extern int drm_edid_header_is_valid(const u8 *raw_edid);
 extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
 extern bool drm_edid_is_valid(struct edid *edid);
+
+extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
+							 char topology[8]);
+extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
+					       char topology[8]);
+extern void drm_mode_put_tile_group(struct drm_device *dev,
+				   struct drm_tile_group *tg);
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh,
 					   bool rb);
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/6] drm/mst: cached EDID for logical ports
  2014-10-22  2:32 tile group support (v2) Dave Airlie
  2014-10-22  2:32 ` [PATCH 1/6] drm/displayid: add displayid defines and edid extension (v2) Dave Airlie
  2014-10-22  2:32 ` [PATCH 2/6] drm: add tile_group support. (v2) Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  2014-10-22  9:06   ` [Intel-gfx] " Daniel Vetter
  2014-10-22  2:32 ` [PATCH 4/6] drm/connector: store tile information from displayid (v2) Dave Airlie
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

Logical ports are never going to have EDID changes,
they are used for the internal ports on MST monitors.

We cache the EDIDs from these to save time at MST probe.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/drm_dp_mst_topology.c | 20 ++++++++++++++++++--
 drivers/gpu/drm/i915/intel_dp_mst.c   |  2 +-
 include/drm/drm_dp_mst_helper.h       |  4 +++-
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 50926db..ce1113c 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -858,6 +858,8 @@ static void drm_dp_destroy_port(struct kref *kref)
 	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
 	if (!port->input) {
 		port->vcpi.num_slots = 0;
+
+		kfree(port->cached_edid);
 		if (port->connector)
 			(*port->mgr->cbs->destroy_connector)(mgr, port->connector);
 		drm_dp_port_teardown_pdt(port, port->pdt);
@@ -1096,6 +1098,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
 		char proppath[255];
 		build_mst_prop_path(port, mstb, proppath);
 		port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
+
+		if (port->port_num >= 8) {
+			port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
+		}
 	}
 
 	/* put reference to this port */
@@ -2149,7 +2155,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
  * This returns the current connection state for a port. It validates the
  * port pointer still exists so the caller doesn't require a reference
  */
-enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
+enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector,
+						 struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
 {
 	enum drm_connector_status status = connector_status_disconnected;
 
@@ -2168,6 +2175,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr
 
 	case DP_PEER_DEVICE_SST_SINK:
 		status = connector_status_connected;
+		/* for logical ports - cache the EDID */
+		if (port->port_num >= 8 && !port->cached_edid) {
+			port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
+		}
 		break;
 	case DP_PEER_DEVICE_DP_LEGACY_CONV:
 		if (port->ldps)
@@ -2199,7 +2210,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
 	if (!port)
 		return NULL;
 
-	edid = drm_get_edid(connector, &port->aux.ddc);
+	if (port->cached_edid)
+		edid = drm_edid_duplicate(port->cached_edid);
+	else
+		edid = drm_get_edid(connector, &port->aux.ddc);
+
+	drm_mode_connector_set_tile_property(connector);
 	drm_dp_put_port(port);
 	return edid;
 }
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index d9a7a78..c66e73a 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -283,7 +283,7 @@ intel_mst_port_dp_detect(struct drm_connector *connector)
 	struct intel_connector *intel_connector = to_intel_connector(connector);
 	struct intel_dp *intel_dp = intel_connector->mst_port;
 
-	return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port);
+	return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port);
 }
 
 static enum drm_connector_status
diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
index 338fc10..ee6fbad 100644
--- a/include/drm/drm_dp_mst_helper.h
+++ b/include/drm/drm_dp_mst_helper.h
@@ -92,6 +92,8 @@ struct drm_dp_mst_port {
 	struct drm_dp_vcpi vcpi;
 	struct drm_connector *connector;
 	struct drm_dp_mst_topology_mgr *mgr;
+
+	struct edid *cached_edid; /* for DP logical ports - make tiling work */
 };
 
 /**
@@ -474,7 +476,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
 int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
 
 
-enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
+enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
 struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/6] drm/connector: store tile information from displayid (v2)
  2014-10-22  2:32 tile group support (v2) Dave Airlie
                   ` (2 preceding siblings ...)
  2014-10-22  2:32 ` [PATCH 3/6] drm/mst: cached EDID for logical ports Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  2014-10-22  2:32 ` [PATCH 5/6] drm/tile: expose the tile property to userspace (v2) Dave Airlie
  2014-10-22  2:32 ` [PATCH 6/6] drm/fb: add support for tiled monitor configurations Dave Airlie
  5 siblings, 0 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

This creates a tile group from DisplayID block, and
stores the pieces of parsed info from the DisplayID block
into the connector.

v2: add missing signoff, add new connector bits to docs.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/drm_crtc.c |   5 ++
 drivers/gpu/drm/drm_edid.c | 139 ++++++++++++++++++++++++++++++++++++++++++++-
 include/drm/drm_crtc.h     |  18 ++++++
 3 files changed, 160 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7f45fdc..f3e082d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -939,6 +939,11 @@ void drm_connector_cleanup(struct drm_connector *connector)
 	struct drm_device *dev = connector->dev;
 	struct drm_display_mode *mode, *t;
 
+	if (connector->tile_group) {
+		drm_mode_put_tile_group(dev, connector->tile_group);
+		connector->tile_group = NULL;
+	}
+
 	list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
 		drm_mode_remove(connector, mode);
 
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 1dbf3bc..7cbdbe5 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_displayid.h>
 
 #define version_greater(edid, maj, min) \
 	(((edid)->version > (maj)) || \
@@ -1014,6 +1015,8 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
 MODULE_PARM_DESC(edid_fixup,
 		 "Minimum number of valid EDID header bytes (0-8, default 6)");
 
+static void drm_get_displayid(struct drm_connector *connector,
+			      struct edid *edid);
 /**
  * drm_edid_block_valid - Sanity check the EDID block (base or extension)
  * @raw_edid: pointer to raw EDID block
@@ -1294,6 +1297,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 	if (drm_probe_ddc(adapter))
 		edid = (struct edid *)drm_do_get_edid(connector, adapter);
 
+	if (edid)
+		drm_get_displayid(connector, edid);
 	return edid;
 }
 EXPORT_SYMBOL(drm_get_edid);
@@ -2386,7 +2391,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
  * Search EDID for CEA extension block.
  */
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 {
 	u8 *edid_ext = NULL;
 	int i;
@@ -2398,7 +2403,7 @@ static u8 *drm_find_cea_extension(struct edid *edid)
 	/* Find CEA extension */
 	for (i = 0; i < edid->extensions; i++) {
 		edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
-		if (edid_ext[0] == CEA_EXT)
+		if (edid_ext[0] == ext_id)
 			break;
 	}
 
@@ -2408,6 +2413,16 @@ static u8 *drm_find_cea_extension(struct edid *edid)
 	return edid_ext;
 }
 
+static u8 *drm_find_cea_extension(struct edid *edid)
+{
+	return drm_find_edid_extension(edid, CEA_EXT);
+}
+
+static u8 *drm_find_displayid_extension(struct edid *edid)
+{
+	return drm_find_edid_extension(edid, DISPLAYID_EXT);
+}
+
 /*
  * Calculate the alternate clock for the CEA mode
  * (60Hz vs. 59.94Hz etc.)
@@ -3865,3 +3880,123 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
 	return 0;
 }
 EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
+
+static int drm_parse_display_id(struct drm_connector *connector,
+				u8 *displayid, int length,
+				bool is_edid_extension)
+{
+	/* if this is an EDID extension the first byte will be 0x70 */
+	int idx = 0;
+	struct displayid_hdr *base;
+	struct displayid_block *block;
+	u8 csum = 0;
+	int i;
+
+	if (is_edid_extension)
+		idx = 1;
+
+	base = (struct displayid_hdr *)&displayid[idx];
+
+	printk("base revision 0x%x, length %d, %d %d\n",
+	       base->rev, base->bytes, base->prod_id, base->ext_count);
+
+	if (base->bytes + 5 > length - idx)
+		return -EINVAL;
+
+	for (i = idx; i <= base->bytes + 5; i++) {
+		csum += displayid[i];
+	}
+	if (csum) {
+		DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum);
+		return -EINVAL;
+	}
+
+	block = (struct displayid_block *)&displayid[idx + 4];
+	printk("block id %d, rev %d, len %d\n",
+	       block->tag, block->rev, block->num_bytes);
+
+	switch (block->tag) {
+	case DATA_BLOCK_TILED_DISPLAY: {
+		struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
+
+		u16 w, h;
+		u8 tile_v_loc, tile_h_loc;
+		u8 num_v_tile, num_h_tile;
+		struct drm_tile_group *tg;
+
+		w = tile->tile_size[0] | tile->tile_size[1] << 8;
+		h = tile->tile_size[2] | tile->tile_size[3] << 8;
+
+		num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30);
+		num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30);
+		tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4);
+		tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4);
+
+		connector->has_tile = true;
+		if (tile->tile_cap & 0x80)
+			connector->tile_is_single_monitor = true;
+
+		connector->num_h_tile = num_h_tile + 1;
+		connector->num_v_tile = num_v_tile + 1;
+		connector->tile_h_loc = tile_h_loc;
+		connector->tile_v_loc = tile_v_loc;
+		connector->tile_h_size = w + 1;
+		connector->tile_v_size = h + 1;
+
+		DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
+		DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
+		DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
+		       num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
+		DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
+
+		tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
+		if (!tg) {
+			tg = drm_mode_create_tile_group(connector->dev, tile->topology_id);
+		}
+		if (!tg)
+			return -ENOMEM;
+
+		if (connector->tile_group != tg) {
+			/* if we haven't got a pointer,
+			   take the reference, drop ref to old tile group */
+			if (connector->tile_group) {
+				drm_mode_put_tile_group(connector->dev, connector->tile_group);
+			}
+			connector->tile_group = tg;
+		} else
+			/* if same tile group, then release the ref we just took. */
+			drm_mode_put_tile_group(connector->dev, tg);
+	}
+		break;
+	default:
+		printk("unknown displayid tag %d\n", block->tag);
+		break;
+	}
+	return 0;
+}
+
+static void drm_get_displayid(struct drm_connector *connector,
+			      struct edid *edid)
+{
+	void *displayid = NULL;
+	int ret;
+	connector->has_tile = false;
+	displayid = drm_find_displayid_extension(edid);
+	if (!displayid) {
+		/* drop reference to any tile group we had */
+		goto out_drop_ref;
+	}
+
+	ret = drm_parse_display_id(connector, displayid, EDID_LENGTH, true);
+	if (ret < 0)
+		goto out_drop_ref;
+	if (!connector->has_tile)
+		goto out_drop_ref;
+	return;
+out_drop_ref:
+	if (connector->tile_group) {
+		drm_mode_put_tile_group(connector->dev, connector->tile_group);
+		connector->tile_group = NULL;
+	}
+	return;
+}
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index afaec4b..39c9858 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -513,6 +513,15 @@ struct drm_encoder {
  * @video_latency: video latency info from ELD, if found
  * @audio_latency: audio latency info from ELD, if found
  * @null_edid_counter: track sinks that give us all zeros for the EDID
+ * @has_tile: is this connector connected to a tiled monitor
+ * @tile_group: tile group for the connected monitor
+ * @tile_is_single_monitor: whether the tile is one monitor housing
+ * @num_h_tile: number of horizontal tiles in the tile group
+ * @num_v_tile: number of vertical tiles in the tile group
+ * @tile_h_loc: horizontal location of this tile
+ * @tile_v_loc: vertical location of this tile
+ * @tile_h_size: horizontal size of this tile.
+ * @tile_v_size: vertical size of this tile.
  *
  * Each connector may be connected to one or more CRTCs, or may be clonable by
  * another connector if they can share a CRTC.  Each connector also has a specific
@@ -572,6 +581,15 @@ struct drm_connector {
 	unsigned bad_edid_counter;
 
 	struct dentry *debugfs_entry;
+
+	/* DisplayID bits */
+	bool has_tile;
+	struct drm_tile_group *tile_group;
+	bool tile_is_single_monitor;
+
+	uint8_t num_h_tile, num_v_tile;
+	uint8_t tile_h_loc, tile_v_loc;
+	uint16_t tile_h_size, tile_v_size;
 };
 
 /**
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/6] drm/tile: expose the tile property to userspace (v2)
  2014-10-22  2:32 tile group support (v2) Dave Airlie
                   ` (3 preceding siblings ...)
  2014-10-22  2:32 ` [PATCH 4/6] drm/connector: store tile information from displayid (v2) Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  2014-10-22  8:56   ` Daniel Vetter
  2014-10-22  2:32 ` [PATCH 6/6] drm/fb: add support for tiled monitor configurations Dave Airlie
  5 siblings, 1 reply; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

This takes the tiling info from the connector and
exposes it to userspace, as a blob object in a
connector property.

The contents of the blob is ABI.

v2: add property + function documentation.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 Documentation/DocBook/drm.tmpl      |  9 +++++++-
 drivers/gpu/drm/drm_crtc.c          | 44 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dp_mst.c |  2 ++
 include/drm/drm_crtc.h              |  4 ++++
 4 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 5ea6289..1f19340 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -2513,7 +2513,7 @@ void intel_crt_init(struct drm_device *dev)
 	</tr>
 	<tr>
 	<td rowspan="21" valign="top" >DRM</td>
-	<td rowspan="3" valign="top" >Generic</td>
+	<td rowspan="4" valign="top" >Generic</td>
 	<td valign="top" >“EDID”</td>
 	<td valign="top" >BLOB | IMMUTABLE</td>
 	<td valign="top" >0</td>
@@ -2535,6 +2535,13 @@ void intel_crt_init(struct drm_device *dev)
 	<td valign="top" >Contains topology path to a connector.</td>
 	</tr>
 	<tr>
+	<td valign="top" >“TILE”</td>
+	<td valign="top" >BLOB | IMMUTABLE</td>
+	<td valign="top" >0</td>
+	<td valign="top" >Connector</td>
+	<td valign="top" >Contains tiling information for a connector.</td>
+	</tr>
+	<tr>
 	<td rowspan="1" valign="top" >Plane</td>
 	<td valign="top" >“type”</td>
 	<td valign="top" >ENUM | IMMUTABLE</td>
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f3e082d..1c64f5f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1319,6 +1319,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 				       "PATH", 0);
 	dev->mode_config.path_property = dev_path;
 
+	dev->mode_config.tile_property = drm_property_create(dev,
+							     DRM_MODE_PROP_BLOB |
+							     DRM_MODE_PROP_IMMUTABLE,
+							     "TILE", 0);
+
 	return 0;
 }
 
@@ -4015,6 +4020,45 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
 EXPORT_SYMBOL(drm_mode_connector_set_path_property);
 
 /**
+ * drm_mode_connector_set_tile_property - set tile property on connector
+ * @connector: connector to set property on.
+ *
+ * This looks up the tile information for a connector, and creates a
+ * property for userspace to parse if it exists. The property is of
+ * the form of 8 integers using ':' as a separator.
+ */
+int drm_mode_connector_set_tile_property(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	int ret, size;
+	char tile[256];
+
+	if (connector->tile_blob_ptr)
+		drm_property_destroy_blob(dev, connector->tile_blob_ptr);
+
+	if (!connector->has_tile) {
+		connector->tile_blob_ptr = NULL;
+		ret = drm_object_property_set_value(&connector->base,
+						    dev->mode_config.tile_property, 0);
+		return ret;
+	}
+
+	snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", connector->tile_group->id, connector->tile_is_single_monitor, connector->num_h_tile, connector->num_v_tile, connector->tile_h_loc, connector->tile_v_loc, connector->tile_h_size, connector->tile_v_size);
+	size = strlen(tile) + 1;
+
+	connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
+							    size, tile);
+	if (!connector->tile_blob_ptr)
+		return -EINVAL;
+
+	ret = drm_object_property_set_value(&connector->base,
+					    dev->mode_config.tile_property,
+					    connector->tile_blob_ptr->base.id);
+	return ret;
+}
+EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
+
+/**
  * drm_mode_connector_update_edid_property - update the edid property of a connector
  * @connector: drm connector
  * @edid: new value of the edid property
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index c66e73a..c5529ff 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -422,6 +422,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
 	intel_dp_add_properties(intel_dp, connector);
 
 	drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
+	drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
+
 	drm_mode_connector_set_path_property(connector, pathprop);
 	drm_reinit_primary_mode_group(dev);
 	mutex_lock(&dev->mode_config.mutex);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 39c9858..c41cd51 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -557,6 +557,8 @@ struct drm_connector {
 
 	struct drm_property_blob *path_blob_ptr;
 
+	struct drm_property_blob *tile_blob_ptr;
+
 	uint8_t polled; /* DRM_CONNECTOR_POLL_* */
 
 	/* requested DPMS state */
@@ -847,6 +849,7 @@ struct drm_mode_config {
 	struct drm_property *edid_property;
 	struct drm_property *dpms_property;
 	struct drm_property *path_property;
+	struct drm_property *tile_property;
 	struct drm_property *plane_type_property;
 
 	/* DVI-I properties */
@@ -999,6 +1002,7 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
 
 extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
 						char *path);
+int drm_mode_connector_set_tile_property(struct drm_connector *connector);
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 						struct edid *edid);
 
-- 
2.1.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/6] drm/fb: add support for tiled monitor configurations.
  2014-10-22  2:32 tile group support (v2) Dave Airlie
                   ` (4 preceding siblings ...)
  2014-10-22  2:32 ` [PATCH 5/6] drm/tile: expose the tile property to userspace (v2) Dave Airlie
@ 2014-10-22  2:32 ` Dave Airlie
  5 siblings, 0 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-22  2:32 UTC (permalink / raw)
  To: dri-devel, intel-gfx

From: Dave Airlie <airlied@redhat.com>

This adds fbdev/con support for tiled monitors, so that we
only set a mode on the correct half of the monitor, or
span the two halves if needed.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/drm_fb_helper.c    | 122 +++++++++++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_fbdev.c |  25 +++++++-
 include/drm/drm_fb_helper.h        |   6 ++
 3 files changed, 130 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 3144db9..095f9d5 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1042,19 +1042,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
 	crtc_count = 0;
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_display_mode *desired_mode;
+		int x, y;
 		desired_mode = fb_helper->crtc_info[i].desired_mode;
-
+		x = fb_helper->crtc_info[i].x;
+		y = fb_helper->crtc_info[i].y;
 		if (desired_mode) {
 			if (gamma_size == 0)
 				gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
-			if (desired_mode->hdisplay < sizes.fb_width)
-				sizes.fb_width = desired_mode->hdisplay;
-			if (desired_mode->vdisplay < sizes.fb_height)
-				sizes.fb_height = desired_mode->vdisplay;
-			if (desired_mode->hdisplay > sizes.surface_width)
-				sizes.surface_width = desired_mode->hdisplay;
-			if (desired_mode->vdisplay > sizes.surface_height)
-				sizes.surface_height = desired_mode->vdisplay;
+			if (desired_mode->hdisplay + x < sizes.fb_width)
+				sizes.fb_width = desired_mode->hdisplay + x;
+			if (desired_mode->vdisplay + y < sizes.fb_height)
+				sizes.fb_height = desired_mode->vdisplay + y;
+			if (desired_mode->hdisplay + x > sizes.surface_width)
+				sizes.surface_width = desired_mode->hdisplay + x;
+			if (desired_mode->vdisplay + y > sizes.surface_height)
+				sizes.surface_height = desired_mode->vdisplay + y;
 			crtc_count++;
 		}
 	}
@@ -1356,6 +1358,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
 
 static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 			      struct drm_display_mode **modes,
+			      struct drm_fb_offset *offsets,
 			      bool *enabled, int width, int height)
 {
 	int count, i, j;
@@ -1427,27 +1430,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
 	return false;
 }
 
+static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
+				struct drm_display_mode **modes,
+				struct drm_fb_offset *offsets,
+				int idx,
+				int h_idx, int v_idx)
+{
+	struct drm_fb_helper_connector *fb_helper_conn;
+	int i;
+	int hoffset = 0, voffset = 0;
+
+	for (i = 0; i < fb_helper->connector_count; i++) {
+		fb_helper_conn = fb_helper->connector_info[i];
+		if (!fb_helper_conn->connector->has_tile)
+			continue;
+
+		if (!modes[i] && (h_idx || v_idx)) {
+			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
+				      fb_helper_conn->connector->base.id);
+			continue;
+		}
+		if (fb_helper_conn->connector->tile_h_loc < h_idx)
+			hoffset += modes[i]->hdisplay;
+
+		if (fb_helper_conn->connector->tile_v_loc < v_idx)
+			voffset += modes[i]->vdisplay;
+	}
+	offsets[idx].x = hoffset;
+	offsets[idx].y = voffset;
+	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
+	return 0;
+}
+
 static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 				 struct drm_display_mode **modes,
+				 struct drm_fb_offset *offsets,
 				 bool *enabled, int width, int height)
 {
 	struct drm_fb_helper_connector *fb_helper_conn;
 	int i;
-
+	uint64_t conn_configured = 0, mask;
+	int tile_pass = 0;
+	mask = (1 << fb_helper->connector_count) - 1;
+retry:
 	for (i = 0; i < fb_helper->connector_count; i++) {
 		fb_helper_conn = fb_helper->connector_info[i];
 
-		if (enabled[i] == false)
+		if (conn_configured & (1 << i))
+			continue;
+
+		if (enabled[i] == false) {
+			conn_configured |= (1 << i);
+			continue;
+		}
+
+		/* first pass over all the untiled connectors */
+		if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
 			continue;
 
+		if (tile_pass == 1) {
+			if (fb_helper_conn->connector->tile_h_loc != 0 ||
+			    fb_helper_conn->connector->tile_v_loc != 0)
+				continue;
+
+		} else {
+			if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 &&
+			    fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
+			/* if this tile_pass doesn't cover any of the tiles - keep going */
+				continue;
+
+			/* find the tile offsets for this pass - need
+			   to find all tiles left and above */
+			drm_get_tile_offsets(fb_helper, modes, offsets,
+					     i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
+		}
 		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
 			      fb_helper_conn->connector->base.id);
 
 		/* got for command line mode first */
 		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
 		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
-				      fb_helper_conn->connector->base.id);
+			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
+				      fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
 			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
 		}
 		/* No preferred modes, pick one off the list */
@@ -1457,6 +1521,13 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
 		}
 		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
 			  "none");
+		conn_configured |= (1 << i);
+	}
+
+	if ((conn_configured & mask) != mask) {
+		DRM_ERROR("not all connectors configured  %d %llx %llx\n", tile_pass, conn_configured, mask);
+		tile_pass++;
+		goto retry;
 	}
 	return true;
 }
@@ -1546,6 +1617,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 	struct drm_device *dev = fb_helper->dev;
 	struct drm_fb_helper_crtc **crtcs;
 	struct drm_display_mode **modes;
+	struct drm_fb_offset *offsets;
 	struct drm_mode_set *modeset;
 	bool *enabled;
 	int width, height;
@@ -1560,9 +1632,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
 	modes = kcalloc(dev->mode_config.num_connector,
 			sizeof(struct drm_display_mode *), GFP_KERNEL);
+	offsets = kcalloc(dev->mode_config.num_connector,
+			  sizeof(struct drm_fb_offset), GFP_KERNEL);
 	enabled = kcalloc(dev->mode_config.num_connector,
 			  sizeof(bool), GFP_KERNEL);
-	if (!crtcs || !modes || !enabled) {
+	if (!crtcs || !modes || !enabled | !offsets) {
 		DRM_ERROR("Memory allocation failed\n");
 		goto out;
 	}
@@ -1572,14 +1646,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 
 	if (!(fb_helper->funcs->initial_config &&
 	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
+					       offsets,
 					       enabled, width, height))) {
 		memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
 		memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
+		memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
 
-		if (!drm_target_cloned(fb_helper,
-				       modes, enabled, width, height) &&
-		    !drm_target_preferred(fb_helper,
-					  modes, enabled, width, height))
+		if (!drm_target_cloned(fb_helper, modes, offsets,
+				       enabled, width, height) &&
+		    !drm_target_preferred(fb_helper, modes, offsets,
+					  enabled, width, height))
 			DRM_ERROR("Unable to find initial modes\n");
 
 		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
@@ -1599,18 +1675,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 	for (i = 0; i < fb_helper->connector_count; i++) {
 		struct drm_display_mode *mode = modes[i];
 		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
+		struct drm_fb_offset *offset = &offsets[i];
 		modeset = &fb_crtc->mode_set;
 
 		if (mode && fb_crtc) {
-			DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
-				      mode->name, fb_crtc->mode_set.crtc->base.id);
+			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
+				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
 			fb_crtc->desired_mode = mode;
+			fb_crtc->x = offset->x;
+			fb_crtc->y = offset->y;
 			if (modeset->mode)
 				drm_mode_destroy(dev, modeset->mode);
 			modeset->mode = drm_mode_duplicate(dev,
 							   fb_crtc->desired_mode);
 			modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
 			modeset->fb = fb_helper->fb;
+			modeset->x = offset->x;
+			modeset->y = offset->y;
 		}
 	}
 
@@ -1628,6 +1709,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 out:
 	kfree(crtcs);
 	kfree(modes);
+	kfree(offsets);
 	kfree(enabled);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index f475414..73faf85 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -322,6 +322,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
 static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 				    struct drm_fb_helper_crtc **crtcs,
 				    struct drm_display_mode **modes,
+				    struct drm_fb_offset *offsets,
 				    bool *enabled, int width, int height)
 {
 	struct drm_device *dev = fb_helper->dev;
@@ -330,6 +331,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 	bool fallback = true;
 	int num_connectors_enabled = 0;
 	int num_connectors_detected = 0;
+	uint64_t conn_configured = 0, mask;
+	int pass = 0;
 
 	/*
 	 * If the user specified any force options, just bail here
@@ -355,7 +358,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 		return false;
 
 	memcpy(save_enabled, enabled, dev->mode_config.num_connector);
-
+	mask = (1 << fb_helper->connector_count) - 1;
+retry:
 	for (i = 0; i < fb_helper->connector_count; i++) {
 		struct drm_fb_helper_connector *fb_conn;
 		struct drm_connector *connector;
@@ -365,12 +369,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 		fb_conn = fb_helper->connector_info[i];
 		connector = fb_conn->connector;
 
+		if (conn_configured & (1 << i))
+			continue;
+
+		if (pass == 0 && !connector->has_tile)
+			continue;
+
 		if (connector->status == connector_status_connected)
 			num_connectors_detected++;
 
 		if (!enabled[i]) {
 			DRM_DEBUG_KMS("connector %s not enabled, skipping\n",
 				      connector->name);
+			conn_configured |= (1 << i);
 			continue;
 		}
 
@@ -379,6 +390,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 			DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n",
 				      connector->name);
 			enabled[i] = false;
+			conn_configured |= (1 << i);
 			continue;
 		}
 
@@ -407,8 +419,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 
 		/* try for preferred next */
 		if (!modes[i]) {
-			DRM_DEBUG_KMS("looking for preferred mode on connector %s\n",
-				      connector->name);
+			DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
+				      connector->name, connector->has_tile);
 			modes[i] = drm_has_preferred_mode(fb_conn, width,
 							  height);
 		}
@@ -451,6 +463,13 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 			      modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :"");
 
 		fallback = false;
+		conn_configured |= (1 << i);
+	}
+
+	if ((conn_configured & mask) != mask) {
+		DRM_ERROR("not all connectors configured  %d %llx %llx\n", pass, conn_configured, mask);
+		pass++;
+		goto retry;
 	}
 
 	/*
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index bfd329d..7fcb1e7 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -34,9 +34,14 @@ struct drm_fb_helper;
 
 #include <linux/kgdb.h>
 
+struct drm_fb_offset {
+	int x, y;
+};
+
 struct drm_fb_helper_crtc {
 	struct drm_mode_set mode_set;
 	struct drm_display_mode *desired_mode;
+	int x, y;
 };
 
 struct drm_fb_helper_surface_size {
@@ -72,6 +77,7 @@ struct drm_fb_helper_funcs {
 	bool (*initial_config)(struct drm_fb_helper *fb_helper,
 			       struct drm_fb_helper_crtc **crtcs,
 			       struct drm_display_mode **modes,
+			       struct drm_fb_offset *offsets,
 			       bool *enabled, int width, int height);
 };
 
-- 
2.1.0

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/6] drm: add tile_group support. (v2)
  2014-10-22  2:32 ` [PATCH 2/6] drm: add tile_group support. (v2) Dave Airlie
@ 2014-10-22  8:15   ` Daniel Vetter
  2014-10-28  6:54   ` Dave Airlie
  1 sibling, 0 replies; 12+ messages in thread
From: Daniel Vetter @ 2014-10-22  8:15 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx, dri-devel

On Wed, Oct 22, 2014 at 12:32:03PM +1000, Dave Airlie wrote:
> From: Dave Airlie <airlied@redhat.com>
> 
> A tile group is an identifier shared by a single monitor,
> DisplayID topology has 8 bytes we can use for this, just
> use those for now until something else comes up in the
> future. We assign these to an idr and use the idr to
> tell userspace what connectors are in the same tile group.
> 
> DisplayID v1.3 says the serial number must be unique for
> displays from the same manufacturer.
> 
> v2:
> destroy idr (dvdhrm)
> add docbook (danvet)
> airlied:- not sure how to make docbook add fns to tile group section.

Either you have to extract them into a new file or you have to list them
all explicitly. The kerneldoc nano howto has the various options you can
use. Thus far we haven't documented drm-internal functions though, only
those exported to drivers or helpers as guidelines to driver writers. Not
stopping you ofc ;-) But imo just documenting the tile prop registration
function is good enough.

wrt the patch I'm not 100% sure the kref_get_unless_zero is perfectly
race-free, but that depends upon how we solve the hotplugging of
properties and stuff I think.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  Documentation/DocBook/drm.tmpl |  4 ++
>  drivers/gpu/drm/drm_crtc.c     | 99 ++++++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_crtc.h         | 16 +++++++
>  3 files changed, 119 insertions(+)
> 
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 0a5cbbb..5ea6289 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -2374,6 +2374,10 @@ void intel_crt_init(struct drm_device *dev)
>        <title id="drm-kms-planehelpers">Plane Helper Reference</title>
>  !Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
>      </sect2>
> +    <sect2>
> +	  <title>Tile group</title>
> +!Pdrivers/gpu/drm/drm_crtc.c Tile group
> +    </sect2>
>    </sect1>
>  
>    <!-- Internals: kms properties -->
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 363301c..7f45fdc 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -5047,6 +5047,7 @@ void drm_mode_config_init(struct drm_device *dev)
>  	INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
>  	INIT_LIST_HEAD(&dev->mode_config.plane_list);
>  	idr_init(&dev->mode_config.crtc_idr);
> +	idr_init(&dev->mode_config.tile_idr);
>  
>  	drm_modeset_lock_all(dev);
>  	drm_mode_create_standard_connector_properties(dev);
> @@ -5134,6 +5135,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
>  		crtc->funcs->destroy(crtc);
>  	}
>  
> +	idr_destroy(&dev->mode_config.tile_idr);
>  	idr_destroy(&dev->mode_config.crtc_idr);
>  	drm_modeset_lock_fini(&dev->mode_config.connection_mutex);
>  }
> @@ -5156,3 +5158,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
>  					   supported_rotations);
>  }
>  EXPORT_SYMBOL(drm_mode_create_rotation_property);
> +
> +/**
> + * DOC: Tile group
> + *
> + * Tile groups are used to represent tiled monitors with a unique
> + * integer identifier. Tiled monitors using DisplayID v1.3 have
> + * a unique 8-byte handle, we store this in a tile group, so we
> + * have a common identifier for all tiles in a monitor group.
> + */
> +static void drm_tile_group_free(struct kref *kref)
> +{
> +	struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
> +	struct drm_device *dev = tg->dev;
> +	mutex_lock(&dev->mode_config.idr_mutex);
> +	idr_remove(&dev->mode_config.tile_idr, tg->id);
> +	mutex_lock(&dev->mode_config.idr_mutex);
> +	kfree(tg);
> +}
> +
> +/**
> + * drm_mode_put_tile_group - drop a reference to a tile group.
> + * @dev: DRM device
> + * @tg: tile group to drop reference to.
> + *
> + * drop reference to tile group and free if 0.
> + */
> +void drm_mode_put_tile_group(struct drm_device *dev,
> +			     struct drm_tile_group *tg)
> +{
> +	kref_put(&tg->refcount, drm_tile_group_free);
> +}
> +
> +/**
> + * drm_mode_get_tile_group - get a reference to an existing tile group
> + * @dev: DRM device
> + * @topology: 8-bytes unique per monitor.
> + *
> + * Use the unique bytes to get a reference to an existing tile group.
> + *
> + * RETURNS:
> + * tile group or NULL if not found.
> + */
> +struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
> +					       char topology[8])
> +{
> +	struct drm_tile_group *tg;
> +	int id;
> +	mutex_lock(&dev->mode_config.idr_mutex);
> +	idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
> +		if (!memcmp(tg->group_data, topology, 8)) {
> +			if (!kref_get_unless_zero(&tg->refcount))
> +				tg = NULL;
> +			mutex_unlock(&dev->mode_config.idr_mutex);
> +			return tg;
> +		}
> +	}
> +	mutex_unlock(&dev->mode_config.idr_mutex);
> +	return NULL;
> +}
> +
> +/**
> + * drm_mode_create_tile_group - create a tile group from a displayid description
> + * @dev: DRM device
> + * @topology: 8-bytes unique per monitor.
> + *
> + * Create a tile group for the unique monitor, and get a unique
> + * identifier for the tile group.
> + *
> + * RETURNS:
> + * new tile group or error.
> + */
> +struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
> +						  char topology[8])
> +{
> +	struct drm_tile_group *tg;
> +	int ret;
> +
> +	tg = kzalloc(sizeof(*tg), GFP_KERNEL);
> +	if (!tg)
> +		return ERR_PTR(-ENOMEM);
> +
> +	kref_init(&tg->refcount);
> +	memcpy(tg->group_data, topology, 8);
> +	tg->dev = dev;
> +
> +	mutex_lock(&dev->mode_config.idr_mutex);
> +	ret = idr_alloc(&dev->mode_config.tile_idr, tg, 1, 0, GFP_KERNEL);
> +	if (ret >= 0) {
> +		tg->id = ret;
> +	} else {
> +		kfree(tg);
> +		tg = ERR_PTR(ret);
> +	}
> +
> +	mutex_unlock(&dev->mode_config.idr_mutex);
> +	return tg;
> +}
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index f1105d0..afaec4b 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -136,6 +136,14 @@ struct drm_display_info {
>  	u8 cea_rev;
>  };
>  
> +/* data corresponds to displayid vend/prod/serial */
> +struct drm_tile_group {
> +	struct kref refcount;
> +	struct drm_device *dev;
> +	int id;
> +	u8 group_data[8];
> +};
> +
>  struct drm_framebuffer_funcs {
>  	/* note: use drm_framebuffer_remove() */
>  	void (*destroy)(struct drm_framebuffer *framebuffer);
> @@ -770,6 +778,7 @@ struct drm_mode_config {
>  	struct drm_modeset_acquire_ctx *acquire_ctx; /* for legacy _lock_all() / _unlock_all() */
>  	struct mutex idr_mutex; /* for IDR management */
>  	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
> +	struct idr tile_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
>  	/* this is limited to one for now */
>  
>  
> @@ -1106,6 +1115,13 @@ extern void drm_set_preferred_mode(struct drm_connector *connector,
>  extern int drm_edid_header_is_valid(const u8 *raw_edid);
>  extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
>  extern bool drm_edid_is_valid(struct edid *edid);
> +
> +extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
> +							 char topology[8]);
> +extern struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
> +					       char topology[8]);
> +extern void drm_mode_put_tile_group(struct drm_device *dev,
> +				   struct drm_tile_group *tg);
>  struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
>  					   int hsize, int vsize, int fresh,
>  					   bool rb);
> -- 
> 2.1.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/6] drm/tile: expose the tile property to userspace (v2)
  2014-10-22  2:32 ` [PATCH 5/6] drm/tile: expose the tile property to userspace (v2) Dave Airlie
@ 2014-10-22  8:56   ` Daniel Vetter
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Vetter @ 2014-10-22  8:56 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx, dri-devel

On Wed, Oct 22, 2014 at 12:32:06PM +1000, Dave Airlie wrote:
> From: Dave Airlie <airlied@redhat.com>
> 
> This takes the tiling info from the connector and
> exposes it to userspace, as a blob object in a
> connector property.
> 
> The contents of the blob is ABI.
> 
> v2: add property + function documentation.
> 
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  Documentation/DocBook/drm.tmpl      |  9 +++++++-
>  drivers/gpu/drm/drm_crtc.c          | 44 +++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_dp_mst.c |  2 ++
>  include/drm/drm_crtc.h              |  4 ++++
>  4 files changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
> index 5ea6289..1f19340 100644
> --- a/Documentation/DocBook/drm.tmpl
> +++ b/Documentation/DocBook/drm.tmpl
> @@ -2513,7 +2513,7 @@ void intel_crt_init(struct drm_device *dev)
>  	</tr>
>  	<tr>
>  	<td rowspan="21" valign="top" >DRM</td>
> -	<td rowspan="3" valign="top" >Generic</td>
> +	<td rowspan="4" valign="top" >Generic</td>
>  	<td valign="top" >“EDID”</td>
>  	<td valign="top" >BLOB | IMMUTABLE</td>
>  	<td valign="top" >0</td>
> @@ -2535,6 +2535,13 @@ void intel_crt_init(struct drm_device *dev)
>  	<td valign="top" >Contains topology path to a connector.</td>
>  	</tr>
>  	<tr>
> +	<td valign="top" >“TILE”</td>
> +	<td valign="top" >BLOB | IMMUTABLE</td>
> +	<td valign="top" >0</td>
> +	<td valign="top" >Connector</td>
> +	<td valign="top" >Contains tiling information for a connector.</td>
> +	</tr>
> +	<tr>
>  	<td rowspan="1" valign="top" >Plane</td>
>  	<td valign="top" >“type”</td>
>  	<td valign="top" >ENUM | IMMUTABLE</td>
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index f3e082d..1c64f5f 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -1319,6 +1319,11 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
>  				       "PATH", 0);
>  	dev->mode_config.path_property = dev_path;
>  
> +	dev->mode_config.tile_property = drm_property_create(dev,
> +							     DRM_MODE_PROP_BLOB |
> +							     DRM_MODE_PROP_IMMUTABLE,
> +							     "TILE", 0);
> +
>  	return 0;
>  }
>  
> @@ -4015,6 +4020,45 @@ int drm_mode_connector_set_path_property(struct drm_connector *connector,
>  EXPORT_SYMBOL(drm_mode_connector_set_path_property);
>  
>  /**
> + * drm_mode_connector_set_tile_property - set tile property on connector
> + * @connector: connector to set property on.
> + *
> + * This looks up the tile information for a connector, and creates a
> + * property for userspace to parse if it exists. The property is of
> + * the form of 8 integers using ':' as a separator.
> + */

Again return value boilerplate missing.

> +int drm_mode_connector_set_tile_property(struct drm_connector *connector)
> +{
> +	struct drm_device *dev = connector->dev;
> +	int ret, size;
> +	char tile[256];
> +
> +	if (connector->tile_blob_ptr)
> +		drm_property_destroy_blob(dev, connector->tile_blob_ptr);
> +
> +	if (!connector->has_tile) {
> +		connector->tile_blob_ptr = NULL;
> +		ret = drm_object_property_set_value(&connector->base,
> +						    dev->mode_config.tile_property, 0);
> +		return ret;
> +	}
> +
> +	snprintf(tile, 256, "%d:%d:%d:%d:%d:%d:%d:%d", connector->tile_group->id, connector->tile_is_single_monitor, connector->num_h_tile, connector->num_v_tile, connector->tile_h_loc, connector->tile_v_loc, connector->tile_h_size, connector->tile_v_size);

Long line.

With both nits fixed this is Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> +	size = strlen(tile) + 1;
> +
> +	connector->tile_blob_ptr = drm_property_create_blob(connector->dev,
> +							    size, tile);
> +	if (!connector->tile_blob_ptr)
> +		return -EINVAL;
> +
> +	ret = drm_object_property_set_value(&connector->base,
> +					    dev->mode_config.tile_property,
> +					    connector->tile_blob_ptr->base.id);
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_mode_connector_set_tile_property);
> +
> +/**
>   * drm_mode_connector_update_edid_property - update the edid property of a connector
>   * @connector: drm connector
>   * @edid: new value of the edid property
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index c66e73a..c5529ff 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -422,6 +422,8 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
>  	intel_dp_add_properties(intel_dp, connector);
>  
>  	drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0);
> +	drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0);
> +
>  	drm_mode_connector_set_path_property(connector, pathprop);
>  	drm_reinit_primary_mode_group(dev);
>  	mutex_lock(&dev->mode_config.mutex);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 39c9858..c41cd51 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -557,6 +557,8 @@ struct drm_connector {
>  
>  	struct drm_property_blob *path_blob_ptr;
>  
> +	struct drm_property_blob *tile_blob_ptr;
> +
>  	uint8_t polled; /* DRM_CONNECTOR_POLL_* */
>  
>  	/* requested DPMS state */
> @@ -847,6 +849,7 @@ struct drm_mode_config {
>  	struct drm_property *edid_property;
>  	struct drm_property *dpms_property;
>  	struct drm_property *path_property;
> +	struct drm_property *tile_property;
>  	struct drm_property *plane_type_property;
>  
>  	/* DVI-I properties */
> @@ -999,6 +1002,7 @@ extern void drm_mode_config_cleanup(struct drm_device *dev);
>  
>  extern int drm_mode_connector_set_path_property(struct drm_connector *connector,
>  						char *path);
> +int drm_mode_connector_set_tile_property(struct drm_connector *connector);
>  extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
>  						struct edid *edid);
>  
> -- 
> 2.1.0
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Intel-gfx] [PATCH 3/6] drm/mst: cached EDID for logical ports
  2014-10-22  2:32 ` [PATCH 3/6] drm/mst: cached EDID for logical ports Dave Airlie
@ 2014-10-22  9:06   ` Daniel Vetter
  2014-11-10  2:11     ` Dave Airlie
  0 siblings, 1 reply; 12+ messages in thread
From: Daniel Vetter @ 2014-10-22  9:06 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx, dri-devel

On Wed, Oct 22, 2014 at 12:32:04PM +1000, Dave Airlie wrote:
> From: Dave Airlie <airlied@redhat.com>
> 
> Logical ports are never going to have EDID changes,
> they are used for the internal ports on MST monitors.
> 
> We cache the EDIDs from these to save time at MST probe.
> 
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/drm_dp_mst_topology.c | 20 ++++++++++++++++++--
>  drivers/gpu/drm/i915/intel_dp_mst.c   |  2 +-
>  include/drm/drm_dp_mst_helper.h       |  4 +++-
>  3 files changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
> index 50926db..ce1113c 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -858,6 +858,8 @@ static void drm_dp_destroy_port(struct kref *kref)
>  	struct drm_dp_mst_topology_mgr *mgr = port->mgr;
>  	if (!port->input) {
>  		port->vcpi.num_slots = 0;
> +
> +		kfree(port->cached_edid);
>  		if (port->connector)
>  			(*port->mgr->cbs->destroy_connector)(mgr, port->connector);
>  		drm_dp_port_teardown_pdt(port, port->pdt);
> @@ -1096,6 +1098,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
>  		char proppath[255];
>  		build_mst_prop_path(port, mstb, proppath);
>  		port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
> +
> +		if (port->port_num >= 8) {
> +			port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
> +		}

I'm confused about how this works ... the tile property gets added in the
intel ->add_connector callback already, but that relies upon drm_get_edid
having parsed the displayid stuff. What am I missing?
-Daniel

>  	}
>  
>  	/* put reference to this port */
> @@ -2149,7 +2155,8 @@ EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
>   * This returns the current connection state for a port. It validates the
>   * port pointer still exists so the caller doesn't require a reference
>   */
> -enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
> +enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector,
> +						 struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
>  {
>  	enum drm_connector_status status = connector_status_disconnected;
>  
> @@ -2168,6 +2175,10 @@ enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr
>  
>  	case DP_PEER_DEVICE_SST_SINK:
>  		status = connector_status_connected;
> +		/* for logical ports - cache the EDID */
> +		if (port->port_num >= 8 && !port->cached_edid) {
> +			port->cached_edid = drm_get_edid(connector, &port->aux.ddc);
> +		}
>  		break;
>  	case DP_PEER_DEVICE_DP_LEGACY_CONV:
>  		if (port->ldps)
> @@ -2199,7 +2210,12 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
>  	if (!port)
>  		return NULL;
>  
> -	edid = drm_get_edid(connector, &port->aux.ddc);
> +	if (port->cached_edid)
> +		edid = drm_edid_duplicate(port->cached_edid);
> +	else
> +		edid = drm_get_edid(connector, &port->aux.ddc);
> +
> +	drm_mode_connector_set_tile_property(connector);
>  	drm_dp_put_port(port);
>  	return edid;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index d9a7a78..c66e73a 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -283,7 +283,7 @@ intel_mst_port_dp_detect(struct drm_connector *connector)
>  	struct intel_connector *intel_connector = to_intel_connector(connector);
>  	struct intel_dp *intel_dp = intel_connector->mst_port;
>  
> -	return drm_dp_mst_detect_port(&intel_dp->mst_mgr, intel_connector->port);
> +	return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port);
>  }
>  
>  static enum drm_connector_status
> diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
> index 338fc10..ee6fbad 100644
> --- a/include/drm/drm_dp_mst_helper.h
> +++ b/include/drm/drm_dp_mst_helper.h
> @@ -92,6 +92,8 @@ struct drm_dp_mst_port {
>  	struct drm_dp_vcpi vcpi;
>  	struct drm_connector *connector;
>  	struct drm_dp_mst_topology_mgr *mgr;
> +
> +	struct edid *cached_edid; /* for DP logical ports - make tiling work */
>  };
>  
>  /**
> @@ -474,7 +476,7 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms
>  int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
>  
>  
> -enum drm_connector_status drm_dp_mst_detect_port(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
> +enum drm_connector_status drm_dp_mst_detect_port(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
>  
>  struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port);
>  
> -- 
> 2.1.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 2/6] drm: add tile_group support. (v2)
  2014-10-22  2:32 ` [PATCH 2/6] drm: add tile_group support. (v2) Dave Airlie
  2014-10-22  8:15   ` Daniel Vetter
@ 2014-10-28  6:54   ` Dave Airlie
  1 sibling, 0 replies; 12+ messages in thread
From: Dave Airlie @ 2014-10-28  6:54 UTC (permalink / raw)
  To: dri-devel, intel-gfx@lists.freedesktop.org

> @@ -5156,3 +5158,100 @@ struct drm_property *drm_mode_create_rotation_property(struct drm_device *dev,
>                                            supported_rotations);
>  }
>  EXPORT_SYMBOL(drm_mode_create_rotation_property);
> +
> +/**
> + * DOC: Tile group
> + *
> + * Tile groups are used to represent tiled monitors with a unique
> + * integer identifier. Tiled monitors using DisplayID v1.3 have
> + * a unique 8-byte handle, we store this in a tile group, so we
> + * have a common identifier for all tiles in a monitor group.
> + */
> +static void drm_tile_group_free(struct kref *kref)
> +{
> +       struct drm_tile_group *tg = container_of(kref, struct drm_tile_group, refcount);
> +       struct drm_device *dev = tg->dev;
> +       mutex_lock(&dev->mode_config.idr_mutex);
> +       idr_remove(&dev->mode_config.tile_idr, tg->id);
> +       mutex_lock(&dev->mode_config.idr_mutex);

Review not to self:

*un*lock.

Dave.
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/6] drm/mst: cached EDID for logical ports
  2014-10-22  9:06   ` [Intel-gfx] " Daniel Vetter
@ 2014-11-10  2:11     ` Dave Airlie
  0 siblings, 0 replies; 12+ messages in thread
From: Dave Airlie @ 2014-11-10  2:11 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx@lists.freedesktop.org, dri-devel

On 22 October 2014 19:06, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Wed, Oct 22, 2014 at 12:32:04PM +1000, Dave Airlie wrote:
>> From: Dave Airlie <airlied@redhat.com>
>>
>> Logical ports are never going to have EDID changes,
>> they are used for the internal ports on MST monitors.
>>
>> We cache the EDIDs from these to save time at MST probe.
>>
>> Signed-off-by: Dave Airlie <airlied@redhat.com>
>> ---
>>  drivers/gpu/drm/drm_dp_mst_topology.c | 20 ++++++++++++++++++--
>>  drivers/gpu/drm/i915/intel_dp_mst.c   |  2 +-
>>  include/drm/drm_dp_mst_helper.h       |  4 +++-
>>  3 files changed, 22 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
>> index 50926db..ce1113c 100644
>> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
>> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
>> @@ -858,6 +858,8 @@ static void drm_dp_destroy_port(struct kref *kref)
>>       struct drm_dp_mst_topology_mgr *mgr = port->mgr;
>>       if (!port->input) {
>>               port->vcpi.num_slots = 0;
>> +
>> +             kfree(port->cached_edid);
>>               if (port->connector)
>>                       (*port->mgr->cbs->destroy_connector)(mgr, port->connector);
>>               drm_dp_port_teardown_pdt(port, port->pdt);
>> @@ -1096,6 +1098,10 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
>>               char proppath[255];
>>               build_mst_prop_path(port, mstb, proppath);
>>               port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
>> +
>> +             if (port->port_num >= 8) {
>> +                     port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
>> +             }
>
> I'm confused about how this works ... the tile property gets added in the
> intel ->add_connector callback already, but that relies upon drm_get_edid
> having parsed the displayid stuff. What am I missing?

The tile property gets added to the connector with no value, but only
gets set with a value here.

Since we rely on the EDID to know the value.

Also previous version of the patch had the call to set the property up
in the wrong patch.

Dave.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-11-10  2:11 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-22  2:32 tile group support (v2) Dave Airlie
2014-10-22  2:32 ` [PATCH 1/6] drm/displayid: add displayid defines and edid extension (v2) Dave Airlie
2014-10-22  2:32 ` [PATCH 2/6] drm: add tile_group support. (v2) Dave Airlie
2014-10-22  8:15   ` Daniel Vetter
2014-10-28  6:54   ` Dave Airlie
2014-10-22  2:32 ` [PATCH 3/6] drm/mst: cached EDID for logical ports Dave Airlie
2014-10-22  9:06   ` [Intel-gfx] " Daniel Vetter
2014-11-10  2:11     ` Dave Airlie
2014-10-22  2:32 ` [PATCH 4/6] drm/connector: store tile information from displayid (v2) Dave Airlie
2014-10-22  2:32 ` [PATCH 5/6] drm/tile: expose the tile property to userspace (v2) Dave Airlie
2014-10-22  8:56   ` Daniel Vetter
2014-10-22  2:32 ` [PATCH 6/6] drm/fb: add support for tiled monitor configurations Dave Airlie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox