375 lines
12 KiB
C
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;
|
|
}
|
|
|
|
|