drv_ccap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2022-8-16 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_CCAP)
  14. #include <rthw.h>
  15. #include "NuMicro.h"
  16. #include "ccap_sensor.h"
  17. #include "drv_ccap.h"
  18. #define LOG_TAG "drv.ccap"
  19. #define DBG_ENABLE
  20. #define DBG_SECTION_NAME LOG_TAG
  21. #define DBG_LEVEL LOG_LVL_INFO
  22. #define DBG_COLOR
  23. #include <rtdbg.h>
  24. /* Private Typedef --------------------------------------------------------------*/
  25. enum
  26. {
  27. CCAP_START = -1,
  28. #if defined(BSP_USING_CCAP0)
  29. CCAP0_IDX,
  30. #endif
  31. #if defined(BSP_USING_CCAP1)
  32. CCAP1_IDX,
  33. #endif
  34. CCAP_CNT
  35. };
  36. struct nu_ccap
  37. {
  38. struct rt_device device;
  39. char *name;
  40. CCAP_T *base;
  41. uint32_t rstidx;
  42. uint32_t modid_ccap;
  43. IRQn_Type irqn;
  44. ccap_config sConfig;
  45. };
  46. typedef struct nu_ccap *nu_ccap_t;
  47. static struct nu_ccap nu_ccap_arr [] =
  48. {
  49. #if defined(BSP_USING_CCAP0)
  50. {
  51. .name = "ccap0",
  52. .base = CCAP0,
  53. .rstidx = CCAP0_RST,
  54. .modid_ccap = CCAP0_MODULE,
  55. .irqn = CCAP0_IRQn,
  56. },
  57. #endif
  58. #if defined(BSP_USING_CCAP1)
  59. {
  60. .name = "ccap1",
  61. .base = CCAP1,
  62. .rstidx = CCAP1_RST,
  63. .modid_ccap = CCAP1_MODULE,
  64. .irqn = CCAP1_IRQn,
  65. },
  66. #endif
  67. };
  68. static void nu_ccap_isr(int vector, void *param)
  69. {
  70. nu_ccap_t ccap = (nu_ccap_t)param;
  71. CCAP_T *base = ccap->base;
  72. uint32_t u32CapInt, u32EvtMsk;
  73. u32CapInt = base->INT;
  74. u32EvtMsk = 0;
  75. if ((u32CapInt & (CCAP_INT_VIEN_Msk | CCAP_INT_VINTF_Msk)) == (CCAP_INT_VIEN_Msk | CCAP_INT_VINTF_Msk))
  76. {
  77. base->INT |= CCAP_INT_VINTF_Msk; /* Clear Frame end interrupt */
  78. u32EvtMsk |= NU_CCAP_FRAME_END;
  79. }
  80. if ((u32CapInt & (CCAP_INT_ADDRMIEN_Msk | CCAP_INT_ADDRMINTF_Msk)) == (CCAP_INT_ADDRMIEN_Msk | CCAP_INT_ADDRMINTF_Msk))
  81. {
  82. base->INT |= CCAP_INT_ADDRMINTF_Msk; /* Clear Address match interrupt */
  83. u32EvtMsk |= NU_CCAP_ADDRESS_MATCH;
  84. }
  85. if ((u32CapInt & (CCAP_INT_MEIEN_Msk | CCAP_INT_MEINTF_Msk)) == (CCAP_INT_MEIEN_Msk | CCAP_INT_MEINTF_Msk))
  86. {
  87. base->INT |= CCAP_INT_MEINTF_Msk; /* Clear Memory error interrupt */
  88. u32EvtMsk |= NU_CCAP_MEMORY_ERROR;
  89. }
  90. /* Invoke callback */
  91. if (ccap->device.rx_indicate != RT_NULL)
  92. ccap->device.rx_indicate(&ccap->device, 1);
  93. if (ccap->sConfig.pfnEvHndler && u32EvtMsk)
  94. ccap->sConfig.pfnEvHndler(ccap->sConfig.pvData, u32EvtMsk);
  95. base->CTL = base->CTL | CCAP_CTL_UPDATE;
  96. }
  97. /* common device interface */
  98. static rt_err_t ccap_init(rt_device_t dev)
  99. {
  100. return RT_EOK;
  101. }
  102. static void ccap_sensor_setfreq(nu_ccap_t psNuCcap, uint32_t u32SensorFreq)
  103. {
  104. uint32_t u32RegLockLevel = SYS_IsRegLocked();
  105. /* Unlock protected registers */
  106. if (u32RegLockLevel)
  107. SYS_UnlockReg();
  108. if (u32SensorFreq > 0)
  109. {
  110. int32_t i32Div;
  111. /* Specified sensor clock */
  112. i32Div = CLK_GetPLLClockFreq(SYSPLL) / u32SensorFreq;
  113. if (i32Div == 0)
  114. i32Div = 1;
  115. CLK_EnableModuleClock(psNuCcap->modid_ccap);
  116. if (psNuCcap->base == CCAP0)
  117. CLK_SetModuleClock(psNuCcap->modid_ccap, CLK_CLKSEL0_CCAP0SEL_SYSPLL, CLK_CLKDIV1_CCAP0(i32Div));
  118. else if (psNuCcap->base == CCAP1)
  119. CLK_SetModuleClock(psNuCcap->modid_ccap, CLK_CLKSEL0_CCAP1SEL_SYSPLL, CLK_CLKDIV1_CCAP1(i32Div));
  120. else
  121. return;
  122. LOG_I("CCAP Engine clock:%d", CLK_GetPLLClockFreq(SYSPLL));
  123. LOG_I("CCAP Sensor preferred clock %d, divider:%d", u32SensorFreq, i32Div);
  124. LOG_I("CCAP Sensor actully clock:%d", CLK_GetPLLClockFreq(SYSPLL) / i32Div);
  125. }
  126. else
  127. {
  128. CLK_DisableModuleClock(psNuCcap->modid_ccap);
  129. }
  130. /* Lock protected registers */
  131. if (u32RegLockLevel)
  132. SYS_LockReg();
  133. }
  134. static rt_err_t ccap_pipe_configure(nu_ccap_t psNuCcap, ccap_view_info_t psViewInfo)
  135. {
  136. sensor_mode_info_t psSensorModeInfo = (sensor_mode_info_t)psViewInfo;
  137. ccap_config_t psCcapConf = &psNuCcap->sConfig;
  138. uint32_t u32PipeEnabling = 0;
  139. struct rt_device_rect_info *psRectCropping = &psCcapConf->sRectCropping;
  140. /* Set Cropping Window Vertical/Horizontal Starting Address and Cropping Window Size */
  141. CCAP_SetCroppingWindow(psNuCcap->base, psRectCropping->y, psRectCropping->x, psRectCropping->height, psRectCropping->width);
  142. if (psCcapConf->sPipeInfo_Packet.pu8FarmAddr)
  143. {
  144. uint32_t u32WM, u32WN, u32HM, u32HN;
  145. /* Set System Memory Packet Base Address Register */
  146. CCAP_SetPacketBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Packet.pu8FarmAddr);
  147. u32WM = u32WN = u32HM = u32HN = 0;
  148. /* Set Packet Scaling Vertical/Horizontal Factor Register */
  149. if (psCcapConf->sPipeInfo_Packet.u32Height < psRectCropping->height)
  150. {
  151. u32HN = psCcapConf->sPipeInfo_Packet.u32Height;
  152. u32HM = psRectCropping->height;
  153. }
  154. if (psCcapConf->sPipeInfo_Packet.u32Width < psRectCropping->width)
  155. {
  156. u32WN = psCcapConf->sPipeInfo_Packet.u32Width;
  157. u32WM = psRectCropping->width;
  158. }
  159. CCAP_SetPacketScaling(psNuCcap->base,
  160. u32HN,
  161. u32HM,
  162. u32WN,
  163. u32WM);
  164. /* Set Packet Frame Output Pixel Stride Width */
  165. CCAP_SetPacketStride(psNuCcap->base, psCcapConf->u32Stride_Packet);
  166. u32PipeEnabling |= CCAP_CTL_PKTEN;
  167. }
  168. if (psCcapConf->sPipeInfo_Planar.pu8FarmAddr)
  169. {
  170. uint32_t u32Offset = 0;
  171. uint32_t u32WM, u32WN, u32HM, u32HN;
  172. uint32_t u32Div = 0;
  173. if (psCcapConf->sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV422)
  174. {
  175. /* U/V farm size equals Y/2 farm size */
  176. u32Div = 2;
  177. }
  178. else if (psCcapConf->sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV420)
  179. {
  180. /* U/V farm size equals Y/4 farm size */
  181. u32Div = 4;
  182. }
  183. else
  184. {
  185. goto fail_ccap_pipe_configure;
  186. }
  187. /* Set System Memory Planar Y Base Address Register */
  188. CCAP_SetPlanarYBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  189. u32Offset = psCcapConf->sPipeInfo_Planar.u32Height * psCcapConf->sPipeInfo_Planar.u32Width;
  190. /* Set System Memory Planar U Base Address Register */
  191. CCAP_SetPlanarUBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  192. u32Offset += ((psCcapConf->sPipeInfo_Planar.u32Height * psCcapConf->sPipeInfo_Planar.u32Width) / u32Div);
  193. /* Set System Memory Planar V Base Address Register */
  194. CCAP_SetPlanarVBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  195. u32WM = u32WN = u32HM = u32HN = 0;
  196. /* Set Planar Scaling Vertical/Horizontal Factor Register */
  197. if (psCcapConf->sPipeInfo_Planar.u32Height < psRectCropping->height)
  198. {
  199. u32HN = psCcapConf->sPipeInfo_Planar.u32Height;
  200. u32HM = psRectCropping->height;
  201. }
  202. if (psCcapConf->sPipeInfo_Planar.u32Width < psRectCropping->width)
  203. {
  204. u32WN = psCcapConf->sPipeInfo_Planar.u32Width;
  205. u32WM = psRectCropping->width;
  206. }
  207. /* Set Planar Scaling Vertical/Horizontal Factor Register */
  208. CCAP_SetPlanarScaling(psNuCcap->base,
  209. u32HN,
  210. u32HM,
  211. u32WN,
  212. u32WM);
  213. /* Set Planar Frame Output Pixel Stride Width */
  214. CCAP_SetPlanarStride(psNuCcap->base, psCcapConf->u32Stride_Planar);
  215. u32PipeEnabling |= CCAP_CTL_PLNEN;
  216. }
  217. /* Set Vsync polarity, Hsync polarity, pixel clock polarity, Sensor Format and Order */
  218. CCAP_Open(psNuCcap->base,
  219. psSensorModeInfo->u32Polarity |
  220. psViewInfo->u32PixFmt |
  221. psCcapConf->sPipeInfo_Packet.u32PixFmt |
  222. psCcapConf->sPipeInfo_Planar.u32PixFmt,
  223. u32PipeEnabling);
  224. return RT_EOK;
  225. fail_ccap_pipe_configure:
  226. return -RT_ERROR;
  227. }
  228. static rt_err_t ccap_open(rt_device_t dev, rt_uint16_t oflag)
  229. {
  230. nu_ccap_t psNuCcap = (nu_ccap_t)dev;
  231. uint32_t u32RegLockLevel = SYS_IsRegLocked();
  232. /* Unlock protected registers */
  233. if (u32RegLockLevel)
  234. SYS_UnlockReg();
  235. /* Enable clock */
  236. ccap_sensor_setfreq(psNuCcap, 24000000);
  237. /* Reset IP */
  238. SYS_ResetModule(psNuCcap->rstidx);
  239. /* Lock protected registers */
  240. if (u32RegLockLevel)
  241. SYS_LockReg();
  242. /* Unmask External CCAP Interrupt */
  243. rt_hw_interrupt_umask(psNuCcap->irqn);
  244. return RT_EOK;
  245. }
  246. static rt_err_t ccap_close(rt_device_t dev)
  247. {
  248. nu_ccap_t psNuCcap = (nu_ccap_t)dev;
  249. /* Stop capture engine */
  250. CCAP_Stop(psNuCcap->base, FALSE);
  251. /* Disable CCAP Interrupt */
  252. CCAP_DisableInt(psNuCcap->base, CCAP_INT_VIEN_Msk);
  253. /* Mask External CCAP Interrupt */
  254. rt_hw_interrupt_mask(psNuCcap->irqn);
  255. /* Disable clock */
  256. ccap_sensor_setfreq(psNuCcap, 0);
  257. return RT_EOK;
  258. }
  259. static rt_err_t ccap_control(rt_device_t dev, int cmd, void *args)
  260. {
  261. nu_ccap_t psNuCcap = (nu_ccap_t)dev;
  262. rt_err_t ret = -RT_ERROR;
  263. if (psNuCcap == RT_NULL)
  264. goto exit_ccap_control;
  265. switch (cmd)
  266. {
  267. case CCAP_CMD_CONFIG:
  268. {
  269. ccap_config *psCcapConf = (ccap_config *)args;
  270. if (args == RT_NULL)
  271. goto exit_ccap_control;
  272. rt_memcpy(&psNuCcap->sConfig, psCcapConf, sizeof(ccap_config));
  273. }
  274. break;
  275. case CCAP_CMD_START_CAPTURE:
  276. /* Enable CCAP Interrupt */
  277. CCAP_EnableInt(psNuCcap->base, CCAP_INT_VIEN_Msk);
  278. /* Start capture engine */
  279. CCAP_Start(psNuCcap->base);
  280. break;
  281. case CCAP_CMD_STOP_CAPTURE:
  282. /* Disable CCAP Interrupt */
  283. CCAP_DisableInt(psNuCcap->base, CCAP_INT_VIEN_Msk);
  284. /* Stop capture engine */
  285. CCAP_Stop(psNuCcap->base, FALSE);
  286. break;
  287. case CCAP_CMD_SET_SENCLK:
  288. {
  289. rt_uint32_t u32SenClk;
  290. RT_ASSERT(args);
  291. u32SenClk = *((rt_uint32_t *)args);
  292. if (u32SenClk > 0)
  293. ccap_sensor_setfreq(psNuCcap, u32SenClk);
  294. }
  295. break;
  296. case CCAP_CMD_SET_PIPES:
  297. {
  298. ccap_view_info_t psViewInfo;
  299. RT_ASSERT(args);
  300. psViewInfo = (ccap_view_info_t)args;
  301. ret = ccap_pipe_configure(psNuCcap, psViewInfo);
  302. }
  303. break;
  304. case CCAP_CMD_SET_OPMODE:
  305. {
  306. RT_ASSERT(args);
  307. int i32IsOneSutterMode = *((int *)args);
  308. /* Set shutter or continuous mode */
  309. CCAP_SET_CTL(psNuCcap->base, (i32IsOneSutterMode > 0) ? CCAP_CTL_SHUTTER_Msk : 0);
  310. }
  311. break;
  312. case CCAP_CMD_SET_BASEADDR:
  313. {
  314. uint32_t u32Offset = 0;
  315. ccap_config_t psCcapConf;
  316. RT_ASSERT(args);
  317. psCcapConf = (ccap_config_t)args;
  318. /* Set System Memory Packet Base Address Register */
  319. CCAP_SetPacketBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Packet.pu8FarmAddr);
  320. /* Set System Memory Planar Y Base Address Register */
  321. CCAP_SetPlanarYBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  322. u32Offset = psCcapConf->sPipeInfo_Planar.u32Height * psCcapConf->sPipeInfo_Planar.u32Width;
  323. /* Set System Memory Planar U Base Address Register */
  324. CCAP_SetPlanarUBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  325. u32Offset += ((psCcapConf->sPipeInfo_Planar.u32Height * psCcapConf->sPipeInfo_Planar.u32Width) / 2);
  326. /* Set System Memory Planar V Base Address Register */
  327. CCAP_SetPlanarVBuf(psNuCcap->base, (uint32_t)psCcapConf->sPipeInfo_Planar.pu8FarmAddr + u32Offset);
  328. }
  329. break;
  330. default:
  331. return -RT_ENOSYS;
  332. }
  333. ret = RT_EOK;
  334. exit_ccap_control:
  335. return ret;
  336. }
  337. #ifdef RT_USING_DEVICE_OPS
  338. static struct rt_device_ops ccap_ops =
  339. {
  340. .init = ccap_init,
  341. .open = ccap_open,
  342. .close = ccap_close,
  343. .read = RT_NULL,
  344. .write = RT_NULL,
  345. .control = ccap_control,
  346. };
  347. #endif
  348. static rt_err_t ccap_register(struct rt_device *device, const char *name, void *user_data)
  349. {
  350. RT_ASSERT(device);
  351. device->type = RT_Device_Class_Miscellaneous;
  352. device->rx_indicate = RT_NULL;
  353. device->tx_complete = RT_NULL;
  354. #ifdef RT_USING_DEVICE_OPS
  355. device->ops = &inputcapture_ops;
  356. #else
  357. device->init = ccap_init;
  358. device->open = ccap_open;
  359. device->close = ccap_close;
  360. device->read = RT_NULL;
  361. device->write = RT_NULL;
  362. device->control = ccap_control;
  363. #endif
  364. device->user_data = user_data;
  365. return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
  366. }
  367. /**
  368. * Hardware CCAP Initialization
  369. */
  370. int rt_hw_ccap_init(void)
  371. {
  372. int i;
  373. rt_err_t ret = RT_EOK;
  374. for (i = (CCAP_START + 1); i < CCAP_CNT; i++)
  375. {
  376. rt_memset(&nu_ccap_arr[i].sConfig, 0, sizeof(ccap_config));
  377. rt_hw_interrupt_install(nu_ccap_arr[i].irqn, nu_ccap_isr, &nu_ccap_arr[i], nu_ccap_arr[i].name);
  378. ret = ccap_register(&nu_ccap_arr[i].device, nu_ccap_arr[i].name, NULL);
  379. RT_ASSERT(ret == RT_EOK);
  380. }
  381. return ret;
  382. }
  383. INIT_DEVICE_EXPORT(rt_hw_ccap_init);
  384. #endif