1From bbe6d49bdcb7b6a53044f494e31a90f4eed65b0e Mon Sep 17 00:00:00 2001
2From: ZiHan Huang <zack.huang@rock-chips.com>
3Date: Fri, 6 Jan 2023 10:17:22 +0800
4Subject: [PATCH 6/8] drm: Reconstructs the drm display driver
5
6Signed-off-by: ZiHan Huang <zack.huang@rock-chips.com>
7---
8 display/drm.c | 1488 +++++++++++++++++++++++++++----------------------
9 display/drm.h |    7 +-
10 2 files changed, 832 insertions(+), 663 deletions(-)
11
12diff --git a/display/drm.c b/display/drm.c
13index 9cec6e3..17af072 100644
14--- a/display/drm.c
15+++ b/display/drm.c
16@@ -22,780 +22,950 @@
17 #include <errno.h>
18 #include <sys/mman.h>
19 #include <inttypes.h>
20+#include <poll.h>
21+#include <malloc.h>
22
23+#include <drm_fourcc.h>
24+#include <drm_mode.h>
25+#include <lvgl/lvgl.h>
26 #include <xf86drm.h>
27 #include <xf86drmMode.h>
28-#include <drm_fourcc.h>
29
30 #define DBG_TAG "drm"
31+#define NUM_DUMB_BO 3
32+#define VIDEO_PLANE_ENABLE 1
33+#define DEBUG
34+#ifdef DEBUG
35+#define DRM_DEBUG(fmt, ...) \
36+    if (getenv("MJPG_DRM_DEBUG")) \
37+        printf("DRM_DEBUG: %s(%d) " fmt, __func__, __LINE__, ##__VA_ARGS__)
38+#else
39+#define DRM_DEBUG(fmt, ...)
40+#endif
41
42-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
43-
44-#define print(msg, ...)	fprintf(stderr, msg, ##__VA_ARGS__);
45-#define err(msg, ...)  print("error: " msg "\n", ##__VA_ARGS__)
46-#define info(msg, ...) print(msg "\n", ##__VA_ARGS__)
47-#define dbg(msg, ...)  {} //print(DBG_TAG ": " msg "\n", ##__VA_ARGS__)
48-
49-struct drm_buffer {
50-	uint32_t handle;
51-	uint32_t pitch;
52-	uint32_t offset;
53-	unsigned long int size;
54-	void * map;
55-	uint32_t fb_handle;
56+#define ALIGN(x, a)     (((x) + (a - 1)) & ~(a - 1))
57+
58+struct drm_bo {
59+    int fd;
60+    void *ptr;
61+    size_t size;
62+    size_t offset;
63+    size_t pitch;
64+    unsigned int handle;
65+    int fb_id;
66+    int buf_fd;
67+    int w;
68+    int h;
69 };
70
71-struct drm_dev {
72-	int fd;
73-	uint32_t conn_id, enc_id, crtc_id, plane_id, crtc_idx;
74-	uint32_t width, height;
75-	uint32_t mmWidth, mmHeight;
76-	uint32_t fourcc;
77-	drmModeModeInfo mode;
78-	uint32_t blob_id;
79-	drmModeCrtc *saved_crtc;
80-	drmModeAtomicReq *req;
81-	drmEventContext drm_event_ctx;
82-	drmModePlane *plane;
83-	drmModeCrtc *crtc;
84-	drmModeConnector *conn;
85-	uint32_t count_plane_props;
86-	uint32_t count_crtc_props;
87-	uint32_t count_conn_props;
88-	drmModePropertyPtr plane_props[128];
89-	drmModePropertyPtr crtc_props[128];
90-	drmModePropertyPtr conn_props[128];
91-	struct drm_buffer drm_bufs[2]; /* DUMB buffers */
92-	struct drm_buffer *cur_bufs[2]; /* double buffering handling */
93-} drm_dev;
94+struct device {
95+    int fd;
96
97-static uint32_t get_plane_property_id(const char *name)
98-{
99-	uint32_t i;
100+    struct {
101+        int width;
102+        int height;
103
104-	dbg("Find plane property: %s", name);
105+        int hdisplay;
106+        int vdisplay;
107
108-	for (i = 0; i < drm_dev.count_plane_props; ++i)
109-		if (!strcmp(drm_dev.plane_props[i]->name, name))
110-			return drm_dev.plane_props[i]->prop_id;
111+        int current;
112+        int fb_num;
113+        int bpp;
114+    } mode;
115
116-	dbg("Unknown plane property: %s", name);
117+    drmModeResPtr res;
118
119-	return 0;
120-}
121+    int connector_id;
122+    int encoder_id;
123+    int crtc_id;
124+    int plane_id;
125+    int last_fb_id;
126
127-static uint32_t get_crtc_property_id(const char *name)
128-{
129-	uint32_t i;
130+    int waiting_for_flip;
131+    struct pollfd drm_pollfd;
132+    drmEventContext drm_evctx;
133+};
134
135-	dbg("Find crtc property: %s", name);
136+static int lcd_w;
137+static int lcd_h;
138+static int lcd_sw;
139+static char* drm_buff;
140+static lv_color_t *buf_1;
141
142-	for (i = 0; i < drm_dev.count_crtc_props; ++i)
143-		if (!strcmp(drm_dev.crtc_props[i]->name, name))
144-			return drm_dev.crtc_props[i]->prop_id;
145+static int quit = 0;
146+static pthread_t drm_thread_pid;
147+static pthread_mutex_t draw_mutex;
148+static int draw_update = 0;
149+static struct drm_bo *gbo;
150
151-	dbg("Unknown crtc property: %s", name);
152+struct device *pdev;
153
154-	return 0;
155+static int bo_map(struct device *dev, struct drm_bo *bo)
156+{
157+    struct drm_mode_map_dumb arg = {
158+        .handle = bo->handle,
159+    };
160+    struct drm_prime_handle fd_args = {
161+        .fd = -1,
162+        .handle = bo->handle,
163+        .flags = 0,
164+    };
165+    int ret;
166+
167+    ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
168+    if (ret)
169+        return ret;
170+
171+    ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &fd_args);
172+    if (ret)
173+    {
174+        printf("handle_to_fd failed ret=%d, handle=%x \n", ret ,fd_args.handle);
175+        return -1;
176+    }
177+    bo->buf_fd = fd_args.fd;
178+
179+    bo->ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
180+                   dev->fd, arg.offset);
181+    if (bo->ptr == MAP_FAILED) {
182+        bo->ptr = NULL;
183+        return -1;
184+    }
185+
186+    return 0;
187 }
188
189-static uint32_t get_conn_property_id(const char *name)
190+static void bo_unmap(struct device *dev, struct drm_bo *bo)
191 {
192-	uint32_t i;
193+    if (dev == NULL)
194+        return;
195+    if (!bo->ptr)
196+        return;
197+
198+    drmUnmap(bo->ptr, bo->size);
199+    if (bo->buf_fd > 0)
200+        close(bo->buf_fd);
201+    bo->ptr = NULL;
202+}
203
204-	dbg("Find conn property: %s", name);
205+void bo_destroy(struct device *dev, struct drm_bo *bo)
206+{
207+    struct drm_mode_destroy_dumb arg = {
208+        .handle = bo->handle,
209+    };
210
211-	for (i = 0; i < drm_dev.count_conn_props; ++i)
212-		if (!strcmp(drm_dev.conn_props[i]->name, name))
213-			return drm_dev.conn_props[i]->prop_id;
214+    if (bo->fb_id)
215+        drmModeRmFB(dev->fd, bo->fb_id);
216
217-	dbg("Unknown conn property: %s", name);
218+    bo_unmap(dev, bo);
219
220-	return 0;
221-}
222+    if (bo->handle)
223+        drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
224
225-static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
226-			      unsigned int tv_usec, void *user_data)
227-{
228-	dbg("flip");
229+    free(bo);
230 }
231
232-static int drm_get_plane_props(void)
233+static struct drm_bo *
234+bo_create(struct device *dev, int width, int height, int format)
235 {
236-	uint32_t i;
237-
238-	drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.plane_id,
239-								      DRM_MODE_OBJECT_PLANE);
240-	if (!props) {
241-		err("drmModeObjectGetProperties failed");
242-		return -1;
243-	}
244-	dbg("Found %u plane props", props->count_props);
245-	drm_dev.count_plane_props = props->count_props;
246-	for (i = 0; i < props->count_props; i++) {
247-		drm_dev.plane_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
248-		dbg("Added plane prop %u:%s", drm_dev.plane_props[i]->prop_id, drm_dev.plane_props[i]->name);
249-	}
250-	drmModeFreeObjectProperties(props);
251-
252-	return 0;
253+    struct drm_mode_create_dumb arg = {
254+        .bpp = 32,
255+        .width = ALIGN(width, 16),
256+        .height = ALIGN(height, 16),
257+    };
258+    struct drm_bo *bo;
259+    uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
260+    int ret;
261+
262+    bo = malloc(sizeof(struct drm_bo));
263+    if (bo == NULL) {
264+        fprintf(stderr, "allocate bo failed\n");
265+        return NULL;
266+    }
267+    memset(bo, 0, sizeof(*bo));
268+    if (format == DRM_FORMAT_NV12) {
269+        arg.bpp = 8;
270+        arg.height = height * 3 / 2;
271+    }
272+
273+    ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
274+    if (ret) {
275+        fprintf(stderr, "create dumb failed\n");
276+        goto err;
277+    }
278+
279+    bo->fd = dev->fd;
280+    bo->handle = arg.handle;
281+    bo->size = arg.size;
282+    bo->pitch = arg.pitch;
283+    bo->w = width;
284+    bo->h = height;
285+
286+    ret = bo_map(dev, bo);
287+    if (ret) {
288+        fprintf(stderr, "map bo failed\n");
289+        goto err;
290+    }
291+
292+    switch (format) {
293+    case DRM_FORMAT_NV12:
294+    case DRM_FORMAT_NV16:
295+      handles[0] = bo->handle;
296+      pitches[0] = bo->pitch ;
297+      offsets[0] = 0;
298+      handles[1] = bo->handle;
299+      pitches[1] = pitches[0];
300+      offsets[1] = pitches[0] * height;
301+      break;
302+    case DRM_FORMAT_RGB332:
303+      handles[0] = bo->handle;
304+      pitches[0] = bo->pitch;
305+      offsets[0] = 0;
306+      break;
307+    case DRM_FORMAT_RGB565:
308+    case DRM_FORMAT_BGR565:
309+      handles[0] = bo->handle;
310+      pitches[0] = bo->pitch ;
311+      offsets[0] = 0;
312+      break;
313+    case DRM_FORMAT_RGB888:
314+    case DRM_FORMAT_BGR888:
315+      handles[0] = bo->handle;
316+      pitches[0] = bo->pitch ;
317+      offsets[0] = 0;
318+      break;
319+    case DRM_FORMAT_ARGB8888:
320+    case DRM_FORMAT_ABGR8888:
321+    case DRM_FORMAT_RGBA8888:
322+    case DRM_FORMAT_BGRA8888:
323+      handles[0] = bo->handle;
324+      pitches[0] = bo->pitch ;
325+      offsets[0] = 0;
326+      break;
327+    }
328+
329+    ret = drmModeAddFB2(dev->fd, width, height, format, handles,
330+                        pitches, offsets, (uint32_t *)&bo->fb_id, 0);
331+    if (ret) {
332+        fprintf(stderr, "add fb failed\n");
333+        goto err;
334+    }
335+    DRM_DEBUG("Created bo: %d, %dx%d\n", bo->fb_id, width, height);
336+
337+    return bo;
338+err:
339+    bo_destroy(dev, bo);
340+    return NULL;
341 }
342
343-static int drm_get_crtc_props(void)
344+struct drm_bo *malloc_drm_bo(int width, int height, int format)
345 {
346-	uint32_t i;
347-
348-	drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.crtc_id,
349-								      DRM_MODE_OBJECT_CRTC);
350-	if (!props) {
351-		err("drmModeObjectGetProperties failed");
352-		return -1;
353-	}
354-	dbg("Found %u crtc props", props->count_props);
355-	drm_dev.count_crtc_props = props->count_props;
356-	for (i = 0; i < props->count_props; i++) {
357-		drm_dev.crtc_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
358-		dbg("Added crtc prop %u:%s", drm_dev.crtc_props[i]->prop_id, drm_dev.crtc_props[i]->name);
359-	}
360-	drmModeFreeObjectProperties(props);
361-
362-	return 0;
363+    struct device *dev = pdev;
364+    return bo_create(dev, width, height, format);
365 }
366
367-static int drm_get_conn_props(void)
368+void free_drm_bo(struct drm_bo *bo)
369 {
370-	uint32_t i;
371-
372-	drmModeObjectPropertiesPtr props = drmModeObjectGetProperties(drm_dev.fd, drm_dev.conn_id,
373-								      DRM_MODE_OBJECT_CONNECTOR);
374-	if (!props) {
375-		err("drmModeObjectGetProperties failed");
376-		return -1;
377-	}
378-	dbg("Found %u connector props", props->count_props);
379-	drm_dev.count_conn_props = props->count_props;
380-	for (i = 0; i < props->count_props; i++) {
381-		drm_dev.conn_props[i] = drmModeGetProperty(drm_dev.fd, props->props[i]);
382-		dbg("Added connector prop %u:%s", drm_dev.conn_props[i]->prop_id, drm_dev.conn_props[i]->name);
383-	}
384-	drmModeFreeObjectProperties(props);
385-
386-	return 0;
387+    struct device *dev = pdev;
388+    if (bo)
389+        bo_destroy(dev, bo);
390 }
391
392-static int drm_add_plane_property(const char *name, uint64_t value)
393+static void free_fb(struct device *dev)
394 {
395-	int ret;
396-	uint32_t prop_id = get_plane_property_id(name);
397-
398-	if (!prop_id) {
399-		err("Couldn't find plane prop %s", name);
400-		return -1;
401-	}
402+    DRM_DEBUG("Free fb, num: %d, bpp: %d\n", dev->mode.fb_num, dev->mode.bpp);
403
404-	ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.plane_id, get_plane_property_id(name), value);
405-	if (ret < 0) {
406-		err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
407-		return ret;
408-	}
409-
410-	return 0;
411+    dev->mode.fb_num = 0;
412+    dev->mode.bpp = 0;
413+    dev->mode.current = 0;
414 }
415
416-static int drm_add_crtc_property(const char *name, uint64_t value)
417+static int alloc_fb(struct device *dev, int num, int bpp)
418 {
419-	int ret;
420-	uint32_t prop_id = get_crtc_property_id(name);
421-
422-	if (!prop_id) {
423-		err("Couldn't find crtc prop %s", name);
424-		return -1;
425-	}
426+    DRM_DEBUG("Alloc fb num: %d, bpp: %d\n", num, bpp);
427
428-	ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.crtc_id, get_crtc_property_id(name), value);
429-	if (ret < 0) {
430-		err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
431-		return ret;
432-	}
433+    dev->mode.fb_num = num;
434+    dev->mode.bpp = bpp;
435+    dev->mode.current = 0;
436
437-	return 0;
438+    return 0;
439 }
440
441-static int drm_add_conn_property(const char *name, uint64_t value)
442+static int drm_get_preferred_connector(void)
443 {
444-	int ret;
445-	uint32_t prop_id = get_conn_property_id(name);
446-
447-	if (!prop_id) {
448-		err("Couldn't find conn prop %s", name);
449-		return -1;
450-	}
451-
452-	ret = drmModeAtomicAddProperty(drm_dev.req, drm_dev.conn_id, get_conn_property_id(name), value);
453-	if (ret < 0) {
454-		err("drmModeAtomicAddProperty (%s:%" PRIu64 ") failed: %d", name, value, ret);
455-		return ret;
456-	}
457-
458-	return 0;
459+    const char *path;
460+    char buf[256] = "\0";
461+    int fd;
462+
463+#define DRM_CONNECTOR_CFG_PATH_ENV	"DRM_CONNECTOR_CFG_PATH"
464+#define DRM_CONNECTOR_CFG_PATH_DEFAULT	"/tmp/drm_connector.cfg"
465+    path = getenv(DRM_CONNECTOR_CFG_PATH_ENV);
466+    if (!path)
467+        path = DRM_CONNECTOR_CFG_PATH_DEFAULT;
468+
469+    fd = open(path, O_RDONLY);
470+    if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
471+        DRM_DEBUG("Warning: read failed\n");
472+    }
473+    close(fd);
474+
475+    if (!buf[0])
476+        return -1;
477+
478+    return atoi(buf);
479 }
480
481-static int drm_dmabuf_set_plane(struct drm_buffer *buf)
482+static int drm_get_preferred_mode(int *width, int *height)
483 {
484-	int ret;
485-	static int first = 1;
486-	uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT;
487-
488-	drm_dev.req = drmModeAtomicAlloc();
489+    const char *path;
490+    char buf[256] = "\0";
491+    int fd, w, h;
492
493-	/* On first Atomic commit, do a modeset */
494-	if (first) {
495-		drm_add_conn_property("CRTC_ID", drm_dev.crtc_id);
496+#define DRM_MODE_CFG_PATH_ENV	"DRM_CONNECTOR_CFG_PATH"
497+#define DRM_MODE_CFG_PATH_DEFAULT	"/tmp/drm_mode.cfg"
498+    path = getenv(DRM_MODE_CFG_PATH_ENV);
499+    if (!path)
500+        path = DRM_MODE_CFG_PATH_DEFAULT;
501
502-		drm_add_crtc_property("MODE_ID", drm_dev.blob_id);
503-		drm_add_crtc_property("ACTIVE", 1);
504+    fd = open(path, O_RDONLY);
505+    if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
506+        DRM_DEBUG("Warning: read failed\n");
507+    }
508+    close(fd);
509
510-		flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
511+    if (!buf[0])
512+        return -1;
513
514-		first = 0;
515-	}
516+    if (2 != sscanf(buf, "%dx%d", &w, &h))
517+        return -1;
518
519-	drm_add_plane_property("FB_ID", buf->fb_handle);
520-	drm_add_plane_property("CRTC_ID", drm_dev.crtc_id);
521-	drm_add_plane_property("SRC_X", 0);
522-	drm_add_plane_property("SRC_Y", 0);
523-	drm_add_plane_property("SRC_W", drm_dev.width << 16);
524-	drm_add_plane_property("SRC_H", drm_dev.height << 16);
525-	drm_add_plane_property("CRTC_X", 0);
526-	drm_add_plane_property("CRTC_Y", 0);
527-	drm_add_plane_property("CRTC_W", drm_dev.width);
528-	drm_add_plane_property("CRTC_H", drm_dev.height);
529+    *width = w;
530+    *height = h;
531
532-	ret = drmModeAtomicCommit(drm_dev.fd, drm_dev.req, flags, NULL);
533-	if (ret) {
534-		err("drmModeAtomicCommit failed: %s", strerror(errno));
535-		drmModeAtomicFree(drm_dev.req);
536-		return ret;
537-	}
538-
539-	return 0;
540+    return 0;
541 }
542
543-static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
544+static drmModeConnectorPtr
545+drm_get_connector(struct device *dev, int connector_id)
546 {
547-	drmModePlaneResPtr planes;
548-	drmModePlanePtr plane;
549-	unsigned int i;
550-	unsigned int j;
551-	int ret = 0;
552-	unsigned int format = fourcc;
553-
554-	planes = drmModeGetPlaneResources(drm_dev.fd);
555-	if (!planes) {
556-		err("drmModeGetPlaneResources failed");
557-		return -1;
558-	}
559-
560-	dbg("drm: found planes %u", planes->count_planes);
561-
562-	for (i = 0; i < planes->count_planes; ++i) {
563-		plane = drmModeGetPlane(drm_dev.fd, planes->planes[i]);
564-		if (!plane) {
565-			err("drmModeGetPlane failed: %s", strerror(errno));
566-			break;
567-		}
568-
569-		if (!(plane->possible_crtcs & (1 << crtc_idx))) {
570-			drmModeFreePlane(plane);
571-			continue;
572-		}
573-
574-		for (j = 0; j < plane->count_formats; ++j) {
575-			if (plane->formats[j] == format)
576-				break;
577-		}
578+    drmModeConnectorPtr conn;
579
580-		if (j == plane->count_formats) {
581-			drmModeFreePlane(plane);
582-			continue;
583-		}
584+    conn = drmModeGetConnector(dev->fd, connector_id);
585+    if (!conn)
586+        return NULL;
587
588-		*plane_id = plane->plane_id;
589-		drmModeFreePlane(plane);
590+    DRM_DEBUG("Connector id: %d, %sconnected, modes: %d\n", connector_id,
591+              (conn->connection == DRM_MODE_CONNECTED) ? "" : "dis",
592+              conn->count_modes);
593+    if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes)
594+        return conn;
595
596-		dbg("found plane %d", *plane_id);
597+    drmModeFreeConnector(conn);
598+    return NULL;
599+}
600
601-		break;
602-	}
603+static drmModeConnectorPtr
604+drm_find_best_connector(struct device *dev)
605+{
606+    drmModeResPtr res = dev->res;
607+    drmModeConnectorPtr conn;
608+    int i, preferred_connector_id = drm_get_preferred_connector();
609+
610+    DRM_DEBUG("Preferred connector id: %d\n", preferred_connector_id);
611+    conn = drm_get_connector(dev, preferred_connector_id);
612+    if (conn)
613+        return conn;
614+
615+    for (i = 0; i < res->count_connectors; i++) {
616+        conn = drm_get_connector(dev, res->connectors[i]);
617+        if (conn)
618+            return conn;
619+    }
620+    return NULL;
621+}
622
623-	if (i == planes->count_planes)
624-		ret = -1;
625+static drmModeCrtcPtr
626+drm_find_best_crtc(struct device *dev, drmModeConnectorPtr conn)
627+{
628+    drmModeResPtr res = dev->res;
629+    drmModeEncoderPtr encoder;
630+    drmModeCrtcPtr crtc;
631+    int i, preferred_crtc_id = 0;
632+    int crtcs_for_connector = 0;
633+
634+    encoder = drmModeGetEncoder(dev->fd, conn->encoder_id);
635+    if (encoder) {
636+        preferred_crtc_id = encoder->crtc_id;
637+        drmModeFreeEncoder(encoder);
638+    }
639+    DRM_DEBUG("Preferred crtc: %d\n", preferred_crtc_id);
640+
641+    crtc = drmModeGetCrtc(dev->fd, preferred_crtc_id);
642+    if (crtc)
643+        return crtc;
644+
645+    for (i = 0; i < res->count_encoders; i++) {
646+        encoder = drmModeGetEncoder(dev->fd, res->encoders[i]);
647+        if (encoder)
648+            crtcs_for_connector |= encoder->possible_crtcs;
649+        drmModeFreeEncoder(encoder);
650+    }
651+    DRM_DEBUG("Possible crtcs: %x\n", crtcs_for_connector);
652+    if (!crtcs_for_connector)
653+        return NULL;
654+
655+    return drmModeGetCrtc(dev->fd, res->crtcs[ffs(crtcs_for_connector) - 1]);
656+}
657
658-	drmModeFreePlaneResources(planes);
659+int
660+drm_plane_is_primary(struct device *dev, int plane_id)
661+{
662+    drmModeObjectPropertiesPtr props;
663+    drmModePropertyPtr prop;
664+    unsigned int i;
665+    int type = 0;
666+
667+    props = drmModeObjectGetProperties(dev->fd, plane_id,
668+                                       DRM_MODE_OBJECT_PLANE);
669+    if (!props)
670+        return 0;
671+
672+    for (i = 0; i < props->count_props; i++) {
673+        prop = drmModeGetProperty(dev->fd, props->props[i]);
674+        if (prop && !strcmp(prop->name, "type"))
675+            type = props->prop_values[i];
676+        drmModeFreeProperty(prop);
677+    }
678+    DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
679+
680+    drmModeFreeObjectProperties(props);
681+    return type == DRM_PLANE_TYPE_PRIMARY;
682+}
683
684-	return ret;
685+int
686+drm_plane_is_overlay(struct device *dev, int plane_id)
687+{
688+    drmModeObjectPropertiesPtr props;
689+    drmModePropertyPtr prop;
690+    unsigned int i;
691+    int type = 0;
692+
693+    props = drmModeObjectGetProperties(dev->fd, plane_id,
694+                                       DRM_MODE_OBJECT_PLANE);
695+    if (!props)
696+        return 0;
697+
698+    for (i = 0; i < props->count_props; i++) {
699+        prop = drmModeGetProperty(dev->fd, props->props[i]);
700+        if (prop && !strcmp(prop->name, "type"))
701+            type = props->prop_values[i];
702+        drmModeFreeProperty(prop);
703+    }
704+    DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
705+
706+    drmModeFreeObjectProperties(props);
707+    return type == DRM_PLANE_TYPE_OVERLAY;
708 }
709
710-static int drm_find_connector(void)
711+static drmModePlanePtr
712+drm_get_plane(struct device *dev, int plane_id, int pipe)
713 {
714-	drmModeConnector *conn = NULL;
715-	drmModeEncoder *enc = NULL;
716-	drmModeRes *res;
717-	int i;
718+    drmModePlanePtr plane;
719
720-	if ((res = drmModeGetResources(drm_dev.fd)) == NULL) {
721-		err("drmModeGetResources() failed");
722-		return -1;
723-	}
724+    plane = drmModeGetPlane(dev->fd, plane_id);
725+    if (!plane)
726+        return NULL;
727
728-	if (res->count_crtcs <= 0) {
729-		err("no Crtcs");
730-		goto free_res;
731-	}
732-
733-	/* find all available connectors */
734-	for (i = 0; i < res->count_connectors; i++) {
735-		conn = drmModeGetConnector(drm_dev.fd, res->connectors[i]);
736-		if (!conn)
737-			continue;
738-
739-#if DRM_CONNECTOR_ID >= 0
740-		if (conn->connector_id != DRM_CONNECTOR_ID) {
741-			drmModeFreeConnector(conn);
742-			continue;
743-		}
744-#endif
745+    DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id,
746+              plane->possible_crtcs);
747+    if (drm_plane_is_primary(dev, plane_id)) {
748+        if (plane->possible_crtcs & (1 << pipe))
749+            return plane;
750+    }
751
752-		if (conn->connection == DRM_MODE_CONNECTED) {
753-			dbg("drm: connector %d: connected", conn->connector_id);
754-		} else if (conn->connection == DRM_MODE_DISCONNECTED) {
755-			dbg("drm: connector %d: disconnected", conn->connector_id);
756-		} else if (conn->connection == DRM_MODE_UNKNOWNCONNECTION) {
757-			dbg("drm: connector %d: unknownconnection", conn->connector_id);
758-		} else {
759-			dbg("drm: connector %d: unknown", conn->connector_id);
760-		}
761-
762-		if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0)
763-			break;
764-
765-		drmModeFreeConnector(conn);
766-		conn = NULL;
767-	};
768-
769-	if (!conn) {
770-		err("suitable connector not found");
771-		goto free_res;
772-	}
773+    drmModeFreePlane(plane);
774+    return NULL;
775+}
776
777-	drm_dev.conn_id = conn->connector_id;
778-	dbg("conn_id: %d", drm_dev.conn_id);
779-	drm_dev.mmWidth = conn->mmWidth;
780-	drm_dev.mmHeight = conn->mmHeight;
781+static drmModePlanePtr
782+drm_find_best_plane(struct device *dev, drmModeCrtcPtr crtc)
783+{
784+    drmModeResPtr res = dev->res;
785+    drmModePlaneResPtr pres;
786+    drmModePlanePtr plane;
787+    unsigned int i;
788+    int pipe;
789+
790+    for (pipe = 0; pipe < res->count_crtcs; pipe++) {
791+        if (crtc->crtc_id == res->crtcs[pipe])
792+            break;
793+    }
794+    if (pipe == res->count_crtcs)
795+        return NULL;
796+
797+    pres = drmModeGetPlaneResources(dev->fd);
798+    if (!pres)
799+        return NULL;
800+
801+    for (i = 0; i < pres->count_planes; i++) {
802+        plane = drm_get_plane(dev, pres->planes[i], pipe);
803+        if (plane) {
804+            drmModeFreePlaneResources(pres);
805+            return plane;
806+        }
807+        drmModeFreePlane(plane);
808+    }
809+
810+    drmModeFreePlaneResources(pres);
811+    return NULL;
812+}
813
814-	memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
815+static drmModeModeInfoPtr
816+drm_find_best_mode(struct device *dev, drmModeConnectorPtr conn)
817+{
818+    drmModeModeInfoPtr mode;
819+    int i, preferred_width = 1920, preferred_height = 1080;
820+
821+    if (dev == NULL)
822+        return 0;
823+    drm_get_preferred_mode(&preferred_width, &preferred_height);
824+    DRM_DEBUG("Preferred mode: %dx%d\n", preferred_width, preferred_height);
825+
826+    mode = &conn->modes[0];
827+    for (i = 0; i < conn->count_modes; i++) {
828+        DRM_DEBUG("Check mode: %dx%d\n",
829+                conn->modes[i].hdisplay, conn->modes[i].vdisplay);
830+        if (conn->modes[i].hdisplay == preferred_width &&
831+                conn->modes[i].vdisplay == preferred_height) {
832+            mode = &conn->modes[i];
833+            break;
834+        }
835+    }
836+
837+    return mode;
838+}
839
840-	if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
841-				      &drm_dev.blob_id)) {
842-		err("error creating mode blob");
843-		goto free_res;
844-	}
845+static int drm_get_preferred_fb_mode(int *width, int *height)
846+{
847+    char *buf;
848+    int w, h;
849
850-	drm_dev.width = conn->modes[0].hdisplay;
851-	drm_dev.height = conn->modes[0].vdisplay;
852+    buf = getenv("MINIGUI_DRM_FB_MODE");
853+    if (!buf)
854+        return -1;
855
856-	for (i = 0 ; i < res->count_encoders; i++) {
857-		enc = drmModeGetEncoder(drm_dev.fd, res->encoders[i]);
858-		if (!enc)
859-			continue;
860-
861-		dbg("enc%d enc_id %d conn enc_id %d", i, enc->encoder_id, conn->encoder_id);
862-
863-		if (enc->encoder_id == conn->encoder_id)
864-			break;
865-
866-		drmModeFreeEncoder(enc);
867-		enc = NULL;
868-	}
869-
870-	if (enc) {
871-		drm_dev.enc_id = enc->encoder_id;
872-		dbg("enc_id: %d", drm_dev.enc_id);
873-		drm_dev.crtc_id = enc->crtc_id;
874-		dbg("crtc_id: %d", drm_dev.crtc_id);
875-		drmModeFreeEncoder(enc);
876-	} else {
877-		/* Encoder hasn't been associated yet, look it up */
878-		for (i = 0; i < conn->count_encoders; i++) {
879-			int crtc, crtc_id = -1;
880-
881-			enc = drmModeGetEncoder(drm_dev.fd, conn->encoders[i]);
882-			if (!enc)
883-				continue;
884-
885-			for (crtc = 0 ; crtc < res->count_crtcs; crtc++) {
886-				uint32_t crtc_mask = 1 << crtc;
887-
888-				crtc_id = res->crtcs[crtc];
889-
890-				dbg("enc_id %d crtc%d id %d mask %x possible %x", enc->encoder_id, crtc, crtc_id, crtc_mask, enc->possible_crtcs);
891-
892-				if (enc->possible_crtcs & crtc_mask)
893-					break;
894-			}
895-
896-			if (crtc_id > 0) {
897-				drm_dev.enc_id = enc->encoder_id;
898-				dbg("enc_id: %d", drm_dev.enc_id);
899-				drm_dev.crtc_id = crtc_id;
900-				dbg("crtc_id: %d", drm_dev.crtc_id);
901-				break;
902-			}
903-
904-			drmModeFreeEncoder(enc);
905-			enc = NULL;
906-		}
907-
908-		if (!enc) {
909-			err("suitable encoder not found");
910-			goto free_res;
911-		}
912-
913-		drmModeFreeEncoder(enc);
914-	}
915-
916-	drm_dev.crtc_idx = -1;
917-
918-	for (i = 0; i < res->count_crtcs; ++i) {
919-		if (drm_dev.crtc_id == res->crtcs[i]) {
920-			drm_dev.crtc_idx = i;
921-			break;
922-		}
923-	}
924-
925-	if (drm_dev.crtc_idx == -1) {
926-		err("drm: CRTC not found");
927-		goto free_res;
928-	}
929+    if (2 != sscanf(buf, "%dx%d", &w, &h))
930+        return -1;
931
932-	dbg("crtc_idx: %d", drm_dev.crtc_idx);
933-
934-	return 0;
935+    DRM_DEBUG("Preferred fb mode: %dx%d\n", w, h);
936+    *width = w;
937+    *height = h;
938
939-free_res:
940-	drmModeFreeResources(res);
941-
942-	return -1;
943+    return 0;
944 }
945
946-static int drm_open(const char *path)
947+static void drm_setup_fb_mode(struct device *dev)
948 {
949-	int fd, flags;
950-	uint64_t has_dumb;
951-	int ret;
952-
953-	fd = open(path, O_RDWR);
954-	if (fd < 0) {
955-		err("cannot open \"%s\"", path);
956-		return -1;
957-	}
958+    drmModeResPtr res = dev->res;
959+    drmModeConnectorPtr conn;
960+    drmModeModeInfoPtr mode;
961+    int i;
962+
963+    if (dev->mode.width && dev->mode.height)
964+        return;
965+
966+    if (!drm_get_preferred_fb_mode(&dev->mode.width, &dev->mode.height))
967+        return;
968+
969+    dev->mode.width = dev->mode.hdisplay;
970+    dev->mode.height = dev->mode.vdisplay;
971+
972+    for (i = 0; i < res->count_connectors; i++) {
973+        conn = drm_get_connector(dev, res->connectors[i]);
974+        if (!conn)
975+            continue;
976+
977+        mode = drm_find_best_mode(dev, conn);
978+        if (mode) {
979+            DRM_DEBUG("Best mode for connector(%d): %dx%d\n",
980+                      conn->connector_id, mode->hdisplay, mode->vdisplay);
981+            if (dev->mode.width > mode->hdisplay ||
982+                    dev->mode.height > mode->vdisplay) {
983+                dev->mode.width = mode->hdisplay;
984+                dev->mode.height = mode->vdisplay;
985+            }
986+        }
987+        drmModeFreeConnector(conn);
988+    }
989+}
990
991-	/* set FD_CLOEXEC flag */
992-	if ((flags = fcntl(fd, F_GETFD)) < 0 ||
993-	     fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
994-		err("fcntl FD_CLOEXEC failed");
995-		goto err;
996-	}
997+static void drm_free(struct device *dev)
998+{
999+    int i;
1000+
1001+    if (dev->res) {
1002+        drmModeFreeResources(dev->res);
1003+        dev->res = NULL;
1004+    }
1005+
1006+    dev->connector_id = 0;
1007+    dev->crtc_id = 0;
1008+    dev->plane_id = 0;
1009+    dev->mode.hdisplay = 0;
1010+    dev->mode.vdisplay = 0;
1011+}
1012
1013-	/* check capability */
1014-	ret = drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb);
1015-	if (ret < 0 || has_dumb == 0) {
1016-		err("drmGetCap DRM_CAP_DUMB_BUFFER failed or \"%s\" doesn't have dumb "
1017-		    "buffer", path);
1018-		goto err;
1019-	}
1020-
1021-	return fd;
1022-err:
1023-	close(fd);
1024-	return -1;
1025-}
1026-
1027-static int drm_setup(unsigned int fourcc)
1028-{
1029-	int ret;
1030-	const char *device_path = NULL;
1031-
1032-	device_path = getenv("DRM_CARD");
1033-	if (!device_path)
1034-		device_path = DRM_CARD;
1035-
1036-	drm_dev.fd = drm_open(device_path);
1037-	if (drm_dev.fd < 0)
1038-		return -1;
1039-
1040-	ret = drmSetClientCap(drm_dev.fd, DRM_CLIENT_CAP_ATOMIC, 1);
1041-	if (ret) {
1042-		err("No atomic modesetting support: %s", strerror(errno));
1043-		goto err;
1044-	}
1045-
1046-	ret = drm_find_connector();
1047-	if (ret) {
1048-		err("available drm devices not found");
1049-		goto err;
1050-	}
1051-
1052-	ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
1053-	if (ret) {
1054-		err("Cannot find plane");
1055-		goto err;
1056-	}
1057-
1058-	drm_dev.plane = drmModeGetPlane(drm_dev.fd, drm_dev.plane_id);
1059-	if (!drm_dev.plane) {
1060-		err("Cannot get plane");
1061-		goto err;
1062-	}
1063-
1064-	drm_dev.crtc = drmModeGetCrtc(drm_dev.fd, drm_dev.crtc_id);
1065-	if (!drm_dev.crtc) {
1066-		err("Cannot get crtc");
1067-		goto err;
1068-	}
1069-
1070-	drm_dev.conn = drmModeGetConnector(drm_dev.fd, drm_dev.conn_id);
1071-	if (!drm_dev.conn) {
1072-		err("Cannot get connector");
1073-		goto err;
1074-	}
1075-
1076-	ret = drm_get_plane_props();
1077-	if (ret) {
1078-		err("Cannot get plane props");
1079-		goto err;
1080-	}
1081-
1082-	ret = drm_get_crtc_props();
1083-	if (ret) {
1084-		err("Cannot get crtc props");
1085-		goto err;
1086-	}
1087-
1088-	ret = drm_get_conn_props();
1089-	if (ret) {
1090-		err("Cannot get connector props");
1091-		goto err;
1092-	}
1093-
1094-	drm_dev.drm_event_ctx.version = DRM_EVENT_CONTEXT_VERSION;
1095-	drm_dev.drm_event_ctx.page_flip_handler = page_flip_handler;
1096-	drm_dev.fourcc = fourcc;
1097-
1098-	info("drm: Found plane_id: %u connector_id: %d crtc_id: %d",
1099-		drm_dev.plane_id, drm_dev.conn_id, drm_dev.crtc_id);
1100-
1101-	info("drm: %dx%d (%dmm X% dmm) pixel format %c%c%c%c",
1102-	     drm_dev.width, drm_dev.height, drm_dev.mmWidth, drm_dev.mmHeight,
1103-	     (fourcc>>0)&0xff, (fourcc>>8)&0xff, (fourcc>>16)&0xff, (fourcc>>24)&0xff);
1104-
1105-	return 0;
1106+static void configure_plane_zpos(struct device *self, int plane_id, uint64_t zpos)
1107+{
1108+    drmModeObjectPropertiesPtr props = NULL;
1109+    drmModePropertyPtr prop = NULL;
1110+    char *buf;
1111+    unsigned int i;
1112+
1113+    if (plane_id <= 0)
1114+        return;
1115+
1116+    if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_ATOMIC, 1))
1117+        return;
1118+
1119+    props = drmModeObjectGetProperties (self->fd, plane_id,
1120+          DRM_MODE_OBJECT_PLANE);
1121+    if (!props)
1122+        goto out;
1123+
1124+    for (i = 0; i < props->count_props; i++) {
1125+        prop = drmModeGetProperty (self->fd, props->props[i]);
1126+        if (prop && !strcmp (prop->name, "ZPOS"))
1127+          break;
1128+        drmModeFreeProperty (prop);
1129+        prop = NULL;
1130+    }
1131+
1132+    if (!prop)
1133+        goto out;
1134+
1135+    drmModeObjectSetProperty (self->fd, plane_id,
1136+          DRM_MODE_OBJECT_PLANE, props->props[i], zpos);
1137+out:
1138+    drmModeFreeProperty (prop);
1139+    drmModeFreeObjectProperties (props);
1140+}
1141
1142+static int drm_setup(struct device *dev)
1143+{
1144+    drmModeConnectorPtr conn = NULL;
1145+    drmModeModeInfoPtr mode;
1146+    drmModePlanePtr plane = NULL;
1147+    drmModeCrtcPtr crtc = NULL;
1148+    //int ret;
1149+    int i, success = 0;
1150+
1151+    dev->res = drmModeGetResources(dev->fd);
1152+    if (!dev->res) {
1153+        fprintf(stderr, "drm get resource failed\n");
1154+        goto err;
1155+    }
1156+
1157+    conn = drm_find_best_connector(dev);
1158+    if (!conn) {
1159+        fprintf(stderr, "drm find connector failed\n");
1160+        goto err;
1161+    }
1162+    DRM_DEBUG("Best connector id: %d\n", conn->connector_id);
1163+
1164+    mode = drm_find_best_mode(dev, conn);
1165+    if (!mode) {
1166+        fprintf(stderr, "drm find mode failed\n");
1167+        goto err;
1168+    }
1169+    DRM_DEBUG("Best mode: %dx%d\n", mode->hdisplay, mode->vdisplay);
1170+
1171+    crtc = drm_find_best_crtc(dev, conn);
1172+    if (!crtc) {
1173+        fprintf(stderr, "drm find crtc failed\n");
1174+        goto err;
1175+    }
1176+    DRM_DEBUG("Best crtc: %d\n", crtc->crtc_id);
1177+
1178+    plane = drm_find_best_plane(dev, crtc);
1179+    if (!plane) {
1180+        fprintf(stderr, "drm find plane failed\n");
1181+        goto err;
1182+    }
1183+    configure_plane_zpos(dev, plane->plane_id, 1);
1184+    printf("Best plane: %d\n", plane->plane_id);
1185+    dev->connector_id = conn->connector_id;
1186+    dev->crtc_id = crtc->crtc_id;
1187+    dev->plane_id = plane->plane_id;
1188+    dev->last_fb_id = 0;
1189+    dev->mode.hdisplay = mode->hdisplay;
1190+    dev->mode.vdisplay = mode->vdisplay;
1191+
1192+    drm_setup_fb_mode(dev);
1193+    DRM_DEBUG("Drm fb mode: %dx%d\n", dev->mode.width, dev->mode.height);
1194+
1195+    success = 1;
1196 err:
1197-	close(drm_dev.fd);
1198-	return -1;
1199-}
1200-
1201-static int drm_allocate_dumb(struct drm_buffer *buf)
1202-{
1203-	struct drm_mode_create_dumb creq;
1204-	struct drm_mode_map_dumb mreq;
1205-	uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
1206-	int ret;
1207-
1208-	/* create dumb buffer */
1209-	memset(&creq, 0, sizeof(creq));
1210-	creq.width = drm_dev.width;
1211-	creq.height = drm_dev.height;
1212-	creq.bpp = LV_COLOR_DEPTH;
1213-	ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq);
1214-	if (ret < 0) {
1215-		err("DRM_IOCTL_MODE_CREATE_DUMB fail");
1216-		return -1;
1217-	}
1218-
1219-	buf->handle = creq.handle;
1220-	buf->pitch = creq.pitch;
1221-	dbg("pitch %d", buf->pitch);
1222-	buf->size = creq.size;
1223-	dbg("size %d", buf->size);
1224-
1225-	/* prepare buffer for memory mapping */
1226-	memset(&mreq, 0, sizeof(mreq));
1227-	mreq.handle = creq.handle;
1228-	ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
1229-	if (ret) {
1230-		err("DRM_IOCTL_MODE_MAP_DUMB fail");
1231-		return -1;
1232-	}
1233-
1234-	buf->offset = mreq.offset;
1235-
1236-	/* perform actual memory mapping */
1237-	buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
1238-	if (buf->map == MAP_FAILED) {
1239-		err("mmap fail");
1240-		return -1;
1241-	}
1242-
1243-	/* clear the framebuffer to 0 (= full transparency in ARGB8888) */
1244-	memset(buf->map, 0, creq.size);
1245-
1246-	/* create framebuffer object for the dumb-buffer */
1247-	handles[0] = creq.handle;
1248-	pitches[0] = creq.pitch;
1249-	offsets[0] = 0;
1250-	ret = drmModeAddFB2(drm_dev.fd, drm_dev.width, drm_dev.height, drm_dev.fourcc,
1251-			    handles, pitches, offsets, &buf->fb_handle, 0);
1252-	if (ret) {
1253-		err("drmModeAddFB fail");
1254-		return -1;
1255-	}
1256-
1257-	return 0;
1258+    drmModeFreeConnector(conn);
1259+    drmModeFreePlane(plane);
1260+    drmModeFreeCrtc(crtc);
1261+    if (!success) {
1262+        drm_free(dev);
1263+        return -1;
1264+    }
1265+    return 0;
1266 }
1267
1268-static int drm_setup_buffers(void)
1269+static void drm_flip_handler(int fd, unsigned frame, unsigned sec,
1270+                             unsigned usec, void *data)
1271 {
1272-	int ret;
1273-
1274-	/* Allocate DUMB buffers */
1275-	ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
1276-	if (ret)
1277-		return ret;
1278-
1279-	ret = drm_allocate_dumb(&drm_dev.drm_bufs[1]);
1280-	if (ret)
1281-		return ret;
1282-
1283-	/* Set buffering handling */
1284-	drm_dev.cur_bufs[0] = NULL;
1285-	drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
1286-
1287-	return 0;
1288+    // data is &dev->waiting_for_flip
1289+    DRM_DEBUG("Page flip received(%d)!, %d, %d, %d, %d\n", *(int*)data, fd, frame, sec, usec);
1290+    *(int*)data = 0;
1291 }
1292
1293-void drm_wait_vsync(lv_disp_drv_t *disp_drv)
1294+int drm_init(int bpp)
1295 {
1296-	int ret;
1297-	fd_set fds;
1298-	FD_ZERO(&fds);
1299-	FD_SET(drm_dev.fd, &fds);
1300-
1301-	do {
1302-		ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL);
1303-	} while (ret == -1 && errno == EINTR);
1304-
1305-	if (ret < 0) {
1306-		err("select failed: %s", strerror(errno));
1307-		drmModeAtomicFree(drm_dev.req);
1308-		drm_dev.req = NULL;
1309-		return;
1310-	}
1311-
1312-	if (FD_ISSET(drm_dev.fd, &fds))
1313-		drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
1314-
1315-	drmModeAtomicFree(drm_dev.req);
1316-	drm_dev.req = NULL;
1317+    int ret;
1318+
1319+    pdev = malloc(sizeof(struct device));
1320+    if (pdev == NULL) {
1321+        fprintf(stderr, "allocate device failed\n");
1322+        return -1;
1323+    }
1324+    memset(pdev, 0, sizeof(*pdev));
1325+
1326+    //drm_install_sighandler(pdev);
1327+
1328+    pdev->fd = drmOpen(NULL, NULL);
1329+    if (pdev->fd < 0)
1330+        pdev->fd = open("/dev/dri/card0", O_RDWR);
1331+    if (pdev->fd < 0) {
1332+        fprintf(stderr, "drm open failed\n");
1333+        goto err_drm_open;
1334+    }
1335+    fcntl(pdev->fd, F_SETFD, FD_CLOEXEC);
1336+
1337+    drmSetClientCap(pdev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1338+
1339+    ret = alloc_fb(pdev, NUM_DUMB_BO, bpp);
1340+    if (ret) {
1341+        fprintf(stderr, "alloc fb failed\n");
1342+        goto err_alloc_fb;
1343+    }
1344+
1345+    ret = drm_setup(pdev);
1346+    if (ret) {
1347+        fprintf(stderr, "drm setup failed\n");
1348+        goto err_drm_setup;
1349+    }
1350+
1351+    pdev->drm_pollfd.fd = pdev->fd;
1352+    pdev->drm_pollfd.events = POLLIN;
1353+
1354+    pdev->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
1355+    pdev->drm_evctx.page_flip_handler = drm_flip_handler;
1356+
1357+    return 0;
1358+err_alloc_fb:
1359+    drm_free(pdev);
1360+err_drm_setup:
1361+    drmClose(pdev->fd);
1362+err_drm_open:
1363+    free(pdev);
1364+    pdev = NULL;
1365+    return -1;
1366 }
1367
1368-void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
1369+int drm_exit(void)
1370 {
1371-	struct drm_buffer *fbuf = drm_dev.cur_bufs[1];
1372-	lv_coord_t w = (area->x2 - area->x1 + 1);
1373-	lv_coord_t h = (area->y2 - area->y1 + 1);
1374-	int i, y;
1375+    struct device* dev = pdev;
1376+    if (!dev)
1377+        return 0;
1378
1379-	dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h);
1380+    free_fb(dev);
1381+    drm_free(dev);
1382
1383-	/* Partial update */
1384-	if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0])
1385-		memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size);
1386+    if (pdev->fd > 0)
1387+        drmClose(dev->fd);
1388
1389-	for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) {
1390-                memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i),
1391-                       (uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
1392-		       w * (LV_COLOR_SIZE/8));
1393-	}
1394+    free(pdev);
1395+    pdev = NULL;
1396
1397-	if (drm_dev.req)
1398-		drm_wait_vsync(disp_drv);
1399+    return 0;
1400+}
1401
1402-	/* show fbuf plane */
1403-	if (drm_dmabuf_set_plane(fbuf)) {
1404-		err("Flush fail");
1405-		return;
1406-	}
1407-	else
1408-		dbg("Flush done");
1409+int getdrmfd(void)
1410+{
1411+    return pdev->fd;
1412+}
1413
1414-	if (!drm_dev.cur_bufs[0])
1415-		drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1];
1416-	else
1417-		drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
1418+static void drm_wait_flip(struct device* dev, int timeout)
1419+{
1420+    int ret;
1421
1422-	drm_dev.cur_bufs[0] = fbuf;
1423+    while (dev->waiting_for_flip) {
1424+        dev->drm_pollfd.revents = 0;
1425+        ret = poll(&dev->drm_pollfd, 1, timeout);
1426+        if (ret <= 0)
1427+            return;
1428
1429-	lv_disp_flush_ready(disp_drv);
1430+        drmHandleEvent(dev->fd, &dev->drm_evctx);
1431+    }
1432 }
1433
1434-#if LV_COLOR_DEPTH == 32
1435-#define DRM_FOURCC DRM_FORMAT_ARGB8888
1436-#elif LV_COLOR_DEPTH == 16
1437-#define DRM_FOURCC DRM_FORMAT_RGB565
1438-#else
1439-#error LV_COLOR_DEPTH not supported
1440-#endif
1441-
1442-void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
1443+void setdrmdisp(struct drm_bo *bo)
1444 {
1445-	if (width)
1446-		*width = drm_dev.width;
1447-
1448-	if (height)
1449-		*height = drm_dev.height;
1450-
1451-	if (dpi && drm_dev.mmWidth)
1452-		*dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
1453+    struct device* dev = pdev;
1454+    int crtc_x, crtc_y, crtc_w, crtc_h;
1455+    int ret;
1456+    int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height;
1457+
1458+    if (dev == NULL)
1459+        return;
1460+
1461+    crtc_w = dev->mode.width;
1462+    crtc_h = dev->mode.height;
1463+    crtc_x = 0;
1464+    crtc_y = 0;
1465+
1466+    DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh,
1467+             crtc_x, crtc_y, crtc_w, crtc_h);
1468+    ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, fb, 0,
1469+                          crtc_x, crtc_y, crtc_w, crtc_h,
1470+                          0, 0, sw << 16, sh << 16);
1471+    if (ret) {
1472+        fprintf(stderr, "drm set plane failed\n");
1473+        return;
1474+    }
1475+    if (0) {
1476+        // Queue page flip
1477+        dev->waiting_for_flip = 1;
1478+        ret = drmModePageFlip(dev->fd, dev->crtc_id, fb,
1479+                              DRM_MODE_PAGE_FLIP_EVENT, &dev->waiting_for_flip);
1480+        if (ret) {
1481+            fprintf(stderr, "drm page flip failed\n");
1482+            return;
1483+        }
1484+        // Wait for last page flip
1485+        drm_wait_flip(dev, -1);
1486+    }
1487 }
1488
1489-void drm_init(void)
1490+void getdrmresolve(int *w, int *h)
1491 {
1492-	int ret;
1493+    *w = pdev->mode.width;
1494+    *h = pdev->mode.height;
1495+}
1496
1497-	ret = drm_setup(DRM_FOURCC);
1498-	if (ret) {
1499-		close(drm_dev.fd);
1500-		drm_dev.fd = -1;
1501-		return;
1502-	}
1503+static void *drm_thread(void *arg)
1504+{
1505+    while (!quit) {
1506+        pthread_mutex_lock(&draw_mutex);
1507+        if (draw_update) {
1508+            setdrmdisp(gbo);
1509+            draw_update = 0;
1510+        }
1511+        pthread_mutex_unlock(&draw_mutex);
1512+        usleep(10000);
1513+    }
1514+    return NULL;
1515+}
1516
1517-	ret = drm_setup_buffers();
1518-	if (ret) {
1519-		err("DRM buffer allocation failed");
1520-		close(drm_dev.fd);
1521-		drm_dev.fd = -1;
1522-		return;
1523-	}
1524+void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
1525+{
1526+   /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
1527+    int32_t x;
1528+    int32_t y;
1529+
1530+    pthread_mutex_lock(&draw_mutex);
1531+    for(y = area->y1; y <= area->y2; y++) {
1532+        int area_w = area->x2 - area->x1 + 1;
1533+        lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_sw + area->x1) * 4);
1534+        memcpy(disp, color_p, area_w * 4);
1535+        color_p += area_w;
1536+    }
1537+    draw_update = 1;
1538+    pthread_mutex_unlock(&draw_mutex);
1539+    /*IMPORTANT!!!
1540+     *Inform the graphics library that you are ready with the flushing*/
1541+    lv_disp_flush_ready(disp_drv);
1542+}
1543
1544-	info("DRM subsystem and buffer mapped successfully");
1545+void disp_init(void)
1546+{
1547+    /*You code here*/
1548+    drm_init(32);
1549+    getdrmresolve(&lcd_w, &lcd_h);
1550+    gbo = malloc_drm_bo(lcd_w, lcd_h, DRM_FORMAT_ARGB8888);
1551+    drm_buff = gbo->ptr;
1552+    lcd_sw = gbo->pitch / 4;
1553+
1554+    printf("DRM subsystem and buffer mapped successfully\n");
1555 }
1556
1557-void drm_exit(void)
1558+void drm_disp_drv_init(int rot)
1559 {
1560-	close(drm_dev.fd);
1561-	drm_dev.fd = -1;
1562+    /*-------------------------
1563+     * Initialize your display
1564+     * -----------------------*/
1565+    disp_init();
1566+
1567+    /*-----------------------------
1568+     * Create a buffer for drawing
1569+     *----------------------------*/
1570+
1571+    /**
1572+     * LVGL requires a buffer where it internally draws the widgets.
1573+     * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
1574+     * The buffer has to be greater than 1 display row
1575+     *
1576+     * There are 3 buffering configurations:
1577+     * 1. Create ONE buffer:
1578+     *      LVGL will draw the display's content here and writes it to your display
1579+     *
1580+     * 2. Create TWO buffer:
1581+     *      LVGL will draw the display's content to a buffer and writes it your display.
1582+     *      You should use DMA to write the buffer's content to the display.
1583+     *      It will enable LVGL to draw the next part of the screen to the other buffer while
1584+     *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
1585+     *
1586+     * 3. Double buffering
1587+     *      Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
1588+     *      This way LVGL will always provide the whole rendered screen in `flush_cb`
1589+     *      and you only need to change the frame buffer's address.
1590+     */
1591+
1592+    /* Example for 1) */
1593+    static lv_disp_draw_buf_t draw_buf_dsc_1;
1594+    buf_1 = memalign(64, lcd_w * lcd_h * 4);
1595+
1596+    lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, lcd_w * lcd_h);   /*Initialize the display buffer*/
1597+
1598+    /*-----------------------------------
1599+     * Register the display in LVGL
1600+     *----------------------------------*/
1601+
1602+    static lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
1603+    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/
1604+
1605+    /*Set up the functions to access to your display*/
1606+
1607+    /*Set the resolution of the display*/
1608+    disp_drv.hor_res = lcd_w;
1609+    disp_drv.ver_res = lcd_h;
1610+
1611+    disp_drv.sw_rotate = 0;
1612+    disp_drv.rotated = LV_DISP_ROT_NONE;
1613+    /*Used to copy the buffer's content to the display*/
1614+    disp_drv.flush_cb = drm_flush;
1615+
1616+    /*Set a display buffer*/
1617+    disp_drv.draw_buf = &draw_buf_dsc_1;
1618+
1619+    /*Finally register the driver*/
1620+    lv_disp_drv_register(&disp_drv);
1621+    pthread_mutex_init(&draw_mutex, NULL);
1622+    pthread_create(&drm_thread_pid, NULL, drm_thread, NULL);
1623 }
1624
1625 #endif
1626diff --git a/display/drm.h b/display/drm.h
1627index ebf2e28..74695a9 100644
1628--- a/display/drm.h
1629+++ b/display/drm.h
1630@@ -40,11 +40,10 @@ extern "C" {
1631 /**********************
1632  * GLOBAL PROTOTYPES
1633  **********************/
1634-void drm_init(void);
1635-void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi);
1636-void drm_exit(void);
1637+int drm_init(int bpp);
1638+void drm_disp_drv_init(int rot);
1639+int drm_exit(void);
1640 void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
1641-void drm_wait_vsync(lv_disp_drv_t * drv);
1642
1643
1644 /**********************
1645--
16462.25.1
1647
1648