/**************************************************************************//** * * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-4-13 Wayne First version * ******************************************************************************/ #include #if defined(BSP_USING_VPOST) #include #include #include #include "NuMicro.h" #include /* Private typedef --------------------------------------------------------------*/ typedef enum { eVpost_LCD, #if defined(BSP_USING_VPOST_OSD) eVpost_OSD, #endif eVpost_Cnt } E_VPOST_LAYER; struct nu_vpost { struct rt_device dev; char *name; E_VPOST_LAYER layer; IRQn_Type irqn; E_SYS_IPRST rstidx; E_SYS_IPCLK clkidx; struct rt_device_graphic_info info; }; typedef struct nu_vpost *nu_vpost_t; static struct nu_vpost nu_fbdev[eVpost_Cnt] = { { .name = "lcd", .layer = eVpost_LCD, .irqn = IRQ_LCD, .rstidx = LCDRST, .clkidx = LCDCKEN, } #if defined(BSP_USING_VPOST_OSD) , { .name = "osd", .layer = eVpost_OSD, .irqn = (IRQn_Type) - 1, .rstidx = SYS_IPRST_NA, .clkidx = SYS_IPCLK_NA, } #endif }; static rt_err_t vpost_layer_open(rt_device_t dev, rt_uint16_t oflag) { nu_vpost_t psVpost = (nu_vpost_t)dev; RT_ASSERT(psVpost != RT_NULL); switch (psVpost->layer) { case eVpost_LCD: vpostVAStartTrigger(); break; #if defined(BSP_USING_VPOST_OSD) case eVpost_OSD: vpostVAStartTrigger(); /* Set scale to 1:1 */ vpostOSDScalingCtrl(1, 0, 0); #if (LCM_USING_BPP==4) vpostOSDSetColMask(0xff, 0xff, 0xff); #else vpostOSDSetColMask(0x1f, 0x3f, 0x1f); #endif /* Enable color key function */ vpostOSDSetColKey(0, 0, 0); /* Configure overlay function of OSD to display OSD image */ vpostOSDSetOverlay(DISPLAY_OSD, DISPLAY_OSD, 0); vpostOSDEnable(); break; #endif default: return -RT_ERROR; } return RT_EOK; } static rt_err_t vpost_layer_close(rt_device_t dev) { nu_vpost_t psVpost = (nu_vpost_t)dev; RT_ASSERT(psVpost != RT_NULL); switch (psVpost->layer) { case eVpost_LCD: #if defined(BSP_USING_VPOST_OSD) if (nu_fbdev[eVpost_OSD].dev.ref_count == 0) #endif vpostVAStopTrigger(); break; #if defined(BSP_USING_VPOST_OSD) case eVpost_OSD: vpostOSDDisable(); if (nu_fbdev[eVpost_LCD].dev.ref_count == 0) { /* Also stop displaying */ vpostVAStopTrigger(); } break; #endif default: return -RT_ERROR; } return RT_EOK; } static rt_err_t vpost_layer_control(rt_device_t dev, int cmd, void *args) { nu_vpost_t psVpost = (nu_vpost_t)dev; RT_ASSERT(psVpost != RT_NULL); switch (cmd) { case RTGRAPHIC_CTRL_GET_INFO: { struct rt_device_graphic_info *info = (struct rt_device_graphic_info *) args; RT_ASSERT(info != RT_NULL); rt_memcpy(args, (void *)&psVpost->info, sizeof(struct rt_device_graphic_info)); } break; default: break; } return RT_EOK; } static rt_err_t vpost_layer_init(rt_device_t dev) { nu_vpost_t psVpost = (nu_vpost_t)dev; RT_ASSERT(psVpost != RT_NULL); /* Enable VPOST engine clock. */ nu_sys_ipclk_enable(LCDCKEN); return RT_EOK; } int rt_hw_vpost_init(void) { int i = -1; rt_err_t ret; VPOST_T *psVpostLcmInst = vpostLCMGetInstance(VPOST_USING_LCD_IDX); RT_ASSERT(psVpostLcmInst != RT_NULL); #if (LCM_USING_BPP==4 ) /* LCD clock is selected from UPLL and divide to 30MHz */ outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0x918); #else /* LCD clock is selected from UPLL and divide to 20MHz */ outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0xE18); #endif /* Initial LCM */ vpostLCMInit(VPOST_USING_LCD_IDX); /* Set scale to 1:1 */ vpostVAScalingCtrl(1, 0, 1, 0, VA_SCALE_INTERPOLATION); for (i = eVpost_LCD; i < eVpost_Cnt; i++) { nu_vpost_t psVpost = &nu_fbdev[i]; rt_memset((void *)&psVpost->info, 0, sizeof(struct rt_device_graphic_info)); /* Register VPOST information */ psVpost->info.bits_per_pixel = LCM_USING_BPP * 8; psVpost->info.pixel_format = (LCM_USING_BPP == 4) ? RTGRAPHIC_PIXEL_FORMAT_ARGB888 : RTGRAPHIC_PIXEL_FORMAT_RGB565; psVpost->info.pitch = psVpostLcmInst->u32DevWidth * LCM_USING_BPP; psVpost->info.width = psVpostLcmInst->u32DevWidth; psVpost->info.height = psVpostLcmInst->u32DevHeight; /* Get pointer of video frame buffer */ /* Set display color depth */ /* Note: before get pointer of frame buffer, must set display color depth first */ if (psVpost->layer == eVpost_LCD) { #if (LCM_USING_BPP==4) vpostSetVASrc(VA_SRC_RGB888); #else vpostSetVASrc(VA_SRC_RGB565); #endif psVpost->info.framebuffer = (rt_uint8_t *)vpostGetFrameBuffer(); } #if defined(BSP_USING_VPOST_OSD) else if (psVpost->layer == eVpost_OSD) { vpostOSDSetWindow(0, 0, psVpost->info.width, psVpost->info.height); #if (LCM_USING_BPP==4) vpostSetOSDSrc(OSD_SRC_RGB888); #else vpostSetOSDSrc(OSD_SRC_RGB565); #endif psVpost->info.framebuffer = (rt_uint8_t *)vpostGetOSDBuffer(); } #endif if (psVpost->info.framebuffer == NULL) { rt_kprintf("Fail to get VRAM buffer.\n"); RT_ASSERT(0); } /* Register member functions of lcd device */ psVpost->dev.type = RT_Device_Class_Graphic; psVpost->dev.init = vpost_layer_init; psVpost->dev.open = vpost_layer_open; psVpost->dev.close = vpost_layer_close; psVpost->dev.control = vpost_layer_control; /* register graphic device driver */ ret = rt_device_register(&psVpost->dev, psVpost->name, RT_DEVICE_FLAG_RDWR); RT_ASSERT(ret == RT_EOK); rt_kprintf("%s's fbmem at 0x%08x.\n", psVpost->name, psVpost->info.framebuffer); } /* For saving memory bandwidth. */ vpostLCMDeinit(); return (int)ret; } INIT_DEVICE_EXPORT(rt_hw_vpost_init); /* Support "vpost_set_osd_colkey" command line in msh mode */ static rt_err_t vpost_set_osd_colkey(int argc, char **argv) { rt_uint32_t index, len, arg[4]; rt_memset(arg, 0, sizeof(arg)); len = (argc >= 4) ? 4 : argc; for (index = 0; index < (len - 1); index ++) { arg[index] = atol(argv[index + 1]); } /* Enable color key function */ vpostOSDSetColKey(arg[0], arg[1], arg[2]); /* Configure overlay function of OSD to display VIDEO image */ vpostOSDSetOverlay(DISPLAY_VIDEO, DISPLAY_OSD, 0); return 0; } MSH_CMD_EXPORT(vpost_set_osd_colkey, e.g: vpost_set_osd_colkey R G B); /* Support "vpost_show_layer" command line in msh mode */ static rt_err_t vpost_show_layer(int argc, char **argv) { rt_uint32_t index, len, arg[2]; nu_vpost_t psVpostLayer; rt_memset(arg, 0, sizeof(arg)); len = (argc >= 2) ? 2 : argc; for (index = 0; index < (len - 1); index ++) { arg[index] = atol(argv[index + 1]); } psVpostLayer = &nu_fbdev[arg[0]]; return rt_device_open(&psVpostLayer->dev, RT_DEVICE_FLAG_RDWR); } MSH_CMD_EXPORT(vpost_show_layer, e.g: vpost_show_layer layer); /* Support "vpost_hide_layer" command line in msh mode */ static rt_err_t vpost_hide_layer(int argc, char **argv) { rt_uint32_t index, len, arg[2]; nu_vpost_t psVpostLayer; rt_memset(arg, 0, sizeof(arg)); len = (argc >= 2) ? 2 : argc; for (index = 0; index < (len - 1); index ++) { arg[index] = atol(argv[index + 1]); } psVpostLayer = &nu_fbdev[arg[0]]; return rt_device_close(&psVpostLayer->dev); } MSH_CMD_EXPORT(vpost_hide_layer, e.g: vpost_hide_layer layer); /* Support "vpost_fill_color" command line in msh mode */ static rt_err_t vpost_fill_color(int argc, char **argv) { rt_uint32_t index, len, arg[5]; nu_vpost_t psVpostLayer; rt_memset(arg, 0, sizeof(arg)); len = (argc >= 5) ? 5 : argc; for (index = 0; index < (len - 1); index ++) { arg[index] = atol(argv[index + 1]); } psVpostLayer = &nu_fbdev[arg[0]]; if (psVpostLayer->info.framebuffer != RT_NULL) { int i; uint32_t fill_num = psVpostLayer->info.height * psVpostLayer->info.width; uint32_t *fbmem_start = (uint32_t *)psVpostLayer->info.framebuffer; uint32_t color = (arg[1] << 16) | (arg[2] << 8) | arg[3] ; for (i = 0; i < fill_num; i++) { rt_memcpy((void *)&fbmem_start[i], &color, (psVpostLayer->info.bits_per_pixel / 8)); } } return 0; } MSH_CMD_EXPORT(vpost_fill_color, e.g: vpost_fill_color layer R G B); #endif /* if defined(BSP_USING_VPOST) */