summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tdm_drm.c6
-rw-r--r--src/tdm_drm.h2
-rw-r--r--src/tdm_drm_display.c227
3 files changed, 203 insertions, 32 deletions
diff --git a/src/tdm_drm.c b/src/tdm_drm.c
index 179c359..b55cbde 100644
--- a/src/tdm_drm.c
+++ b/src/tdm_drm.c
@@ -224,8 +224,12 @@ tdm_drm_init(tdm_display *dpy, tdm_error *error)
}
#if LIBDRM_MAJOR_VERSION >= 2 && LIBDRM_MINOR_VERSION >= 4 && LIBDRM_MICRO_VERSION >= 47
- if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0)
+ if (drmSetClientCap(drm_data->drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1) < 0) {
TDM_WRN("Set DRM_CLIENT_CAP_UNIVERSAL_PLANES failed");
+ } else {
+ TDM_INFO("has universal planes");
+ drm_data->has_universal_plane = 1;
+ }
#endif
drm_data->mode_res = drmModeGetResources(drm_data->drm_fd);
diff --git a/src/tdm_drm.h b/src/tdm_drm.h
index 3aa86a7..952f959 100644
--- a/src/tdm_drm.h
+++ b/src/tdm_drm.h
@@ -97,6 +97,8 @@ typedef struct _tdm_drm_data
int drm_fd;
+ int has_universal_plane;
+
drmModeResPtr mode_res;
drmModePlaneResPtr plane_res;
diff --git a/src/tdm_drm_display.c b/src/tdm_drm_display.c
index 20ca626..3ec906c 100644
--- a/src/tdm_drm_display.c
+++ b/src/tdm_drm_display.c
@@ -183,6 +183,43 @@ _tdm_drm_display_wait_vblank(int fd, int pipe, uint *target_msc, void *data)
}
static tdm_error
+_tdm_drm_display_get_property(tdm_drm_data *drm_data,
+ unsigned int obj_id, unsigned int obj_type,
+ const char *name, unsigned int *value,
+ int *is_immutable)
+{
+ drmModeObjectPropertiesPtr props = NULL;
+ int i;
+
+ props = drmModeObjectGetProperties(drm_data->drm_fd, obj_id, obj_type);
+ if (!props)
+ return TDM_ERROR_OPERATION_FAILED;
+
+ for (i = 0; i < props->count_props; i++) {
+ drmModePropertyPtr prop = drmModeGetProperty(drm_data->drm_fd,
+ props->props[i]);
+
+ if (!prop)
+ continue;
+
+ if (!strcmp(prop->name, name)) {
+ if (is_immutable)
+ *is_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
+ if (value)
+ *value = (unsigned int)props->prop_values[i];
+ drmModeFreeProperty(prop);
+ drmModeFreeObjectProperties(props);
+ return TDM_ERROR_NONE;
+ }
+
+ drmModeFreeProperty(prop);
+ }
+ drmModeFreeObjectProperties(props);
+ TDM_DBG("coundn't find '%s' property", name);
+ return TDM_ERROR_OPERATION_FAILED;
+}
+
+static tdm_error
_tdm_drm_display_commit_primary_layer(tdm_drm_layer_data *layer_data,
void *user_data, int *do_waitvblank)
{
@@ -344,34 +381,127 @@ _tdm_drm_display_cb_event(int fd, unsigned int sequence,
static tdm_error
_tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
{
+ tdm_drm_output_data *output_data = NULL;
int i;
+ /* The TDM drm backend only support one output. */
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
+ break;
+ }
+
+ if (!output_data) {
+ TDM_ERR("no output");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
if (drm_data->plane_res->count_planes == 0) {
TDM_ERR("no layer error");
return TDM_ERROR_OPERATION_FAILED;
}
for (i = 0; i < drm_data->plane_res->count_planes; i++) {
- tdm_drm_output_data *output_data = NULL;
tdm_drm_layer_data *layer_data;
drmModePlanePtr plane;
- if (i == 3) {
- TDM_DBG("doesn't need more layer set");
- break;
+ plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
+ if (!plane) {
+ TDM_ERR("no plane");
+ continue;
}
- LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
- if (output_data->pipe == 0)
- break;
+ if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
+ drmModeFreePlane(plane);
+ continue;
}
+ layer_data = calloc(1, sizeof(tdm_drm_layer_data));
+ if (!layer_data) {
+ TDM_ERR("alloc failed");
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ layer_data->drm_data = drm_data;
+ layer_data->output_data = output_data;
+ layer_data->plane_id = drm_data->plane_res->planes[i];
+
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
+ TDM_LAYER_CAPABILITY_GRAPHIC;
+ output_data->primary_layer = layer_data;
+
+ TDM_DBG("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
+ layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
+ layer_data->capabilities);
+
+ LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
+
+ drmModeFreePlane(plane);
+
+ /* can't take care of other planes for various hardware devices */
+ break;
+ }
+
+ return TDM_ERROR_NONE;
+}
+
+static tdm_error
+_tdm_drm_display_create_layer_list_type(tdm_drm_data *drm_data)
+{
+ tdm_drm_output_data *output_data = NULL;
+ unsigned int type = 0;
+ tdm_error ret;
+ int i;
+
+ /* The TDM drm backend only support one output. */
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
+ break;
+ }
+
+ if (!output_data) {
+ TDM_ERR("no output");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
+ ret = _tdm_drm_display_get_property(drm_data,
+ drm_data->plane_res->planes[0],
+ DRM_MODE_OBJECT_PLANE, "type", &type,
+ NULL);
+ if (ret != TDM_ERROR_NONE) {
+ TDM_ERR("plane doesn't have 'type' property. Call a fallback function");
+
+ /* if a plane doesn't have "type" property, we call a fallback function
+ * as default
+ */
+ return _tdm_drm_display_create_layer_list(drm_data);
+ }
+
+ for (i = 0; i < drm_data->plane_res->count_planes; i++) {
+ tdm_drm_layer_data *layer_data;
+ drmModePlanePtr plane;
+ unsigned int type = 0;
+
plane = drmModeGetPlane(drm_data->drm_fd, drm_data->plane_res->planes[i]);
if (!plane) {
TDM_ERR("no plane");
continue;
}
+ if ((plane->possible_crtcs & (1 << output_data->pipe)) == 0) {
+ drmModeFreePlane(plane);
+ continue;
+ }
+
+ ret = _tdm_drm_display_get_property(drm_data,
+ drm_data->plane_res->planes[i],
+ DRM_MODE_OBJECT_PLANE, "type", &type,
+ NULL);
+ if (ret != TDM_ERROR_NONE) {
+ TDM_ERR("plane(%d) doesn't have 'type' info",
+ drm_data->plane_res->planes[i]);
+ drmModeFreePlane(plane);
+ continue;
+ }
+
layer_data = calloc(1, sizeof(tdm_drm_layer_data));
if (!layer_data) {
TDM_ERR("alloc failed");
@@ -379,40 +509,44 @@ _tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
continue;
}
+ LIST_FOR_EACH_ENTRY(output_data, &drm_data->output_list, link) {
+ if (plane->possible_crtcs & (1 << output_data->pipe))
+ break;
+ }
+
+ if (!output_data) {
+ TDM_ERR("plane(%d) couldn't found proper output", plane->plane_id);
+ drmModeFreePlane(plane);
+ free(layer_data);
+ continue;
+ }
+
layer_data->drm_data = drm_data;
layer_data->output_data = output_data;
layer_data->plane_id = drm_data->plane_res->planes[i];
- if (drm_data->plane_res->count_planes == 1) {
+ if (type == DRM_PLANE_TYPE_CURSOR) {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
+ TDM_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = 2;
+ } else if (type == DRM_PLANE_TYPE_OVERLAY) {
+ layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
+ TDM_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = 1;
+ } else if (type == DRM_PLANE_TYPE_PRIMARY) {
layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
TDM_LAYER_CAPABILITY_GRAPHIC;
+ layer_data->zpos = 0;
output_data->primary_layer = layer_data;
- } else if (drm_data->plane_res->count_planes == 2) {
- if (i == 0) {
- layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
- TDM_LAYER_CAPABILITY_GRAPHIC;
- output_data->primary_layer = layer_data;
- } else {
- layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
- TDM_LAYER_CAPABILITY_GRAPHIC;
- }
} else {
- if (i == 0) {
- layer_data->capabilities = TDM_LAYER_CAPABILITY_CURSOR |
- TDM_LAYER_CAPABILITY_GRAPHIC;
- } else if (i == 1) {
- layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY |
- TDM_LAYER_CAPABILITY_GRAPHIC;
- output_data->primary_layer = layer_data;
- } else {
- layer_data->capabilities = TDM_LAYER_CAPABILITY_OVERLAY |
- TDM_LAYER_CAPABILITY_GRAPHIC;
- }
+ drmModeFreePlane(plane);
+ free(layer_data);
+ continue;
}
- TDM_DBG("layer_data(%p) plane_id(%d) crtc_id(%d) capabilities(%x)",
+ TDM_DBG("layer_data(%p) plane_id(%d) crtc_id(%d) zpos(%d) capabilities(%x)",
layer_data, layer_data->plane_id, layer_data->output_data->crtc_id,
- layer_data->capabilities);
+ layer_data->zpos, layer_data->capabilities);
LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
@@ -466,7 +600,11 @@ tdm_drm_display_create_layer_list(tdm_drm_data *drm_data)
tdm_drm_output_data *output_data = NULL;
tdm_error ret;
- ret = _tdm_drm_display_create_layer_list(drm_data);
+ if (!drm_data->has_universal_plane)
+ ret = _tdm_drm_display_create_layer_list(drm_data);
+ else
+ ret = _tdm_drm_display_create_layer_list_type(drm_data);
+
if (ret != TDM_ERROR_NONE)
return ret;
@@ -527,6 +665,17 @@ tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
goto failed_create;
}
+ /* The TDM drm backend is not interested with disconnected connectors.
+ * And it only considers 1 connected connector because it is the TDM
+ * reference backend and can't take care of all hardware devices.
+ * To support various connectors, planes and crtcs, the new TDM backend
+ * should be implemented.
+ */
+ if (connector->connection != DRM_MODE_CONNECTED) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
if (connector->count_encoders != 1) {
TDM_ERR("too many encoders: %d", connector->count_encoders);
drmModeFreeConnector(connector);
@@ -598,6 +747,9 @@ tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
drmModeFreeProperty(prop);
}
+ if (output_data->dpms_prop_id == 0)
+ TDM_WRN("not support DPMS");
+
output_data->count_modes = connector->count_modes;
output_data->drm_modes = calloc(connector->count_modes,
sizeof(drmModeModeInfo));
@@ -636,6 +788,14 @@ tdm_drm_display_create_output_list(tdm_drm_data *drm_data)
drmModeFreeEncoder(encoder);
drmModeFreeConnector(connector);
+
+ /* The TDM drm backend is not interested with disconnected connectors.
+ * And it only considers 1 connected connector because it is the TDM
+ * reference backend and can't take care of all hardware devices.
+ * To support various connectors, planes and crtcs, the new TDM backend
+ * should be implemented.
+ */
+ break;
}
TDM_DBG("output count: %d", drm_data->mode_res->count_connectors);
@@ -1079,6 +1239,11 @@ drm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
+ if (output_data->dpms_prop_id == 0) {
+ TDM_WRN("not support DPMS");
+ return TDM_ERROR_OPERATION_FAILED;
+ }
+
drm_data = output_data->drm_data;
ret = drmModeObjectSetProperty(drm_data->drm_fd,
output_data->connector_id, DRM_MODE_OBJECT_CONNECTOR,