HYL_OK3568_LINUX/buildroot/package/lvgl/lv_drivers/0006-drm-Reconstructs-the-drm-display-driver.patch
2025-05-10 21:49:39 +08:00

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