Commit f035faec authored by Tom Denis's avatar Tom Denis Committed by Michel Dänzer
Browse files

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 Denis's avatarTom St Denis <tom.stdenis@amd.com>
Reviewed-by: Michel Dänzer's avatarMichel Dänzer <michel.daenzer@amd.com>
parent aee72b29
......@@ -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) */
......
......@@ -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,
......
......@@ -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
......
......@@ -52,6 +52,8 @@ typedef struct {
#endif
drmEventContext event_context;
int count_crtcs;
Bool delete_dp_12_displays;
} drmmode_rec, *drmmode_ptr;
typedef struct {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment