dvp.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /* Copyright 2018 Canaan Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #include <math.h>
  16. #include <stddef.h>
  17. #include <stdint.h>
  18. #include "dvp.h"
  19. #include "fpioa.h"
  20. #include "sysctl.h"
  21. #include "utils.h"
  22. volatile dvp_t *const dvp = (volatile dvp_t *)DVP_BASE_ADDR;
  23. static uint8_t g_sccb_reg_len = 8;
  24. static void mdelay(uint32_t ms)
  25. {
  26. uint32_t i;
  27. while(ms && ms--)
  28. {
  29. for(i = 0; i < 25000; i++)
  30. __asm__ __volatile__("nop");
  31. }
  32. }
  33. static void dvp_sccb_clk_init(void)
  34. {
  35. uint32_t tmp;
  36. tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK));
  37. tmp |= DVP_SCCB_SCL_LCNT(255) | DVP_SCCB_SCL_HCNT(255);
  38. dvp->sccb_cfg = tmp;
  39. }
  40. uint32_t dvp_sccb_set_clk_rate(uint32_t clk_rate)
  41. {
  42. uint32_t tmp;
  43. uint32_t v_sccb_freq = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1);
  44. uint16_t v_period_clk_cnt = round(v_sccb_freq / clk_rate / 2.0);
  45. if(v_period_clk_cnt > 255)
  46. {
  47. return 0;
  48. }
  49. tmp = dvp->sccb_cfg & (~(DVP_SCCB_SCL_LCNT_MASK | DVP_SCCB_SCL_HCNT_MASK));
  50. tmp |= DVP_SCCB_SCL_LCNT(v_period_clk_cnt) | DVP_SCCB_SCL_HCNT(v_period_clk_cnt);
  51. dvp->sccb_cfg = tmp;
  52. return sysctl_clock_get_freq(SYSCTL_CLOCK_DVP) / (v_period_clk_cnt * 2);
  53. }
  54. static void dvp_sccb_start_transfer(void)
  55. {
  56. while(dvp->sts & DVP_STS_SCCB_EN)
  57. ;
  58. dvp->sts = DVP_STS_SCCB_EN | DVP_STS_SCCB_EN_WE;
  59. while(dvp->sts & DVP_STS_SCCB_EN)
  60. ;
  61. }
  62. void dvp_sccb_send_data(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data)
  63. {
  64. uint32_t tmp;
  65. tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
  66. (g_sccb_reg_len == 8) ? (tmp |= DVP_SCCB_BYTE_NUM_3) : (tmp |= DVP_SCCB_BYTE_NUM_4);
  67. dvp->sccb_cfg = tmp;
  68. if(g_sccb_reg_len == 8)
  69. {
  70. dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr) | DVP_SCCB_WDATA_BYTE0(reg_data);
  71. } else
  72. {
  73. dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff) | DVP_SCCB_WDATA_BYTE1(reg_data);
  74. }
  75. dvp_sccb_start_transfer();
  76. }
  77. uint8_t dvp_sccb_receive_data(uint8_t dev_addr, uint16_t reg_addr)
  78. {
  79. uint32_t tmp;
  80. tmp = dvp->sccb_cfg & (~DVP_SCCB_BYTE_NUM_MASK);
  81. if(g_sccb_reg_len == 8)
  82. tmp |= DVP_SCCB_BYTE_NUM_2;
  83. else
  84. tmp |= DVP_SCCB_BYTE_NUM_3;
  85. dvp->sccb_cfg = tmp;
  86. if(g_sccb_reg_len == 8)
  87. {
  88. dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr);
  89. } else
  90. {
  91. dvp->sccb_ctl = DVP_SCCB_WRITE_DATA_ENABLE | DVP_SCCB_DEVICE_ADDRESS(dev_addr) | DVP_SCCB_REG_ADDRESS(reg_addr >> 8) | DVP_SCCB_WDATA_BYTE0(reg_addr & 0xff);
  92. }
  93. dvp_sccb_start_transfer();
  94. dvp->sccb_ctl = DVP_SCCB_DEVICE_ADDRESS(dev_addr);
  95. dvp_sccb_start_transfer();
  96. return (uint8_t)DVP_SCCB_RDATA_BYTE(dvp->sccb_cfg);
  97. }
  98. static void dvp_reset(void)
  99. {
  100. /* First power down */
  101. dvp->cmos_cfg |= DVP_CMOS_POWER_DOWN;
  102. mdelay(200);
  103. dvp->cmos_cfg &= ~DVP_CMOS_POWER_DOWN;
  104. mdelay(200);
  105. /* Second reset */
  106. dvp->cmos_cfg &= ~DVP_CMOS_RESET;
  107. mdelay(200);
  108. dvp->cmos_cfg |= DVP_CMOS_RESET;
  109. mdelay(200);
  110. }
  111. void dvp_init(uint8_t reg_len)
  112. {
  113. g_sccb_reg_len = reg_len;
  114. sysctl_clock_enable(SYSCTL_CLOCK_DVP);
  115. sysctl_reset(SYSCTL_RESET_DVP);
  116. dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK);
  117. dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(3) | DVP_CMOS_CLK_ENABLE;
  118. dvp_sccb_clk_init();
  119. dvp_reset();
  120. }
  121. uint32_t dvp_set_xclk_rate(uint32_t xclk_rate)
  122. {
  123. uint32_t v_apb1_clk = sysctl_clock_get_freq(SYSCTL_CLOCK_APB1);
  124. uint32_t v_period;
  125. if(v_apb1_clk > xclk_rate * 2)
  126. v_period = round(v_apb1_clk / (xclk_rate * 2.0)) - 1;
  127. else
  128. v_period = 0;
  129. if(v_period > 255)
  130. v_period = 255;
  131. dvp->cmos_cfg &= (~DVP_CMOS_CLK_DIV_MASK);
  132. dvp->cmos_cfg |= DVP_CMOS_CLK_DIV(v_period) | DVP_CMOS_CLK_ENABLE;
  133. dvp_reset();
  134. return v_apb1_clk / ((v_period + 1) * 2);
  135. }
  136. void dvp_set_image_format(uint32_t format)
  137. {
  138. uint32_t tmp;
  139. tmp = dvp->dvp_cfg & (~DVP_CFG_FORMAT_MASK);
  140. dvp->dvp_cfg = tmp | format;
  141. }
  142. void dvp_enable_burst(void)
  143. {
  144. dvp->dvp_cfg |= DVP_CFG_BURST_SIZE_4BEATS;
  145. dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
  146. dvp->axi |= DVP_AXI_GM_MLEN_4BYTE;
  147. }
  148. void dvp_disable_burst(void)
  149. {
  150. dvp->dvp_cfg &= (~DVP_CFG_BURST_SIZE_4BEATS);
  151. dvp->axi &= (~DVP_AXI_GM_MLEN_MASK);
  152. dvp->axi |= DVP_AXI_GM_MLEN_1BYTE;
  153. }
  154. void dvp_set_image_size(uint32_t width, uint32_t height)
  155. {
  156. uint32_t tmp;
  157. tmp = dvp->dvp_cfg & (~(DVP_CFG_HREF_BURST_NUM_MASK | DVP_CFG_LINE_NUM_MASK));
  158. tmp |= DVP_CFG_LINE_NUM(height);
  159. if(dvp->dvp_cfg & DVP_CFG_BURST_SIZE_4BEATS)
  160. tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 4);
  161. else
  162. tmp |= DVP_CFG_HREF_BURST_NUM(width / 8 / 1);
  163. dvp->dvp_cfg = tmp;
  164. }
  165. void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)
  166. {
  167. #if FIX_CACHE
  168. configASSERT(!is_memory_cache((uintptr_t)r_addr));
  169. configASSERT(!is_memory_cache((uintptr_t)g_addr));
  170. configASSERT(!is_memory_cache((uintptr_t)b_addr));
  171. #endif
  172. dvp->r_addr = r_addr;
  173. dvp->g_addr = g_addr;
  174. dvp->b_addr = b_addr;
  175. }
  176. void dvp_set_display_addr(uint32_t addr)
  177. {
  178. #if FIX_CACHE
  179. configASSERT(!is_memory_cache((uintptr_t)addr));
  180. #endif
  181. dvp->rgb_addr = addr;
  182. }
  183. void dvp_start_frame(void)
  184. {
  185. while(!(dvp->sts & DVP_STS_FRAME_START))
  186. ;
  187. dvp->sts = (DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE);
  188. }
  189. void dvp_start_convert(void)
  190. {
  191. dvp->sts = DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
  192. }
  193. void dvp_finish_convert(void)
  194. {
  195. while(!(dvp->sts & DVP_STS_FRAME_FINISH))
  196. ;
  197. dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE;
  198. }
  199. void dvp_get_image(void)
  200. {
  201. while(!(dvp->sts & DVP_STS_FRAME_START))
  202. ;
  203. dvp->sts = DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE;
  204. while(!(dvp->sts & DVP_STS_FRAME_START))
  205. ;
  206. dvp->sts = DVP_STS_FRAME_FINISH | DVP_STS_FRAME_FINISH_WE | DVP_STS_FRAME_START | DVP_STS_FRAME_START_WE | DVP_STS_DVP_EN | DVP_STS_DVP_EN_WE;
  207. while(!(dvp->sts & DVP_STS_FRAME_FINISH))
  208. ;
  209. }
  210. void dvp_config_interrupt(uint32_t interrupt, uint8_t enable)
  211. {
  212. if(enable)
  213. dvp->dvp_cfg |= interrupt;
  214. else
  215. dvp->dvp_cfg &= (~interrupt);
  216. }
  217. int dvp_get_interrupt(uint32_t interrupt)
  218. {
  219. if(dvp->sts & interrupt)
  220. return 1;
  221. return 0;
  222. }
  223. void dvp_clear_interrupt(uint32_t interrupt)
  224. {
  225. interrupt |= (interrupt << 1);
  226. dvp->sts |= interrupt;
  227. }
  228. void dvp_enable_auto(void)
  229. {
  230. dvp->dvp_cfg |= DVP_CFG_AUTO_ENABLE;
  231. }
  232. void dvp_disable_auto(void)
  233. {
  234. dvp->dvp_cfg &= (~DVP_CFG_AUTO_ENABLE);
  235. }
  236. void dvp_set_output_enable(dvp_output_mode_t index, int enable)
  237. {
  238. configASSERT(index < 2);
  239. if(index == 0)
  240. {
  241. if(enable)
  242. dvp->dvp_cfg |= DVP_CFG_AI_OUTPUT_ENABLE;
  243. else
  244. dvp->dvp_cfg &= ~DVP_CFG_AI_OUTPUT_ENABLE;
  245. } else
  246. {
  247. if(enable)
  248. dvp->dvp_cfg |= DVP_CFG_DISPLAY_OUTPUT_ENABLE;
  249. else
  250. dvp->dvp_cfg &= ~DVP_CFG_DISPLAY_OUTPUT_ENABLE;
  251. }
  252. }