From b9870339c0a04779e01f09b2a0ddc285fd377813 Mon Sep 17 00:00:00 2001
|
From: Jinkun Hong <jinkun.hong@rock-chips.com>
|
Date: Tue, 7 Jun 2022 10:01:58 +0800
|
Subject: [PATCH 7/7] add rk_lvgl_demo
|
|
Signed-off-by: Jinkun Hong <jinkun.hong@rock-chips.com>
|
---
|
rk_lvgl_demo/CMakeLists.txt | 30 +
|
rk_lvgl_demo/main.c | 75 +++
|
rk_lvgl_demo/src/hal/drm_display.c | 1141 +++++++++++++++++++++++++++++++++
|
rk_lvgl_demo/src/hal/drm_display.h | 36 ++
|
rk_lvgl_demo/src/hal/evdev.c | 257 ++++++++
|
rk_lvgl_demo/src/hal/evdev.h | 83 +++
|
rk_lvgl_demo/src/hal/key.c | 110 ++++
|
rk_lvgl_demo/src/hal/key.h | 58 ++
|
rk_lvgl_demo/src/lvgl/lv_port_disp.c | 287 +++++++++
|
rk_lvgl_demo/src/lvgl/lv_port_disp.h | 21 +
|
rk_lvgl_demo/src/lvgl/lv_port_indev.c | 116 ++++
|
rk_lvgl_demo/src/lvgl/lv_port_indev.h | 27 +
|
rk_lvgl_demo/src/ui/demo.c | 18 +
|
rk_lvgl_demo/src/ui/demo.h | 7 +
|
14 files changed, 2266 insertions(+)
|
create mode 100644 rk_lvgl_demo/CMakeLists.txt
|
create mode 100644 rk_lvgl_demo/main.c
|
create mode 100644 rk_lvgl_demo/src/hal/drm_display.c
|
create mode 100644 rk_lvgl_demo/src/hal/drm_display.h
|
create mode 100644 rk_lvgl_demo/src/hal/evdev.c
|
create mode 100644 rk_lvgl_demo/src/hal/evdev.h
|
create mode 100644 rk_lvgl_demo/src/hal/key.c
|
create mode 100644 rk_lvgl_demo/src/hal/key.h
|
create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_disp.c
|
create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_disp.h
|
create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_indev.c
|
create mode 100644 rk_lvgl_demo/src/lvgl/lv_port_indev.h
|
create mode 100644 rk_lvgl_demo/src/ui/demo.c
|
create mode 100644 rk_lvgl_demo/src/ui/demo.h
|
|
diff --git a/rk_lvgl_demo/CMakeLists.txt b/rk_lvgl_demo/CMakeLists.txt
|
new file mode 100644
|
index 0000000..ab4683d
|
--- /dev/null
|
+++ b/rk_lvgl_demo/CMakeLists.txt
|
@@ -0,0 +1,30 @@
|
+cmake_minimum_required(VERSION 3.8)
|
+
|
+project(rk_lvgl_demo)
|
+
|
+include(FindPkgConfig)
|
+
|
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
+
|
+include_directories(
|
+ ${PROJECT_SOURCE_DIR}/./
|
+ ${PROJECT_SOURCE_DIR}/src/
|
+ ${CMAKE_SYSROOT}/usr/include/lvgl/
|
+ ${CMAKE_SYSROOT}/usr/include/libdrm/
|
+ ${CMAKE_SYSROOT}/usr/include/rockchip/
|
+ )
|
+
|
+link_directories(
|
+ ${PROJECT_SOURCE_DIR}/./lib)
|
+
|
+aux_source_directory(./ SRCS)
|
+aux_source_directory(./src/hal/ SRCS)
|
+aux_source_directory(./src/lvgl SRCS)
|
+aux_source_directory(./src/ui SRCS)
|
+
|
+add_executable(${PROJECT_NAME} ${SRCS})
|
+
|
+target_link_libraries(${PROJECT_NAME}
|
+ drm lvgl rga pthread m lvgl_demos)
|
+
|
+install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
|
diff --git a/rk_lvgl_demo/main.c b/rk_lvgl_demo/main.c
|
new file mode 100644
|
index 0000000..f46179b
|
--- /dev/null
|
+++ b/rk_lvgl_demo/main.c
|
@@ -0,0 +1,75 @@
|
+/*
|
+ * Copyright (c) 2021 Rockchip, Inc. All Rights Reserved.
|
+ *
|
+ * Licensed under the Apache License, Version 2.0 (the "License");
|
+ * you may not use this file except in compliance with the License.
|
+ * You may obtain a copy of the License at
|
+ *
|
+ * http://www.apache.org/licenses/LICENSE-2.0
|
+ *
|
+ * Unless required by applicable law or agreed to in writing, software
|
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
+ * See the License for the specific language governing permissions and
|
+ * limitations under the License.
|
+ */
|
+
|
+#include <errno.h>
|
+#include <fcntl.h>
|
+#include <pthread.h>
|
+#include <signal.h>
|
+#include <stdbool.h>
|
+#include <stdio.h>
|
+#include <string.h>
|
+#include <unistd.h>
|
+#include <sys/prctl.h>
|
+
|
+#include <linux/netlink.h>
|
+#include <linux/kd.h>
|
+#include <linux/input.h>
|
+#include <sys/socket.h>
|
+#include <sys/time.h>
|
+
|
+#include <rga/rga.h>
|
+#include <rga/RgaApi.h>
|
+
|
+#include "lvgl.h"
|
+
|
+#include "lvgl/lv_port_disp.h"
|
+#include "lvgl/lv_port_indev.h"
|
+#include "src/ui/demo.h"
|
+
|
+#define LVGL_TICK 5
|
+
|
+static int g_ui_rotation = 0;
|
+static int quit = 0;
|
+
|
+static void sigterm_handler(int sig) {
|
+ fprintf(stderr, "signal %d\n", sig);
|
+ quit = 1;
|
+}
|
+
|
+static void lvgl_init(void)
|
+{
|
+ lv_init();
|
+ lv_port_disp_init(g_ui_rotation);
|
+ lv_port_indev_init(g_ui_rotation);
|
+}
|
+
|
+int main(int argc, char **argv)
|
+{
|
+ signal(SIGINT, sigterm_handler);
|
+ c_RkRgaInit();
|
+ lvgl_init();
|
+
|
+ demo_start();
|
+
|
+ while(!quit) {
|
+ lv_tick_inc(LVGL_TICK);
|
+ lv_task_handler();
|
+ usleep(LVGL_TICK * 1000);
|
+ }
|
+ c_RkRgaDeInit();
|
+
|
+ return 0;
|
+}
|
diff --git a/rk_lvgl_demo/src/hal/drm_display.c b/rk_lvgl_demo/src/hal/drm_display.c
|
new file mode 100644
|
index 0000000..85dce61
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/drm_display.c
|
@@ -0,0 +1,1141 @@
|
+#include <fcntl.h>
|
+#include <poll.h>
|
+#include <signal.h>
|
+#include <stdio.h>
|
+#include <stdlib.h>
|
+#include <string.h>
|
+#include <unistd.h>
|
+#include <sys/ioctl.h>
|
+#include <sys/mman.h>
|
+
|
+#include <xf86drm.h>
|
+#include <xf86drmMode.h>
|
+#include <drm_fourcc.h>
|
+#include <drm_mode.h>
|
+
|
+#include <sys/time.h>
|
+
|
+#include "drm_display.h"
|
+
|
+#define NUM_DUMB_BO 3
|
+
|
+#define DEBUG
|
+#ifdef DEBUG
|
+#define DRM_DEBUG(fmt, ...) \
|
+ if (getenv("MJPG_DRM_DEBUG")) \
|
+ printf("DRM_DEBUG: %s(%d) " fmt, __func__, __LINE__, __VA_ARGS__)
|
+#else
|
+#define DRM_DEBUG(fmt, ...)
|
+#endif
|
+
|
+struct device {
|
+ int fd;
|
+
|
+ struct {
|
+ int width;
|
+ int height;
|
+
|
+ int hdisplay;
|
+ int vdisplay;
|
+
|
+ int current;
|
+ int fb_num;
|
+ int bpp;
|
+ } mode;
|
+
|
+ drmModeResPtr res;
|
+
|
+ int connector_id;
|
+ int encoder_id;
|
+ int crtc_id;
|
+ int plane_id;
|
+ int video_plane_id;
|
+ int last_fb_id;
|
+
|
+ struct drm_bo *dumb_bo[NUM_DUMB_BO];
|
+ struct drm_bo *video_bo[NUM_DUMB_BO];
|
+ int current_dumb;
|
+ int current_video;
|
+
|
+ int waiting_for_flip;
|
+ struct pollfd drm_pollfd;
|
+ drmEventContext drm_evctx;
|
+ int rot;
|
+
|
+ int drm_invalide;
|
+ int screen_state;
|
+};
|
+
|
+struct device *pdev;
|
+
|
+static int bo_map(struct device *dev, struct drm_bo *bo)
|
+{
|
+ struct drm_mode_map_dumb arg = {
|
+ .handle = bo->handle,
|
+ };
|
+ int ret;
|
+
|
+ ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
|
+ if (ret)
|
+ return ret;
|
+
|
+ bo->ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
+ dev->fd, arg.offset);
|
+ if (bo->ptr == MAP_FAILED) {
|
+ bo->ptr = NULL;
|
+ return -1;
|
+ }
|
+
|
+ return 0;
|
+}
|
+
|
+static void bo_unmap(struct device *dev, struct drm_bo *bo)
|
+{
|
+ if (dev == NULL)
|
+ return;
|
+ if (!bo->ptr)
|
+ return;
|
+
|
+ drmUnmap(bo->ptr, bo->size);
|
+ bo->ptr = NULL;
|
+}
|
+
|
+void bo_destroy(struct device *dev, struct drm_bo *bo)
|
+{
|
+ struct drm_mode_destroy_dumb arg = {
|
+ .handle = bo->handle,
|
+ };
|
+
|
+ if (bo->fb_id)
|
+ drmModeRmFB(dev->fd, bo->fb_id);
|
+
|
+ bo_unmap(dev, bo);
|
+
|
+ if (bo->handle)
|
+ drmIoctl(dev->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
|
+
|
+ free(bo);
|
+}
|
+
|
+static struct drm_bo *
|
+bo_create(struct device *dev, int width, int height, int format)
|
+{
|
+ struct drm_mode_create_dumb arg = {
|
+ .bpp = 32,
|
+ .width = width,
|
+ .height = height,
|
+ };
|
+ struct drm_bo *bo;
|
+ uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0};
|
+ int ret;
|
+
|
+ bo = malloc(sizeof(struct drm_bo));
|
+ if (bo == NULL) {
|
+ fprintf(stderr, "allocate bo failed\n");
|
+ return NULL;
|
+ }
|
+ memset(bo, 0, sizeof(*bo));
|
+ if (format == DRM_FORMAT_NV12) {
|
+ arg.bpp = 8;
|
+ arg.height = height * 3 / 2;
|
+ }
|
+
|
+ ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
|
+ if (ret) {
|
+ fprintf(stderr, "create dumb failed\n");
|
+ goto err;
|
+ }
|
+
|
+ bo->fd = dev->fd;
|
+ bo->handle = arg.handle;
|
+ bo->size = arg.size;
|
+ bo->pitch = arg.pitch;
|
+
|
+ ret = bo_map(dev, bo);
|
+ if (ret) {
|
+ fprintf(stderr, "map bo failed\n");
|
+ goto err;
|
+ }
|
+
|
+ switch (format) {
|
+ case DRM_FORMAT_NV12:
|
+ case DRM_FORMAT_NV16:
|
+ handles[0] = bo->handle;
|
+ pitches[0] = bo->pitch ;
|
+ offsets[0] = 0;
|
+ handles[1] = bo->handle;
|
+ pitches[1] = pitches[0];
|
+ offsets[1] = pitches[0] * height;
|
+ break;
|
+ case DRM_FORMAT_RGB332:
|
+ handles[0] = bo->handle;
|
+ pitches[0] = bo->pitch;
|
+ offsets[0] = 0;
|
+ break;
|
+ case DRM_FORMAT_RGB565:
|
+ case DRM_FORMAT_BGR565:
|
+ handles[0] = bo->handle;
|
+ pitches[0] = bo->pitch ;
|
+ offsets[0] = 0;
|
+ break;
|
+ case DRM_FORMAT_RGB888:
|
+ case DRM_FORMAT_BGR888:
|
+ handles[0] = bo->handle;
|
+ pitches[0] = bo->pitch ;
|
+ offsets[0] = 0;
|
+ break;
|
+ case DRM_FORMAT_ARGB8888:
|
+ case DRM_FORMAT_ABGR8888:
|
+ case DRM_FORMAT_RGBA8888:
|
+ case DRM_FORMAT_BGRA8888:
|
+ handles[0] = bo->handle;
|
+ pitches[0] = bo->pitch ;
|
+ offsets[0] = 0;
|
+ break;
|
+ }
|
+
|
+ ret = drmModeAddFB2(dev->fd, width, height, format, handles,
|
+ pitches, offsets, (uint32_t *)&bo->fb_id, 0);
|
+ if (ret) {
|
+ fprintf(stderr, "add fb failed\n");
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Created bo: %d, %dx%d\n", bo->fb_id, width, height);
|
+
|
+ return bo;
|
+err:
|
+ bo_destroy(dev, bo);
|
+ return NULL;
|
+}
|
+
|
+static void free_fb(struct device *dev)
|
+{
|
+ DRM_DEBUG("Free fb, num: %d, bpp: %d\n", dev->mode.fb_num, dev->mode.bpp);
|
+
|
+ dev->mode.fb_num = 0;
|
+ dev->mode.bpp = 0;
|
+ dev->mode.current = 0;
|
+}
|
+
|
+static int alloc_fb(struct device *dev, int num, int bpp)
|
+{
|
+ DRM_DEBUG("Alloc fb num: %d, bpp: %d\n", num, bpp);
|
+
|
+ dev->mode.fb_num = num;
|
+ dev->mode.bpp = bpp;
|
+ dev->mode.current = 0;
|
+
|
+ return 0;
|
+}
|
+
|
+static int drm_get_preferred_connector(void)
|
+{
|
+ const char *path;
|
+ char buf[256] = "\0";
|
+ int fd;
|
+
|
+#define DRM_CONNECTOR_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH"
|
+#define DRM_CONNECTOR_CFG_PATH_DEFAULT "/tmp/drm_connector.cfg"
|
+ path = getenv(DRM_CONNECTOR_CFG_PATH_ENV);
|
+ if (!path)
|
+ path = DRM_CONNECTOR_CFG_PATH_DEFAULT;
|
+
|
+ fd = open(path, O_RDONLY);
|
+ read(fd, buf, sizeof(buf));
|
+ close(fd);
|
+
|
+ if (!buf[0])
|
+ return -1;
|
+
|
+ return atoi(buf);
|
+}
|
+
|
+static int drm_get_preferred_mode(int *width, int *height)
|
+{
|
+ const char *path;
|
+ char buf[256] = "\0";
|
+ int fd, w, h;
|
+
|
+#define DRM_MODE_CFG_PATH_ENV "DRM_CONNECTOR_CFG_PATH"
|
+#define DRM_MODE_CFG_PATH_DEFAULT "/tmp/drm_mode.cfg"
|
+ path = getenv(DRM_MODE_CFG_PATH_ENV);
|
+ if (!path)
|
+ path = DRM_MODE_CFG_PATH_DEFAULT;
|
+
|
+ fd = open(path, O_RDONLY);
|
+ read(fd, buf, sizeof(buf));
|
+ close(fd);
|
+
|
+ if (!buf[0])
|
+ return -1;
|
+
|
+ if (2 != sscanf(buf, "%dx%d", &w, &h))
|
+ return -1;
|
+
|
+ *width = w;
|
+ *height = h;
|
+
|
+ return 0;
|
+}
|
+
|
+static drmModeConnectorPtr
|
+drm_get_connector(struct device *dev, int connector_id)
|
+{
|
+ drmModeConnectorPtr conn;
|
+
|
+ conn = drmModeGetConnector(dev->fd, connector_id);
|
+ if (!conn)
|
+ return NULL;
|
+
|
+ DRM_DEBUG("Connector id: %d, %sconnected, modes: %d\n", connector_id,
|
+ (conn->connection == DRM_MODE_CONNECTED) ? "" : "dis",
|
+ conn->count_modes);
|
+ if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes)
|
+ return conn;
|
+
|
+ drmModeFreeConnector(conn);
|
+ return NULL;
|
+}
|
+
|
+static drmModeConnectorPtr
|
+drm_find_best_connector(struct device *dev)
|
+{
|
+ drmModeResPtr res = dev->res;
|
+ drmModeConnectorPtr conn;
|
+ int i, preferred_connector_id = drm_get_preferred_connector();
|
+
|
+ DRM_DEBUG("Preferred connector id: %d\n", preferred_connector_id);
|
+ conn = drm_get_connector(dev, preferred_connector_id);
|
+ if (conn)
|
+ return conn;
|
+
|
+ for (i = 0; i < res->count_connectors; i++) {
|
+ conn = drm_get_connector(dev, res->connectors[i]);
|
+ if (conn)
|
+ return conn;
|
+ }
|
+ return NULL;
|
+}
|
+
|
+static drmModeCrtcPtr
|
+drm_find_best_crtc(struct device *dev, drmModeConnectorPtr conn)
|
+{
|
+ drmModeResPtr res = dev->res;
|
+ drmModeEncoderPtr encoder;
|
+ drmModeCrtcPtr crtc;
|
+ int i, preferred_crtc_id = 0;
|
+ int crtcs_for_connector = 0;
|
+
|
+ encoder = drmModeGetEncoder(dev->fd, conn->encoder_id);
|
+ if (encoder) {
|
+ preferred_crtc_id = encoder->crtc_id;
|
+ drmModeFreeEncoder(encoder);
|
+ }
|
+ DRM_DEBUG("Preferred crtc: %d\n", preferred_crtc_id);
|
+
|
+ crtc = drmModeGetCrtc(dev->fd, preferred_crtc_id);
|
+ if (crtc)
|
+ return crtc;
|
+
|
+ for (i = 0; i < res->count_encoders; i++) {
|
+ encoder = drmModeGetEncoder(dev->fd, res->encoders[i]);
|
+ if (encoder)
|
+ crtcs_for_connector |= encoder->possible_crtcs;
|
+ drmModeFreeEncoder(encoder);
|
+ }
|
+ DRM_DEBUG("Possible crtcs: %x\n", crtcs_for_connector);
|
+ if (!crtcs_for_connector)
|
+ return NULL;
|
+
|
+ return drmModeGetCrtc(dev->fd, res->crtcs[ffs(crtcs_for_connector) - 1]);
|
+}
|
+
|
+int
|
+drm_plane_is_primary(struct device *dev, int plane_id)
|
+{
|
+ drmModeObjectPropertiesPtr props;
|
+ drmModePropertyPtr prop;
|
+ unsigned int i;
|
+ int type = 0;
|
+
|
+ props = drmModeObjectGetProperties(dev->fd, plane_id,
|
+ DRM_MODE_OBJECT_PLANE);
|
+ if (!props)
|
+ return 0;
|
+
|
+ for (i = 0; i < props->count_props; i++) {
|
+ prop = drmModeGetProperty(dev->fd, props->props[i]);
|
+ if (prop && !strcmp(prop->name, "type"))
|
+ type = props->prop_values[i];
|
+ drmModeFreeProperty(prop);
|
+ }
|
+ DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
|
+
|
+ drmModeFreeObjectProperties(props);
|
+ return type == DRM_PLANE_TYPE_PRIMARY;
|
+}
|
+
|
+int
|
+drm_plane_is_overlay(struct device *dev, int plane_id)
|
+{
|
+ drmModeObjectPropertiesPtr props;
|
+ drmModePropertyPtr prop;
|
+ unsigned int i;
|
+ int type = 0;
|
+
|
+ props = drmModeObjectGetProperties(dev->fd, plane_id,
|
+ DRM_MODE_OBJECT_PLANE);
|
+ if (!props)
|
+ return 0;
|
+
|
+ for (i = 0; i < props->count_props; i++) {
|
+ prop = drmModeGetProperty(dev->fd, props->props[i]);
|
+ if (prop && !strcmp(prop->name, "type"))
|
+ type = props->prop_values[i];
|
+ drmModeFreeProperty(prop);
|
+ }
|
+ DRM_DEBUG("Plane: %d, type: %d\n", plane_id, type);
|
+
|
+ drmModeFreeObjectProperties(props);
|
+ return type == DRM_PLANE_TYPE_OVERLAY;
|
+}
|
+
|
+static drmModePlanePtr
|
+drm_get_plane(struct device *dev, int plane_id, int pipe)
|
+{
|
+ drmModePlanePtr plane;
|
+
|
+ plane = drmModeGetPlane(dev->fd, plane_id);
|
+ if (!plane)
|
+ return NULL;
|
+
|
+ DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id,
|
+ plane->possible_crtcs);
|
+ if (drm_plane_is_overlay(dev, plane_id)) {
|
+ if (plane->possible_crtcs & (1 << pipe))
|
+ return plane;
|
+ }
|
+
|
+ drmModeFreePlane(plane);
|
+ return NULL;
|
+}
|
+
|
+static drmModePlanePtr
|
+drm_get_video_plane(struct device *dev, int plane_id, int pipe)
|
+{
|
+ drmModePlanePtr plane;
|
+
|
+ plane = drmModeGetPlane(dev->fd, plane_id);
|
+ if (!plane)
|
+ return NULL;
|
+
|
+ DRM_DEBUG("Check plane: %d, possible_crtcs: %x\n", plane_id,
|
+ plane->possible_crtcs);
|
+ if (drm_plane_is_primary(dev, plane_id)) {
|
+ if (plane->possible_crtcs & (1 << pipe))
|
+ return plane;
|
+ }
|
+
|
+ drmModeFreePlane(plane);
|
+ return NULL;
|
+}
|
+
|
+static drmModePlanePtr
|
+drm_find_best_plane(struct device *dev, drmModeCrtcPtr crtc)
|
+{
|
+ drmModeResPtr res = dev->res;
|
+ drmModePlaneResPtr pres;
|
+ drmModePlanePtr plane;
|
+ unsigned int i;
|
+ int pipe;
|
+
|
+ for (pipe = 0; pipe < res->count_crtcs; pipe++) {
|
+ if (crtc->crtc_id == res->crtcs[pipe])
|
+ break;
|
+ }
|
+ if (pipe == res->count_crtcs)
|
+ return NULL;
|
+
|
+ pres = drmModeGetPlaneResources(dev->fd);
|
+ if (!pres)
|
+ return NULL;
|
+
|
+ for (i = 0; i < pres->count_planes; i++) {
|
+ plane = drm_get_plane(dev, pres->planes[i], pipe);
|
+ if (plane) {
|
+ drmModeFreePlaneResources(pres);
|
+ return plane;
|
+ }
|
+ drmModeFreePlane(plane);
|
+ }
|
+
|
+ drmModeFreePlaneResources(pres);
|
+ return NULL;
|
+}
|
+
|
+static drmModePlanePtr
|
+drm_find_video_plane(struct device *dev, drmModeCrtcPtr crtc)
|
+{
|
+ drmModeResPtr res = dev->res;
|
+ drmModePlaneResPtr pres;
|
+ drmModePlanePtr plane;
|
+ unsigned int i;
|
+ int pipe;
|
+
|
+ for (pipe = 0; pipe < res->count_crtcs; pipe++) {
|
+ if (crtc->crtc_id == res->crtcs[pipe])
|
+ break;
|
+ }
|
+ if (pipe == res->count_crtcs)
|
+ return NULL;
|
+
|
+ pres = drmModeGetPlaneResources(dev->fd);
|
+ if (!pres)
|
+ return NULL;
|
+
|
+ for (i = 0; i < pres->count_planes; i++) {
|
+ plane = drm_get_video_plane(dev, pres->planes[i], pipe);
|
+ if (plane) {
|
+ drmModeFreePlaneResources(pres);
|
+ return plane;
|
+ }
|
+ drmModeFreePlane(plane);
|
+ }
|
+
|
+ drmModeFreePlaneResources(pres);
|
+ return NULL;
|
+}
|
+
|
+static drmModeModeInfoPtr
|
+drm_find_best_mode(struct device *dev, drmModeConnectorPtr conn)
|
+{
|
+ drmModeModeInfoPtr mode;
|
+ int i, preferred_width = 1920, preferred_height = 1080;
|
+
|
+ if (dev == NULL)
|
+ return 0;
|
+ drm_get_preferred_mode(&preferred_width, &preferred_height);
|
+ DRM_DEBUG("Preferred mode: %dx%d\n", preferred_width, preferred_height);
|
+
|
+ mode = &conn->modes[0];
|
+ for (i = 0; i < conn->count_modes; i++) {
|
+ DRM_DEBUG("Check mode: %dx%d\n",
|
+ conn->modes[i].hdisplay, conn->modes[i].vdisplay);
|
+ if (conn->modes[i].hdisplay == preferred_width &&
|
+ conn->modes[i].vdisplay == preferred_height) {
|
+ mode = &conn->modes[i];
|
+ break;
|
+ }
|
+ }
|
+
|
+ return mode;
|
+}
|
+
|
+static int drm_get_preferred_fb_mode(int *width, int *height)
|
+{
|
+ char *buf;
|
+ int w, h;
|
+
|
+ buf = getenv("MINIGUI_DRM_FB_MODE");
|
+ if (!buf)
|
+ return -1;
|
+
|
+ if (2 != sscanf(buf, "%dx%d", &w, &h))
|
+ return -1;
|
+
|
+ DRM_DEBUG("Preferred fb mode: %dx%d\n", w, h);
|
+ *width = w;
|
+ *height = h;
|
+
|
+ return 0;
|
+}
|
+
|
+static void drm_setup_fb_mode(struct device *dev)
|
+{
|
+ drmModeResPtr res = dev->res;
|
+ drmModeConnectorPtr conn;
|
+ drmModeModeInfoPtr mode;
|
+ int i;
|
+
|
+ if (dev->mode.width && dev->mode.height)
|
+ return;
|
+
|
+ if (!drm_get_preferred_fb_mode(&dev->mode.width, &dev->mode.height))
|
+ return;
|
+
|
+ dev->mode.width = dev->mode.hdisplay;
|
+ dev->mode.height = dev->mode.vdisplay;
|
+
|
+ for (i = 0; i < res->count_connectors; i++) {
|
+ conn = drm_get_connector(dev, res->connectors[i]);
|
+ if (!conn)
|
+ continue;
|
+
|
+ mode = drm_find_best_mode(dev, conn);
|
+ if (mode) {
|
+ DRM_DEBUG("Best mode for connector(%d): %dx%d\n",
|
+ conn->connector_id, mode->hdisplay, mode->vdisplay);
|
+ if (dev->mode.width > mode->hdisplay ||
|
+ dev->mode.height > mode->vdisplay) {
|
+ dev->mode.width = mode->hdisplay;
|
+ dev->mode.height = mode->vdisplay;
|
+ }
|
+ }
|
+ drmModeFreeConnector(conn);
|
+ }
|
+}
|
+
|
+static void drm_free(struct device *dev)
|
+{
|
+ int i;
|
+
|
+ for (i = 0; i < NUM_DUMB_BO; i++) {
|
+ if (dev->dumb_bo[i]) {
|
+ bo_destroy(dev, dev->dumb_bo[i]);
|
+ dev->dumb_bo[i] = NULL;
|
+ }
|
+ if (dev->video_bo[i]) {
|
+ bo_destroy(dev, dev->video_bo[i]);
|
+ dev->video_bo[i] = NULL;
|
+ }
|
+ }
|
+
|
+ if (dev->res) {
|
+ drmModeFreeResources(dev->res);
|
+ dev->res = NULL;
|
+ }
|
+
|
+ dev->connector_id = 0;
|
+ dev->crtc_id = 0;
|
+ dev->plane_id = 0;
|
+ dev->video_plane_id = 0;
|
+ dev->mode.hdisplay = 0;
|
+ dev->mode.vdisplay = 0;
|
+}
|
+
|
+static void configure_plane_zpos (struct device *self, int plane_id, uint64_t zpos)
|
+{
|
+ drmModeObjectPropertiesPtr props = NULL;
|
+ drmModePropertyPtr prop = NULL;
|
+ char *buf;
|
+ unsigned int i;
|
+
|
+ if (plane_id <= 0)
|
+ return;
|
+
|
+ if (drmSetClientCap (self->fd, DRM_CLIENT_CAP_ATOMIC, 1))
|
+ return;
|
+
|
+ props = drmModeObjectGetProperties (self->fd, plane_id,
|
+ DRM_MODE_OBJECT_PLANE);
|
+ if (!props)
|
+ goto out;
|
+
|
+ for (i = 0; i < props->count_props; i++) {
|
+ prop = drmModeGetProperty (self->fd, props->props[i]);
|
+ if (prop && !strcmp (prop->name, "ZPOS"))
|
+ break;
|
+ drmModeFreeProperty (prop);
|
+ prop = NULL;
|
+ }
|
+
|
+ if (!prop)
|
+ goto out;
|
+
|
+ drmModeObjectSetProperty (self->fd, plane_id,
|
+ DRM_MODE_OBJECT_PLANE, props->props[i], zpos);
|
+out:
|
+ drmModeFreeProperty (prop);
|
+ drmModeFreeObjectProperties (props);
|
+}
|
+
|
+static int drm_setup(struct device *dev)
|
+{
|
+ drmModeConnectorPtr conn = NULL;
|
+ drmModeModeInfoPtr mode;
|
+ drmModePlanePtr plane = NULL;
|
+ drmModePlanePtr video_plane = NULL;
|
+ drmModeCrtcPtr crtc = NULL;
|
+ //int ret;
|
+ int i, success = 0;
|
+
|
+ dev->res = drmModeGetResources(dev->fd);
|
+ if (!dev->res) {
|
+ fprintf(stderr, "drm get resource failed\n");
|
+ goto err;
|
+ }
|
+
|
+ conn = drm_find_best_connector(dev);
|
+ if (!conn) {
|
+ fprintf(stderr, "drm find connector failed\n");
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Best connector id: %d\n", conn->connector_id);
|
+
|
+ mode = drm_find_best_mode(dev, conn);
|
+ if (!mode) {
|
+ fprintf(stderr, "drm find mode failed\n");
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Best mode: %dx%d\n", mode->hdisplay, mode->vdisplay);
|
+
|
+ crtc = drm_find_best_crtc(dev, conn);
|
+ if (!crtc) {
|
+ fprintf(stderr, "drm find crtc failed\n");
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Best crtc: %d\n", crtc->crtc_id);
|
+
|
+ plane = drm_find_best_plane(dev, crtc);
|
+ if (!plane) {
|
+ fprintf(stderr, "drm find plane failed\n");
|
+ goto err;
|
+ }
|
+ configure_plane_zpos(dev, plane->plane_id, 1);
|
+ DRM_DEBUG("Best plane: %d\n", plane->plane_id);
|
+
|
+ video_plane = drm_find_video_plane(dev, crtc);
|
+ if (!video_plane) {
|
+ fprintf(stderr, "drm find video plane failed\n");
|
+ goto err;
|
+ }
|
+ configure_plane_zpos(dev, video_plane->plane_id, 0);
|
+ DRM_DEBUG("video plane: %d\n", video_plane->plane_id);
|
+
|
+ for (i = 0; i < NUM_DUMB_BO; i++) {
|
+ dev->dumb_bo[i] = bo_create(dev, mode->hdisplay, mode->vdisplay, DRM_FORMAT_ARGB8888);
|
+ if (!dev->dumb_bo[i]) {
|
+ fprintf(stderr, "create dumb bo %d failed\n", i);
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Created dumb bo fb: %d\n", dev->dumb_bo[i]->fb_id);
|
+ }
|
+ for (i = 0; i < NUM_DUMB_BO; i++) {
|
+ dev->video_bo[i] = bo_create(dev, mode->hdisplay, mode->vdisplay, DRM_FORMAT_ARGB8888/*DRM_FORMAT_NV12*/);
|
+ if (!dev->video_bo[i]) {
|
+ fprintf(stderr, "create video bo %d failed\n", i);
|
+ goto err;
|
+ }
|
+ DRM_DEBUG("Created video bo fb: %d\n", dev->video_bo[i]->fb_id);
|
+ }
|
+
|
+ dev->current_dumb = 0;
|
+ dev->current_video = 0;
|
+#if 0
|
+ ret = drmModeSetCrtc(dev->fd, crtc->crtc_id,
|
+ dev->dumb_bo[dev->current_dumb]->fb_id, 0, 0,
|
+ &conn->connector_id, 1, mode);
|
+ if (ret) {
|
+ fprintf(stderr, "drm set mode failed\n");
|
+ goto err;
|
+ }
|
+#endif
|
+ dev->connector_id = conn->connector_id;
|
+ dev->crtc_id = crtc->crtc_id;
|
+ dev->plane_id = plane->plane_id;
|
+ dev->video_plane_id = video_plane->plane_id;
|
+
|
+ dev->last_fb_id = 0;
|
+ dev->mode.hdisplay = mode->hdisplay;
|
+ dev->mode.vdisplay = mode->vdisplay;
|
+
|
+ drm_setup_fb_mode(dev);
|
+ DRM_DEBUG("Drm fb mode: %dx%d\n", dev->mode.width, dev->mode.height);
|
+
|
+ success = 1;
|
+err:
|
+ drmModeFreeConnector(conn);
|
+ drmModeFreePlane(plane);
|
+ drmModeFreePlane(video_plane);
|
+ drmModeFreeCrtc(crtc);
|
+ if (!success) {
|
+ drm_free(dev);
|
+ return -1;
|
+ }
|
+ return 0;
|
+}
|
+
|
+static void drm_flip_handler(int fd, unsigned frame, unsigned sec,
|
+ unsigned usec, void *data)
|
+{
|
+ // data is &dev->waiting_for_flip
|
+ DRM_DEBUG("Page flip received(%d)!, %d, %d, %d, %d\n", *(int*)data, fd, frame, sec, usec);
|
+ *(int*)data = 0;
|
+}
|
+#if 0
|
+void drm_sighandler(int sig)
|
+{
|
+ if (!pdev)
|
+ return;
|
+
|
+ if (sig == SIGUSR2) {
|
+ DRM_DEBUG("Request reinit drm by sig: %d\n", sig);
|
+ pdev->drm_invalide = 1;
|
+ }
|
+}
|
+
|
+static void drm_install_sighandler(struct device* dev)
|
+{
|
+ struct sigaction sa;
|
+ if (dev == NULL)
|
+ return;
|
+ sa.sa_sigaction = NULL;
|
+ sa.sa_handler = drm_sighandler;
|
+ sa.sa_flags = SA_RESTART;
|
+ sigemptyset(&sa.sa_mask);
|
+ sigaction(SIGUSR2, &sa, NULL);
|
+}
|
+#endif
|
+
|
+int drm_init(int bpp, int rot)
|
+{
|
+ int ret;
|
+
|
+ pdev = malloc(sizeof(struct device));
|
+ if (pdev == NULL) {
|
+ fprintf(stderr, "allocate device failed\n");
|
+ return -1;
|
+ }
|
+ memset(pdev, 0, sizeof(*pdev));
|
+ pdev->screen_state = 1;
|
+
|
+ //drm_install_sighandler(pdev);
|
+
|
+ pdev->fd = drmOpen(NULL, NULL);
|
+ if (pdev->fd < 0)
|
+ pdev->fd = open("/dev/dri/card0", O_RDWR);
|
+ if (pdev->fd < 0) {
|
+ fprintf(stderr, "drm open failed\n");
|
+ goto err_drm_open;
|
+ }
|
+ fcntl(pdev->fd, F_SETFD, FD_CLOEXEC);
|
+
|
+ drmSetClientCap(pdev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
|
+
|
+ ret = alloc_fb(pdev, NUM_DUMB_BO, bpp);
|
+ if (ret) {
|
+ fprintf(stderr, "alloc fb failed\n");
|
+ goto err_alloc_fb;
|
+ }
|
+
|
+ ret = drm_setup(pdev);
|
+ if (ret) {
|
+ fprintf(stderr, "drm setup failed\n");
|
+ goto err_drm_setup;
|
+ }
|
+
|
+ pdev->drm_pollfd.fd = pdev->fd;
|
+ pdev->drm_pollfd.events = POLLIN;
|
+
|
+ pdev->drm_evctx.version = DRM_EVENT_CONTEXT_VERSION;
|
+ pdev->drm_evctx.page_flip_handler = drm_flip_handler;
|
+ pdev->rot = rot;
|
+
|
+ return 0;
|
+err_alloc_fb:
|
+ drm_free(pdev);
|
+err_drm_setup:
|
+ drmClose(pdev->fd);
|
+err_drm_open:
|
+ free(pdev);
|
+ pdev = NULL;
|
+ return -1;
|
+}
|
+
|
+int drm_deinit(void)
|
+{
|
+ struct device* dev = pdev;
|
+ if (!dev)
|
+ return 0;
|
+
|
+ free_fb(dev);
|
+ drm_free(dev);
|
+
|
+ if (pdev->fd > 0)
|
+ drmClose(dev->fd);
|
+
|
+ free(pdev);
|
+ pdev = NULL;
|
+
|
+ return 0;
|
+}
|
+
|
+int getdrmrot(void)
|
+{
|
+ return pdev->rot;
|
+}
|
+
|
+void getdrmdispbuff(char **buff)
|
+{
|
+ *buff = pdev->dumb_bo[pdev->current_dumb]->ptr;
|
+}
|
+
|
+int getdrmdispinfo(struct drm_bo *bo, int *w, int *h)
|
+{
|
+ if (pdev->dumb_bo[pdev->current_dumb]) {
|
+ memcpy(bo, pdev->dumb_bo[pdev->current_dumb], sizeof(struct drm_bo));
|
+ *w = pdev->mode.width;
|
+ *h = pdev->mode.height;
|
+ }
|
+
|
+ return 0;
|
+}
|
+
|
+struct drm_bo *getdrmdisp(void)
|
+{
|
+ if (pdev->screen_state)
|
+ pdev->current_dumb ++;
|
+ if (pdev->current_dumb >= NUM_DUMB_BO)
|
+ pdev->current_dumb = 0;
|
+ return pdev->dumb_bo[pdev->current_dumb];
|
+}
|
+
|
+static void drm_wait_flip(struct device* dev, int timeout)
|
+{
|
+ int ret;
|
+
|
+ while (dev->waiting_for_flip) {
|
+ dev->drm_pollfd.revents = 0;
|
+ ret = poll(&dev->drm_pollfd, 1, timeout);
|
+ if (ret <= 0)
|
+ return;
|
+
|
+ drmHandleEvent(dev->fd, &dev->drm_evctx);
|
+ }
|
+}
|
+
|
+void setdrmdisp(struct drm_bo *bo)
|
+{
|
+ struct device* dev = pdev;
|
+ int crtc_x, crtc_y, crtc_w, crtc_h;
|
+ int ret;
|
+ int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height;
|
+
|
+ if (dev == NULL)
|
+ return;
|
+ if (!dev->screen_state)
|
+ return;
|
+
|
+ crtc_w = dev->mode.width;
|
+ crtc_h = dev->mode.height;
|
+ crtc_x = 0;
|
+ crtc_y = 0;
|
+
|
+ DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh,
|
+ crtc_x, crtc_y, crtc_w, crtc_h);
|
+ ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, fb, 0,
|
+ crtc_x, crtc_y, crtc_w, crtc_h,
|
+ 0, 0, sw << 16, sh << 16);
|
+ if (ret) {
|
+ fprintf(stderr, "drm set plane failed\n");
|
+ return;
|
+ }
|
+ if (0) {
|
+ // Queue page flip
|
+ dev->waiting_for_flip = 1;
|
+ ret = drmModePageFlip(dev->fd, dev->crtc_id, fb,
|
+ DRM_MODE_PAGE_FLIP_EVENT, &dev->waiting_for_flip);
|
+ if (ret) {
|
+ fprintf(stderr, "drm page flip failed\n");
|
+ return;
|
+ }
|
+ // Wait for last page flip
|
+ drm_wait_flip(dev, -1);
|
+ }
|
+}
|
+
|
+void getdrmvideodispbuff(char **buff)
|
+{
|
+ if (pdev->video_bo[pdev->current_video])
|
+ *buff = pdev->video_bo[pdev->current_video]->ptr;
|
+}
|
+
|
+int getdrmvideodispinfo(struct drm_bo *bo, int *w, int *h)
|
+{
|
+ if (pdev->video_bo[pdev->current_video]) {
|
+ memcpy(bo, pdev->video_bo[pdev->current_video], sizeof(struct drm_bo));
|
+ *w = pdev->mode.width;
|
+ *h = pdev->mode.height;
|
+ }
|
+
|
+ return 0;
|
+}
|
+
|
+struct drm_bo *getdrmvideodisp(void)
|
+{
|
+ if (pdev->screen_state)
|
+ pdev->current_video ++;
|
+ if (pdev->current_video >= NUM_DUMB_BO)
|
+ pdev->current_video = 0;
|
+ return pdev->video_bo[pdev->current_video];
|
+}
|
+
|
+void setdrmvideodisp(struct drm_bo *bo)
|
+{
|
+ struct device* dev = pdev;
|
+ int crtc_x, crtc_y, crtc_w, crtc_h;
|
+ int ret;
|
+ int fb = bo->fb_id, sw = dev->mode.width, sh = dev->mode.height;
|
+
|
+ if (dev == NULL)
|
+ return;
|
+ if (!dev->screen_state)
|
+ return;
|
+
|
+ crtc_w = dev->mode.width;
|
+ crtc_h = dev->mode.height;
|
+ crtc_x = 0;
|
+ crtc_y = 0;
|
+
|
+ DRM_DEBUG("Display bo %d(%dx%d) at (%d,%d) %dx%d\n", fb, sw, sh,
|
+ crtc_x, crtc_y, crtc_w, crtc_h);
|
+ ret = drmModeSetPlane(dev->fd, dev->video_plane_id, dev->crtc_id, fb, 0,
|
+ crtc_x, crtc_y, crtc_w, crtc_h,
|
+ 0, 0, sw << 16, sh << 16);
|
+ if (ret) {
|
+ fprintf(stderr, "drm set plane failed\n");
|
+ return;
|
+ }
|
+}
|
+
|
+void drmvideodispblack(void)
|
+{
|
+ struct drm_bo *bo;
|
+ int w;
|
+ int sw;
|
+ int h;
|
+ int *buff;
|
+ int i, j;
|
+
|
+ getdrmresolve(&w, &h);
|
+ sw = getdrmvideowstride();
|
+ for (j = 0; j < NUM_DUMB_BO; j++) {
|
+ bo = getdrmvideodisp();
|
+ getdrmvideodispbuff(&buff);
|
+ for (i = 0; i < sw * h; i++) {
|
+ buff[i] = 0xff000000;
|
+ }
|
+ setdrmvideodisp(bo);
|
+ }
|
+}
|
+
|
+int drm_screen_off(void)
|
+{
|
+ struct device *dev = pdev;
|
+ struct drm_bo *bo;
|
+ int current_dumb;
|
+ int *buff;
|
+ int sw;
|
+ int w, h;
|
+ int ret;
|
+ int i;
|
+
|
+ if (dev == NULL)
|
+ return;
|
+ if (!dev->screen_state)
|
+ return -1;
|
+ dev->screen_state = 0;
|
+ current_dumb = pdev->current_dumb + 1;
|
+
|
+ if (current_dumb >= NUM_DUMB_BO)
|
+ current_dumb = 0;
|
+ bo = pdev->dumb_bo[current_dumb];
|
+ buff = bo->ptr;
|
+ getdrmresolve(&w, &h);
|
+ sw = getdrmvideowstride();
|
+ for (i = 0; i < sw * h; i++) {
|
+ buff[i] = 0xff000000;
|
+ }
|
+ ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, bo->fb_id, 0,
|
+ 0, 0, dev->mode.width, dev->mode.height,
|
+ 0, 0, dev->mode.width << 16, dev->mode.height << 16);
|
+ if (ret) {
|
+ fprintf(stderr, "drm set plane failed\n");
|
+ }
|
+ return 0;
|
+}
|
+
|
+int drm_screen_on(void)
|
+{
|
+ struct device *dev = pdev;
|
+ struct drm_bo *bo;
|
+ int current_dumb;
|
+ int ret;
|
+ if (dev->screen_state)
|
+ return -1;
|
+ current_dumb = pdev->current_dumb;
|
+
|
+ bo = pdev->dumb_bo[current_dumb];
|
+
|
+ ret = drmModeSetPlane(dev->fd, dev->plane_id, dev->crtc_id, bo->fb_id, 0,
|
+ 0, 0, dev->mode.width, dev->mode.height,
|
+ 0, 0, dev->mode.width << 16, dev->mode.height << 16);
|
+ if (ret) {
|
+ fprintf(stderr, "drm set plane failed\n");
|
+ }
|
+ dev->screen_state = 1;
|
+
|
+ return 0;
|
+}
|
+
|
+int drm_invalide(void)
|
+{
|
+ return pdev && pdev->drm_invalide;
|
+}
|
+
|
+void getdrmdispbpp(int *bpp)
|
+{
|
+ *bpp = pdev->mode.bpp;
|
+}
|
+
|
+int getdrmwstride(void)
|
+{
|
+ return pdev->dumb_bo[pdev->current_dumb]->pitch / 4;
|
+}
|
+
|
+int getdrmvideowstride(void)
|
+{
|
+ return pdev->video_bo[pdev->current_video]->pitch / 4;
|
+}
|
+
|
+void getdrmresolve(int *w, int *h)
|
+{
|
+ *w = pdev->mode.width;
|
+ *h = pdev->mode.height;
|
+}
|
+
|
+#if 0
|
+int main(int argc, char **argv)
|
+{
|
+ int i;
|
+ int val = 0xff;
|
+ int w;
|
+ int h;
|
+ char *viraddr;
|
+
|
+ printf("drm_display run\n");
|
+ if (drm_init(32, 0) < 0)
|
+ return -1;
|
+
|
+ getdrmresolve(&w, &h);
|
+ struct drm_bo *bo = getdrmdisp();
|
+ getdrmdispbuff(&viraddr);
|
+ printf("%d, %d\n", w, h);
|
+ memset(viraddr, 0x00, w * h * 4);
|
+ setdrmdisp(bo);
|
+ while(1) {
|
+ if (val == 0xff) {
|
+ val = 0x80;
|
+ } else {
|
+ val = 0xff;
|
+ }
|
+ memset(viraddr, val, w * h * 4);
|
+ sleep(1);
|
+ }
|
+
|
+ drm_deinit();
|
+ printf("drm_display exit\n");
|
+
|
+ return 0;
|
+}
|
+#endif
|
\ No newline at end of file
|
diff --git a/rk_lvgl_demo/src/hal/drm_display.h b/rk_lvgl_demo/src/hal/drm_display.h
|
new file mode 100644
|
index 0000000..bccbced
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/drm_display.h
|
@@ -0,0 +1,36 @@
|
+#ifndef __DRM_DISPLAY_H__
|
+#define __DRM_DISPLAY_H__
|
+
|
+struct drm_bo {
|
+ int fd;
|
+ void *ptr;
|
+ size_t size;
|
+ size_t offset;
|
+ size_t pitch;
|
+ unsigned int handle;
|
+ int fb_id;
|
+};
|
+
|
+int drm_init(int bpp, int rot);
|
+int drm_deinit(void);
|
+void getdrmdispbuff(char **buff);
|
+int getdrmdispinfo(struct drm_bo *bo, int *w, int *h);
|
+struct drm_bo *getdrmdisp(void);
|
+void setdrmdisp(struct drm_bo *bo);
|
+int drm_setmode(int num, int bpp);
|
+int drm_invalide(void);
|
+void getdrmdispbpp(int *bpp);
|
+void getdrmresolve(int *w, int *h);
|
+void getdrmvideodispbuff(char **buff);
|
+int getdrmvideodispinfo(struct drm_bo *bo, int *w, int *h);
|
+struct drm_bo *getdrmvideodisp(void);
|
+void setdrmvideodisp(struct drm_bo *bo);
|
+void drmvideodispblack(void);
|
+int getdrmwstride(void);
|
+int getdrmvideowstride(void);
|
+int getdrmrot(void);
|
+
|
+int drm_screen_off(void);
|
+int drm_screen_on(void);
|
+
|
+#endif
|
diff --git a/rk_lvgl_demo/src/hal/evdev.c b/rk_lvgl_demo/src/hal/evdev.c
|
new file mode 100644
|
index 0000000..0c9c4f0
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/evdev.c
|
@@ -0,0 +1,257 @@
|
+/**
|
+ * @file evdev.c
|
+ *
|
+ */
|
+
|
+/*********************
|
+ * INCLUDES
|
+ *********************/
|
+#include "evdev.h"
|
+#if USE_EVDEV != 0 || USE_BSD_EVDEV
|
+
|
+#include <stdio.h>
|
+#include <unistd.h>
|
+#include <fcntl.h>
|
+#if USE_BSD_EVDEV
|
+#include <dev/evdev/input.h>
|
+#else
|
+#include <linux/input.h>
|
+#endif
|
+
|
+/*********************
|
+ * DEFINES
|
+ *********************/
|
+
|
+/**********************
|
+ * TYPEDEFS
|
+ **********************/
|
+
|
+/**********************
|
+ * STATIC PROTOTYPES
|
+ **********************/
|
+int map(int x, int in_min, int in_max, int out_min, int out_max);
|
+
|
+/**********************
|
+ * STATIC VARIABLES
|
+ **********************/
|
+int evdev_fd;
|
+int evdev_root_x;
|
+int evdev_root_y;
|
+int evdev_button;
|
+
|
+int evdev_key_val;
|
+
|
+int evdev_rot;
|
+/**********************
|
+ * MACROS
|
+ **********************/
|
+
|
+/**********************
|
+ * GLOBAL FUNCTIONS
|
+ **********************/
|
+
|
+/**
|
+ * Initialize the evdev interface
|
+ */
|
+void evdev_init(int rot)
|
+{
|
+ evdev_rot = rot;
|
+#if USE_BSD_EVDEV
|
+ evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY);
|
+#else
|
+ evdev_fd = open(EVDEV_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
|
+#endif
|
+ if(evdev_fd == -1) {
|
+ perror("unable open evdev interface:");
|
+ return;
|
+ }
|
+
|
+#if USE_BSD_EVDEV
|
+ fcntl(evdev_fd, F_SETFL, O_NONBLOCK);
|
+#else
|
+ fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
|
+#endif
|
+
|
+ evdev_root_x = 0;
|
+ evdev_root_y = 0;
|
+ evdev_key_val = 0;
|
+ evdev_button = LV_INDEV_STATE_REL;
|
+}
|
+/**
|
+ * reconfigure the device file for evdev
|
+ * @param dev_name set the evdev device filename
|
+ * @return true: the device file set complete
|
+ * false: the device file doesn't exist current system
|
+ */
|
+bool evdev_set_file(char* dev_name)
|
+{
|
+ if(evdev_fd != -1) {
|
+ close(evdev_fd);
|
+ }
|
+#if USE_BSD_EVDEV
|
+ evdev_fd = open(dev_name, O_RDWR | O_NOCTTY);
|
+#else
|
+ evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY);
|
+#endif
|
+
|
+ if(evdev_fd == -1) {
|
+ perror("unable open evdev interface:");
|
+ return false;
|
+ }
|
+
|
+#if USE_BSD_EVDEV
|
+ fcntl(evdev_fd, F_SETFL, O_NONBLOCK);
|
+#else
|
+ fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
|
+#endif
|
+
|
+ evdev_root_x = 0;
|
+ evdev_root_y = 0;
|
+ evdev_key_val = 0;
|
+ evdev_button = LV_INDEV_STATE_REL;
|
+
|
+ return true;
|
+}
|
+/**
|
+ * Get the current position and state of the evdev
|
+ * @param data store the evdev data here
|
+ * @return false: because the points are not buffered, so no more data to be read
|
+ */
|
+void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
|
+{
|
+ struct input_event in;
|
+
|
+ while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {
|
+ if(in.type == EV_REL) {
|
+ if(in.code == REL_X)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_y += in.value;
|
+#else
|
+ evdev_root_x += in.value;
|
+#endif
|
+ else if(in.code == REL_Y)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_x += in.value;
|
+#else
|
+ evdev_root_y += in.value;
|
+#endif
|
+ } else if(in.type == EV_ABS) {
|
+ if(in.code == ABS_X)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_y = in.value;
|
+#else
|
+ evdev_root_x = in.value;
|
+#endif
|
+ else if(in.code == ABS_Y)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_x = in.value;
|
+#else
|
+ evdev_root_y = in.value;
|
+#endif
|
+ else if(in.code == ABS_MT_POSITION_X)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_y = in.value;
|
+#else
|
+ evdev_root_x = in.value;
|
+#endif
|
+ else if(in.code == ABS_MT_POSITION_Y)
|
+#if EVDEV_SWAP_AXES
|
+ evdev_root_x = in.value;
|
+#else
|
+ evdev_root_y = in.value;
|
+#endif
|
+ else if(in.code == ABS_MT_TRACKING_ID)
|
+ if(in.value == -1)
|
+ evdev_button = LV_INDEV_STATE_REL;
|
+ else if(in.value == 0)
|
+ evdev_button = LV_INDEV_STATE_PR;
|
+ } else if(in.type == EV_KEY) {
|
+ if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
|
+ if(in.value == 0)
|
+ evdev_button = LV_INDEV_STATE_REL;
|
+ else if(in.value == 1)
|
+ evdev_button = LV_INDEV_STATE_PR;
|
+ } else if(drv->type == LV_INDEV_TYPE_KEYPAD) {
|
+ data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
+ switch(in.code) {
|
+ case KEY_BACKSPACE:
|
+ data->key = LV_KEY_BACKSPACE;
|
+ break;
|
+ case KEY_ENTER:
|
+ data->key = LV_KEY_ENTER;
|
+ break;
|
+ case KEY_UP:
|
+ data->key = LV_KEY_UP;
|
+ break;
|
+ case KEY_LEFT:
|
+ data->key = LV_KEY_PREV;
|
+ break;
|
+ case KEY_RIGHT:
|
+ data->key = LV_KEY_NEXT;
|
+ break;
|
+ case KEY_DOWN:
|
+ data->key = LV_KEY_DOWN;
|
+ break;
|
+ default:
|
+ data->key = 0;
|
+ break;
|
+ }
|
+ evdev_key_val = data->key;
|
+ evdev_button = data->state;
|
+ return ;
|
+ }
|
+ }
|
+ }
|
+
|
+ if(drv->type == LV_INDEV_TYPE_KEYPAD) {
|
+ /* No data retrieved */
|
+ data->key = evdev_key_val;
|
+ data->state = evdev_button;
|
+ return ;
|
+ }
|
+ if(drv->type != LV_INDEV_TYPE_POINTER)
|
+ return ;
|
+ /*Store the collected data*/
|
+
|
+#if EVDEV_CALIBRATE
|
+ data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, drv->disp->driver->hor_res);
|
+ data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, drv->disp->driver->ver_res);
|
+#else
|
+ data->point.x = evdev_root_x;
|
+ data->point.y = evdev_root_y;
|
+#endif
|
+
|
+ data->state = evdev_button;
|
+
|
+ if(data->point.x < 0)
|
+ data->point.x = 0;
|
+ if(data->point.y < 0)
|
+ data->point.y = 0;
|
+ if (evdev_rot == 90 || evdev_rot == 270) {
|
+ int tmp;
|
+ if(data->point.x >= drv->disp->driver->ver_res)
|
+ data->point.x = drv->disp->driver->ver_res - 1;
|
+ if(data->point.y >= drv->disp->driver->hor_res)
|
+ data->point.y = drv->disp->driver->hor_res - 1;
|
+ tmp = data->point.x;
|
+ data->point.x = data->point.y;
|
+ data->point.y = drv->disp->driver->ver_res - 1 - tmp;
|
+ } else {
|
+ if(data->point.x >= drv->disp->driver->hor_res)
|
+ data->point.x = drv->disp->driver->hor_res - 1;
|
+ if(data->point.y >= drv->disp->driver->ver_res)
|
+ data->point.y = drv->disp->driver->ver_res - 1;
|
+ }
|
+
|
+ return ;
|
+}
|
+
|
+/**********************
|
+ * STATIC FUNCTIONS
|
+ **********************/
|
+int map(int x, int in_min, int in_max, int out_min, int out_max)
|
+{
|
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
+}
|
+
|
+#endif
|
diff --git a/rk_lvgl_demo/src/hal/evdev.h b/rk_lvgl_demo/src/hal/evdev.h
|
new file mode 100644
|
index 0000000..95a0588
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/evdev.h
|
@@ -0,0 +1,83 @@
|
+/**
|
+ * @file evdev.h
|
+ *
|
+ */
|
+
|
+#ifndef EVDEV_H
|
+#define EVDEV_H
|
+
|
+#ifdef __cplusplus
|
+extern "C" {
|
+#endif
|
+
|
+/*-------------------------------------------------
|
+ * Mouse or touchpad as evdev interface (for Linux based systems)
|
+ *------------------------------------------------*/
|
+#ifndef USE_EVDEV
|
+# define USE_EVDEV 1
|
+#endif
|
+
|
+#ifndef USE_BSD_EVDEV
|
+# define USE_BSD_EVDEV 0
|
+#endif
|
+
|
+#if USE_EVDEV || USE_BSD_EVDEV
|
+# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
+# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/
|
+
|
+# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
|
+
|
+# if EVDEV_CALIBRATE
|
+# define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
|
+# define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/
|
+# define EVDEV_VER_MIN 0
|
+# define EVDEV_VER_MAX 4096
|
+# endif /*EVDEV_CALIBRATE*/
|
+#endif /*USE_EVDEV*/
|
+
|
+#if USE_EVDEV || USE_BSD_EVDEV
|
+
|
+#include "lvgl.h"
|
+
|
+/*********************
|
+ * DEFINES
|
+ *********************/
|
+
|
+/**********************
|
+ * TYPEDEFS
|
+ **********************/
|
+
|
+/**********************
|
+ * GLOBAL PROTOTYPES
|
+ **********************/
|
+
|
+/**
|
+ * Initialize the evdev
|
+ */
|
+void evdev_init(int rot);
|
+/**
|
+ * reconfigure the device file for evdev
|
+ * @param dev_name set the evdev device filename
|
+ * @return true: the device file set complete
|
+ * false: the device file doesn't exist current system
|
+ */
|
+bool evdev_set_file(char* dev_name);
|
+/**
|
+ * Get the current position and state of the evdev
|
+ * @param data store the evdev data here
|
+ * @return false: because the points are not buffered, so no more data to be read
|
+ */
|
+void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
|
+
|
+
|
+/**********************
|
+ * MACROS
|
+ **********************/
|
+
|
+#endif /* USE_EVDEV */
|
+
|
+#ifdef __cplusplus
|
+} /* extern "C" */
|
+#endif
|
+
|
+#endif /* EVDEV_H */
|
diff --git a/rk_lvgl_demo/src/hal/key.c b/rk_lvgl_demo/src/hal/key.c
|
new file mode 100644
|
index 0000000..036b510
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/key.c
|
@@ -0,0 +1,110 @@
|
+/**
|
+ * @file evdev.c
|
+ *
|
+ */
|
+
|
+/*********************
|
+ * INCLUDES
|
+ *********************/
|
+#include "key.h"
|
+#if USE_KEY != 0
|
+
|
+#include <stdio.h>
|
+#include <unistd.h>
|
+#include <fcntl.h>
|
+#include <linux/input.h>
|
+
|
+/*********************
|
+ * DEFINES
|
+ *********************/
|
+
|
+/**********************
|
+ * TYPEDEFS
|
+ **********************/
|
+
|
+/**********************
|
+ * STATIC PROTOTYPES
|
+ **********************/
|
+
|
+/**********************
|
+ * STATIC VARIABLES
|
+ **********************/
|
+static int key_fd;
|
+static int key_button;
|
+
|
+static int key_val;
|
+/**********************
|
+ * MACROS
|
+ **********************/
|
+
|
+/**********************
|
+ * GLOBAL FUNCTIONS
|
+ **********************/
|
+
|
+/**
|
+ * Initialize the evdev interface
|
+ */
|
+void key_init(void)
|
+{
|
+ key_fd = open(KEY_NAME, O_RDWR | O_NOCTTY | O_NDELAY);
|
+
|
+ if(key_fd == -1) {
|
+ perror("unable open evdev interface:");
|
+ return;
|
+ }
|
+
|
+ fcntl(key_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
|
+
|
+ key_val = 0;
|
+ key_button = LV_INDEV_STATE_REL;
|
+}
|
+
|
+/**
|
+ * Get the current position and state of the evdev
|
+ * @param data store the evdev data here
|
+ * @return false: because the points are not buffered, so no more data to be read
|
+ */
|
+void key_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
|
+{
|
+ struct input_event in;
|
+
|
+ while(read(key_fd, &in, sizeof(struct input_event)) > 0) {
|
+ if(in.type == EV_KEY) {
|
+ data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
+ switch(in.code) {
|
+ case 1:
|
+ data->key = LV_KEY_ESC;
|
+ break;
|
+ case 139:
|
+ data->key = LV_KEY_ENTER;
|
+ break;
|
+ //case KEY_UP:
|
+ // data->key = LV_KEY_UP;
|
+ // break;
|
+ case 105:
|
+ data->key = LV_KEY_PREV;
|
+ break;
|
+ case 106:
|
+ data->key = LV_KEY_NEXT;
|
+ break;
|
+ //case KEY_DOWN:
|
+ // data->key = LV_KEY_DOWN;
|
+ // break;
|
+ default:
|
+ data->key = 0;
|
+ break;
|
+ }
|
+ key_val = data->key;
|
+ key_button = data->state;
|
+ return ;
|
+ }
|
+ }
|
+
|
+ if(drv->type == LV_INDEV_TYPE_KEYPAD) {
|
+ /* No data retrieved */
|
+ data->key = key_val;
|
+ data->state = key_button;
|
+ return ;
|
+ }
|
+}
|
+#endif
|
diff --git a/rk_lvgl_demo/src/hal/key.h b/rk_lvgl_demo/src/hal/key.h
|
new file mode 100644
|
index 0000000..dc3110b
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/hal/key.h
|
@@ -0,0 +1,58 @@
|
+/**
|
+ * @file key.h
|
+ *
|
+ */
|
+
|
+#ifndef KEY_H
|
+#define KEY_H
|
+
|
+#ifdef __cplusplus
|
+extern "C" {
|
+#endif
|
+
|
+/*-------------------------------------------------
|
+ * Mouse or touchpad as evdev interface (for Linux based systems)
|
+ *------------------------------------------------*/
|
+#define USE_KEY 0
|
+
|
+#if USE_KEY
|
+# define KEY_NAME "/dev/input/event2"
|
+
|
+#include "lvgl.h"
|
+
|
+/*********************
|
+ * DEFINES
|
+ *********************/
|
+
|
+/**********************
|
+ * TYPEDEFS
|
+ **********************/
|
+
|
+/**********************
|
+ * GLOBAL PROTOTYPES
|
+ **********************/
|
+
|
+/**
|
+ * Initialize the evdev
|
+ */
|
+void key_init(void);
|
+
|
+/**
|
+ * Get the current position and state of the evdev
|
+ * @param data store the evdev data here
|
+ * @return false: because the points are not buffered, so no more data to be read
|
+ */
|
+void key_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
|
+
|
+
|
+/**********************
|
+ * MACROS
|
+ **********************/
|
+
|
+#endif /* USE_KEY */
|
+
|
+#ifdef __cplusplus
|
+} /* extern "C" */
|
+#endif
|
+
|
+#endif /* KEY_H */
|
diff --git a/rk_lvgl_demo/src/lvgl/lv_port_disp.c b/rk_lvgl_demo/src/lvgl/lv_port_disp.c
|
new file mode 100644
|
index 0000000..5f6ac8b
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/lvgl/lv_port_disp.c
|
@@ -0,0 +1,287 @@
|
+/**
|
+ * @file lv_port_disp_templ.c
|
+ *
|
+ */
|
+
|
+ /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
|
+
|
+#include <pthread.h>
|
+#include <stdlib.h>
|
+#include <stdint.h>
|
+
|
+#include <rga/rga.h>
|
+#include <rga/RgaApi.h>
|
+
|
+#include "lv_port_disp.h"
|
+#include "lvgl.h"
|
+
|
+#include "hal/drm_display.h"
|
+
|
+static int rot_disp = 90;
|
+static int lcd_w;
|
+static int lcd_h;
|
+static int lcd_sw;
|
+static char* drm_buff;
|
+static lv_color_t *buf_1;
|
+
|
+//static struct timeval tvCbBegin;
|
+//static struct timeval tvCbEnd;
|
+static int quit = 0;
|
+static pthread_t disp_thread_pid;
|
+static pthread_mutex_t draw_mutex;
|
+static int draw_update = 0;
|
+
|
+static void disp_init(void);
|
+
|
+static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
|
+//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
|
+// const lv_area_t * fill_area, lv_color_t color);
|
+
|
+static void *disp_thread(void *arg)
|
+{
|
+ while (!quit) {
|
+ pthread_mutex_lock(&draw_mutex);
|
+ if (draw_update) {
|
+ struct drm_bo *bo = getdrmdisp();
|
+ char *dst_buff = NULL;
|
+ getdrmdispbuff(&dst_buff);
|
+ draw_update = 0;
|
+ if (rot_disp == 90 || rot_disp == 270) {
|
+ rga_info_t src;
|
+ rga_info_t dst;
|
+ memset(&src, 0, sizeof(rga_info_t));
|
+ memset(&dst, 0, sizeof(rga_info_t));
|
+ src.virAddr = drm_buff;
|
+ //src.fd = RK_MPI_MB_GetFD(mb1);
|
+ src.fd = -1;
|
+ src.mmuFlag = 1;
|
+ //dst.fd = bo->fb_id;
|
+ dst.fd = -1;
|
+ dst.virAddr = dst_buff;
|
+ dst.mmuFlag = 1;
|
+ //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride);
|
+ rga_set_rect(&src.rect, 0, 0, lcd_h, lcd_w, lcd_h, lcd_w, RK_FORMAT_BGRA_8888);
|
+ src.rotation = HAL_TRANSFORM_ROT_90;
|
+ //src.blend = 0xff0405;
|
+ rga_set_rect(&dst.rect, 0, 0, lcd_w, lcd_h, lcd_sw, lcd_h, RK_FORMAT_BGRA_8888);
|
+
|
+ int ret = c_RkRgaBlit(&src, &dst, NULL);
|
+ if (ret)
|
+ printf("c_RkRgaBlit2 error : %s\n", strerror(errno));
|
+ } else {
|
+#if 0
|
+ memcpy(dst_buff, drm_buff, lcd_w * lcd_h * 4);
|
+#else
|
+ rga_info_t src;
|
+ rga_info_t dst;
|
+ memset(&src, 0, sizeof(rga_info_t));
|
+ memset(&dst, 0, sizeof(rga_info_t));
|
+ src.virAddr = drm_buff;
|
+ //src.fd = RK_MPI_MB_GetFD(mb1);
|
+ src.mmuFlag = 1;
|
+ //dst.fd = bo->fb_id;
|
+ dst.virAddr = dst_buff;
|
+ dst.mmuFlag = 1;
|
+ //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride);
|
+ rga_set_rect(&src.rect, 0, 0, lcd_w, lcd_h, lcd_w, lcd_h, RK_FORMAT_BGRA_8888);
|
+ //src.rotation = HAL_TRANSFORM_ROT_90;
|
+ //src.blend = 0xff0105;
|
+ rga_set_rect(&dst.rect, 0, 0, lcd_w, lcd_h, lcd_sw, lcd_h, RK_FORMAT_BGRA_8888);
|
+
|
+ int ret = c_RkRgaBlit(&src, &dst, NULL);
|
+ if (ret)
|
+ printf("c_RkRgaBlit2 error : %s\n", strerror(errno));
|
+#endif
|
+ }
|
+ pthread_mutex_unlock(&draw_mutex);
|
+ setdrmdisp(bo);
|
+ } else {
|
+ pthread_mutex_unlock(&draw_mutex);
|
+ }
|
+ usleep(17000);
|
+ }
|
+ return NULL;
|
+}
|
+
|
+void lv_port_disp_init(int rot)
|
+{
|
+ rot_disp = rot;
|
+ /*-------------------------
|
+ * Initialize your display
|
+ * -----------------------*/
|
+ disp_init();
|
+
|
+ /*-----------------------------
|
+ * Create a buffer for drawing
|
+ *----------------------------*/
|
+
|
+ /**
|
+ * LVGL requires a buffer where it internally draws the widgets.
|
+ * Later this buffer will passed to your display driver's `flush_cb` to copy its content to your display.
|
+ * The buffer has to be greater than 1 display row
|
+ *
|
+ * There are 3 buffering configurations:
|
+ * 1. Create ONE buffer:
|
+ * LVGL will draw the display's content here and writes it to your display
|
+ *
|
+ * 2. Create TWO buffer:
|
+ * LVGL will draw the display's content to a buffer and writes it your display.
|
+ * You should use DMA to write the buffer's content to the display.
|
+ * It will enable LVGL to draw the next part of the screen to the other buffer while
|
+ * the data is being sent form the first buffer. It makes rendering and flushing parallel.
|
+ *
|
+ * 3. Double buffering
|
+ * Set 2 screens sized buffers and set disp_drv.full_refresh = 1.
|
+ * This way LVGL will always provide the whole rendered screen in `flush_cb`
|
+ * and you only need to change the frame buffer's address.
|
+ */
|
+
|
+ /* Example for 1) */
|
+ static lv_disp_draw_buf_t draw_buf_dsc_1;
|
+ buf_1 = malloc(lcd_w * lcd_h * 4);
|
+
|
+ lv_disp_draw_buf_init(&draw_buf_dsc_1, buf_1, NULL, lcd_w * lcd_h); /*Initialize the display buffer*/
|
+
|
+ /*-----------------------------------
|
+ * Register the display in LVGL
|
+ *----------------------------------*/
|
+
|
+ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
+ lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
+
|
+ /*Set up the functions to access to your display*/
|
+
|
+ /*Set the resolution of the display*/
|
+ if (rot_disp == 0) {
|
+ disp_drv.hor_res = lcd_w;
|
+ disp_drv.ver_res = lcd_h;
|
+
|
+ disp_drv.sw_rotate = 0;
|
+ disp_drv.rotated = LV_DISP_ROT_NONE;
|
+ } else if (rot_disp == 180) {
|
+ disp_drv.hor_res = lcd_w;
|
+ disp_drv.ver_res = lcd_h;
|
+
|
+ disp_drv.sw_rotate = 1;
|
+ disp_drv.rotated = LV_DISP_ROT_180;
|
+ } else if (rot_disp == 90) {
|
+ disp_drv.hor_res = lcd_h;
|
+ disp_drv.ver_res = lcd_w;
|
+
|
+ disp_drv.sw_rotate = 0;
|
+ disp_drv.rotated = LV_DISP_ROT_NONE;
|
+ } else if (rot_disp == 270) {
|
+ disp_drv.hor_res = lcd_h;
|
+ disp_drv.ver_res = lcd_w;
|
+
|
+ disp_drv.sw_rotate = 1;
|
+ disp_drv.rotated = LV_DISP_ROT_180;
|
+ }
|
+ /*Used to copy the buffer's content to the display*/
|
+ disp_drv.flush_cb = disp_flush;
|
+
|
+ /*Set a display buffer*/
|
+ disp_drv.draw_buf = &draw_buf_dsc_1;
|
+
|
+ /*Required for Example 3)*/
|
+ //disp_drv.full_refresh = 1
|
+
|
+ /* Fill a memory array with a color if you have GPU.
|
+ * Note that, in lv_conf.h you can enable GPUs that has built-in support in LVGL.
|
+ * But if you have a different GPU you can use with this callback.*/
|
+ //disp_drv.gpu_fill_cb = gpu_fill;
|
+
|
+ /*Finally register the driver*/
|
+ lv_disp_drv_register(&disp_drv);
|
+ pthread_mutex_init(&draw_mutex, NULL);
|
+ pthread_create(&disp_thread_pid, NULL, disp_thread, NULL);
|
+}
|
+
|
+/*Initialize your display and the required peripherals.*/
|
+static void disp_init(void)
|
+{
|
+ /*You code here*/
|
+ drm_init(32, rot_disp);
|
+ getdrmresolve(&lcd_w, &lcd_h);
|
+ lcd_sw = getdrmwstride();
|
+ drm_buff = malloc(lcd_w * lcd_h * 4);
|
+}
|
+
|
+/*Flush the content of the internal buffer the specific area on the display
|
+ *You can use DMA or any hardware acceleration to do this operation in the background but
|
+ *'lv_disp_flush_ready()' has to be called when finished.*/
|
+static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
+{
|
+ /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
|
+ int32_t x;
|
+ int32_t y;
|
+
|
+ //printf("%s, x1 = %d, y1 = %d, x2 = %d, y2 = %d, %d, %d\n\n\n", __func__, area->x1, area->y1, area->x2, area->y2, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1);
|
+ //gettimeofday(&tvCbBegin, NULL);
|
+ pthread_mutex_lock(&draw_mutex);
|
+ if (rot_disp == 90 || rot_disp == 270) {
|
+ for(y = area->y1; y <= area->y2; y++) {
|
+ int area_w = area->x2 - area->x1 + 1;
|
+ lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_h + area->x1) * 4);
|
+ memcpy(disp, color_p, area_w * 4);
|
+ color_p += area_w;
|
+ }
|
+ } else {
|
+#if 1
|
+ for(y = area->y1; y <= area->y2; y++) {
|
+ int area_w = area->x2 - area->x1 + 1;
|
+ lv_color_t *disp = (lv_color_t*)(drm_buff + (y * lcd_w + area->x1) * 4);
|
+ memcpy(disp, color_p, area_w * 4);
|
+ color_p += area_w;
|
+ }
|
+#else
|
+ rga_info_t src;
|
+ rga_info_t dst;
|
+ int area_w = area->x2 - area->x1 + 1;
|
+ int area_h = area->y2 - area->y1 + 1;
|
+ memset(&src, 0, sizeof(rga_info_t));
|
+ memset(&dst, 0, sizeof(rga_info_t));
|
+ src.virAddr = color_p;
|
+ //src.fd = RK_MPI_MB_GetFD(mb1);
|
+ src.mmuFlag = 1;
|
+ //dst.fd = bo->fb_id;
|
+ dst.virAddr = drm_buff;
|
+ dst.mmuFlag = 1;
|
+ //printf("%d, %d, %d, %d\n", stImageInfo.u32Width, stImageInfo.u32Height, stImageInfo.u32HorStride, stImageInfo.u32VerStride);
|
+ rga_set_rect(&src.rect, 0, 0, area_w, area_h, area_w, area_h, RK_FORMAT_RGBA_8888);
|
+ //src.rotation = HAL_TRANSFORM_ROT_90;
|
+ //src.blend = 0xff0105;
|
+ rga_set_rect(&dst.rect, area->x1, area->y1, area_w, area_h, lcd_w, lcd_h, RK_FORMAT_RGBA_8888);
|
+
|
+ int ret = c_RkRgaBlit(&src, &dst, NULL);
|
+ if (ret)
|
+ printf("c_RkRgaBlit2 error : %s\n", strerror(errno));
|
+#endif
|
+ }
|
+ draw_update = 1;
|
+ pthread_mutex_unlock(&draw_mutex);
|
+ //gettimeofday(&tvCbEnd, NULL);
|
+ //double dDuration = 1000 * (tvCbEnd.tv_sec - tvCbBegin.tv_sec) + ((tvCbEnd.tv_usec - tvCbBegin.tv_usec) / 1000.0);
|
+ //printf("%s dDuration = %f\n", __func__, dDuration);
|
+ /*IMPORTANT!!!
|
+ *Inform the graphics library that you are ready with the flushing*/
|
+ lv_disp_flush_ready(disp_drv);
|
+}
|
+
|
+/*OPTIONAL: GPU INTERFACE*/
|
+
|
+/*If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color*/
|
+//static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
|
+// const lv_area_t * fill_area, lv_color_t color)
|
+//{
|
+// /*It's an example code which should be done by your GPU*/
|
+// int32_t x, y;
|
+// dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
|
+//
|
+// for(y = fill_area->y1; y <= fill_area->y2; y++) {
|
+// for(x = fill_area->x1; x <= fill_area->x2; x++) {
|
+// dest_buf[x] = color;
|
+// }
|
+// dest_buf+=dest_width; /*Go to the next line*/
|
+// }
|
+//}
|
\ No newline at end of file
|
diff --git a/rk_lvgl_demo/src/lvgl/lv_port_disp.h b/rk_lvgl_demo/src/lvgl/lv_port_disp.h
|
new file mode 100644
|
index 0000000..2c9bfe8
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/lvgl/lv_port_disp.h
|
@@ -0,0 +1,21 @@
|
+/**
|
+ * @file lv_port_disp_templ.h
|
+ *
|
+ */
|
+
|
+ /*Copy this file as "lv_port_disp.h" and set this value to "1" to enable content*/
|
+
|
+#ifndef LV_PORT_DISP_TEMPL_H
|
+#define LV_PORT_DISP_TEMPL_H
|
+
|
+#ifdef __cplusplus
|
+extern "C" {
|
+#endif
|
+
|
+void lv_port_disp_init(int rot);
|
+
|
+#ifdef __cplusplus
|
+} /*extern "C"*/
|
+#endif
|
+
|
+#endif /*LV_PORT_DISP_TEMPL_H*/
|
diff --git a/rk_lvgl_demo/src/lvgl/lv_port_indev.c b/rk_lvgl_demo/src/lvgl/lv_port_indev.c
|
new file mode 100644
|
index 0000000..ea519fb
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/lvgl/lv_port_indev.c
|
@@ -0,0 +1,116 @@
|
+/**
|
+ * @file lv_port_indev_templ.c
|
+ *
|
+ */
|
+
|
+ /* Copy this file as "lv_port_indev.c" and set this value to "1" to enable conten */
|
+
|
+#include "lvgl.h"
|
+#include "lv_port_indev.h"
|
+
|
+#include "hal/evdev.h"
|
+#include "hal/key.h"
|
+
|
+typedef struct _GROUP_NODE {
|
+ struct _GROUP_NODE *next;
|
+ lv_group_t *group;
|
+} GROUP_NODE;
|
+
|
+static int rot_indev;
|
+lv_indev_t * indev_touchpad;
|
+lv_indev_t * indev_key;
|
+
|
+GROUP_NODE *group_list = NULL;
|
+
|
+lv_group_t *lv_port_indev_group_create(void)
|
+{
|
+ struct _GROUP_NODE *group_node = NULL;
|
+ lv_group_t *group = lv_group_create();
|
+
|
+ lv_indev_set_group(indev_key, group);
|
+ lv_group_set_default(group);
|
+
|
+ group_node = (struct _GROUP_NODE *)malloc(sizeof(struct _GROUP_NODE));
|
+ group_node->group = group;
|
+ group_node->next = NULL;
|
+ if (group_list) {
|
+ group_node->next = group_list;
|
+ group_list = group_node;
|
+ } else {
|
+ group_list = group_node;
|
+ }
|
+
|
+ return group;
|
+}
|
+
|
+void lv_port_indev_group_destroy(lv_group_t *group)
|
+{
|
+ if (group_list) {
|
+ struct _GROUP_NODE *group_node = NULL;
|
+ group_node = group_list;
|
+ if (group_list->group == group) {
|
+ group_list = group_list->next;
|
+ if (group_list) {
|
+ lv_indev_set_group(indev_key, group_list->group);
|
+ lv_group_set_default(group_list->group);
|
+ } else {
|
+ lv_indev_set_group(indev_key, NULL);
|
+ lv_group_set_default(NULL);
|
+ }
|
+ free(group_node);
|
+ } else {
|
+ while (group_node->next) {
|
+ struct _GROUP_NODE *group_node_next = group_node->next;
|
+ if (group_node_next->group == group) {
|
+ group_node->next = group_node_next->next;
|
+ free(group_node_next);
|
+ break;
|
+ }
|
+ group_node = group_node->next;
|
+ }
|
+ }
|
+ lv_group_del(group);
|
+ }
|
+}
|
+
|
+void lv_port_indev_init(int rot)
|
+{
|
+ /**
|
+ * Here you will find example implementation of input devices supported by LittelvGL:
|
+ * - Touchpad
|
+ * - Mouse (with cursor support)
|
+ * - Keypad (supports GUI usage only with key)
|
+ * - Encoder (supports GUI usage only with: left, right, push)
|
+ * - Button (external buttons to press points on the screen)
|
+ *
|
+ * The `..._read()` function are only examples.
|
+ * You should shape them according to your hardware
|
+ */
|
+
|
+ static lv_indev_drv_t indev_drv;
|
+ static lv_indev_drv_t key_drv;
|
+
|
+ rot_indev = rot;
|
+
|
+ /*------------------
|
+ * Touchpad
|
+ * -----------------*/
|
+
|
+ /*Initialize your touchpad if you have*/
|
+ evdev_init(rot);
|
+
|
+ /*Register a touchpad input device*/
|
+ lv_indev_drv_init(&indev_drv);
|
+ indev_drv.type = LV_INDEV_TYPE_POINTER;
|
+ indev_drv.read_cb = evdev_read;
|
+ indev_touchpad = lv_indev_drv_register(&indev_drv);
|
+
|
+#if USE_KEY
|
+ key_init();
|
+ lv_indev_drv_init(&key_drv);
|
+ key_drv.type = LV_INDEV_TYPE_KEYPAD;
|
+ key_drv.read_cb = key_read;
|
+ indev_key = lv_indev_drv_register(&key_drv);
|
+ lv_port_indev_group_create();
|
+#endif
|
+}
|
diff --git a/rk_lvgl_demo/src/lvgl/lv_port_indev.h b/rk_lvgl_demo/src/lvgl/lv_port_indev.h
|
new file mode 100644
|
index 0000000..3d9c54b
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/lvgl/lv_port_indev.h
|
@@ -0,0 +1,27 @@
|
+
|
+/**
|
+ * @file lv_port_indev_templ.h
|
+ *
|
+ */
|
+
|
+ /*Copy this file as "lv_port_indev.h" and set this value to "1" to enable content*/
|
+#if 1
|
+
|
+#ifndef LV_PORT_INDEV_TEMPL_H
|
+#define LV_PORT_INDEV_TEMPL_H
|
+
|
+#ifdef __cplusplus
|
+extern "C" {
|
+#endif
|
+
|
+void lv_port_indev_init(int rot);
|
+lv_group_t *lv_port_indev_group_create(void);
|
+void lv_port_indev_group_destroy(lv_group_t *group);
|
+
|
+#ifdef __cplusplus
|
+} /*extern "C"*/
|
+#endif
|
+
|
+#endif /*LV_PORT_INDEV_TEMPL_H*/
|
+
|
+#endif /*Disable/Enable content*/
|
diff --git a/rk_lvgl_demo/src/ui/demo.c b/rk_lvgl_demo/src/ui/demo.c
|
new file mode 100644
|
index 0000000..174b08f
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/ui/demo.c
|
@@ -0,0 +1,18 @@
|
+#include <stdio.h>
|
+#include <stdlib.h>
|
+#include <string.h>
|
+#include <unistd.h>
|
+#include <time.h>
|
+
|
+#include "lvgl.h"
|
+#include "../../../demos/music/lv_demo_music.h"
|
+
|
+void demo_start(void)
|
+{
|
+ lv_demo_music();
|
+}
|
+
|
+void demo_stop(void)
|
+{
|
+
|
+}
|
\ No newline at end of file
|
diff --git a/rk_lvgl_demo/src/ui/demo.h b/rk_lvgl_demo/src/ui/demo.h
|
new file mode 100644
|
index 0000000..1ffa602
|
--- /dev/null
|
+++ b/rk_lvgl_demo/src/ui/demo.h
|
@@ -0,0 +1,7 @@
|
+#ifndef __DEMO_H__
|
+#define __DEMO_H__
|
+
|
+void demo_start(void);
|
+void demo_start(void);
|
+
|
+#endif
|
--
|
2.7.4
|