/* * lvgl_disp_drv.c * * Copyright (c) 2019 Semidrive Semiconductor. * All rights reserved. * * Description: * * Revision History: * ----------------- * 011, 07/13/2019 BI create this file */ #include #include "lvgl_disp_drv.h" #include "lv_gpu_sdrv_dma2d.h" #include #include #include #if WITH_KERNEL_VM #include #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; }