diff --git a/src/drivers/display/drm/lv_linux_drm.c b/src/drivers/display/drm/lv_linux_drm.c index 050556e06b..50ee6e0293 100644 --- a/src/drivers/display/drm/lv_linux_drm.c +++ b/src/drivers/display/drm/lv_linux_drm.c @@ -26,11 +26,9 @@ #include "../../../draw/lv_draw_buf.h" #if LV_USE_LINUX_DRM_GBM_BUFFERS - #include #include #include - #endif /********************* @@ -118,6 +116,7 @@ static int drm_dmabuf_set_plane(drm_dev_t * drm_dev, drm_buffer_t * buf); static void drm_flush_wait(lv_display_t * drm_dev); static void drm_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map); static void drm_dmabuf_set_active_buf(lv_event_t * event); +static void drm_del_event_cb(lv_event_t * event); /********************** * STATIC VARIABLES @@ -154,6 +153,7 @@ lv_display_t * lv_linux_drm_create(void) lv_display_set_driver_data(disp, drm_dev); lv_display_set_flush_wait_cb(disp, drm_flush_wait); lv_display_set_flush_cb(disp, drm_flush); + lv_display_add_event_cb(disp, drm_del_event_cb, LV_EVENT_DELETE, NULL); return disp; } @@ -164,7 +164,6 @@ lv_display_t * lv_linux_drm_create(void) * before the atomic commit */ static void drm_dmabuf_set_active_buf(lv_event_t * event) { - drm_dev_t * drm_dev; lv_display_t * disp; lv_draw_buf_t * act_buf; @@ -184,9 +183,7 @@ static void drm_dmabuf_set_active_buf(lv_event_t * event) } } - #if LV_USE_LINUX_DRM_GBM_BUFFERS - struct dma_buf_sync sync_req; sync_req.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; int res; @@ -502,7 +499,6 @@ static int find_plane(drm_dev_t * drm_dev, unsigned int fourcc, uint32_t * plane unsigned int i; unsigned int j; int ret = 0; - unsigned int format = fourcc; planes = drmModeGetPlaneResources(drm_dev->fd); if(!planes) { @@ -516,6 +512,7 @@ static int find_plane(drm_dev_t * drm_dev, unsigned int fourcc, uint32_t * plane plane = drmModeGetPlane(drm_dev->fd, planes->planes[i]); if(!plane) { LV_LOG_ERROR("drmModeGetPlane failed: %s", strerror(errno)); + ret = -1; break; } @@ -525,7 +522,7 @@ static int find_plane(drm_dev_t * drm_dev, unsigned int fourcc, uint32_t * plane } for(j = 0; j < plane->count_formats; ++j) { - if(plane->formats[j] == format) + if(plane->formats[j] == fourcc) break; } @@ -539,14 +536,14 @@ static int find_plane(drm_dev_t * drm_dev, unsigned int fourcc, uint32_t * plane LV_LOG_TRACE("found plane %d", *plane_id); - break; + /* Success */ + goto out; } if(i == planes->count_planes) ret = -1; - +out: drmModeFreePlaneResources(planes); - return ret; } @@ -556,10 +553,11 @@ static int drm_find_connector(drm_dev_t * drm_dev, int64_t connector_id) drmModeEncoder * enc = NULL; drmModeRes * res; int i; + int ret = -1; if((res = drmModeGetResources(drm_dev->fd)) == NULL) { LV_LOG_ERROR("drmModeGetResources() failed"); - return -1; + goto free_res; } if(res->count_crtcs <= 0) { @@ -639,9 +637,11 @@ static int drm_find_connector(drm_dev_t * drm_dev, int64_t connector_id) drm_dev->crtc_id = enc->crtc_id; LV_LOG_TRACE("crtc_id: %d", drm_dev->crtc_id); drmModeFreeEncoder(enc); + enc = NULL; } else { /* Encoder hasn't been associated yet, look it up */ + bool found = false; for(i = 0; i < conn->count_encoders; i++) { int crtc, crtc_id = -1; @@ -666,6 +666,9 @@ static int drm_find_connector(drm_dev_t * drm_dev, int64_t connector_id) LV_LOG_TRACE("enc_id: %d", drm_dev->enc_id); drm_dev->crtc_id = crtc_id; LV_LOG_TRACE("crtc_id: %d", drm_dev->crtc_id); + drmModeFreeEncoder(enc); + enc = NULL; + found = true; break; } @@ -673,12 +676,10 @@ static int drm_find_connector(drm_dev_t * drm_dev, int64_t connector_id) enc = NULL; } - if(!enc) { + if(!found) { LV_LOG_ERROR("suitable encoder not found"); goto free_res; } - - drmModeFreeEncoder(enc); } drm_dev->crtc_idx = UINT32_MAX; @@ -696,13 +697,22 @@ static int drm_find_connector(drm_dev_t * drm_dev, int64_t connector_id) } LV_LOG_TRACE("crtc_idx: %d", drm_dev->crtc_idx); - - return 0; + ret = 0; free_res: - drmModeFreeResources(res); - - return -1; + if(enc) { + drmModeFreeEncoder(enc); + enc = NULL; + } + if(conn) { + drmModeFreeConnector(conn); + conn = NULL; + } + if(res) { + drmModeFreeResources(res); + res = NULL; + } + return ret; } static int drm_open(const char * path) @@ -828,7 +838,29 @@ static int drm_setup(drm_dev_t * drm_dev, const char * device_path, int64_t conn return 0; err: - close(drm_dev->fd); +#if LV_USE_LINUX_DRM_GBM_BUFFERS + if(drm_dev->gbm_device) { + gbm_device_destroy(drm_dev->gbm_device); + drm_dev->gbm_device = NULL; + } +#endif + + if(drm_dev->plane) { + drmModeFreePlane(drm_dev->plane); + drm_dev->plane = NULL; + } + if(drm_dev->crtc) { + drmModeFreeCrtc(drm_dev->crtc); + drm_dev->crtc = NULL; + } + if(drm_dev->conn) { + drmModeFreeConnector(drm_dev->conn); + drm_dev->conn = NULL; + } + if(drm_dev->fd >= 0) { + close(drm_dev->fd); + drm_dev->fd = -1; + } return -1; } @@ -896,7 +928,6 @@ static int drm_allocate_dumb(drm_dev_t * drm_dev, drm_buffer_t * buf) static int create_gbm_buffer(drm_dev_t * drm_dev, drm_buffer_t * buf) { - struct gbm_bo * gbm_bo; int prime_fd; uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; @@ -983,7 +1014,6 @@ static int drm_setup_buffers(drm_dev_t * drm_dev) int ret; #if LV_USE_LINUX_DRM_GBM_BUFFERS - ret = create_gbm_buffer(drm_dev, &drm_dev->drm_bufs[0]); if(ret < 0) { return ret; @@ -995,7 +1025,6 @@ static int drm_setup_buffers(drm_dev_t * drm_dev) } #else - /* Use dumb buffers */ ret = drm_allocate_dumb(drm_dev, &drm_dev->drm_bufs[0]); if(ret) @@ -1035,7 +1064,6 @@ static void drm_flush_wait(lv_display_t * disp) static void drm_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) { - if(!lv_display_flush_is_last(disp)) return; LV_UNUSED(area); @@ -1053,6 +1081,131 @@ static void drm_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_ } +static void drm_del_event_cb(lv_event_t * e) +{ + if(LV_EVENT_DELETE != lv_event_get_code(e)) + return; + + lv_display_t * disp = lv_event_get_current_target(e); + drm_dev_t * drm_dev = lv_display_get_driver_data(disp); + if(!drm_dev) return; + + /* Restore original CRTC if saved */ + if(drm_dev->fd >= 0 && drm_dev->saved_crtc) { + drmModeCrtc * s_crtc = drm_dev->saved_crtc; + drmModeSetCrtc(drm_dev->fd, s_crtc->crtc_id, s_crtc->buffer_id, 0, 0, + NULL, 0, &s_crtc->mode); + drmModeFreeCrtc(s_crtc); + drm_dev->saved_crtc = NULL; + } + + /* Prevent further flushes & free any pending atomic request */ + lv_display_set_flush_cb(disp, NULL); + if(drm_dev->req) { + drmModeAtomicFree(drm_dev->req); + drm_dev->req = NULL; + } + +#if LV_USE_LINUX_DRM_GBM_BUFFERS + for(int i = 0; i < BUFFER_CNT; ++i) { + drm_buffer_t * b = &drm_dev->drm_bufs[i]; + + if(b->fb_handle) { + drmModeRmFB(drm_dev->fd, b->fb_handle); + b->fb_handle = 0; + } + + if(MAP_FAILED != b->map) { + munmap(b->map, b->size); + b->map = MAP_FAILED; + } + + if((int)b->handle >= 0) { + close((int)b->handle); + b->handle = 0; + } + } + + if(drm_dev->gbm_device) { + gbm_device_destroy(drm_dev->gbm_device); + drm_dev->gbm_device = NULL; + } + +#else /* dumb buffers */ + for(int i = 0; i < BUFFER_CNT; ++i) { + drm_buffer_t * b = &drm_dev->drm_bufs[i]; + + if(b->fb_handle) { + drmModeRmFB(drm_dev->fd, b->fb_handle); + b->fb_handle = 0; + } + if(MAP_FAILED != b->map) { + munmap(b->map, b->size); + b->map = MAP_FAILED; + } + if(b->handle) { + struct drm_mode_destroy_dumb d = { .handle = b->handle }; + /* Dumb buffers should be destroyed if they are closed, but might as well use the DRM_IOCTL_MODE_DESTROY_DUMB */ + drmIoctl(drm_dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &d); + b->handle = 0; + } + } +#endif + + /* Free DRM properties */ + for(uint32_t i = 0; i < drm_dev->count_plane_props; ++i) { + if(drm_dev->plane_props[i]) { + drmModeFreeProperty(drm_dev->plane_props[i]); + drm_dev->plane_props[i] = NULL; + } + } + drm_dev->count_plane_props = 0; + + for(uint32_t i = 0; i < drm_dev->count_crtc_props; ++i) { + if(drm_dev->crtc_props[i]) { + drmModeFreeProperty(drm_dev->crtc_props[i]); + drm_dev->crtc_props[i] = NULL; + } + } + drm_dev->count_crtc_props = 0; + + for(uint32_t i = 0; i < drm_dev->count_conn_props; ++i) { + if(drm_dev->conn_props[i]) { + drmModeFreeProperty(drm_dev->conn_props[i]); + drm_dev->conn_props[i] = NULL; + } + } + drm_dev->count_conn_props = 0; + + if(drm_dev->blob_id) { + drmModeDestroyPropertyBlob(drm_dev->fd, drm_dev->blob_id); + drm_dev->blob_id = 0; + } + + if(drm_dev->conn) { + drmModeFreeConnector(drm_dev->conn); + drm_dev->conn = NULL; + } + + if(drm_dev->crtc) { + drmModeFreeCrtc(drm_dev->crtc); + drm_dev->crtc = NULL; + } + + if(drm_dev->plane) { + drmModeFreePlane(drm_dev->plane); + drm_dev->plane = NULL; + } + + if(drm_dev->fd >= 0) { + close(drm_dev->fd); + drm_dev->fd = -1; + } + + lv_display_set_driver_data(disp, NULL); + lv_free(drm_dev); +} + static uint32_t tick_get_cb(void) { struct timespec t;