diff options
author | Tom St Denis <tom.stdenis@amd.com> | 2015-10-01 12:56:05 -0400 |
---|---|---|
committer | Michel Dänzer <michel@daenzer.net> | 2015-10-05 16:37:15 +0900 |
commit | f035faec041cb5df65c78effa58eb50197cedf88 (patch) | |
tree | 2493face700dac4ea08db376eceb4138a5b1fe37 /src | |
parent | aee72b29210d79dbf41bde6eef16d7fe817e6cf4 (diff) |
add support for DP 1.2 display hotplug
Based on radeon commit 2f11dcd43966cf2ee26e61960fd72e6644f5e037
> This allows for dynamic creation of conneectors when the
> kernel tells us.
>
> v2: fix dpms off crash
Signed-off-by: Tom St Denis <tom.stdenis@amd.com>
Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/amdgpu_drv.h | 1 | ||||
-rw-r--r-- | src/amdgpu_kms.c | 5 | ||||
-rw-r--r-- | src/drmmode_display.c | 244 | ||||
-rw-r--r-- | src/drmmode_display.h | 2 |
4 files changed, 213 insertions, 39 deletions
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h index 82dd05b..ff3bc02 100644 --- a/src/amdgpu_drv.h +++ b/src/amdgpu_drv.h @@ -145,6 +145,7 @@ typedef enum { OPTION_DRI, OPTION_SHADOW_PRIMARY, OPTION_TEAR_FREE, + OPTION_DELETE_DP12, } AMDGPUOpts; #define AMDGPU_VSYNC_TIMEOUT 20000 /* Maximum wait for VSYNC (in usecs) */ diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index 5ee53fb..19ee1b1 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -70,6 +70,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = { {OPTION_DRI, "DRI", OPTV_INTEGER, {0}, FALSE}, {OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE}, {OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE}, + {OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE}, {-1, NULL, OPTV_NONE, {0}, FALSE} }; @@ -825,6 +826,10 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) info->allowPageFlip ? "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, diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 7f4e0c9..4cb1ba4 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -431,7 +431,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) static void drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, - struct drmmode_scanout *scanout) + struct drmmode_scanout *scanout) { if (scanout->pixmap) { @@ -471,8 +471,8 @@ drmmode_scanout_free(ScrnInfoPtr scrn) static void * drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc, - struct drmmode_scanout *scanout, - int width, int height) + struct drmmode_scanout *scanout, + int width, int height) { ScrnInfoPtr pScrn = crtc->scrn; AMDGPUInfoPtr info = AMDGPUPTR(pScrn); @@ -520,8 +520,8 @@ drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc, static PixmapPtr drmmode_crtc_scanout_create(xf86CrtcPtr crtc, - struct drmmode_scanout *scanout, - void *data, int width, int height) + struct drmmode_scanout *scanout, + void *data, int width, int height) { ScrnInfoPtr pScrn = crtc->scrn; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; @@ -548,7 +548,7 @@ drmmode_crtc_scanout_create(xf86CrtcPtr crtc, scanout->bo); if (scanout->pixmap == NULL) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow pixmap for rotated CRTC\n"); + "Couldn't allocate shadow pixmap for rotated CRTC\n"); } return scanout->pixmap; @@ -1337,56 +1337,114 @@ 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) { - if (koutput->connector_type >= NUM_OUTPUT_NAMES) - snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); + 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); #ifdef AMDGPU_PIXMAP_SHARING - else if (pScrn->is_gpu) - snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], - pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); + else if (pScrn->is_gpu) + snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], + pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); #endif - else { - /* need to do smart conversion here for compat with non-kms ATI driver */ - if (koutput->connector_type_id == 1) { - switch(koutput->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_DVIA: - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); - (*num_dvi)++; - break; - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_HDMIB: - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); - (*num_hdmi)++; - break; - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_DisplayPort: + else { + /* need to do smart conversion here for compat with non-kms ATI driver */ + if (koutput->connector_type_id == 1) { + switch(koutput->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DVIA: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); + (*num_dvi)++; + break; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); + (*num_hdmi)++; + break; + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_DisplayPort: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); + break; + default: + snprintf(name, 32, "%s", output_names[koutput->connector_type]); + break; + } + } else { snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); - break; - default: - snprintf(name, 32, "%s", output_names[koutput->connector_type]); - break; } - } else { - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); } } } static unsigned int -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); AMDGPUInfoPtr info = AMDGPUPTR(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; @@ -1397,6 +1455,18 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_r if (!koutput) return 0; + 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; @@ -1410,7 +1480,27 @@ 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 1; + } + } if (xf86IsEntityShared(pScrn->entityList[0])) { if ((s = @@ -1468,6 +1558,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 1; out_free_encoders: if (kencoders) { @@ -1778,7 +1873,7 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, "Initializing outputs ...\n"); for (i = 0; i < mode_res->count_connectors; i++) - crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi); + crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, "%d crtcs needed for screen.\n", crtcs_needed); @@ -2022,6 +2117,77 @@ Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) return TRUE; } + +void +amdgpu_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) { @@ -2032,7 +2198,7 @@ static void drmmode_handle_uevents(int fd, void *closure) if (!dev) return; - RRGetInfo(xf86ScrnToScreen(scrn), TRUE); + amdgpu_mode_hotplug(scrn, drmmode); udev_device_unref(dev); } #endif diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 9c95c14..177dfc7 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -52,6 +52,8 @@ typedef struct { #endif drmEventContext event_context; int count_crtcs; + + Bool delete_dp_12_displays; } drmmode_rec, *drmmode_ptr; typedef struct { |