summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@armlinux.org.uk>2017-02-25 11:06:17 +0000
committerRussell King <rmk@armlinux.org.uk>2017-02-25 17:16:10 +0000
commit8c9ffafc41e95dc2130ffbfe5b48fe2555a91f9b (patch)
tree6751907a1f471e824d3d630ccdc8f9b00e2c8786
parent77f88d4a1f54cd3a4fd34f8aa738cb7ea1084dbc (diff)
src: add universal plane support
Add universal plane support to the common drm implementation - this gets all planes and plane properties from the kernel for overlay planes, and stores the primary plane ID in our CRTC structure. Signed-off-by: Russell King <rmk@armlinux.org.uk>
-rw-r--r--src/Makefile.am3
-rw-r--r--src/common_drm.h16
-rw-r--r--src/common_drm_plane.c304
3 files changed, 322 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3bf4abb..923a39f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,7 +31,8 @@ armada_drv_la_SOURCES = armada_accel.h \
armada_ioctl.h \
common_drm.c \
common_drm.h \
- common_drm_helper.h
+ common_drm_helper.h \
+ common_drm_plane.c
if HAVE_DRI2
armada_drv_la_SOURCES += \
common_drm_dri2.c \
diff --git a/src/common_drm.h b/src/common_drm.h
index 537c88d..62cbd17 100644
--- a/src/common_drm.h
+++ b/src/common_drm.h
@@ -17,6 +17,7 @@ struct common_crtc_info {
int drm_fd;
unsigned num;
drmModeCrtcPtr mode_crtc;
+ uint32_t primary_plane_id;
void *cursor_data;
uint32_t cursor_handle;
uint32_t rotate_fb_id;
@@ -35,6 +36,11 @@ struct drm_udev_info {
CloseScreenProcPtr CloseScreen;
};
+struct common_drm_plane {
+ drmModePlanePtr mode_plane;
+ drmModeObjectPropertiesPtr mode_props;
+};
+
struct common_drm_info {
int fd;
struct common_drm_device *dev;
@@ -61,6 +67,11 @@ struct common_drm_info {
struct drm_udev_info udev;
#endif
+ Bool has_universal_planes;
+ void *plane_property_hash;
+ unsigned int num_overlay_planes;
+ struct common_drm_plane *overlay_planes;
+
OptionInfoPtr Options;
CloseScreenProcPtr CloseScreen;
@@ -99,6 +110,11 @@ void common_drm_crtc_shadow_destroy(xf86CrtcPtr crtc);
Bool common_drm_init_mode_resources(ScrnInfoPtr pScrn,
const xf86CrtcFuncsRec *funcs);
+drmModePropertyPtr common_drm_plane_get_property(ScrnInfoPtr pScrn,
+ uint32_t prop_id);
+void common_drm_cleanup_plane_resources(ScrnInfoPtr pScrn);
+Bool common_drm_init_plane_resources(ScrnInfoPtr pScrn);
+
Bool common_drm_flip(ScrnInfoPtr pScrn, PixmapPtr pixmap,
struct common_drm_event *event, xf86CrtcPtr ref_crtc);
void common_drm_flip_pixmap(ScreenPtr pScreen, PixmapPtr a, PixmapPtr b);
diff --git a/src/common_drm_plane.c b/src/common_drm_plane.c
new file mode 100644
index 0000000..db73c3a
--- /dev/null
+++ b/src/common_drm_plane.c
@@ -0,0 +1,304 @@
+/*
+ * Marvell Armada DRM-based driver
+ *
+ * Written by Russell King, 2012, derived in part from the
+ * Intel xorg X server driver.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "xf86.h"
+
+#include "common_drm.h"
+
+static drmModePropertyPtr plane_hash_property(struct common_drm_info *drm,
+ uint32_t prop_id, Bool create)
+{
+ void *property;
+
+ if (drmHashLookup(drm->plane_property_hash, prop_id, &property)) {
+ property = drmModeGetProperty(drm->fd, prop_id);
+ if (!property)
+ return NULL;
+
+ drmHashInsert(drm->plane_property_hash, prop_id, property);
+ }
+
+ return property;
+}
+
+static Bool property_enum_val(drmModePropertyPtr prop, const char *name,
+ uint64_t *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < prop->count_enums; i++)
+ if (strcmp(prop->enums[i].name, name) == 0) {
+ *val = prop->enums[i].value;
+ return TRUE;
+ }
+
+ *val = ~0ULL;
+
+ return FALSE;
+}
+
+static Bool plane_get_property_val(drmModeObjectPropertiesPtr mode_props,
+ const drmModePropertyPtr property, uint64_t *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < mode_props->count_props; i++)
+ if (mode_props->props[i] == property->prop_id) {
+ *val = mode_props->prop_values[i];
+ return TRUE;
+ }
+
+ *val = ~0ULL;
+
+ return FALSE;
+}
+
+static drmModePropertyPtr plane_find_property(struct common_drm_info *drm,
+ const char *name)
+{
+ drmModePropertyPtr property;
+ unsigned long key;
+ void *p;
+
+ if (drmHashFirst(drm->plane_property_hash, &key, &p)) do {
+ property = p;
+ if (strcmp(property->name, name) == 0)
+ return property;
+ } while (drmHashNext(drm->plane_property_hash, &key, &p));
+
+ return NULL;
+}
+
+static void plane_free_all(struct common_drm_plane *planes, unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ if (planes[i].mode_plane)
+ drmModeFreePlane(planes[i].mode_plane);
+ if (planes[i].mode_props)
+ drmModeFreeObjectProperties(planes[i].mode_props);
+ }
+
+ free(planes);
+}
+
+static xf86CrtcPtr plane_get_crtc(ScrnInfoPtr pScrn, drmModePlanePtr mode_plane)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ struct common_crtc_info *drmc;
+ unsigned int i;
+ uint32_t crtcs = mode_plane->possible_crtcs;
+
+ /* Must be a power of two */
+ if (!crtcs || (crtcs & (crtcs - 1)) != 0)
+ return NULL;
+
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ drmc = common_crtc(xf86_config->crtc[i]);
+ if (crtcs & 1 << drmc->num)
+ return xf86_config->crtc[i];
+ }
+
+ return NULL;
+}
+
+static int plane_get_all(ScrnInfoPtr pScrn, struct common_drm_plane **pplanes)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+ drmModeObjectPropertiesPtr mode_props;
+ drmModePlanePtr mode_plane;
+ drmModePlaneResPtr res;
+ struct common_drm_plane *planes;
+ unsigned int i, j, num;
+
+ res = drmModeGetPlaneResources(drm->fd);
+ if (!res)
+ return -1;
+
+ *pplanes = planes = calloc(sizeof(*planes), res->count_planes);
+ if (!*pplanes)
+ goto err;
+
+ for (i = num = 0; i < res->count_planes; i++) {
+ mode_plane = drmModeGetPlane(drm->fd, res->planes[i]);
+ if (!mode_plane)
+ goto err;
+
+ planes[num++].mode_plane = mode_plane;
+
+ mode_props = drmModeObjectGetProperties(drm->fd, res->planes[i],
+ DRM_MODE_OBJECT_PLANE);
+ if (!mode_props)
+ goto err;
+
+ planes[num - 1].mode_props = mode_props;
+
+ for (j = 0; j < mode_props->count_props; j++)
+ if (!plane_hash_property(drm, mode_props->props[j],
+ TRUE))
+ goto err;
+ }
+
+ drmModeFreePlaneResources(res);
+
+ return num;
+
+err:
+ if (planes)
+ plane_free_all(planes, num);
+
+ drmModeFreePlaneResources(res);
+
+ return -1;
+}
+
+static Bool plane_parse_types(ScrnInfoPtr pScrn,
+ struct common_drm_plane **pplanes, int *pnum)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+ struct common_drm_plane *overlays, *planes = *pplanes;
+ drmModePropertyPtr type;
+ uint64_t primary, overlay, val;
+ unsigned int i, num_overlay, num = *pnum;
+ xf86CrtcPtr crtc;
+
+ type = plane_find_property(drm, "type");
+ if (!type)
+ return TRUE;
+
+ if (!property_enum_val(type, "Primary", &primary) ||
+ !property_enum_val(type, "Overlay", &overlay))
+ return TRUE;
+
+ for (i = num_overlay = 0; i < num; i++)
+ if (plane_get_property_val(planes[i].mode_props, type, &val) &&
+ val == overlay)
+ num_overlay++;
+
+ overlays = calloc(sizeof(*overlays), num_overlay);
+ if (!overlays)
+ return FALSE;
+
+ for (i = num_overlay = 0; i < num; i++) {
+ if (!plane_get_property_val(planes[i].mode_props, type, &val))
+ continue;
+
+ if (val == overlay) {
+ overlays[num_overlay++] = planes[i];
+ continue;
+ }
+
+ crtc = plane_get_crtc(pScrn, planes[i].mode_plane);
+ if (crtc && val == primary)
+ common_crtc(crtc)->primary_plane_id =
+ planes[i].mode_plane->plane_id;
+
+ drmModeFreePlane(planes[i].mode_plane);
+ drmModeFreeObjectProperties(planes[i].mode_props);
+ }
+
+ free(planes);
+
+ *pplanes = overlays;
+ *pnum = num_overlay;
+
+ return TRUE;
+}
+
+static Bool plane_universal_planes(ScrnInfoPtr pScrn, Bool enable)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+ struct drm_set_client_cap cap = {
+ .capability = DRM_CLIENT_CAP_UNIVERSAL_PLANES,
+ .value = enable,
+ };
+
+ return drmIoctl(drm->fd, DRM_IOCTL_SET_CLIENT_CAP, &cap) == 0;
+}
+
+drmModePropertyPtr common_drm_plane_get_property(ScrnInfoPtr pScrn,
+ uint32_t prop_id)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+
+ return plane_hash_property(drm, prop_id, FALSE);
+}
+
+void common_drm_cleanup_plane_resources(ScrnInfoPtr pScrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+ struct common_crtc_info *drmc;
+ unsigned int i;
+ unsigned long key;
+ void *val, *hash;
+
+ for (i = 0; i < xf86_config->num_crtc; i++) {
+ drmc = common_crtc(xf86_config->crtc[i]);
+ drmc->primary_plane_id = 0;
+ }
+
+ if (drm->overlay_planes) {
+ plane_free_all(drm->overlay_planes, drm->num_overlay_planes);
+ drm->overlay_planes = NULL;
+ drm->num_overlay_planes = 0;
+ }
+
+ if (drm->plane_property_hash) {
+ hash = drm->plane_property_hash;
+
+ if (drmHashFirst(hash, &key, &val)) do {
+ drmModeFreeProperty(val);
+ } while (drmHashNext(hash, &key, &val));
+
+ drmHashDestroy(hash);
+ drm->plane_property_hash = NULL;
+ }
+
+ drm->has_universal_planes = FALSE;
+}
+
+Bool common_drm_init_plane_resources(ScrnInfoPtr pScrn)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(pScrn);
+ struct common_drm_plane *planes;
+ int num;
+
+ drm->plane_property_hash = drmHashCreate();
+ if (!drm->plane_property_hash)
+ return FALSE;
+
+ if (plane_universal_planes(pScrn, TRUE))
+ drm->has_universal_planes = TRUE;
+
+ num = plane_get_all(pScrn, &planes);
+ if (num < 0) {
+ common_drm_cleanup_plane_resources(pScrn);
+ return FALSE;
+ }
+
+ if (drm->has_universal_planes &&
+ !plane_parse_types(pScrn, &planes, &num)) {
+ common_drm_cleanup_plane_resources(pScrn);
+ return FALSE;
+ }
+
+ drm->num_overlay_planes = num;
+ drm->overlay_planes = planes;
+
+ return TRUE;
+}