drv_disp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2021-8-11 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_DISP)
  14. #include <rthw.h>
  15. #include <rtdevice.h>
  16. #include <rtdbg.h>
  17. #include "NuMicro.h"
  18. #include <drv_sys.h>
  19. #include <string.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #if !defined(DISP_USING_LCD_IDX)
  23. #define DISP_USING_LCD_IDX eDispLcd_1024x600
  24. #endif
  25. #if !defined(BSP_LCD_BPP)
  26. #define BSP_LCD_BPP 32
  27. #endif
  28. #if !defined(DISP_USING_OVERLAY)
  29. #define DISP_USING_OVERLAY
  30. #endif
  31. #define DEF_VPOST_BUFFER_NUMBER 3
  32. /* Private typedef --------------------------------------------------------------*/
  33. struct nu_disp
  34. {
  35. struct rt_device dev;
  36. char *name;
  37. E_DISP_LAYER layer;
  38. uint32_t last_commit;
  39. uint32_t ref_count;
  40. struct rt_device_graphic_info info;
  41. rt_uint8_t *pu8FBDMABuf;
  42. };
  43. typedef struct nu_disp *nu_disp_t;
  44. static volatile uint32_t g_u32VSyncBlank = 0;
  45. static struct rt_completion vsync_wq;
  46. static struct nu_disp nu_fbdev[eLayer_Cnt] =
  47. {
  48. {
  49. .name = "lcd",
  50. .layer = eLayer_Video,
  51. .ref_count = 0,
  52. }
  53. #if defined(DISP_USING_OVERLAY)
  54. , {
  55. .name = "overlay",
  56. .layer = eLayer_Overlay,
  57. .ref_count = 0,
  58. }
  59. #endif
  60. };
  61. rt_weak void nu_lcd_backlight_on(void) { }
  62. rt_weak void nu_lcd_backlight_off(void) { }
  63. static void nu_disp_isr(int vector, void *param)
  64. {
  65. /* Get DISP INTSTS */
  66. if (DISP_GET_INTSTS())
  67. {
  68. g_u32VSyncBlank++;
  69. rt_completion_done(&vsync_wq);
  70. }
  71. }
  72. static rt_err_t disp_layer_open(rt_device_t dev, rt_uint16_t oflag)
  73. {
  74. nu_disp_t psDisp = (nu_disp_t)dev;
  75. RT_ASSERT(psDisp != RT_NULL);
  76. psDisp->ref_count++;
  77. #if defined(DISP_USING_OVERLAY)
  78. if (psDisp->layer == eLayer_Overlay) // Depend on video layer
  79. {
  80. nu_fbdev[eLayer_Video].ref_count++;
  81. }
  82. #endif
  83. if (nu_fbdev[eLayer_Video].ref_count == 1)
  84. {
  85. DISP_SetTransparencyMode(eLayer_Video, eMASK);
  86. DISP_ENABLE_INT();
  87. DISP_Trigger(eLayer_Video, 1);
  88. }
  89. #if defined(DISP_USING_OVERLAY)
  90. if (nu_fbdev[eLayer_Overlay].ref_count == 1)
  91. {
  92. DISP_SetTransparencyMode(eLayer_Overlay, eOPAQUE);
  93. DISP_Trigger(eLayer_Overlay, 1);
  94. }
  95. #endif
  96. return RT_EOK;
  97. }
  98. static rt_err_t disp_layer_close(rt_device_t dev)
  99. {
  100. nu_disp_t psDisp = (nu_disp_t)dev;
  101. RT_ASSERT(psDisp != RT_NULL);
  102. psDisp->ref_count--;
  103. #if defined(DISP_USING_OVERLAY)
  104. if (psDisp->layer == eLayer_Overlay) // Depend on video layer
  105. {
  106. nu_fbdev[eLayer_Video].ref_count--;
  107. }
  108. if (nu_fbdev[eLayer_Overlay].ref_count == 0)
  109. {
  110. DISP_Trigger(eLayer_Overlay, 0);
  111. }
  112. #endif
  113. if (nu_fbdev[eLayer_Video].ref_count == 0)
  114. {
  115. DISP_DISABLE_INT();
  116. DISP_Trigger(eLayer_Video, 0);
  117. }
  118. return RT_EOK;
  119. }
  120. static rt_err_t disp_layer_control(rt_device_t dev, int cmd, void *args)
  121. {
  122. nu_disp_t psDisp = (nu_disp_t)dev;
  123. RT_ASSERT(psDisp != RT_NULL);
  124. switch (cmd)
  125. {
  126. case RTGRAPHIC_CTRL_POWERON:
  127. {
  128. nu_lcd_backlight_on();
  129. }
  130. break;
  131. case RTGRAPHIC_CTRL_POWEROFF:
  132. {
  133. nu_lcd_backlight_off();
  134. }
  135. break;
  136. case RTGRAPHIC_CTRL_GET_INFO:
  137. {
  138. struct rt_device_graphic_info *info = (struct rt_device_graphic_info *) args;
  139. RT_ASSERT(info != RT_NULL);
  140. rt_memcpy(args, (void *)&psDisp->info, sizeof(struct rt_device_graphic_info));
  141. }
  142. break;
  143. case RTGRAPHIC_CTRL_SET_MODE:
  144. {
  145. int pixfmt, bpp;
  146. E_FB_FMT eFBFmt;
  147. RT_ASSERT(args);
  148. pixfmt = *((int *)args);
  149. switch (pixfmt)
  150. {
  151. case RTGRAPHIC_PIXEL_FORMAT_RGB565:
  152. eFBFmt = eFBFmt_R5G6B5;
  153. bpp = 16;
  154. break;
  155. case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
  156. eFBFmt = eFBFmt_A8R8G8B8;
  157. bpp = 32;
  158. break;
  159. case RTGRAPHIC_PIXEL_FORMAT_MONO:
  160. case RTGRAPHIC_PIXEL_FORMAT_GRAY4:
  161. case RTGRAPHIC_PIXEL_FORMAT_GRAY16:
  162. case RTGRAPHIC_PIXEL_FORMAT_RGB332:
  163. case RTGRAPHIC_PIXEL_FORMAT_RGB444:
  164. case RTGRAPHIC_PIXEL_FORMAT_BGR565:
  165. case RTGRAPHIC_PIXEL_FORMAT_RGB666:
  166. case RTGRAPHIC_PIXEL_FORMAT_RGB888:
  167. case RTGRAPHIC_PIXEL_FORMAT_BGR888:
  168. case RTGRAPHIC_PIXEL_FORMAT_ABGR888:
  169. case RTGRAPHIC_PIXEL_FORMAT_RESERVED:
  170. default:
  171. return -RT_ERROR;
  172. }
  173. psDisp->info.bits_per_pixel = bpp;
  174. psDisp->info.pixel_format = pixfmt;
  175. psDisp->info.pitch = psDisp->info.width * (bpp >> 3U);
  176. /* Initial LCD */
  177. DISP_SetFBFmt(psDisp->layer, eFBFmt, psDisp->info.pitch);
  178. }
  179. break;
  180. case RTGRAPHIC_CTRL_GET_MODE:
  181. {
  182. RT_ASSERT(args);
  183. *((int *)args) = psDisp->info.pixel_format;
  184. }
  185. break;
  186. case RTGRAPHIC_CTRL_PAN_DISPLAY:
  187. {
  188. if (args != RT_NULL)
  189. {
  190. uint32_t u32BufPtr = (uint32_t)args;
  191. psDisp->last_commit = g_u32VSyncBlank;
  192. /* Pan display */
  193. return (DISP_SetFBAddr(psDisp->layer, u32BufPtr) == 0) ? RT_EOK : -RT_ERROR;
  194. }
  195. else
  196. return -RT_ERROR;
  197. }
  198. break;
  199. case RTGRAPHIC_CTRL_WAIT_VSYNC:
  200. {
  201. if (args != RT_NULL)
  202. psDisp->last_commit = g_u32VSyncBlank + 1;
  203. if (psDisp->last_commit >= g_u32VSyncBlank)
  204. {
  205. rt_completion_init(&vsync_wq);
  206. rt_completion_wait(&vsync_wq, RT_TICK_PER_SECOND / 60);
  207. }
  208. }
  209. break;
  210. default:
  211. return -RT_ERROR;
  212. }
  213. return RT_EOK;
  214. }
  215. static rt_err_t disp_layer_init(rt_device_t dev)
  216. {
  217. nu_disp_t psDisp = (nu_disp_t)dev;
  218. RT_ASSERT(psDisp != RT_NULL);
  219. rt_completion_init(&vsync_wq);
  220. return RT_EOK;
  221. }
  222. int rt_hw_disp_init(void)
  223. {
  224. int i;
  225. rt_err_t ret;
  226. /* Get LCD panel instance by ID. */
  227. const DISP_LCD_INFO *psDispLcdInstance = DISP_GetLCDInst(DISP_USING_LCD_IDX);
  228. RT_ASSERT(psDispLcdInstance != RT_NULL);
  229. /* Initial LCD */
  230. DISP_LCDInit(psDispLcdInstance);
  231. for (i = eLayer_Video;
  232. #if defined(DISP_USING_OVERLAY)
  233. i < eLayer_Cnt;
  234. #else
  235. i < eLayer_Overlay;
  236. #endif
  237. i++)
  238. {
  239. E_FB_FMT eFbFmt;
  240. nu_disp_t psDisp = &nu_fbdev[i];
  241. rt_memset((void *)&psDisp->info, 0, sizeof(struct rt_device_graphic_info));
  242. /* Register Disp device information */
  243. psDisp->info.bits_per_pixel = BSP_LCD_BPP;
  244. psDisp->info.pixel_format = (BSP_LCD_BPP == 32) ? RTGRAPHIC_PIXEL_FORMAT_ARGB888 : RTGRAPHIC_PIXEL_FORMAT_RGB565;
  245. psDisp->info.pitch = psDispLcdInstance->u32ResolutionWidth * (BSP_LCD_BPP / 8);
  246. psDisp->info.width = psDispLcdInstance->u32ResolutionWidth;
  247. psDisp->info.height = psDispLcdInstance->u32ResolutionHeight;
  248. /* Get pointer of video frame buffer */
  249. rt_uint8_t *pu8FBDMABuf = rt_malloc_align(psDisp->info.pitch * psDisp->info.height * DEF_VPOST_BUFFER_NUMBER, 128);
  250. if (pu8FBDMABuf == NULL)
  251. {
  252. rt_kprintf("Fail to get VRAM buffer for %s layer.\n", psDisp->name);
  253. RT_ASSERT(0);
  254. }
  255. else
  256. {
  257. /* Register non-cacheable DMA address to upper layer. */
  258. psDisp->info.framebuffer = (rt_uint8_t *)((uint32_t)pu8FBDMABuf | UNCACHEABLE);
  259. uint32_t u32FBSize = psDisp->info.pitch * psDispLcdInstance->u32ResolutionHeight;
  260. psDisp->info.smem_len = u32FBSize * DEF_VPOST_BUFFER_NUMBER;
  261. rt_memset(psDisp->info.framebuffer, 0, psDisp->info.smem_len);
  262. }
  263. eFbFmt = (psDisp->info.pixel_format == RTGRAPHIC_PIXEL_FORMAT_ARGB888) ? eFBFmt_A8R8G8B8 : eFBFmt_R5G6B5 ;
  264. ret = (rt_err_t)DISP_SetFBConfig(i, eFbFmt, psDisp->info.width, psDisp->info.height, (uint32_t)pu8FBDMABuf);
  265. RT_ASSERT(ret == RT_EOK);
  266. psDisp->pu8FBDMABuf = pu8FBDMABuf;
  267. /* Register member functions of lcd device */
  268. psDisp->dev.type = RT_Device_Class_Graphic;
  269. psDisp->dev.init = disp_layer_init;
  270. psDisp->dev.open = disp_layer_open;
  271. psDisp->dev.close = disp_layer_close;
  272. psDisp->dev.control = disp_layer_control;
  273. /* register graphic device driver */
  274. ret = rt_device_register(&psDisp->dev, psDisp->name, RT_DEVICE_FLAG_RDWR);
  275. RT_ASSERT(ret == RT_EOK);
  276. rt_kprintf("%s's fbdev video memory at 0x%08x.\n", psDisp->name, psDisp->info.framebuffer);
  277. }
  278. /* Register ISR */
  279. rt_hw_interrupt_install(DISP_IRQn, nu_disp_isr, RT_NULL, "DISP");
  280. /* Enable interrupt. */
  281. rt_hw_interrupt_umask(DISP_IRQn);
  282. return (int)ret;
  283. }
  284. INIT_DEVICE_EXPORT(rt_hw_disp_init);
  285. static void lcd_show_video_layer(void)
  286. {
  287. rt_device_open(&nu_fbdev[eLayer_Video].dev, RT_DEVICE_FLAG_RDWR);
  288. }
  289. MSH_CMD_EXPORT(lcd_show_video_layer, show video layer);
  290. static void lcd_hide_video_layer(void)
  291. {
  292. rt_device_close(&nu_fbdev[eLayer_Video].dev);
  293. }
  294. MSH_CMD_EXPORT(lcd_hide_video_layer, hide video layer);
  295. #if defined(DISP_USING_OVERLAY)
  296. int nu_overlay_set_colkey(uint32_t u32Low, uint32_t u32High)
  297. {
  298. DISP_SetColorKeyValue(u32Low, u32High);
  299. DISP_SetTransparencyMode(eLayer_Overlay, eKEY);
  300. return 0;
  301. }
  302. RTM_EXPORT(nu_overlay_set_colkey);
  303. /* Support "lcd_set_overlay_colkey" command line in msh mode */
  304. static rt_err_t lcd_set_overlay_colkey(int argc, char **argv)
  305. {
  306. unsigned int index, len, arg[2];
  307. rt_memset(arg, 0, sizeof(arg));
  308. len = (argc >= 3) ? 3 : argc;
  309. for (index = 0; index < (len - 1); index ++)
  310. {
  311. if (sscanf(argv[index + 1], "%x", &arg[index]) != 1)
  312. return -1;
  313. }
  314. rt_kprintf("colkeylow:0x%08x colkeyhigh:0x%08x\n", arg[0], arg[1]);
  315. nu_overlay_set_colkey(arg[0], arg[1]);
  316. return 0;
  317. }
  318. MSH_CMD_EXPORT(lcd_set_overlay_colkey, e.g: lcd_set_overlay_colkey colkeylow colkeyhigh);
  319. static void lcd_show_overlay_layer(void)
  320. {
  321. rt_device_open(&nu_fbdev[eLayer_Overlay].dev, RT_DEVICE_FLAG_RDWR);
  322. }
  323. static void lcd_hide_overlay_layer(void)
  324. {
  325. rt_device_close(&nu_fbdev[eLayer_Overlay].dev);
  326. }
  327. MSH_CMD_EXPORT(lcd_show_overlay_layer, show overlay layer);
  328. MSH_CMD_EXPORT(lcd_hide_overlay_layer, hide overlay layer);
  329. static void lcd_fill_layer_color(void)
  330. {
  331. nu_disp_t psDispLayer;
  332. int idx;
  333. for (idx = eLayer_Overlay; //eLayer_Video;
  334. #if defined(DISP_USING_OVERLAY)
  335. idx < eLayer_Cnt;
  336. #else
  337. idx < eLayer_Overlay;
  338. #endif
  339. idx++)
  340. {
  341. psDispLayer = &nu_fbdev[idx];
  342. if (psDispLayer->info.framebuffer != RT_NULL)
  343. {
  344. int i;
  345. uint32_t fill_num = psDispLayer->info.height * psDispLayer->info.width;
  346. uint32_t *fbmem_start = (uint32_t *)psDispLayer->info.framebuffer;
  347. uint32_t color = (0x3F << 24) | (rand() % 0x1000000) ;
  348. rt_kprintf("fill color=0x%08x on %s layer\n", color, psDispLayer->name);
  349. for (i = 0; i < fill_num; i++)
  350. {
  351. rt_memcpy((void *)&fbmem_start[i], &color, (psDispLayer->info.bits_per_pixel / 8));
  352. }
  353. }
  354. }
  355. }
  356. MSH_CMD_EXPORT(lcd_fill_layer_color, fill random color on overlay layer);
  357. static rt_err_t lcd_set_alphablend_opmode(int argc, char **argv)
  358. {
  359. unsigned int index, len, arg[1];
  360. rt_memset(arg, 0, sizeof(arg));
  361. len = (argc >= 2) ? 2 : argc;
  362. for (index = 0; index < (len - 1); index ++)
  363. {
  364. if (sscanf(argv[index + 1], "%x", &arg[index]) != 1)
  365. return -1;
  366. }
  367. rt_kprintf("opmode:0x%08x\n", arg[0]);
  368. if (arg[0] <= DC_BLEND_MODE_SRC_OUT)
  369. DISP_SetBlendOpMode(arg[0], eGloAM_NORMAL, eGloAM_NORMAL);
  370. return 0;
  371. }
  372. MSH_CMD_EXPORT(lcd_set_alphablend_opmode, Set alpha blending opmode);
  373. #endif
  374. #endif /* if defined(BSP_USING_DISP) */