[PATCH 3/3] radeon: add support for DP 1.2 display hotplug
Dave Airlie
airlied at gmail.com
Sun Nov 9 20:22:45 PST 2014
From: Dave Airlie <airlied at redhat.com>
This allows for dynamic creation of conneectors when the
kernel tells us.
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
src/drmmode_display.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/drmmode_display.h | 2 +
src/radeon.h | 3 +-
src/radeon_kms.c | 5 ++
4 files changed, 177 insertions(+), 7 deletions(-)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index dd79db5..fc03842 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1194,11 +1194,66 @@ const char *output_names[] = { "None",
#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
+static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+ for (i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == id)
+ return output;
+ }
+ return NULL;
+}
+
+static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
+{
+ char *conn;
+ char conn_id[5];
+ int id, len;
+ char *blob_data;
+
+ if (!path_blob)
+ return -1;
+
+ blob_data = path_blob->data;
+ /* we only handle MST paths for now */
+ if (strncmp(blob_data, "mst:", 4))
+ return -1;
+
+ conn = strchr(blob_data + 4, '-');
+ if (!conn)
+ return -1;
+ len = conn - (blob_data + 4);
+ if (len + 1 > 5)
+ return -1;
+ memcpy(conn_id, blob_data + 4, len);
+ conn_id[len] = '\0';
+ id = strtoul(conn_id, NULL, 10);
+
+ *conn_base_id = id;
+
+ *path = conn + 1;
+ return 0;
+}
+
static void
drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
- int *num_dvi, int *num_hdmi)
+ drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
{
- {
+ xf86OutputPtr output;
+ int conn_id;
+ char *extra_path;
+
+ output = NULL;
+ if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
+ output = find_output(pScrn, conn_id);
+ if (output) {
+ snprintf(name, 32, "%s-%s", output->name, extra_path);
+ } else {
if (koutput->connector_type >= NUM_OUTPUT_NAMES)
snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
koutput->connector_type_id - 1);
@@ -1241,14 +1296,16 @@ drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
}
static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
RADEONInfoPtr info = RADEONPTR(pScrn);
xf86OutputPtr output;
drmModeConnectorPtr koutput;
drmModeEncoderPtr *kencoders = NULL;
drmmode_output_private_ptr drmmode_output;
drmModePropertyPtr props;
+ drmModePropertyBlobPtr path_blob = NULL;
char name[32];
int i;
const char *s;
@@ -1257,6 +1314,18 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
if (!koutput)
return;
+ for (i = 0; i < koutput->count_props; i++) {
+ props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+ if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
+ if (!strcmp(props->name, "PATH")) {
+ path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+ drmModeFreeProperty(props);
+ break;
+ }
+ drmModeFreeProperty(props);
+ }
+ }
+
kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
if (!kencoders) {
goto out_free_encoders;
@@ -1269,7 +1338,26 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
}
}
- drmmode_create_name(pScrn, koutput, name, num_dvi, num_hdmi);
+ drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
+ if (path_blob)
+ drmModeFreePropertyBlob(path_blob);
+
+ if (path_blob && dynamic) {
+ /* See if we have an output with this name already
+ * and hook stuff up.
+ */
+ for (i = 0; i < xf86_config->num_output; i++) {
+ output = xf86_config->output[i];
+
+ if (strncmp(output->name, name, 32))
+ continue;
+
+ drmmode_output = output->driver_private;
+ drmmode_output->output_id = mode_res->connectors[num];
+ drmmode_output->mode_output = koutput;
+ return;
+ }
+ }
if (xf86IsEntityShared(pScrn->entityList[0])) {
if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
@@ -1325,6 +1413,11 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r
}
}
+ if (dynamic) {
+ output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
+ drmmode_output_create_resources(output);
+ }
+
return;
out_free_encoders:
if (kencoders){
@@ -1756,7 +1849,7 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
drmmode_crtc_init(pScrn, drmmode, mode_res, i);
for (i = 0; i < mode_res->count_connectors; i++)
- drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi);
+ drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0);
/* workout clones */
drmmode_clones_init(pScrn, drmmode, mode_res);
@@ -1982,6 +2075,75 @@ Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
return TRUE;
}
+void
+radeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
+{
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ drmModeResPtr mode_res;
+ int i, j;
+ Bool found;
+ Bool changed = FALSE;
+
+ mode_res = drmModeGetResources(drmmode->fd);
+ if (!mode_res)
+ goto out;
+
+restart_destroy:
+ for (i = 0; i < config->num_output; i++) {
+ xf86OutputPtr output = config->output[i];
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ found = FALSE;
+ for (j = 0; j < mode_res->count_connectors; j++) {
+ if (mode_res->connectors[j] == drmmode_output->output_id) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ drmModeFreeConnector(drmmode_output->mode_output);
+ drmmode_output->mode_output = NULL;
+ drmmode_output->output_id = -1;
+
+ changed = TRUE;
+ if (drmmode->delete_dp_12_displays) {
+ RROutputDestroy(output->randr_output);
+ xf86OutputDestroy(output);
+ goto restart_destroy;
+ }
+ }
+
+ /* find new output ids we don't have outputs for */
+ for (i = 0; i < mode_res->count_connectors; i++) {
+ found = FALSE;
+
+ for (j = 0; j < config->num_output; j++) {
+ xf86OutputPtr output = config->output[j];
+ drmmode_output_private_ptr drmmode_output;
+
+ drmmode_output = output->driver_private;
+ if (mode_res->connectors[i] == drmmode_output->output_id) {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ changed = TRUE;
+ drmmode_output_init(scrn, drmmode, mode_res, i, NULL, NULL, 1);
+ }
+
+ if (changed) {
+ RRSetChanged(xf86ScrnToScreen(scrn));
+ RRTellChanged(xf86ScrnToScreen(scrn));
+ }
+
+ drmModeFreeResources(mode_res);
+out:
+ RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+}
#ifdef HAVE_LIBUDEV
static void
drmmode_handle_uevents(int fd, void *closure)
@@ -1993,7 +2155,7 @@ drmmode_handle_uevents(int fd, void *closure)
if (!dev)
return;
- RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
+ radeon_mode_hotplug(scrn, drmmode);
udev_device_unref(dev);
}
#endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 2e83ed5..c9920e0 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -51,6 +51,8 @@ typedef struct {
#endif
drmEventContext event_context;
int count_crtcs;
+
+ Bool delete_dp_12_displays;
} drmmode_rec, *drmmode_ptr;
typedef struct {
diff --git a/src/radeon.h b/src/radeon.h
index 6123cc2..7b904de 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -148,7 +148,8 @@ typedef enum {
OPTION_ACCELMETHOD,
OPTION_EXA_VSYNC,
OPTION_ZAPHOD_HEADS,
- OPTION_SWAPBUFFERS_WAIT
+ OPTION_SWAPBUFFERS_WAIT,
+ OPTION_DELETE_DP12,
} RADEONOpts;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index c1a4dec..62364d9 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -73,6 +73,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
{ OPTION_EXA_PIXMAPS, "EXAPixmaps", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE },
{ OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -937,6 +938,10 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"SwapBuffers wait for vsync: %sabled\n", info->swapBuffersWait ? "en" : "dis");
+ if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
+ info->drmmode.delete_dp_12_displays = TRUE;
+ }
+
if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
goto fail;
--
1.9.3
More information about the xorg-driver-ati
mailing list