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