summaryrefslogtreecommitdiff
path: root/hw/xfree86/drivers/modesetting/drmmode_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xfree86/drivers/modesetting/drmmode_display.c')
-rw-r--r--hw/xfree86/drivers/modesetting/drmmode_display.c287
1 files changed, 256 insertions, 31 deletions
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c
index a8de5f9e7..f3c9909ef 100644
--- a/hw/xfree86/drivers/modesetting/drmmode_display.c
+++ b/hw/xfree86/drivers/modesetting/drmmode_display.c
@@ -326,6 +326,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
continue;
drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
output_ids[output_count] =
drmmode_output->mode_output->connector_id;
output_count++;
@@ -366,10 +368,14 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
/* go through all the outputs and force DPMS them back on? */
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
+ drmmode_output_private_ptr drmmode_output;
if (output->crtc != crtc)
continue;
+ drmmode_output = output->driver_private;
+ if (drmmode_output->output_id == -1)
+ continue;
output->funcs->dpms(output, DPMSModeOn);
}
}
@@ -687,7 +693,7 @@ drmmode_crtc_vblank_pipe(int crtc_id)
}
static void
-drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
{
xf86CrtcPtr crtc;
drmmode_crtc_private_ptr drmmode_crtc;
@@ -698,7 +704,7 @@ drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
drmmode_crtc->mode_crtc =
- drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
+ drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
drmmode_crtc->drmmode = drmmode;
drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
crtc->driver_private = drmmode_crtc;
@@ -712,6 +718,9 @@ drmmode_output_detect(xf86OutputPtr output)
drmmode_ptr drmmode = drmmode_output->drmmode;
xf86OutputStatus status;
+ if (drmmode_output->output_id == -1)
+ return XF86OutputStatusDisconnected;
+
drmModeFreeConnector(drmmode_output->mode_output);
drmmode_output->mode_output =
@@ -740,6 +749,46 @@ drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
return MODE_OK;
}
+static void
+drmmode_output_attach_tile(xf86OutputPtr output)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ drmModeConnectorPtr koutput = drmmode_output->mode_output;
+ drmmode_ptr drmmode = drmmode_output->drmmode;
+ int i;
+ struct xf86CrtcTileInfo tile_info, *set = NULL;
+
+ if (!koutput) {
+ xf86OutputSetTile(output, NULL);
+ return;
+ }
+
+ /* look for a TILE property */
+ for (i = 0; i < koutput->count_props; i++) {
+ drmModePropertyPtr props;
+ props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
+ if (!props)
+ continue;
+
+ if (!(props->flags & DRM_MODE_PROP_BLOB)) {
+ drmModeFreeProperty(props);
+ continue;
+ }
+
+ if (!strcmp(props->name, "TILE")) {
+ drmModeFreePropertyBlob(drmmode_output->tile_blob);
+ drmmode_output->tile_blob =
+ drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
+ }
+ drmModeFreeProperty(props);
+ }
+ if (drmmode_output->tile_blob) {
+ if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
+ set = &tile_info;
+ }
+ xf86OutputSetTile(output, set);
+}
+
static Bool
has_panel_fitter(xf86OutputPtr output)
{
@@ -848,6 +897,8 @@ drmmode_output_get_modes(xf86OutputPtr output)
}
xf86OutputSetEDID(output, mon);
+ drmmode_output_attach_tile(output);
+
/* modes should already be available */
for (i = 0; i < koutput->count_modes; i++) {
Mode = xnfalloc(sizeof(DisplayModeRec));
@@ -873,11 +924,13 @@ drmmode_output_destroy(xf86OutputPtr output)
free(drmmode_output->props[i].atoms);
}
free(drmmode_output->props);
- for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
- drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+ if (drmmode_output->mode_output) {
+ for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
+ drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
+ }
+ drmModeFreeConnector(drmmode_output->mode_output);
}
free(drmmode_output->mode_encoders);
- drmModeFreeConnector(drmmode_output->mode_output);
free(drmmode_output);
output->driver_private = NULL;
}
@@ -1111,22 +1164,134 @@ static const char *const output_names[] = {
"DSI",
};
+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 + 1] = '\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,
+ drmModePropertyBlobPtr path_blob)
+{
+ int ret;
+ char *extra_path;
+ int conn_id;
+ xf86OutputPtr output;
+
+ ret = parse_path_blob(path_blob, &conn_id, &extra_path);
+ if (ret == -1)
+ goto fallback;
+
+ output = find_output(pScrn, conn_id);
+ if (!output)
+ goto fallback;
+
+ snprintf(name, 32, "%s-%s", output->name, extra_path);
+ return;
+
+ fallback:
+ if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
+ snprintf(name, 32, "Unknown-%d", koutput->connector_type_id - 1);
+#ifdef MODESETTING_OUTPUT_SLAVE_SUPPORT
+ 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
+ snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
+}
+
static void
-drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
+drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic)
{
xf86OutputPtr output;
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
drmModeConnectorPtr koutput;
drmModeEncoderPtr *kencoders = NULL;
drmmode_output_private_ptr drmmode_output;
drmModePropertyPtr props;
char name[32];
int i;
+ drmModePropertyBlobPtr path_blob = NULL;
koutput =
- drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
+ drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
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);
+ }
+ }
+
+ drmmode_create_name(pScrn, koutput, name, path_blob);
+
+ 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;
+ }
+ }
+
kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
if (!kencoders) {
goto out_free_encoders;
@@ -1139,17 +1304,6 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
}
}
- /* need to do smart conversion here for compat with non-kms ATI driver */
- if (koutput->connector_type >= MS_ARRAY_SIZE(output_names))
- snprintf(name, 32, "Unknown-%d", 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);
- else
- snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
- koutput->connector_type_id - 1);
-
output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
if (!output) {
goto out_free_encoders;
@@ -1161,7 +1315,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
goto out_free_encoders;
}
- drmmode_output->output_id = drmmode->mode_res->connectors[num];
+ drmmode_output->output_id = mode_res->connectors[num];
drmmode_output->mode_output = koutput;
drmmode_output->mode_encoders = kencoders;
drmmode_output->drmmode = drmmode;
@@ -1192,6 +1346,8 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
}
}
+ if (dynamic)
+ output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
return;
out_free_encoders:
if (kencoders) {
@@ -1231,7 +1387,7 @@ find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
}
static void
-drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
+drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
{
int i, j;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
@@ -1246,8 +1402,8 @@ drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
int k;
- for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
- if (drmmode->mode_res->encoders[k] ==
+ for (k = 0; k < mode_res->count_encoders; k++) {
+ if (mode_res->encoders[k] ==
drmmode_output->mode_encoders[j]->encoder_id)
drmmode_output->enc_mask |= (1 << k);
}
@@ -1425,6 +1581,7 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
int i;
int ret;
uint64_t value = 0;
+ drmModeResPtr mode_res;
/* check for dumb capability */
ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
@@ -1438,23 +1595,24 @@ drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
drmmode->scrn = pScrn;
drmmode->cpp = cpp;
- drmmode->mode_res = drmModeGetResources(drmmode->fd);
- if (!drmmode->mode_res)
+ mode_res = drmModeGetResources(drmmode->fd);
+ if (!mode_res)
return FALSE;
- xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
- drmmode->mode_res->max_height);
- for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
+ xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
+ mode_res->max_height);
+ for (i = 0; i < mode_res->count_crtcs; i++)
if (!xf86IsEntityShared(pScrn->entityList[0]) ||
pScrn->confScreen->device->screen == i)
- drmmode_crtc_init(pScrn, drmmode, i);
+ drmmode_crtc_init(pScrn, drmmode, mode_res, i);
- for (i = 0; i < drmmode->mode_res->count_connectors; i++)
- drmmode_output_init(pScrn, drmmode, i);
+ for (i = 0; i < mode_res->count_connectors; i++)
+ drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE);
/* workout clones */
- drmmode_clones_init(pScrn, drmmode);
+ drmmode_clones_init(pScrn, drmmode, mode_res);
+ drmModeFreeResources(mode_res);
#if XF86_CRTC_VERSION >= 5
xf86ProviderSetup(pScrn, NULL, "modesetting");
#endif
@@ -1618,11 +1776,78 @@ drmmode_handle_uevents(int fd, void *closure)
drmmode_ptr drmmode = closure;
ScrnInfoPtr scrn = drmmode->scrn;
struct udev_device *dev;
+ drmModeResPtr mode_res;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ int i, j;
+ Bool found;
+ Bool changed = FALSE;
dev = udev_monitor_receive_device(drmmode->uevent_monitor);
if (!dev)
return;
+ mode_res = drmModeGetResources(drmmode->fd);
+ if (!mode_res)
+ goto out;
+
+ if (mode_res->count_crtcs != config->num_crtc) {
+ ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc);
+ goto out_free_res;
+ }
+
+ /* figure out if we have gotten rid of any connectors
+ traverse old output list looking for outputs */
+ for (i = 0; i < config->num_output; i++) {
+ xf86OutputPtr output = config->output[i];
+ drmmode_output_private_ptr drmmode_output;
+
+ 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;
+ }
+
+ /* 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, 1);
+ }
+
+ if (changed) {
+ RRSetChanged(xf86ScrnToScreen(scrn));
+ RRTellChanged(xf86ScrnToScreen(scrn));
+ }
+
+out_free_res:
+ drmModeFreeResources(mode_res);
+out:
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
udev_device_unref(dev);
}