Files
base/middleware/littlevgl/lvgl_sdrv/display/lvgl_disp_drv.c
2025-11-07 09:57:14 +08:00

375 lines
12 KiB
C

/*
* lvgl_disp_drv.c
*
* Copyright (c) 2019 Semidrive Semiconductor.
* All rights reserved.
*
* Description:
*
* Revision History:
* -----------------
* 011, 07/13/2019 BI create this file
*/
#include <debug.h>
#include "lvgl_disp_drv.h"
#include "lv_gpu_sdrv_dma2d.h"
#include <dispss/disp.h>
#include <dispss/disp_data_type.h>
#include <g2dlite/g2dlite.h>
#if WITH_KERNEL_VM
#include <kernel/vm.h>
#endif
#define SCREEN_MAX 3
#define LOGO_LAYER 0
#define BOOT_MENU_LAYER 1
#if WITH_KERNEL_VM
#define v2p(va) (paddr_t)(vaddr_to_paddr(va))
#define p2v(pa) (vaddr_t)(paddr_to_kvaddr(pa))
#else
#define v2p(va) (paddr_t)(va)
#define p2v(pa) (vaddr_t)(pa)
#endif
#if LV_USE_GPU_SEMIDRIVE_G2D
extern struct g2dlite_device g2dlite_dev;
#endif
unsigned int sd_get_color_format(void)
{
unsigned int format;
#if LV_COLOR_DEPTH == 16
format = LV_FMT_RGB565;
#elif LV_COLOR_DEPTH == 32
format = LV_FMT_ARGB8888;
#else
#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 16 or 32!"
#endif
return format;
}
unsigned char sd_get_bpp_by_format(unsigned int format)
{
unsigned char bpp = 0;
switch (format) {
case LV_FMT_RGB565:
bpp = 2;
break;
case LV_FMT_ARGB8888:
bpp = 4;
break;
default:
ssdk_printf(SSDK_INFO, "Not support this format\n");
break;
}
return bpp;
}
int area_valid_check(const lv_area_t * area)
{
int lcd_w, lcd_h;
lcd_w = lv_area_get_width(area);
lcd_h = lv_area_get_height(area);
ssdk_printf(SSDK_INFO, "lcd_w = %d, lcd_h = %d\n", lcd_w, lcd_h);
ssdk_printf(SSDK_INFO, "area x1 = %d, area y1 = %d\n", area->x1, area->y1);
ssdk_printf(SSDK_INFO, "area x2 = %d, area y2 = %d\n", area->x2, area->y2);
if ((area->x2 > lcd_w) || (area->y2 > lcd_h)) {
ssdk_printf(SSDK_INFO, "area size is over lcd size\n");
return -1;
}
return 0;
}
int sd_disp_post(struct _disp_drv_t * disp_drv, const lv_area_t * area,
lv_color_t *buf_bottom, lv_color_t *buf_top,
uint32_t length, lv_opa_t opa) {
LV_GPU_DisplayInfo info;
int i;
int n_layers;
lv_color_t *bufs[] = {buf_bottom, buf_top};
ssdk_printf(SSDK_INFO, "sd_disp_post start\n");
struct disp_data *data = (struct disp_data*)disp_drv->user_data;
memset(&info, 0, sizeof(LV_GPU_DisplayInfo));
if (!buf_bottom) {
ssdk_printf(SSDK_ERR, "Error: buf1 is null\n");
return -3;
}
n_layers = 1;
if (buf_top) {
n_layers ++;
}
info.winCnt = n_layers;
for (i = 0; i < n_layers; i++) {
LV_GPU_WindowInfo *layer = &info.winInfo[i];
layer->addr[0] = bufs[i];
if (i == 1)
layer->alpha = opa;
else
layer->alpha = 0xff;
layer->id = 0;
layer->dirty = 1;
layer->enAlpha = 0;// for bg transp 1->0
layer->ckey = 0;
layer->enCkey = 0;
layer->fmt = sd_get_color_format();
layer->en = 1;
layer->src.x1 = area->x1;
layer->src.y1 = area->y1;
layer->src.x2 = area->x2;
layer->src.y2 = area->y2;
layer->srcStride[0] = lv_area_get_width(area) * sd_get_bpp_by_format(layer->fmt);
// dc do not support scaling.
layer->dst.x1 = area->x1 + LVGL_DISPLAY_OFFSET_X;
layer->dst.y1 = area->y1 + LVGL_DISPLAY_OFFSET_Y;
layer->dst.x2 = area->x2;
layer->dst.y2 = area->y2;
layer->zOrder = 1;
// ssdk_printf(SSDK_INFO, "post_param: %p,0x%x,%d,%d,%d,%d,%d,stride=%d\n", (void *)layer->addr[0],
// layer->alpha, layer->fmt, layer->src.x, layer->src.y, layer->src.w,
//// layer->src.h, layer->src_stride[0]);
}
LV_GPU_DISP_Post(data->dc, &info);
// ssdk_printf(SSDK_INFO, "sd_disp_post end\n");
return 0;
}
#if LV_USE_GPU
void sd_gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa) {
LV_GPU_BlendImgInfo info;
memset(&info, 0, sizeof(info));
int surfaceCnt = 2;
for (int i = 0; i < surfaceCnt; i++) {
LV_GPU_SurfaceInfo *surface = (i == 0) ? &info.fgSurface : &info.bgSurface;
surface->buf = (i == 0) ? (lv_color_t *)src : (lv_color_t *)dest;
surface->alpha = opa;
surface->fmt = sd_get_color_format();
surface->stride = ((i == 0) ? length : disp_drv->hor_res) * sd_get_bpp_by_format(surface->fmt);
surface->maskRes = LV_DRAW_MASK_RES_CHANGED;
surface->srcArea.x1 = 0;
surface->srcArea.y1 = 0;
surface->srcArea.x2 = length - 1;
surface->srcArea.y2 = 0;
surface->dstArea.x1 = 0;
surface->dstArea.y1 = 0;
surface->dstArea.x2 = length - 1;
surface->dstArea.y2 = 0;
}
info.output.area.x1 = 0;
info.output.area.y1 = 0;
info.output.area.x2 = length -1;
info.output.area.y2 = 0;
info.output.fmt = sd_get_color_format();
info.output.buf = (lv_color_t *)dest;
info.output.stride = disp_drv->hor_res * sd_get_bpp_by_format(info.output.fmt);
(void)LV_GPU_G2DLITE_BlendImg(&info);
}
#endif
void disp_flush(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
#if LV_USE_USER_DATA
// struct disp_data *data = (struct disp_data*)disp_drv->user_data;
#endif
ssdk_printf(SSDK_INFO, "disp_flush start\n");
LV_GPU_CacheInfo cache = {0};
cache.area.x1 = 0;
cache.area.x2 = disp_drv->hor_res - 1;
cache.area.y1 = 0;
cache.area.y2 = disp_drv->ver_res - 1;
cache.buf = color_p;
cache.fmt = sd_get_color_format();
cache.stride = disp_drv->hor_res * sd_get_bpp_by_format(cache.fmt);
(void)LV_GPU_CleanInvalidateCacheRange(&cache);
sd_disp_post(disp_drv, area, color_p, NULL, 0, 0xff);
lv_disp_flush_ready(disp_drv);
ssdk_printf(SSDK_INFO, "disp_flush end\n");
}
/** OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the
* number of flushed pixels */
static void sd_monitor_cb(struct _disp_drv_t * disp_drv, uint32_t time, uint32_t px)
{
if (time % 1000 == 5)
ssdk_printf(SSDK_INFO, "time: %d, time %d\n", lv_tick_get(), time);
}
#if LV_USE_GPU
/* If your MCU has hardware accelerator (GPU) then you can use it to blend to memories using opacity
* * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
{
/*It's an example code which should be done by your GPU*/
LV_GPU_CacheInfo cache = {0};
cache.area.x1 = 0;
cache.area.x2 = disp_drv->hor_res - 1;
cache.area.y1 = 0;
cache.area.y2 = 0;
cache.buf = dest;
cache.fmt = sd_get_color_format();
cache.stride = disp_drv->hor_res * sd_get_bpp_by_format(cache.fmt);
(void)LV_GPU_CleanCacheRange(&cache);
sd_gpu_blend(disp_drv, dest, src, length, opa);
}
#endif
static uint32_t argb8888_to_rgb2101010(unsigned int color)
{
return (((color >> 16 & 0x000000ff) << 22) | ((color >> 8 & 0x000000ff) << 12) | ((color & 0x000000ff) << 2));
}
/* If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color
* * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
static void gpu_fill_cb(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)
{
#if LV_USE_GPU
LV_GPU_CacheInfo cache = {0};
cache.area.x1 = fill_area->x1;
cache.area.x2 = fill_area->x2;
cache.area.y1 = fill_area->y1;
cache.area.y2 = fill_area->y2;
cache.buf = dest_buf;
cache.fmt = sd_get_color_format();
cache.stride = dest_width * sd_get_bpp_by_format(cache.fmt);
(void)LV_GPU_CleanInvalidateCacheRange(&cache);
LV_GPU_FillRectInfo info;
memset(&info, 0, sizeof(info));
info.area.x1 = fill_area->x1;
info.area.x2 = fill_area->x2;
info.area.y1 = fill_area->y1;
info.area.y2 = fill_area->y2;
info.buf = dest_buf;
info.color = color;
info.fmt = sd_get_color_format();
info.stride = dest_width * sd_get_bpp_by_format(info.fmt);
(void)LV_GPU_G2DLITE_FillRect(&info);
#else
/*It's an example code which should be done by your GPU*/
lv_coord_t x, y;
// ssdk_printf(SSDK_INFO, "gpu fill.....(%d, %d, %d, %d).\n", fill_area->x1, fill_area->y1, fill_area->x2, fill_area->y2);
lv_color_t *p = dest_buf;
dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
// arch_clean_cache_range((addr_t)dest_buf, dest_width * (fill_area->y2 - fill_area->y1) * 4);
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[x] = lv_color_mix(LV_COLOR_ORANGE, color , LV_OPA_100);
}
dest_buf+=dest_width; /*Go to the next line*/
}
#endif
}
static void gpu_rotation_cb(void * buf_act,const uint8_t * img_map,int img_angle,int hsize,int vsize,uint8_t *map2)
{
#if LV_USE_GPU
ssdk_printf(SSDK_INFO, "not support retation\r\n");
//hal_aswlite_rotaion(buf_act,img_map,img_angle,hsize,vsize,map2);
#endif
}
struct g2dlite {
int index;
addr_t reg_addr;
uint32_t irq_num;
};
lv_disp_t *lvgl_lcd_display_init()
{
//int ret;
struct disp_data *data;
int width = LVGL_DISPLAY_WIDTH;
int height = LVGL_DISPLAY_HEIGHT;
ssdk_printf(SSDK_INFO, "lvgl_lcd_display_init start:width[%d], height[%d], LV_COLOR_DEPTH[%d]\n", width, height, LV_COLOR_DEPTH);
#ifdef USE_STATIC_ADDRESS
lv_color_t *buf3_1 = (lv_color_t *)0x32000000;
lv_color_t *buf3_2 = (lv_color_t *)0x33000000;
#else
lv_color_t *buf3_1 = (lv_color_t *)pvPortMallocAligned(width * height * LV_COLOR_DEPTH / 8, 0x1000);
// lv_color_t *buf3_1 = (lv_color_t *)0x620000;
lv_color_t *buf3_2 = (lv_color_t *)pvPortMallocAligned(width * height * LV_COLOR_DEPTH / 8, 0x1000);
#endif
memset(buf3_1, 0, width * height * LV_COLOR_DEPTH / 8);
memset(buf3_2, 0, width * height * LV_COLOR_DEPTH / 8);
lv_disp_buf_t *disp_buf_3 = (lv_disp_buf_t *)pvPortMalloc(sizeof(lv_disp_buf_t));
lv_disp_buf_init(disp_buf_3, buf3_1, buf3_2, width * height); /*Initialize the display buffer*/
disp_buf_3->area.x1 = 0;
disp_buf_3->area.y1 = 0;
disp_buf_3->area.x2 = width - 1;
disp_buf_3->area.y2 = height - 1;//cxy
ssdk_printf(SSDK_ALERT, "register buffers: %p ,%p for disp\n", buf3_1, buf3_2);
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
data = (struct disp_data *) pvPortMalloc(sizeof(struct disp_data));
if (!data) {
ssdk_printf(SSDK_ALERT, "create disp_data failed\n");
}
/*Set up the functions to access to your display*/
/*Set the resolution of the display*/
disp_drv.hor_res = width;
disp_drv.ver_res = height;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
disp_drv.monitor_cb = sd_monitor_cb;
/*Set a display buffer*/
disp_drv.buffer = disp_buf_3;
data->dc = LV_GPU_DISP_GetHandle(LV_SCREEN_TYPE_CLUSTER);
#if LV_USE_GPU_SEMIDRIVE_G2D
data->g2d = (void *)&g2dlite_dev;
#endif
disp_drv.user_data = data;
#if LV_USE_GPU
/*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
/*Fill a memory array with a color*/
disp_drv.gpu_fill_cb = gpu_fill_cb;
/*Blend two color array using opacity*/
disp_drv.gpu_blend_cb = gpu_blend;
/*Blend img rotation*/
//disp_drv.gpu_rotation_cb = gpu_rotation_cb;
#endif
/*Finally register the driver*/
lv_disp_t *disp = lv_disp_drv_register(&disp_drv);
ssdk_printf(SSDK_INFO, "lvgl_lcd_display_init end %p\n",disp);
return disp;
}