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