drv_vpost.c 11 KB

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