1 /*
2 * Copyright (c) 2021-2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_cam_drv.h"
9
10 #define CAM_RX_FIFO_THRESHOLD (6U)
11
cam_get_default_config(CAM_Type * ptr,cam_config_t * config,display_pixel_format_t pixel_format)12 void cam_get_default_config(CAM_Type *ptr, cam_config_t *config, display_pixel_format_t pixel_format)
13 {
14 (void) ptr;
15 config->width = 320;
16 config->height = 240;
17 config->buffer1 = -1;
18 config->buffer2 = -1;
19 config->pixclk_sampling_falling = false;
20 config->hsync_active_low = false;
21 config->vsync_active_low = false;
22 #if defined(HPM_IP_FEATURE_CAM_INV_DEN) && (HPM_IP_FEATURE_CAM_INV_DEN == 1)
23 config->de_active_low = false;
24 #endif
25 config->color_ext = false;
26 config->data_pack_msb = false;
27 config->data_store_mode = CAM_DATA_STORE_MODE_NORMAL;
28 config->color_format = pixel_format;
29 config->sensor_bitwidth = CAM_SENSOR_BITWIDTH_10BITS;
30
31 switch (pixel_format) {
32 case display_pixel_format_yuv422:
33 config->csc_config.enable = true;
34 config->csc_config.ycbcr_mode = false;
35 config->csc_config.yuv2rgb_coef.c0 = 0x100;
36 config->csc_config.yuv2rgb_coef.uv_offset = 0;
37 config->csc_config.yuv2rgb_coef.y_offset = 0;
38 config->csc_config.yuv2rgb_coef.c1 = 0x123;
39 config->csc_config.yuv2rgb_coef.c2 = 0x76B;
40 config->csc_config.yuv2rgb_coef.c3 = 0x79C;
41 config->csc_config.yuv2rgb_coef.c4 = 0x208;
42 break;
43 case display_pixel_format_ycbcr422:
44 config->csc_config.enable = true;
45 config->csc_config.ycbcr_mode = true;
46 config->csc_config.yuv2rgb_coef.c0 = 0x12A;
47 config->csc_config.yuv2rgb_coef.uv_offset = 0x180;
48 config->csc_config.yuv2rgb_coef.y_offset = 0x1F0;
49 config->csc_config.yuv2rgb_coef.c1 = 0x198;
50 config->csc_config.yuv2rgb_coef.c2 = 0x730;
51 config->csc_config.yuv2rgb_coef.c3 = 0x79C;
52 config->csc_config.yuv2rgb_coef.c4 = 0x204;
53 break;
54 default:
55 config->csc_config.enable = false;
56 config->csc_config.ycbcr_mode = false;
57 config->csc_config.yuv2rgb_coef.c0 = 0;
58 config->csc_config.yuv2rgb_coef.uv_offset = 0;
59 config->csc_config.yuv2rgb_coef.y_offset = 0;
60 config->csc_config.yuv2rgb_coef.c1 = 0;
61 config->csc_config.yuv2rgb_coef.c2 = 0;
62 config->csc_config.yuv2rgb_coef.c3 = 0;
63 config->csc_config.yuv2rgb_coef.c4 = 0;
64 break;
65 }
66 }
67
cam_reset(CAM_Type * ptr)68 void cam_reset(CAM_Type *ptr)
69 {
70 cam_stop(ptr);
71 ptr->CR1 = CAM_CR1_ASYNC_RXFIFO_CLR_MASK;
72 ptr->INT_EN = 0;
73 ptr->CR2 = CAM_CR2_FRMCNT_RST_MASK;
74 ptr->STA = 0xFFFFFFFF;
75 ptr->CR20 = 0;
76 }
77
cam_init(CAM_Type * ptr,cam_config_t * config)78 hpm_stat_t cam_init(CAM_Type *ptr, cam_config_t *config)
79 {
80 hpm_stat_t stat = status_success;
81 uint32_t pixel_format, width;
82
83 pixel_format = config->color_format;
84 width = config->width;
85
86 if ((int)config->buffer1 < 0) {
87 return status_invalid_argument;
88 }
89
90 if (pixel_format == CAM_COLOR_FORMAT_RAW8) {
91 if ((width % 2) != 0) {
92 return status_invalid_argument;
93 }
94 /* use rgb565 format to receive raw8 data and adjust the width to half */
95 pixel_format = CAM_COLOR_FORMAT_RGB565;
96 width /= 2;
97 }
98
99 cam_reset(ptr);
100
101 /*
102 * In DVP mode, de_active_low and hsync_active_low are same.
103 */
104 #if defined(HPM_IP_FEATURE_CAM_INV_DEN) && (HPM_IP_FEATURE_CAM_INV_DEN == 1)
105 if (config->sensor_bitwidth != CAM_SENSOR_BITWIDTH_24BITS) {
106 config->de_active_low = config->hsync_active_low;
107 }
108 #endif
109
110 ptr->CR1 = CAM_CR1_INV_PIXCLK_SET(config->pixclk_sampling_falling)
111 | CAM_CR1_INV_HSYNC_SET(config->hsync_active_low)
112 | CAM_CR1_INV_VSYNC_SET(config->vsync_active_low)
113 #if defined(HPM_IP_FEATURE_CAM_INV_DEN) && (HPM_IP_FEATURE_CAM_INV_DEN == 1)
114 | CAM_CR1_INV_DEN_SET(config->de_active_low)
115 #endif
116 | CAM_CR1_RESTART_BUSPTR_MASK
117 | CAM_CR1_COLOR_EXT_SET(config->color_ext)
118 | CAM_CR1_PACK_DIR_SET(config->data_pack_msb)
119 | config->data_store_mode
120 | pixel_format
121 | config->sensor_bitwidth;
122
123 ptr->IDEAL_WN_SIZE = CAM_IDEAL_WN_SIZE_HEIGHT_SET(config->height)
124 | CAM_IDEAL_WN_SIZE_WIDTH_SET(width);
125
126 ptr->CR2 = CAM_CR2_DMA_REQ_EN_RFF_MASK
127 | CAM_CR2_RXFF_LEVEL_SET(CAM_RX_FIFO_THRESHOLD);
128 ptr->DMASA_FB1 = config->buffer1;
129 if ((int)config->buffer2 < 0) {
130 ptr->DMASA_FB2 = config->buffer1;
131 } else {
132 ptr->DMASA_FB2 = config->buffer2;
133 }
134
135 ptr->CSC_COEF0 = CAM_CSC_COEF0_ENABLE_SET(config->csc_config.enable)
136 | CAM_CSC_COEF0_YCBCR_MODE_SET(config->csc_config.ycbcr_mode)
137 | CAM_CSC_COEF0_C0_SET(config->csc_config.yuv2rgb_coef.c0)
138 | CAM_CSC_COEF0_UV_OFFSET_SET(config->csc_config.yuv2rgb_coef.uv_offset)
139 | CAM_CSC_COEF0_Y_OFFSET_SET(config->csc_config.yuv2rgb_coef.y_offset);
140 ptr->CSC_COEF1 = CAM_CSC_COEF1_C1_SET(config->csc_config.yuv2rgb_coef.c1)
141 | CAM_CSC_COEF1_C4_SET(config->csc_config.yuv2rgb_coef.c4);
142 ptr->CSC_COEF2 = CAM_CSC_COEF2_C2_SET(config->csc_config.yuv2rgb_coef.c2)
143 | CAM_CSC_COEF2_C3_SET(config->csc_config.yuv2rgb_coef.c3);
144
145 return stat;
146 }
147
cam_stop(CAM_Type * ptr)148 void cam_stop(CAM_Type *ptr)
149 {
150 ptr->CR18 &= ~CAM_CR18_CAM_ENABLE_MASK;
151 }
152
cam_start(CAM_Type * ptr)153 void cam_start(CAM_Type *ptr)
154 {
155 ptr->CR18 |= CAM_CR18_CAM_ENABLE_MASK;
156 }
157
cam_stop_safely(CAM_Type * ptr)158 void cam_stop_safely(CAM_Type *ptr)
159 {
160 /*
161 * waiting for capture frame to complete
162 */
163 cam_clear_status(ptr, cam_status_end_of_frame);
164 while (cam_check_status(ptr, cam_status_end_of_frame) == false) {
165 }
166 cam_stop(ptr);
167 }
168