From bbe6d49bdcb7b6a53044f494e31a90f4eed65b0e Mon Sep 17 00:00:00 2001 From: ZiHan Huang Date: Fri, 6 Jan 2023 10:17:22 +0800 Subject: [PATCH 6/8] drm: Reconstructs the drm display driver Signed-off-by: ZiHan Huang --- 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 #include #include +#include +#include +#include +#include +#include #include #include -#include #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