drv_vpost.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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-4-13 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_VPOST)
  14. #include <rthw.h>
  15. #include <rtdevice.h>
  16. #include <rtdbg.h>
  17. #include "NuMicro.h"
  18. #include <drv_sys.h>
  19. /* Private typedef --------------------------------------------------------------*/
  20. #define DEF_VPOST_BUFFER_NUMBER 3
  21. typedef enum
  22. {
  23. eVpost_LCD,
  24. #if defined(BSP_USING_VPOST_OSD)
  25. eVpost_OSD,
  26. #endif
  27. eVpost_Cnt
  28. } E_VPOST_LAYER;
  29. struct nu_vpost
  30. {
  31. struct rt_device dev;
  32. char *name;
  33. E_VPOST_LAYER layer;
  34. IRQn_Type irqn;
  35. E_SYS_IPRST rstidx;
  36. E_SYS_IPCLK clkidx;
  37. uint32_t last_commit;
  38. struct rt_device_graphic_info info;
  39. };
  40. typedef struct nu_vpost *nu_vpost_t;
  41. static volatile uint32_t g_u32VSyncBlank = 0;
  42. static struct rt_completion vsync_wq;
  43. static struct nu_vpost nu_fbdev[eVpost_Cnt] =
  44. {
  45. {
  46. .name = "lcd",
  47. .layer = eVpost_LCD,
  48. .irqn = IRQ_LCD,
  49. .rstidx = LCDRST,
  50. .clkidx = LCDCKEN,
  51. }
  52. #if defined(BSP_USING_VPOST_OSD)
  53. , {
  54. .name = "osd",
  55. .layer = eVpost_OSD,
  56. .irqn = (IRQn_Type) - 1,
  57. .rstidx = SYS_IPRST_NA,
  58. .clkidx = SYS_IPCLK_NA,
  59. }
  60. #endif
  61. };
  62. RT_WEAK void nu_lcd_backlight_on(void) { }
  63. RT_WEAK void nu_lcd_backlight_off(void) { }
  64. static rt_err_t vpost_layer_open(rt_device_t dev, rt_uint16_t oflag)
  65. {
  66. nu_vpost_t psVpost = (nu_vpost_t)dev;
  67. RT_ASSERT(psVpost != RT_NULL);
  68. switch (psVpost->layer)
  69. {
  70. case eVpost_LCD:
  71. vpostVAStartTrigger();
  72. break;
  73. #if defined(BSP_USING_VPOST_OSD)
  74. case eVpost_OSD:
  75. vpostVAStartTrigger();
  76. /* Set scale to 1:1 */
  77. vpostOSDScalingCtrl(1, 0, 0);
  78. #if (BSP_LCD_BPP==32)
  79. vpostOSDSetColMask(0xff, 0xff, 0xff);
  80. #else
  81. vpostOSDSetColMask(0x1f, 0x3f, 0x1f);
  82. #endif
  83. /* Enable color key function */
  84. vpostOSDSetColKey(0, 0, 0);
  85. /* Configure overlay function of OSD to display OSD image */
  86. vpostOSDSetOverlay(DISPLAY_OSD, DISPLAY_OSD, 0);
  87. vpostOSDEnable();
  88. break;
  89. #endif
  90. default:
  91. return -RT_ERROR;
  92. }
  93. return RT_EOK;
  94. }
  95. static rt_err_t vpost_layer_close(rt_device_t dev)
  96. {
  97. nu_vpost_t psVpost = (nu_vpost_t)dev;
  98. RT_ASSERT(psVpost != RT_NULL);
  99. switch (psVpost->layer)
  100. {
  101. case eVpost_LCD:
  102. #if defined(BSP_USING_VPOST_OSD)
  103. if (nu_fbdev[eVpost_OSD].dev.ref_count == 0)
  104. #endif
  105. vpostVAStopTrigger();
  106. break;
  107. #if defined(BSP_USING_VPOST_OSD)
  108. case eVpost_OSD:
  109. vpostOSDDisable();
  110. if (nu_fbdev[eVpost_LCD].dev.ref_count == 0)
  111. {
  112. /* Also stop displaying */
  113. vpostVAStopTrigger();
  114. }
  115. break;
  116. #endif
  117. default:
  118. return -RT_ERROR;
  119. }
  120. return RT_EOK;
  121. }
  122. static rt_err_t vpost_layer_control(rt_device_t dev, int cmd, void *args)
  123. {
  124. nu_vpost_t psVpost = (nu_vpost_t)dev;
  125. RT_ASSERT(psVpost != RT_NULL);
  126. switch (cmd)
  127. {
  128. case RTGRAPHIC_CTRL_POWERON:
  129. {
  130. nu_lcd_backlight_on();
  131. }
  132. break;
  133. case RTGRAPHIC_CTRL_POWEROFF:
  134. {
  135. nu_lcd_backlight_off();
  136. }
  137. break;
  138. case RTGRAPHIC_CTRL_GET_INFO:
  139. {
  140. struct rt_device_graphic_info *info = (struct rt_device_graphic_info *) args;
  141. RT_ASSERT(info != RT_NULL);
  142. rt_memcpy(args, (void *)&psVpost->info, sizeof(struct rt_device_graphic_info));
  143. }
  144. break;
  145. case RTGRAPHIC_CTRL_PAN_DISPLAY:
  146. {
  147. if (args != RT_NULL)
  148. {
  149. uint8_t *pu8BufPtr = (uint8_t *)args;
  150. psVpost->last_commit = g_u32VSyncBlank;
  151. /* Pan display */
  152. switch (psVpost->layer)
  153. {
  154. case eVpost_LCD:
  155. vpostSetFrameBuffer(pu8BufPtr);
  156. break;
  157. #if defined(BSP_USING_VPOST_OSD)
  158. case eVpost_OSD:
  159. vpostSetOSDBuffer(pu8BufPtr);
  160. break;
  161. #endif
  162. default:
  163. return -RT_ERROR;
  164. }
  165. }
  166. else
  167. return -RT_ERROR;
  168. }
  169. break;
  170. case RTGRAPHIC_CTRL_WAIT_VSYNC:
  171. {
  172. if (args != RT_NULL)
  173. psVpost->last_commit = g_u32VSyncBlank + 1;
  174. if (psVpost->last_commit >= g_u32VSyncBlank)
  175. {
  176. rt_completion_init(&vsync_wq);
  177. rt_completion_wait(&vsync_wq, RT_TICK_PER_SECOND / 60);
  178. }
  179. }
  180. break;
  181. default:
  182. return -RT_ERROR;
  183. }
  184. return RT_EOK;
  185. }
  186. static rt_err_t vpost_layer_init(rt_device_t dev)
  187. {
  188. nu_vpost_t psVpost = (nu_vpost_t)dev;
  189. RT_ASSERT(psVpost != RT_NULL);
  190. /* Enable VPOST engine clock. */
  191. nu_sys_ipclk_enable(LCDCKEN);
  192. rt_completion_init(&vsync_wq);
  193. outpw(REG_LCM_INT_CS, VPOSTB_UNDERRUN_EN | VPOSTB_DISP_F_EN);
  194. outpw(REG_LCM_DCCS, (inpw(REG_LCM_DCCS) | (1 << 4)));
  195. return RT_EOK;
  196. }
  197. static void nu_vpost_isr(int vector, void *param)
  198. {
  199. /*
  200. #define VPOSTB_DISP_F_INT ((UINT32)1<<31)
  201. #define VPOSTB_DISP_F_STATUS (1<<30)
  202. #define VPOSTB_UNDERRUN_INT (1<<29)
  203. #define VPOSTB_BUS_ERROR_INT (1<<28)
  204. #define VPOSTB_FLY_ERR (1<<27)
  205. #define VPOSTB_UNDERRUN_EN (1<<1)
  206. #define VPOSTB_DISP_F_EN (1)
  207. */
  208. uint32_t u32VpostIRQStatus = inpw(REG_LCM_INT_CS);
  209. if (u32VpostIRQStatus & VPOSTB_DISP_F_STATUS)
  210. {
  211. outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_DISP_F_STATUS);
  212. g_u32VSyncBlank++;
  213. rt_completion_done(&vsync_wq);
  214. }
  215. else if (u32VpostIRQStatus & VPOSTB_UNDERRUN_INT)
  216. {
  217. outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_UNDERRUN_INT);
  218. }
  219. else if (u32VpostIRQStatus & VPOSTB_BUS_ERROR_INT)
  220. {
  221. outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_BUS_ERROR_INT);
  222. }
  223. }
  224. int rt_hw_vpost_init(void)
  225. {
  226. int i = -1;
  227. rt_err_t ret;
  228. VPOST_T *psVpostLcmInst = vpostLCMGetInstance(VPOST_USING_LCD_IDX);
  229. RT_ASSERT(psVpostLcmInst != RT_NULL);
  230. if ((psVpostLcmInst->u32DevWidth * psVpostLcmInst->u32DevHeight) > (480 * 272))
  231. {
  232. /* LCD clock is selected from UPLL and divide to 20MHz */
  233. outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0xE18);
  234. /* LCD clock is selected from UPLL and divide to 30MHz */
  235. //outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0x918);
  236. }
  237. else
  238. {
  239. /* LCD clock is selected from UPLL and divide to 10MHz */
  240. outpw(REG_CLK_DIVCTL1, (inpw(REG_CLK_DIVCTL1) & ~0xff1f) | 0xE19);
  241. }
  242. /* Initial LCM */
  243. vpostLCMInit(VPOST_USING_LCD_IDX);
  244. /* Set scale to 1:1 */
  245. vpostVAScalingCtrl(1, 0, 1, 0, VA_SCALE_INTERPOLATION);
  246. for (i = eVpost_LCD; i < eVpost_Cnt; i++)
  247. {
  248. nu_vpost_t psVpost = &nu_fbdev[i];
  249. rt_memset((void *)&psVpost->info, 0, sizeof(struct rt_device_graphic_info));
  250. /* Register VPOST information */
  251. psVpost->info.bits_per_pixel = BSP_LCD_BPP;
  252. psVpost->info.pixel_format = (BSP_LCD_BPP == 32) ? RTGRAPHIC_PIXEL_FORMAT_ARGB888 : RTGRAPHIC_PIXEL_FORMAT_RGB565;
  253. psVpost->info.pitch = psVpostLcmInst->u32DevWidth * (BSP_LCD_BPP / 8);
  254. psVpost->info.width = psVpostLcmInst->u32DevWidth;
  255. psVpost->info.height = psVpostLcmInst->u32DevHeight;
  256. /* Get pointer of video frame buffer */
  257. /* Set display color depth */
  258. /* Note: before get pointer of frame buffer, must set display color depth first */
  259. if (psVpost->layer == eVpost_LCD)
  260. {
  261. #if (BSP_LCD_BPP==32)
  262. vpostSetVASrc(VA_SRC_RGB888);
  263. #else
  264. vpostSetVASrc(VA_SRC_RGB565);
  265. #endif
  266. psVpost->info.framebuffer = (rt_uint8_t *)vpostGetMultiFrameBuffer(DEF_VPOST_BUFFER_NUMBER);
  267. }
  268. #if defined(BSP_USING_VPOST_OSD)
  269. else if (psVpost->layer == eVpost_OSD)
  270. {
  271. vpostOSDSetWindow(0, 0, psVpost->info.width, psVpost->info.height);
  272. #if (BSP_LCD_BPP==32)
  273. vpostSetOSDSrc(OSD_SRC_RGB888);
  274. #else
  275. vpostSetOSDSrc(OSD_SRC_RGB565);
  276. #endif
  277. psVpost->info.framebuffer = (rt_uint8_t *)vpostGetMultiOSDBuffer(DEF_VPOST_BUFFER_NUMBER);
  278. }
  279. #endif
  280. if (psVpost->info.framebuffer == NULL)
  281. {
  282. rt_kprintf("Fail to get VRAM buffer.\n");
  283. RT_ASSERT(0);
  284. }
  285. else
  286. {
  287. uint32_t u32FBSize = psVpost->info.pitch * psVpostLcmInst->u32DevHeight;
  288. psVpost->info.smem_len = u32FBSize * DEF_VPOST_BUFFER_NUMBER;
  289. rt_memset(psVpost->info.framebuffer, 0, u32FBSize);
  290. }
  291. /* Register member functions of lcd device */
  292. psVpost->dev.type = RT_Device_Class_Graphic;
  293. psVpost->dev.init = vpost_layer_init;
  294. psVpost->dev.open = vpost_layer_open;
  295. psVpost->dev.close = vpost_layer_close;
  296. psVpost->dev.control = vpost_layer_control;
  297. /* Register graphic device driver */
  298. ret = rt_device_register(&psVpost->dev, psVpost->name, RT_DEVICE_FLAG_RDWR);
  299. RT_ASSERT(ret == RT_EOK);
  300. if (psVpost->layer == eVpost_LCD)
  301. {
  302. rt_hw_interrupt_install(psVpost->irqn, nu_vpost_isr, psVpost, psVpost->name);
  303. rt_hw_interrupt_umask(psVpost->irqn);
  304. }
  305. rt_kprintf("%s's fbmem at 0x%08x.\n", psVpost->name, psVpost->info.framebuffer);
  306. }
  307. /* For saving memory bandwidth. */
  308. vpostLCMDeinit();
  309. return (int)ret;
  310. }
  311. INIT_DEVICE_EXPORT(rt_hw_vpost_init);
  312. /* Support "vpost_set_osd_colkey" command line in msh mode */
  313. static rt_err_t vpost_set_osd_colkey(int argc, char **argv)
  314. {
  315. rt_uint32_t index, len, arg[4];
  316. rt_memset(arg, 0, sizeof(arg));
  317. len = (argc >= 4) ? 4 : argc;
  318. for (index = 0; index < (len - 1); index ++)
  319. {
  320. arg[index] = atol(argv[index + 1]);
  321. }
  322. /* Enable color key function */
  323. vpostOSDSetColKey(arg[0], arg[1], arg[2]);
  324. /* Configure overlay function of OSD to display VIDEO image */
  325. vpostOSDSetOverlay(DISPLAY_VIDEO, DISPLAY_OSD, 0);
  326. return 0;
  327. }
  328. MSH_CMD_EXPORT(vpost_set_osd_colkey, e.g: vpost_set_osd_colkey R G B);
  329. /* Support "vpost_show_layer" command line in msh mode */
  330. static rt_err_t vpost_show_layer(int argc, char **argv)
  331. {
  332. rt_uint32_t index, len, arg[2];
  333. nu_vpost_t psVpostLayer;
  334. rt_memset(arg, 0, sizeof(arg));
  335. len = (argc >= 2) ? 2 : argc;
  336. for (index = 0; index < (len - 1); index ++)
  337. {
  338. arg[index] = atol(argv[index + 1]);
  339. }
  340. psVpostLayer = &nu_fbdev[arg[0]];
  341. return rt_device_open(&psVpostLayer->dev, RT_DEVICE_FLAG_RDWR);
  342. }
  343. MSH_CMD_EXPORT(vpost_show_layer, e.g: vpost_show_layer layer);
  344. /* Support "vpost_hide_layer" command line in msh mode */
  345. static rt_err_t vpost_hide_layer(int argc, char **argv)
  346. {
  347. rt_uint32_t index, len, arg[2];
  348. nu_vpost_t psVpostLayer;
  349. rt_memset(arg, 0, sizeof(arg));
  350. len = (argc >= 2) ? 2 : argc;
  351. for (index = 0; index < (len - 1); index ++)
  352. {
  353. arg[index] = atol(argv[index + 1]);
  354. }
  355. psVpostLayer = &nu_fbdev[arg[0]];
  356. return rt_device_close(&psVpostLayer->dev);
  357. }
  358. MSH_CMD_EXPORT(vpost_hide_layer, e.g: vpost_hide_layer layer);
  359. /* Support "vpost_fill_color" command line in msh mode */
  360. static rt_err_t vpost_fill_color(int argc, char **argv)
  361. {
  362. rt_uint32_t index, len, arg[5];
  363. nu_vpost_t psVpostLayer;
  364. rt_memset(arg, 0, sizeof(arg));
  365. len = (argc >= 5) ? 5 : argc;
  366. for (index = 0; index < (len - 1); index ++)
  367. {
  368. arg[index] = atol(argv[index + 1]);
  369. }
  370. psVpostLayer = &nu_fbdev[arg[0]];
  371. if (psVpostLayer->info.framebuffer != RT_NULL)
  372. {
  373. int i;
  374. uint32_t fill_num = psVpostLayer->info.height * psVpostLayer->info.width;
  375. uint32_t *fbmem_start = (uint32_t *)psVpostLayer->info.framebuffer;
  376. uint32_t color = (arg[1] << 16) | (arg[2] << 8) | arg[3] ;
  377. for (i = 0; i < fill_num; i++)
  378. {
  379. rt_memcpy((void *)&fbmem_start[i], &color, (psVpostLayer->info.bits_per_pixel / 8));
  380. }
  381. }
  382. return 0;
  383. }
  384. MSH_CMD_EXPORT(vpost_fill_color, e.g: vpost_fill_color layer R G B);
  385. #endif /* if defined(BSP_USING_VPOST) */