1648 lines
43 KiB
Diff
1648 lines
43 KiB
Diff
From bbe6d49bdcb7b6a53044f494e31a90f4eed65b0e Mon Sep 17 00:00:00 2001
|
|
From: ZiHan Huang <zack.huang@rock-chips.com>
|
|
Date: Fri, 6 Jan 2023 10:17:22 +0800
|
|
Subject: [PATCH 6/8] drm: Reconstructs the drm display driver
|
|
|
|
Signed-off-by: ZiHan Huang <zack.huang@rock-chips.com>
|
|
---
|
|
display/drm.c | 1488 +++++++++++++++++++++++++++----------------------
|
|
display/drm.h | 7 +-
|
|
2 files changed, 832 insertions(+), 663 deletions(-)
|
|
|
|
diff --git a/display/drm.c b/display/drm.c
|
|
index 9cec6e3..17af072 100644
|
|
--- a/display/drm.c
|
|
+++ b/display/drm.c
|
|
@@ -22,780 +22,950 @@
|
|
#include <errno.h>
|
|
#include <sys/mman.h>
|
|
#include <inttypes.h>
|
|
+#include <poll.h>
|
|
+#include <malloc.h>
|
|
|
|
+#include <drm_fourcc.h>
|
|
+#include <drm_mode.h>
|
|
+#include <lvgl/lvgl.h>
|
|
#include <xf86drm.h>
|
|
#include <xf86drmMode.h>
|
|
-#include <drm_fourcc.h>
|
|
|
|
#define DBG_TAG "drm"
|
|
+#define NUM_DUMB_BO 3
|
|
+#define VIDEO_PLANE_ENABLE 1
|
|
+#define DEBUG
|
|
+#ifdef DEBUG
|
|
+#define DRM_DEBUG(fmt, ...) \
|
|
+ if (getenv("MJPG_DRM_DEBUG")) \
|
|
+ printf("DRM_DEBUG: %s(%d) " fmt, __func__, __LINE__, ##__VA_ARGS__)
|
|
+#else
|
|
+#define DRM_DEBUG(fmt, ...)
|
|
+#endif
|
|
|
|
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
|
|
-
|
|
-#define print(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__);
|
|
-#define err(msg, ...) print("error: " msg "\n", ##__VA_ARGS__)
|
|
-#define info(msg, ...) print(msg "\n", ##__VA_ARGS__)
|
|
-#define dbg(msg, ...) {} //print(DBG_TAG ": " msg "\n", ##__VA_ARGS__)
|
|
-
|
|
-struct drm_buffer {
|
|
- uint32_t handle;
|
|
- uint32_t pitch;
|
|
- uint32_t offset;
|
|
- unsigned long int size;
|
|
- void * map;
|
|
- uint32_t fb_handle;
|
|
+#define ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
|
|
+
|
|
+struct drm_bo {
|
|
+ int fd;
|
|
+ void *ptr;
|
|
+ size_t size;
|
|
+ size_t offset;
|
|
+ size_t pitch;
|
|
+ unsigned int handle;
|
|
+ int fb_id;
|
|
+ int buf_fd;
|
|
+ int w;
|
|
+ int h;
|
|
};
|
|
|
|
-struct drm_dev {
|
|
- int fd;
|
|
- uint32_t conn_id, enc_id, crtc_id, plane_id, crtc_idx;
|
|
- uint32_t width, height;
|
|
- uint32_t mmWidth, mmHeight;
|
|
- uint32_t fourcc;
|
|
- drmModeModeInfo mode;
|
|
- uint32_t blob_id;
|
|
- drmModeCrtc *saved_crtc;
|
|
- drmModeAtomicReq *req;
|
|
- drmEventContext drm_event_ctx;
|
|
- drmModePlane *plane;
|
|
- drmModeCrtc *crtc;
|
|
- drmModeConnector *conn;
|
|
- uint32_t count_plane_props;
|
|
- uint32_t count_crtc_props;
|
|
- uint32_t count_conn_props;
|
|
- drmModePropertyPtr plane_props[128];
|
|
- drmModePropertyPtr crtc_props[128];
|
|
- drmModePropertyPtr conn_props[128];
|
|
- struct drm_buffer drm_bufs[2]; /* DUMB buffers */
|
|
- struct drm_buffer *cur_bufs[2]; /* double buffering handling */
|
|
-} drm_dev;
|
|
+struct device {
|
|
+ int fd;
|
|
|
|
-static uint32_t get_plane_property_id(const char *name)
|
|
-{
|
|
- uint32_t i;
|
|
+ struct {
|
|
+ int width;
|
|
+ int height;
|
|
|
|
- dbg("Find plane property: %s", name);
|
|
+ int hdisplay;
|
|
+ int vdisplay;
|
|
|
|
- for (i = 0; i < drm_dev.count_plane_props; ++i)
|
|
- if (!strcmp(drm_dev.plane_props[i]->name, name))
|
|
- return drm_dev.plane_props[i]->prop_id;
|
|
+ int current;
|
|
+ int fb_num;
|
|
+ int bpp;
|
|
+ } mode;
|
|
|
|
- dbg("Unknown plane property: %s", name);
|
|
+ drmModeResPtr res;
|
|
|
|
- return 0;
|
|
-}
|
|
+ int connector_id;
|
|
+ int encoder_id;
|
|
+ int crtc_id;
|
|
+ int plane_id;
|
|
+ int last_fb_id;
|
|
|
|
-static uint32_t get_crtc_property_id(const char *name)
|
|
-{
|
|
- uint32_t i;
|
|
+ int waiting_for_flip;
|
|
+ struct pollfd drm_pollfd;
|
|
+ drmEventContext drm_evctx;
|
|
+};
|
|
|
|
- dbg("Find crtc property: %s", name);
|
|
+static int lcd_w;
|
|
+static int lcd_h;
|
|
+static int lcd_sw;
|
|
+static char* drm_buff;
|
|
+static lv_color_t *buf_1;
|
|
|
|
- for (i = 0; i < drm_dev.count_crtc_props; ++i)
|
|
- if (!strcmp(drm_dev.crtc_props[i]->name, name))
|
|
- return drm_dev.crtc_props[i]->prop_id;
|
|
+static int quit = 0;
|
|
+static pthread_t drm_thread_pid;
|
|
+static pthread_mutex_t draw_mutex;
|
|
+static int draw_update = 0;
|
|
+static struct drm_bo *gbo;
|
|
|
|
- dbg("Unknown crtc property: %s", name);
|
|
+struct device *pdev;
|
|
|
|
- return 0;
|
|
+static int bo_map(struct device *dev, struct drm_bo *bo)
|
|
+{
|
|
+ struct drm_mode_map_dumb arg = {
|
|
+ .handle = bo->handle,
|
|
+ };
|
|
+ struct drm_prime_handle fd_args = {
|
|
+ .fd = -1,
|
|
+ .handle = bo->handle,
|
|
+ .flags = 0,
|
|
+ };
|
|
+ int ret;
|
|
+
|
|
+ ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &fd_args);
|
|
+ if (ret)
|
|
+ {
|
|
+ printf("handle_to_fd failed ret=%d, handle=%x \n", ret ,fd_args.handle);
|
|
+ return -1;
|
|
+ }
|
|
+ bo->buf_fd = fd_args.fd;
|
|
+
|
|
+ bo->ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
+ dev->fd, arg.offset);
|
|
+ if (bo->ptr == MAP_FAILED) {
|
|
+ bo->ptr = NULL;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
-static uint32_t get_conn_property_id(const char *name)
|
|
+static void bo_unmap(struct device *dev, struct drm_bo *bo)
|
|
{
|
|
- uint32_t i;
|
|
+ if (dev == NULL)
|
|
+ return;
|
|
+ if (!bo->ptr)
|
|
+ return;
|
|
+
|
|
+ drmUnmap(bo->ptr, bo->size);
|
|
+ if (bo->buf_fd > 0)
|
|
+ close(bo->buf_fd);
|
|
+ bo->ptr = NULL;
|
|
+}
|
|
|
|
- dbg("Find conn property: %s", name);
|
|
+void bo_destroy(struct device *dev, struct drm_bo *bo)
|
|
+{
|
|
+ struct drm_mode_destroy_dumb arg = {
|
|
+ .handle = bo->handle,
|
|
+ };
|
|
|
|
- for (i = 0; i < drm_dev.count_conn_props; ++i)
|
|
- if (!strcmp(drm_dev.conn_props[i]->name, name))
|
|
- return drm_dev.conn_props[i]->prop_id;
|
|
+ if (bo->fb_id)
|
|
+ drmModeRmFB(dev->fd, bo->fb_id);
|
|
|
|
- dbg("Unknown conn property: %s", name);
|
|
+ bo_unmap(dev, bo);
|
|
|
|
- return 0;
|
|
-}
|
|
+ if (bo->handle)
|
|
+ drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
|
|
|
-static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
|
|
- unsigned int tv_usec, void *user_data)
|
|
-{
|
|
- dbg("flip");
|
|
+ free(bo);
|
|
}
|
|
|
|
-static int drm_get_plane_props(void)
|
|
+static struct drm_bo *
|
|
+bo_create(struct device *dev, int width, int height, int format)
|
|
{
|
|
- uint32_t i;
|
|
-
|
|
- drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.plane_id,
|
|
- DRM_MODE_OBJECT_PLANE);
|
|
- if (!props) {
|
|
- err("drmModeObjectGetProperties failed");
|
|
- return -1;
|
|
- }
|
|
- dbg("Found %u plane props", props->count_props);
|
|
- drm_dev.count_plane_props = props->count_props;
|
|
- for (i = 0; i < props->count_props; i++) {
|
|
- drm_dev.plane_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
|
- dbg("Added plane prop %u:%s", drm_dev.plane_props[i]->prop_id, drm_dev.plane_props[i]->name);
|
|
- }
|
|
- drmModeFreeObjectProperties(props);
|
|
-
|
|
- return 0;
|
|
+ struct drm_mode_create_dumb arg = {
|
|
+ .bpp = 32,
|
|
+ .width = ALIGN(width, 16),
|
|
+ .height = ALIGN(height, 16),
|
|
+ };
|
|
+ struct drm_bo *bo;
|
|
+ uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
|
+ int ret;
|
|
+
|
|
+ bo = malloc(sizeof(struct drm_bo));
|
|
+ if (bo == NULL) {
|
|
+ fprintf(stderr, "allocate bo failed\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ memset(bo, 0, sizeof(*bo));
|
|
+ if (format == DRM_FORMAT_NV12) {
|
|
+ arg.bpp = 8;
|
|
+ arg.height = height * 3 / 2;
|
|
+ }
|
|
+
|
|
+ ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "create dumb failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ bo->fd = dev->fd;
|
|
+ bo->handle = arg.handle;
|
|
+ bo->size = arg.size;
|
|
+ bo->pitch = arg.pitch;
|
|
+ bo->w = width;
|
|
+ bo->h = height;
|
|
+
|
|
+ ret = bo_map(dev, bo);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "map bo failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ switch (format) {
|
|
+ case DRM_FORMAT_NV12:
|
|
+ case DRM_FORMAT_NV16:
|
|
+ handles[0] = bo->handle;
|
|
+ pitches[0] = bo->pitch ;
|
|
+ offsets[0] = 0;
|
|
+ handles[1] = bo->handle;
|
|
+ pitches[1] = pitches[0];
|
|
+ offsets[1] = pitches[0] * height;
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB332:
|
|
+ handles[0] = bo->handle;
|
|
+ pitches[0] = bo->pitch;
|
|
+ offsets[0] = 0;
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB565:
|
|
+ case DRM_FORMAT_BGR565:
|
|
+ handles[0] = bo->handle;
|
|
+ pitches[0] = bo->pitch ;
|
|
+ offsets[0] = 0;
|
|
+ break;
|
|
+ case DRM_FORMAT_RGB888:
|
|
+ case DRM_FORMAT_BGR888:
|
|
+ handles[0] = bo->handle;
|
|
+ pitches[0] = bo->pitch ;
|
|
+ offsets[0] = 0;
|
|
+ break;
|
|
+ case DRM_FORMAT_ARGB8888:
|
|
+ case DRM_FORMAT_ABGR8888:
|
|
+ case DRM_FORMAT_RGBA8888:
|
|
+ case DRM_FORMAT_BGRA8888:
|
|
+ handles[0] = bo->handle;
|
|
+ pitches[0] = bo->pitch ;
|
|
+ offsets[0] = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ ret = drmModeAddFB2(dev->fd, width, height, format, handles,
|
|
+ pitches, offsets, (uint32_t *)&bo->fb_id, 0);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "add fb failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+ DRM_DEBUG("Created bo: %d, %dx%d\n", bo->fb_id, width, height);
|
|
+
|
|
+ return bo;
|
|
+err:
|
|
+ bo_destroy(dev, bo);
|
|
+ return NULL;
|
|
}
|
|
|
|
-static int drm_get_crtc_props(void)
|
|
+struct drm_bo *malloc_drm_bo(int width, int height, int format)
|
|
{
|
|
- uint32_t i;
|
|
-
|
|
- drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.crtc_id,
|
|
- DRM_MODE_OBJECT_CRTC);
|
|
- if (!props) {
|
|
- err("drmModeObjectGetProperties failed");
|
|
- return -1;
|
|
- }
|
|
- dbg("Found %u crtc props", props->count_props);
|
|
- drm_dev.count_crtc_props = props->count_props;
|
|
- for (i = 0; i < props->count_props; i++) {
|
|
- drm_dev.crtc_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
|
- dbg("Added crtc prop %u:%s", drm_dev.crtc_props[i]->prop_id, drm_dev.crtc_props[i]->name);
|
|
- }
|
|
- drmModeFreeObjectProperties(props);
|
|
-
|
|
- return 0;
|
|
+ struct device *dev = pdev;
|
|
+ return bo_create(dev, width, height, format);
|
|
}
|
|
|
|
-static int drm_get_conn_props(void)
|
|
+void free_drm_bo(struct drm_bo *bo)
|
|
{
|
|
- uint32_t i;
|
|
-
|
|
- drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.conn_id,
|
|
- DRM_MODE_OBJECT_CONNECTOR);
|
|
- if (!props) {
|
|
- err("drmModeObjectGetProperties failed");
|
|
- return -1;
|
|
- }
|
|
- dbg("Found %u connector props", props->count_props);
|
|
- drm_dev.count_conn_props = props->count_props;
|
|
- for (i = 0; i < props->count_props; i++) {
|
|
- drm_dev.conn_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
|
|
- dbg("Added connector prop %u:%s", drm_dev.conn_props[i]->prop_id, drm_dev.conn_props[i]->name);
|
|
- }
|
|
- drmModeFreeObjectProperties(props);
|
|
-
|
|
- return 0;
|
|
+ struct device *dev = pdev;
|
|
+ if (bo)
|
|
+ bo_destroy(dev, bo);
|
|
}
|
|
|
|
-static int drm_add_plane_property(const char *name, uint64_t value)
|
|
+static void free_fb(struct device *dev)
|
|
{
|
|
- int ret;
|
|
- uint32_t prop_id = get_plane_property_id(name);
|
|
-
|
|
- if (!prop_id) {
|
|
- err("Couldn't find plane prop %s", name);
|
|
- return -1;
|
|
- }
|
|
+ DRM_DEBUG("Free fb, num: %d, bpp: %d\n", dev->mode.fb_num, dev->mode.bpp);
|
|
|
|
- ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.plane_id, get_plane_property_id(name), value);
|
|
- if (ret < 0) {
|
|
- err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- return 0;
|
|
+ dev->mode.fb_num = 0;
|
|
+ dev->mode.bpp = 0;
|
|
+ dev->mode.current = 0;
|
|
}
|
|
|
|
-static int drm_add_crtc_property(const char *name, uint64_t value)
|
|
+static int alloc_fb(struct device *dev, int num, int bpp)
|
|
{
|
|
- int ret;
|
|
- uint32_t prop_id = get_crtc_property_id(name);
|
|
-
|
|
- if (!prop_id) {
|
|
- err("Couldn't find crtc prop %s", name);
|
|
- return -1;
|
|
- }
|
|
+ DRM_DEBUG("Alloc fb num: %d, bpp: %d\n", num, bpp);
|
|
|
|
- ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.crtc_id, get_crtc_property_id(name), value);
|
|
- if (ret < 0) {
|
|
- err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
|
- return ret;
|
|
- }
|
|
+ dev->mode.fb_num = num;
|
|
+ dev->mode.bpp = bpp;
|
|
+ dev->mode.current = 0;
|
|
|
|
- return 0;
|
|
+ return 0;
|
|
}
|
|
|
|
-static int drm_add_conn_property(const char *name, uint64_t value)
|
|
+static int drm_get_preferred_connector(void)
|
|
{
|
|
- int ret;
|
|
- uint32_t prop_id = get_conn_property_id(name);
|
|
-
|
|
- if (!prop_id) {
|
|
- err("Couldn't find conn prop %s", name);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.conn_id, get_conn_property_id(name), value);
|
|
- if (ret < 0) {
|
|
- err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- return 0;
|
|
+ const char *path;
|
|
+ char buf[256] = "\0";
|
|
+ int fd;
|
|
+
|
|
+#define DRM_CONNECTOR_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH"
|
|
+#define DRM_CONNECTOR_CFG_PATH_DEFAULT "/tmp/drm_connector.cfg"
|
|
+ path = getenv(DRM_CONNECTOR_CFG_PATH_ENV);
|
|
+ if (!path)
|
|
+ path = DRM_CONNECTOR_CFG_PATH_DEFAULT;
|
|
+
|
|
+ fd = open(path, O_RDONLY);
|
|
+ if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
|
|
+ DRM_DEBUG("Warning: read failed\n");
|
|
+ }
|
|
+ close(fd);
|
|
+
|
|
+ if (!buf[0])
|
|
+ return -1;
|
|
+
|
|
+ return atoi(buf);
|
|
}
|
|
|
|
-static int drm_dmabuf_set_plane(struct drm_buffer *buf)
|
|
+static int drm_get_preferred_mode(int *width, int *height)
|
|
{
|
|
- int ret;
|
|
- static int first = 1;
|
|
- uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
|
|
-
|
|
- drm_dev.req = drmModeAtomicAlloc();
|
|
+ const char *path;
|
|
+ char buf[256] = "\0";
|
|
+ int fd, w, h;
|
|
|
|
- /* On first Atomic commit, do a modeset */
|
|
- if (first) {
|
|
- drm_add_conn_property("CRTC_ID", drm_dev.crtc_id);
|
|
+#define DRM_MODE_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH"
|
|
+#define DRM_MODE_CFG_PATH_DEFAULT "/tmp/drm_mode.cfg"
|
|
+ path = getenv(DRM_MODE_CFG_PATH_ENV);
|
|
+ if (!path)
|
|
+ path = DRM_MODE_CFG_PATH_DEFAULT;
|
|
|
|
- drm_add_crtc_property("MODE_ID", drm_dev.blob_id);
|
|
- drm_add_crtc_property("ACTIVE", 1);
|
|
+ fd = open(path, O_RDONLY);
|
|
+ if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
|
|
+ DRM_DEBUG("Warning: read failed\n");
|
|
+ }
|
|
+ close(fd);
|
|
|
|
- flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
|
+ if (!buf[0])
|
|
+ return -1;
|
|
|
|
- first = 0;
|
|
- }
|
|
+ if (2 != sscanf(buf, "%dx%d", &w, &h))
|
|
+ return -1;
|
|
|
|
- drm_add_plane_property("FB_ID", buf->fb_handle);
|
|
- drm_add_plane_property("CRTC_ID", drm_dev.crtc_id);
|
|
- drm_add_plane_property("SRC_X", 0);
|
|
- drm_add_plane_property("SRC_Y", 0);
|
|
- drm_add_plane_property("SRC_W", drm_dev.width << 16);
|
|
- drm_add_plane_property("SRC_H", drm_dev.height << 16);
|
|
- drm_add_plane_property("CRTC_X", 0);
|
|
- drm_add_plane_property("CRTC_Y", 0);
|
|
- drm_add_plane_property("CRTC_W", drm_dev.width);
|
|
- drm_add_plane_property("CRTC_H", drm_dev.height);
|
|
+ *width = w;
|
|
+ *height = h;
|
|
|
|
- ret = drmModeAtomicCommit(drm_dev.fd, drm_dev.req, flags, NULL);
|
|
- if (ret) {
|
|
- err("drmModeAtomicCommit failed: %s", strerror(errno));
|
|
- drmModeAtomicFree(drm_dev.req);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- return 0;
|
|
+ return 0;
|
|
}
|
|
|
|
-static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
|
|
+static drmModeConnectorPtr
|
|
+drm_get_connector(struct device *dev, int connector_id)
|
|
{
|
|
- drmModePlaneResPtr planes;
|
|
- drmModePlanePtr plane;
|
|
- unsigned int i;
|
|
- unsigned int j;
|
|
- int ret = 0;
|
|
- unsigned int format = fourcc;
|
|
-
|
|
- planes = drmModeGetPlaneResources(drm_dev.fd);
|
|
- if (!planes) {
|
|
- err("drmModeGetPlaneResources failed");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- dbg("drm: found planes %u", planes->count_planes);
|
|
-
|
|
- for (i = 0; i < planes->count_planes; ++i) {
|
|
- plane = drmModeGetPlane(drm_dev.fd, planes->planes[i]);
|
|
- if (!plane) {
|
|
- err("drmModeGetPlane failed: %s", strerror(errno));
|
|
- break;
|
|
- }
|
|
-
|
|
- if (!(plane->possible_crtcs & (1 << crtc_idx))) {
|
|
- drmModeFreePlane(plane);
|
|
- continue;
|
|
- }
|
|
-
|
|
- for (j = 0; j < plane->count_formats; ++j) {
|
|
- if (plane->formats[j] == format)
|
|
- break;
|
|
- }
|
|
+ drmModeConnectorPtr conn;
|
|
|
|
- if (j == plane->count_formats) {
|
|
- drmModeFreePlane(plane);
|
|
- continue;
|
|
- }
|
|
+ conn = drmModeGetConnector(dev->fd, connector_id);
|
|
+ if (!conn)
|
|
+ return NULL;
|
|
|
|
- *plane_id = plane->plane_id;
|
|
- drmModeFreePlane(plane);
|
|
+ DRM_DEBUG("Connector id: %d, %sconnected, modes: %d\n", connector_id,
|
|
+ (conn->connection == DRM_MODE_CONNECTED) ? "" : "dis",
|
|
+ conn->count_modes);
|
|
+ if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes)
|
|
+ return conn;
|
|
|
|
- dbg("found plane %d", *plane_id);
|
|
+ drmModeFreeConnector(conn);
|
|
+ return NULL;
|
|
+}
|
|
|
|
- break;
|
|
- }
|
|
+static drmModeConnectorPtr
|
|
+drm_find_best_connector(struct device *dev)
|
|
+{
|
|
+ drmModeResPtr res = dev->res;
|
|
+ drmModeConnectorPtr conn;
|
|
+ int i, preferred_connector_id = drm_get_preferred_connector();
|
|
+
|
|
+ DRM_DEBUG("Preferred connector id: %d\n", preferred_connector_id);
|
|
+ conn = drm_get_connector(dev, preferred_connector_id);
|
|
+ if (conn)
|
|
+ return conn;
|
|
+
|
|
+ for (i = 0; i < res->count_connectors; i++) {
|
|
+ conn = drm_get_connector(dev, res->connectors[i]);
|
|
+ if (conn)
|
|
+ return conn;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
|
|
- if (i == planes->count_planes)
|
|
- ret = -1;
|
|
+static drmModeCrtcPtr
|
|
+drm_find_best_crtc(struct device *dev, drmModeConnectorPtr conn)
|
|
+{
|
|
+ drmModeResPtr res = dev->res;
|
|
+ drmModeEncoderPtr encoder;
|
|
+ drmModeCrtcPtr crtc;
|
|
+ int i, preferred_crtc_id = 0;
|
|
+ int crtcs_for_connector = 0;
|
|
+
|
|
+ encoder = drmModeGetEncoder(dev->fd, conn->encoder_id);
|
|
+ if (encoder) {
|
|
+ preferred_crtc_id = encoder->crtc_id;
|
|
+ drmModeFreeEncoder(encoder);
|
|
+ }
|
|
+ DRM_DEBUG("Preferred crtc: %d\n", preferred_crtc_id);
|
|
+
|
|
+ crtc = drmModeGetCrtc(dev->fd, preferred_crtc_id);
|
|
+ if (crtc)
|
|
+ return crtc;
|
|
+
|
|
+ for (i = 0; i < res->count_encoders; i++) {
|
|
+ encoder = drmModeGetEncoder(dev->fd, res->encoders[i]);
|
|
+ if (encoder)
|
|
+ crtcs_for_connector |= encoder->possible_crtcs;
|
|
+ drmModeFreeEncoder(encoder);
|
|
+ }
|
|
+ DRM_DEBUG("Possible crtcs: %x\n", crtcs_for_connector);
|
|
+ if (!crtcs_for_connector)
|
|
+ return NULL;
|
|
+
|
|
+ return drmModeGetCrtc(dev->fd, res->crtcs[ffs(crtcs_for_connector) - 1]);
|
|
+}
|
|
|
|
- drmModeFreePlaneResources(planes);
|
|
+int
|
|
+drm_plane_is_primary(struct device *dev, int plane_id)
|
|
+{
|
|
+ drmModeObjectPropertiesPtr props;
|
|
+ drmModePropertyPtr prop;
|
|
+ unsigned int i;
|
|
+ int type = 0;
|
|
+
|
|
+ props = drmModeObjectGetProperties(dev->fd, plane_id,
|
|
+ DRM_MODE_OBJECT_PLANE);
|
|
+ if (!props)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < props->count_props; i++) {
|
|
+ prop = drmModeGetProperty(dev->fd, props->props[i]);
|
|
+ if (prop && !strcmp(prop->name, "type"))
|
|
+ type = props->prop_values[i];
|
|
+ drmModeFreeProperty(prop);
|
|
+ }
|
|
+ DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
|
|
+
|
|
+ drmModeFreeObjectProperties(props);
|
|
+ return type == DRM_PLANE_TYPE_PRIMARY;
|
|
+}
|
|
|
|
- return ret;
|
|
+int
|
|
+drm_plane_is_overlay(struct device *dev, int plane_id)
|
|
+{
|
|
+ drmModeObjectPropertiesPtr props;
|
|
+ drmModePropertyPtr prop;
|
|
+ unsigned int i;
|
|
+ int type = 0;
|
|
+
|
|
+ props = drmModeObjectGetProperties(dev->fd, plane_id,
|
|
+ DRM_MODE_OBJECT_PLANE);
|
|
+ if (!props)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < props->count_props; i++) {
|
|
+ prop = drmModeGetProperty(dev->fd, props->props[i]);
|
|
+ if (prop && !strcmp(prop->name, "type"))
|
|
+ type = props->prop_values[i];
|
|
+ drmModeFreeProperty(prop);
|
|
+ }
|
|
+ DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
|
|
+
|
|
+ drmModeFreeObjectProperties(props);
|
|
+ return type == DRM_PLANE_TYPE_OVERLAY;
|
|
}
|
|
|
|
-static int drm_find_connector(void)
|
|
+static drmModePlanePtr
|
|
+drm_get_plane(struct device *dev, int plane_id, int pipe)
|
|
{
|
|
- drmModeConnector *conn = NULL;
|
|
- drmModeEncoder *enc = NULL;
|
|
- drmModeRes *res;
|
|
- int i;
|
|
+ drmModePlanePtr plane;
|
|
|
|
- if ((res = drmModeGetResources(drm_dev.fd)) == NULL) {
|
|
- err("drmModeGetResources() failed");
|
|
- return -1;
|
|
- }
|
|
+ plane = drmModeGetPlane(dev->fd, plane_id);
|
|
+ if (!plane)
|
|
+ return NULL;
|
|
|
|
- if (res->count_crtcs <= 0) {
|
|
- err("no Crtcs");
|
|
- goto free_res;
|
|
- }
|
|
-
|
|
- /* find all available connectors */
|
|
- for (i = 0; i < res->count_connectors; i++) {
|
|
- conn = drmModeGetConnector(drm_dev.fd, res->connectors[i]);
|
|
- if (!conn)
|
|
- continue;
|
|
-
|
|
-#if DRM_CONNECTOR_ID >= 0
|
|
- if (conn->connector_id != DRM_CONNECTOR_ID) {
|
|
- drmModeFreeConnector(conn);
|
|
- continue;
|
|
- }
|
|
-#endif
|
|
+ DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id,
|
|
+ plane->possible_crtcs);
|
|
+ if (drm_plane_is_primary(dev, plane_id)) {
|
|
+ if (plane->possible_crtcs & (1 << pipe))
|
|
+ return plane;
|
|
+ }
|
|
|
|
- if (conn->connection == DRM_MODE_CONNECTED) {
|
|
- dbg("drm: connector %d: connected", conn->connector_id);
|
|
- } else if (conn->connection == DRM_MODE_DISCONNECTED) {
|
|
- dbg("drm: connector %d: disconnected", conn->connector_id);
|
|
- } else if (conn->connection == DRM_MODE_UNKNOWNCONNECTION) {
|
|
- dbg("drm: connector %d: unknownconnection", conn->connector_id);
|
|
- } else {
|
|
- dbg("drm: connector %d: unknown", conn->connector_id);
|
|
- }
|
|
-
|
|
- if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
|
|
- break;
|
|
-
|
|
- drmModeFreeConnector(conn);
|
|
- conn = NULL;
|
|
- };
|
|
-
|
|
- if (!conn) {
|
|
- err("suitable connector not found");
|
|
- goto free_res;
|
|
- }
|
|
+ drmModeFreePlane(plane);
|
|
+ return NULL;
|
|
+}
|
|
|
|
- drm_dev.conn_id = conn->connector_id;
|
|
- dbg("conn_id: %d", drm_dev.conn_id);
|
|
- drm_dev.mmWidth = conn->mmWidth;
|
|
- drm_dev.mmHeight = conn->mmHeight;
|
|
+static drmModePlanePtr
|
|
+drm_find_best_plane(struct device *dev, drmModeCrtcPtr crtc)
|
|
+{
|
|
+ drmModeResPtr res = dev->res;
|
|
+ drmModePlaneResPtr pres;
|
|
+ drmModePlanePtr plane;
|
|
+ unsigned int i;
|
|
+ int pipe;
|
|
+
|
|
+ for (pipe = 0; pipe < res->count_crtcs; pipe++) {
|
|
+ if (crtc->crtc_id == res->crtcs[pipe])
|
|
+ break;
|
|
+ }
|
|
+ if (pipe == res->count_crtcs)
|
|
+ return NULL;
|
|
+
|
|
+ pres = drmModeGetPlaneResources(dev->fd);
|
|
+ if (!pres)
|
|
+ return NULL;
|
|
+
|
|
+ for (i = 0; i < pres->count_planes; i++) {
|
|
+ plane = drm_get_plane(dev, pres->planes[i], pipe);
|
|
+ if (plane) {
|
|
+ drmModeFreePlaneResources(pres);
|
|
+ return plane;
|
|
+ }
|
|
+ drmModeFreePlane(plane);
|
|
+ }
|
|
+
|
|
+ drmModeFreePlaneResources(pres);
|
|
+ return NULL;
|
|
+}
|
|
|
|
- memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
|
|
+static drmModeModeInfoPtr
|
|
+drm_find_best_mode(struct device *dev, drmModeConnectorPtr conn)
|
|
+{
|
|
+ drmModeModeInfoPtr mode;
|
|
+ int i, preferred_width = 1920, preferred_height = 1080;
|
|
+
|
|
+ if (dev == NULL)
|
|
+ return 0;
|
|
+ drm_get_preferred_mode(&preferred_width, &preferred_height);
|
|
+ DRM_DEBUG("Preferred mode: %dx%d\n", preferred_width, preferred_height);
|
|
+
|
|
+ mode = &conn->modes[0];
|
|
+ for (i = 0; i < conn->count_modes; i++) {
|
|
+ DRM_DEBUG("Check mode: %dx%d\n",
|
|
+ conn->modes[i].hdisplay, conn->modes[i].vdisplay);
|
|
+ if (conn->modes[i].hdisplay == preferred_width &&
|
|
+ conn->modes[i].vdisplay == preferred_height) {
|
|
+ mode = &conn->modes[i];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return mode;
|
|
+}
|
|
|
|
- if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
|
|
- &drm_dev.blob_id)) {
|
|
- err("error creating mode blob");
|
|
- goto free_res;
|
|
- }
|
|
+static int drm_get_preferred_fb_mode(int *width, int *height)
|
|
+{
|
|
+ char *buf;
|
|
+ int w, h;
|
|
|
|
- drm_dev.width = conn->modes[0].hdisplay;
|
|
- drm_dev.height = conn->modes[0].vdisplay;
|
|
+ buf = getenv("MINIGUI_DRM_FB_MODE");
|
|
+ if (!buf)
|
|
+ return -1;
|
|
|
|
- for (i = 0 ; i < res->count_encoders; i++) {
|
|
- enc = drmModeGetEncoder(drm_dev.fd, res->encoders[i]);
|
|
- if (!enc)
|
|
- continue;
|
|
-
|
|
- dbg("enc%d enc_id %d conn enc_id %d", i, enc->encoder_id, conn->encoder_id);
|
|
-
|
|
- if (enc->encoder_id == conn->encoder_id)
|
|
- break;
|
|
-
|
|
- drmModeFreeEncoder(enc);
|
|
- enc = NULL;
|
|
- }
|
|
-
|
|
- if (enc) {
|
|
- drm_dev.enc_id = enc->encoder_id;
|
|
- dbg("enc_id: %d", drm_dev.enc_id);
|
|
- drm_dev.crtc_id = enc->crtc_id;
|
|
- dbg("crtc_id: %d", drm_dev.crtc_id);
|
|
- drmModeFreeEncoder(enc);
|
|
- } else {
|
|
- /* Encoder hasn't been associated yet, look it up */
|
|
- for (i = 0; i < conn->count_encoders; i++) {
|
|
- int crtc, crtc_id = -1;
|
|
-
|
|
- enc = drmModeGetEncoder(drm_dev.fd, conn->encoders[i]);
|
|
- if (!enc)
|
|
- continue;
|
|
-
|
|
- for (crtc = 0 ; crtc < res->count_crtcs; crtc++) {
|
|
- uint32_t crtc_mask = 1 << crtc;
|
|
-
|
|
- crtc_id = res->crtcs[crtc];
|
|
-
|
|
- dbg("enc_id %d crtc%d id %d mask %x possible %x", enc->encoder_id, crtc, crtc_id, crtc_mask, enc->possible_crtcs);
|
|
-
|
|
- if (enc->possible_crtcs & crtc_mask)
|
|
- break;
|
|
- }
|
|
-
|
|
- if (crtc_id > 0) {
|
|
- drm_dev.enc_id = enc->encoder_id;
|
|
- dbg("enc_id: %d", drm_dev.enc_id);
|
|
- drm_dev.crtc_id = crtc_id;
|
|
- dbg("crtc_id: %d", drm_dev.crtc_id);
|
|
- break;
|
|
- }
|
|
-
|
|
- drmModeFreeEncoder(enc);
|
|
- enc = NULL;
|
|
- }
|
|
-
|
|
- if (!enc) {
|
|
- err("suitable encoder not found");
|
|
- goto free_res;
|
|
- }
|
|
-
|
|
- drmModeFreeEncoder(enc);
|
|
- }
|
|
-
|
|
- drm_dev.crtc_idx = -1;
|
|
-
|
|
- for (i = 0; i < res->count_crtcs; ++i) {
|
|
- if (drm_dev.crtc_id == res->crtcs[i]) {
|
|
- drm_dev.crtc_idx = i;
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (drm_dev.crtc_idx == -1) {
|
|
- err("drm: CRTC not found");
|
|
- goto free_res;
|
|
- }
|
|
+ if (2 != sscanf(buf, "%dx%d", &w, &h))
|
|
+ return -1;
|
|
|
|
- dbg("crtc_idx: %d", drm_dev.crtc_idx);
|
|
-
|
|
- return 0;
|
|
+ DRM_DEBUG("Preferred fb mode: %dx%d\n", w, h);
|
|
+ *width = w;
|
|
+ *height = h;
|
|
|
|
-free_res:
|
|
- drmModeFreeResources(res);
|
|
-
|
|
- return -1;
|
|
+ return 0;
|
|
}
|
|
|
|
-static int drm_open(const char *path)
|
|
+static void drm_setup_fb_mode(struct device *dev)
|
|
{
|
|
- int fd, flags;
|
|
- uint64_t has_dumb;
|
|
- int ret;
|
|
-
|
|
- fd = open(path, O_RDWR);
|
|
- if (fd < 0) {
|
|
- err("cannot open \"%s\"", path);
|
|
- return -1;
|
|
- }
|
|
+ drmModeResPtr res = dev->res;
|
|
+ drmModeConnectorPtr conn;
|
|
+ drmModeModeInfoPtr mode;
|
|
+ int i;
|
|
+
|
|
+ if (dev->mode.width && dev->mode.height)
|
|
+ return;
|
|
+
|
|
+ if (!drm_get_preferred_fb_mode(&dev->mode.width, &dev->mode.height))
|
|
+ return;
|
|
+
|
|
+ dev->mode.width = dev->mode.hdisplay;
|
|
+ dev->mode.height = dev->mode.vdisplay;
|
|
+
|
|
+ for (i = 0; i < res->count_connectors; i++) {
|
|
+ conn = drm_get_connector(dev, res->connectors[i]);
|
|
+ if (!conn)
|
|
+ continue;
|
|
+
|
|
+ mode = drm_find_best_mode(dev, conn);
|
|
+ if (mode) {
|
|
+ DRM_DEBUG("Best mode for connector(%d): %dx%d\n",
|
|
+ conn->connector_id, mode->hdisplay, mode->vdisplay);
|
|
+ if (dev->mode.width > mode->hdisplay ||
|
|
+ dev->mode.height > mode->vdisplay) {
|
|
+ dev->mode.width = mode->hdisplay;
|
|
+ dev->mode.height = mode->vdisplay;
|
|
+ }
|
|
+ }
|
|
+ drmModeFreeConnector(conn);
|
|
+ }
|
|
+}
|
|
|
|
- /* set FD_CLOEXEC flag */
|
|
- if ((flags = fcntl(fd, F_GETFD)) < 0 ||
|
|
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
|
|
- err("fcntl FD_CLOEXEC failed");
|
|
- goto err;
|
|
- }
|
|
+static void drm_free(struct device *dev)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (dev->res) {
|
|
+ drmModeFreeResources(dev->res);
|
|
+ dev->res = NULL;
|
|
+ }
|
|
+
|
|
+ dev->connector_id = 0;
|
|
+ dev->crtc_id = 0;
|
|
+ dev->plane_id = 0;
|
|
+ dev->mode.hdisplay = 0;
|
|
+ dev->mode.vdisplay = 0;
|
|
+}
|
|
|
|
- /* check capability */
|
|
- ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
|
|
- if (ret < 0 || has_dumb == 0) {
|
|
- err("drmGetCap DRM_CAP_DUMB_BUFFER failed or \"%s\" doesn't have dumb "
|
|
- "buffer", path);
|
|
- goto err;
|
|
- }
|
|
-
|
|
- return fd;
|
|
-err:
|
|
- close(fd);
|
|
- return -1;
|
|
-}
|
|
-
|
|
-static int drm_setup(unsigned int fourcc)
|
|
-{
|
|
- int ret;
|
|
- const char *device_path = NULL;
|
|
-
|
|
- device_path = getenv("DRM_CARD");
|
|
- if (!device_path)
|
|
- device_path = DRM_CARD;
|
|
-
|
|
- drm_dev.fd = drm_open(device_path);
|
|
- if (drm_dev.fd < 0)
|
|
- return -1;
|
|
-
|
|
- ret = drmSetClientCap(drm_dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
|
|
- if (ret) {
|
|
- err("No atomic modesetting support: %s", strerror(errno));
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = drm_find_connector();
|
|
- if (ret) {
|
|
- err("available drm devices not found");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
|
|
- if (ret) {
|
|
- err("Cannot find plane");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- drm_dev.plane = drmModeGetPlane(drm_dev.fd, drm_dev.plane_id);
|
|
- if (!drm_dev.plane) {
|
|
- err("Cannot get plane");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- drm_dev.crtc = drmModeGetCrtc(drm_dev.fd, drm_dev.crtc_id);
|
|
- if (!drm_dev.crtc) {
|
|
- err("Cannot get crtc");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- drm_dev.conn = drmModeGetConnector(drm_dev.fd, drm_dev.conn_id);
|
|
- if (!drm_dev.conn) {
|
|
- err("Cannot get connector");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = drm_get_plane_props();
|
|
- if (ret) {
|
|
- err("Cannot get plane props");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = drm_get_crtc_props();
|
|
- if (ret) {
|
|
- err("Cannot get crtc props");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- ret = drm_get_conn_props();
|
|
- if (ret) {
|
|
- err("Cannot get connector props");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- drm_dev.drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
|
|
- drm_dev.drm_event_ctx.page_flip_handler = page_flip_handler;
|
|
- drm_dev.fourcc = fourcc;
|
|
-
|
|
- info("drm: Found plane_id: %u connector_id: %d crtc_id: %d",
|
|
- drm_dev.plane_id, drm_dev.conn_id, drm_dev.crtc_id);
|
|
-
|
|
- info("drm: %dx%d (%dmm X% dmm) pixel format %c%c%c%c",
|
|
- drm_dev.width, drm_dev.height, drm_dev.mmWidth, drm_dev.mmHeight,
|
|
- (fourcc>>0)&0xff, (fourcc>>8)&0xff, (fourcc>>16)&0xff, (fourcc>>24)&0xff);
|
|
-
|
|
- return 0;
|
|
+static void configure_plane_zpos(struct device *self, int plane_id, uint64_t zpos)
|
|
+{
|
|
+ drmModeObjectPropertiesPtr props = NULL;
|
|
+ drmModePropertyPtr prop = NULL;
|
|
+ char *buf;
|
|
+ unsigned int i;
|
|
+
|
|
+ if (plane_id <= 0)
|
|
+ return;
|
|
+
|
|
+ if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_ATOMIC, 1))
|
|
+ return;
|
|
+
|
|
+ props = drmModeObjectGetProperties (self->fd, plane_id,
|
|
+ DRM_MODE_OBJECT_PLANE);
|
|
+ if (!props)
|
|
+ goto out;
|
|
+
|
|
+ for (i = 0; i < props->count_props; i++) {
|
|
+ prop = drmModeGetProperty (self->fd, props->props[i]);
|
|
+ if (prop && !strcmp (prop->name, "ZPOS"))
|
|
+ break;
|
|
+ drmModeFreeProperty (prop);
|
|
+ prop = NULL;
|
|
+ }
|
|
+
|
|
+ if (!prop)
|
|
+ goto out;
|
|
+
|
|
+ drmModeObjectSetProperty (self->fd, plane_id,
|
|
+ DRM_MODE_OBJECT_PLANE, props->props[i], zpos);
|
|
+out:
|
|
+ drmModeFreeProperty (prop);
|
|
+ drmModeFreeObjectProperties (props);
|
|
+}
|
|
|
|
+static int drm_setup(struct device *dev)
|
|
+{
|
|
+ drmModeConnectorPtr conn = NULL;
|
|
+ drmModeModeInfoPtr mode;
|
|
+ drmModePlanePtr plane = NULL;
|
|
+ drmModeCrtcPtr crtc = NULL;
|
|
+ //int ret;
|
|
+ int i, success = 0;
|
|
+
|
|
+ dev->res = drmModeGetResources(dev->fd);
|
|
+ if (!dev->res) {
|
|
+ fprintf(stderr, "drm get resource failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ conn = drm_find_best_connector(dev);
|
|
+ if (!conn) {
|
|
+ fprintf(stderr, "drm find connector failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+ DRM_DEBUG("Best connector id: %d\n", conn->connector_id);
|
|
+
|
|
+ mode = drm_find_best_mode(dev, conn);
|
|
+ if (!mode) {
|
|
+ fprintf(stderr, "drm find mode failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+ DRM_DEBUG("Best mode: %dx%d\n", mode->hdisplay, mode->vdisplay);
|
|
+
|
|
+ crtc = drm_find_best_crtc(dev, conn);
|
|
+ if (!crtc) {
|
|
+ fprintf(stderr, "drm find crtc failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+ DRM_DEBUG("Best crtc: %d\n", crtc->crtc_id);
|
|
+
|
|
+ plane = drm_find_best_plane(dev, crtc);
|
|
+ if (!plane) {
|
|
+ fprintf(stderr, "drm find plane failed\n");
|
|
+ goto err;
|
|
+ }
|
|
+ configure_plane_zpos(dev, plane->plane_id, 1);
|
|
+ printf("Best plane: %d\n", plane->plane_id);
|
|
+ dev->connector_id = conn->connector_id;
|
|
+ dev->crtc_id = crtc->crtc_id;
|
|
+ dev->plane_id = plane->plane_id;
|
|
+ dev->last_fb_id = 0;
|
|
+ dev->mode.hdisplay = mode->hdisplay;
|
|
+ dev->mode.vdisplay = mode->vdisplay;
|
|
+
|
|
+ drm_setup_fb_mode(dev);
|
|
+ DRM_DEBUG("Drm fb mode: %dx%d\n", dev->mode.width, dev->mode.height);
|
|
+
|
|
+ success = 1;
|
|
err:
|
|
- close(drm_dev.fd);
|
|
- return -1;
|
|
-}
|
|
-
|
|
-static int drm_allocate_dumb(struct drm_buffer *buf)
|
|
-{
|
|
- struct drm_mode_create_dumb creq;
|
|
- struct drm_mode_map_dumb mreq;
|
|
- uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
|
- int ret;
|
|
-
|
|
- /* create dumb buffer */
|
|
- memset(&creq, 0, sizeof(creq));
|
|
- creq.width = drm_dev.width;
|
|
- creq.height = drm_dev.height;
|
|
- creq.bpp = LV_COLOR_DEPTH;
|
|
- ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
|
|
- if (ret < 0) {
|
|
- err("DRM_IOCTL_MODE_CREATE_DUMB fail");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- buf->handle = creq.handle;
|
|
- buf->pitch = creq.pitch;
|
|
- dbg("pitch %d", buf->pitch);
|
|
- buf->size = creq.size;
|
|
- dbg("size %d", buf->size);
|
|
-
|
|
- /* prepare buffer for memory mapping */
|
|
- memset(&mreq, 0, sizeof(mreq));
|
|
- mreq.handle = creq.handle;
|
|
- ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
|
|
- if (ret) {
|
|
- err("DRM_IOCTL_MODE_MAP_DUMB fail");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- buf->offset = mreq.offset;
|
|
-
|
|
- /* perform actual memory mapping */
|
|
- buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
|
|
- if (buf->map == MAP_FAILED) {
|
|
- err("mmap fail");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- /* clear the framebuffer to 0 (= full transparency in ARGB8888) */
|
|
- memset(buf->map, 0, creq.size);
|
|
-
|
|
- /* create framebuffer object for the dumb-buffer */
|
|
- handles[0] = creq.handle;
|
|
- pitches[0] = creq.pitch;
|
|
- offsets[0] = 0;
|
|
- ret = drmModeAddFB2(drm_dev.fd, drm_dev.width, drm_dev.height, drm_dev.fourcc,
|
|
- handles, pitches, offsets, &buf->fb_handle, 0);
|
|
- if (ret) {
|
|
- err("drmModeAddFB fail");
|
|
- return -1;
|
|
- }
|
|
-
|
|
- return 0;
|
|
+ drmModeFreeConnector(conn);
|
|
+ drmModeFreePlane(plane);
|
|
+ drmModeFreeCrtc(crtc);
|
|
+ if (!success) {
|
|
+ drm_free(dev);
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
|
|
-static int drm_setup_buffers(void)
|
|
+static void drm_flip_handler(int fd, unsigned frame, unsigned sec,
|
|
+ unsigned usec, void *data)
|
|
{
|
|
- int ret;
|
|
-
|
|
- /* Allocate DUMB buffers */
|
|
- ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = drm_allocate_dumb(&drm_dev.drm_bufs[1]);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Set buffering handling */
|
|
- drm_dev.cur_bufs[0] = NULL;
|
|
- drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
|
|
-
|
|
- return 0;
|
|
+ // data is &dev->waiting_for_flip
|
|
+ DRM_DEBUG("Page flip received(%d)!, %d, %d, %d, %d\n", *(int*)data, fd, frame, sec, usec);
|
|
+ *(int*)data = 0;
|
|
}
|
|
|
|
-void drm_wait_vsync(lv_disp_drv_t *disp_drv)
|
|
+int drm_init(int bpp)
|
|
{
|
|
- int ret;
|
|
- fd_set fds;
|
|
- FD_ZERO(&fds);
|
|
- FD_SET(drm_dev.fd, &fds);
|
|
-
|
|
- do {
|
|
- ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL);
|
|
- } while (ret == -1 && errno == EINTR);
|
|
-
|
|
- if (ret < 0) {
|
|
- err("select failed: %s", strerror(errno));
|
|
- drmModeAtomicFree(drm_dev.req);
|
|
- drm_dev.req = NULL;
|
|
- return;
|
|
- }
|
|
-
|
|
- if (FD_ISSET(drm_dev.fd, &fds))
|
|
- drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
|
|
-
|
|
- drmModeAtomicFree(drm_dev.req);
|
|
- drm_dev.req = NULL;
|
|
+ int ret;
|
|
+
|
|
+ pdev = malloc(sizeof(struct device));
|
|
+ if (pdev == NULL) {
|
|
+ fprintf(stderr, "allocate device failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+ memset(pdev, 0, sizeof(*pdev));
|
|
+
|
|
+ //drm_install_sighandler(pdev);
|
|
+
|
|
+ pdev->fd = drmOpen(NULL, NULL);
|
|
+ if (pdev->fd < 0)
|
|
+ pdev->fd = open("/dev/dri/card0", O_RDWR);
|
|
+ if (pdev->fd < 0) {
|
|
+ fprintf(stderr, "drm open failed\n");
|
|
+ goto err_drm_open;
|
|
+ }
|
|
+ fcntl(pdev->fd, F_SETFD, FD_CLOEXEC);
|
|
+
|
|
+ drmSetClientCap(pdev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
|
+
|
|
+ ret = alloc_fb(pdev, NUM_DUMB_BO, bpp);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "alloc fb failed\n");
|
|
+ goto err_alloc_fb;
|
|
+ }
|
|
+
|
|
+ ret = drm_setup(pdev);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "drm setup failed\n");
|
|
+ goto err_drm_setup;
|
|
+ }
|
|
+
|
|
+ pdev->drm_pollfd.fd = pdev->fd;
|
|
+ pdev->drm_pollfd.events = POLLIN;
|
|
+
|
|
+ pdev->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
|
+ pdev->drm_evctx.page_flip_handler = drm_flip_handler;
|
|
+
|
|
+ return 0;
|
|
+err_alloc_fb:
|
|
+ drm_free(pdev);
|
|
+err_drm_setup:
|
|
+ drmClose(pdev->fd);
|
|
+err_drm_open:
|
|
+ free(pdev);
|
|
+ pdev = NULL;
|
|
+ return -1;
|
|
}
|
|
|
|
-void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
|
+int drm_exit(void)
|
|
{
|
|
- struct drm_buffer *fbuf = drm_dev.cur_bufs[1];
|
|
- lv_coord_t w = (area->x2 - area->x1 + 1);
|
|
- lv_coord_t h = (area->y2 - area->y1 + 1);
|
|
- int i, y;
|
|
+ struct device* dev = pdev;
|
|
+ if (!dev)
|
|
+ return 0;
|
|
|
|
- dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h);
|
|
+ free_fb(dev);
|
|
+ drm_free(dev);
|
|
|
|
- /* Partial update */
|
|
- if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0])
|
|
- memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size);
|
|
+ if (pdev->fd > 0)
|
|
+ drmClose(dev->fd);
|
|
|
|
- for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) {
|
|
- memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i),
|
|
- (uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
|
|
- w * (LV_COLOR_SIZE/8));
|
|
- }
|
|
+ free(pdev);
|
|
+ pdev = NULL;
|
|
|
|
- if (drm_dev.req)
|
|
- drm_wait_vsync(disp_drv);
|
|
+ return 0;
|
|
+}
|
|
|
|
- /* show fbuf plane */
|
|
- if (drm_dmabuf_set_plane(fbuf)) {
|
|
- err("Flush fail");
|
|
- return;
|
|
- }
|
|
- else
|
|
- dbg("Flush done");
|
|
+int getdrmfd(void)
|
|
+{
|
|
+ return pdev->fd;
|
|
+}
|
|
|
|
- if (!drm_dev.cur_bufs[0])
|
|
- drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
|
|
- else
|
|
- drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
|
|
+static void drm_wait_flip(struct device* dev, int timeout)
|
|
+{
|
|
+ int ret;
|
|
|
|
- drm_dev.cur_bufs[0] = fbuf;
|
|
+ while (dev->waiting_for_flip) {
|
|
+ dev->drm_pollfd.revents = 0;
|
|
+ ret = poll(&dev->drm_pollfd, 1, timeout);
|
|
+ if (ret <= 0)
|
|
+ return;
|
|
|
|
- lv_disp_flush_ready(disp_drv);
|
|
+ drmHandleEvent(dev->fd, &dev->drm_evctx);
|
|
+ }
|
|
}
|
|
|
|
-#if LV_COLOR_DEPTH == 32
|
|
-#define DRM_FOURCC DRM_FORMAT_ARGB8888
|
|
-#elif LV_COLOR_DEPTH == 16
|
|
-#define DRM_FOURCC DRM_FORMAT_RGB565
|
|
-#else
|
|
-#error LV_COLOR_DEPTH not supported
|
|
-#endif
|
|
-
|
|
-void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
|
|
+void setdrmdisp(struct drm_bo *bo)
|
|
{
|
|
- if (width)
|
|
- *width = drm_dev.width;
|
|
-
|
|
- if (height)
|
|
- *height = drm_dev.height;
|
|
-
|
|
- if (dpi && drm_dev.mmWidth)
|
|
- *dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
|
|
+ struct device* dev = pdev;
|
|
+ int crtc_x, crtc_y, crtc_w, crtc_h;
|
|
+ int ret;
|
|
+ int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height;
|
|
+
|
|
+ if (dev == NULL)
|
|
+ return;
|
|
+
|
|
+ crtc_w = dev->mode.width;
|
|
+ crtc_h = dev->mode.height;
|
|
+ crtc_x = 0;
|
|
+ crtc_y = 0;
|
|
+
|
|
+ DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh,
|
|
+ crtc_x, crtc_y, crtc_w, crtc_h);
|
|
+ ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, fb, 0,
|
|
+ crtc_x, crtc_y, crtc_w, crtc_h,
|
|
+ 0, 0, sw << 16, sh << 16);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "drm set plane failed\n");
|
|
+ return;
|
|
+ }
|
|
+ if (0) {
|
|
+ // Queue page flip
|
|
+ dev->waiting_for_flip = 1;
|
|
+ ret = drmModePageFlip(dev->fd, dev->crtc_id, fb,
|
|
+ DRM_MODE_PAGE_FLIP_EVENT, &dev->waiting_for_flip);
|
|
+ if (ret) {
|
|
+ fprintf(stderr, "drm page flip failed\n");
|
|
+ return;
|
|
+ }
|
|
+ // Wait for last page flip
|
|
+ drm_wait_flip(dev, -1);
|
|
+ }
|
|
}
|
|
|
|
-void drm_init(void)
|
|
+void getdrmresolve(int *w, int *h)
|
|
{
|
|
- int ret;
|
|
+ *w = pdev->mode.width;
|
|
+ *h = pdev->mode.height;
|
|
+}
|
|
|
|
- ret = drm_setup(DRM_FOURCC);
|
|
- if (ret) {
|
|
- close(drm_dev.fd);
|
|
- drm_dev.fd = -1;
|
|
- return;
|
|
- }
|
|
+static void *drm_thread(void *arg)
|
|
+{
|
|
+ while (!quit) {
|
|
+ pthread_mutex_lock(&draw_mutex);
|
|
+ if (draw_update) {
|
|
+ setdrmdisp(gbo);
|
|
+ draw_update = 0;
|
|
+ }
|
|
+ pthread_mutex_unlock(&draw_mutex);
|
|
+ usleep(10000);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
|
|
- ret = drm_setup_buffers();
|
|
- if (ret) {
|
|
- err("DRM buffer allocation failed");
|
|
- close(drm_dev.fd);
|
|
- drm_dev.fd = -1;
|
|
- return;
|
|
- }
|
|
+void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
|
|
+{
|
|
+ /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
|
|
+ int32_t x;
|
|
+ int32_t y;
|
|
+
|
|
+ pthread_mutex_lock(&draw_mutex);
|
|
+ for(y = area->y1; y <= area->y2; y++) {
|
|
+ int area_w = area->x2 - area->x1 + 1;
|
|
+ lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_sw + area->x1) * 4);
|
|
+ memcpy(disp, color_p, area_w * 4);
|
|
+ color_p += area_w;
|
|
+ }
|
|
+ draw_update = 1;
|
|
+ pthread_mutex_unlock(&draw_mutex);
|
|
+ /*IMPORTANT!!!
|
|
+ *Inform the graphics library that you are ready with the flushing*/
|
|
+ lv_disp_flush_ready(disp_drv);
|
|
+}
|
|
|
|
- info("DRM subsystem and buffer mapped successfully");
|
|
+void disp_init(void)
|
|
+{
|
|
+ /*You code here*/
|
|
+ drm_init(32);
|
|
+ getdrmresolve(&lcd_w, &lcd_h);
|
|
+ gbo = malloc_drm_bo(lcd_w, lcd_h, DRM_FORMAT_ARGB8888);
|
|
+ drm_buff = gbo->ptr;
|
|
+ lcd_sw = gbo->pitch / 4;
|
|
+
|
|
+ printf("DRM subsystem and buffer mapped successfully\n");
|
|
}
|
|
|
|
-void drm_exit(void)
|
|
+void drm_disp_drv_init(int rot)
|
|
{
|
|
- close(drm_dev.fd);
|
|
- drm_dev.fd = -1;
|
|
+ /*-------------------------
|
|
+ * Initialize your display
|
|
+ * -----------------------*/
|
|
+ disp_init();
|
|
+
|
|
+ /*-----------------------------
|
|
+ * Create a buffer for drawing
|
|
+ *----------------------------*/
|
|
+
|
|
+ /**
|
|
+ * LVGL requires a buffer where it internally draws the widgets.
|
|
+ * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
|
|
+ * The buffer has to be greater than 1 display row
|
|
+ *
|
|
+ * There are 3 buffering configurations:
|
|
+ * 1. Create ONE buffer:
|
|
+ * LVGL will draw the display's content here and writes it to your display
|
|
+ *
|
|
+ * 2. Create TWO buffer:
|
|
+ * LVGL will draw the display's content to a buffer and writes it your display.
|
|
+ * You should use DMA to write the buffer's content to the display.
|
|
+ * It will enable LVGL to draw the next part of the screen to the other buffer while
|
|
+ * the data is being sent form the first buffer. It makes rendering and flushing parallel.
|
|
+ *
|
|
+ * 3. Double buffering
|
|
+ * Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
|
|
+ * This way LVGL will always provide the whole rendered screen in `flush_cb`
|
|
+ * and you only need to change the frame buffer's address.
|
|
+ */
|
|
+
|
|
+ /* Example for 1) */
|
|
+ static lv_disp_draw_buf_t draw_buf_dsc_1;
|
|
+ buf_1 = memalign(64, lcd_w * lcd_h * 4);
|
|
+
|
|
+ lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, lcd_w * lcd_h); /*Initialize the display buffer*/
|
|
+
|
|
+ /*-----------------------------------
|
|
+ * Register the display in LVGL
|
|
+ *----------------------------------*/
|
|
+
|
|
+ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
|
+ lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
|
+
|
|
+ /*Set up the functions to access to your display*/
|
|
+
|
|
+ /*Set the resolution of the display*/
|
|
+ disp_drv.hor_res = lcd_w;
|
|
+ disp_drv.ver_res = lcd_h;
|
|
+
|
|
+ disp_drv.sw_rotate = 0;
|
|
+ disp_drv.rotated = LV_DISP_ROT_NONE;
|
|
+ /*Used to copy the buffer's content to the display*/
|
|
+ disp_drv.flush_cb = drm_flush;
|
|
+
|
|
+ /*Set a display buffer*/
|
|
+ disp_drv.draw_buf = &draw_buf_dsc_1;
|
|
+
|
|
+ /*Finally register the driver*/
|
|
+ lv_disp_drv_register(&disp_drv);
|
|
+ pthread_mutex_init(&draw_mutex, NULL);
|
|
+ pthread_create(&drm_thread_pid, NULL, drm_thread, NULL);
|
|
}
|
|
|
|
#endif
|
|
diff --git a/display/drm.h b/display/drm.h
|
|
index ebf2e28..74695a9 100644
|
|
--- a/display/drm.h
|
|
+++ b/display/drm.h
|
|
@@ -40,11 +40,10 @@ extern "C" {
|
|
/**********************
|
|
* GLOBAL PROTOTYPES
|
|
**********************/
|
|
-void drm_init(void);
|
|
-void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi);
|
|
-void drm_exit(void);
|
|
+int drm_init(int bpp);
|
|
+void drm_disp_drv_init(int rot);
|
|
+int drm_exit(void);
|
|
void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
|
|
-void drm_wait_vsync(lv_disp_drv_t * drv);
|
|
|
|
|
|
/**********************
|
|
--
|
|
2.25.1
|
|
|