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