1 /*
2 *
3 * SPDX-License-Identifier: GPL-2.0
4 *
5 * Copyright (C) 2011-2018 ARM or its affiliates
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "acamera_fw.h"
21 #include "awb_manual_fsm.h"
22 #include "acamera_3aalg_preset.h"
23 #include "sbuf.h"
24
25 #ifdef LOG_MODULE
26 #undef LOG_MODULE
27 #define LOG_MODULE LOG_MODULE_AWB_MANUAL
28 #endif
29
30 extern void awb_set_new_param( AWB_fsm_ptr_t p_fsm, sbuf_awb_t *p_sbuf_awb );
31
AWB_fsm_clear(AWB_fsm_t * p_fsm)32 void AWB_fsm_clear( AWB_fsm_t *p_fsm )
33 {
34 p_fsm->curr_AWB_ZONES = MAX_AWB_ZONES;
35 p_fsm->awb_enabled = 0;
36 p_fsm->p_high = 50;
37 p_fsm->high_temp = 50;
38 p_fsm->low_temp = 50;
39 p_fsm->avg_GR = 128;
40 p_fsm->avg_GB = 128;
41 p_fsm->stable_avg_RG = D50_DEFAULT;
42 p_fsm->stable_avg_BG = D50_DEFAULT;
43 p_fsm->temperature_detected = 5000;
44 p_fsm->light_source_detected = AWB_LIGHT_SOURCE_D50;
45 p_fsm->light_source_candidate = AWB_LIGHT_SOURCE_D50;
46 p_fsm->detect_light_source_frames_count = 0;
47 p_fsm->max_temp = 10000;
48 p_fsm->min_temp = 2100;
49 p_fsm->max_temp_rg = 256;
50 p_fsm->max_temp_bg = 256;
51 p_fsm->min_temp_rg = 256;
52 p_fsm->min_temp_bg = 256;
53 p_fsm->roi = 65535;
54 p_fsm->switch_light_source_detect_frames_quantity = AWB_DLS_SWITCH_LIGHT_SOURCE_DETECT_FRAMES_QUANTITY;
55 p_fsm->switch_light_source_change_frames_quantity = AWB_DLS_SWITCH_LIGHT_SOURCE_CHANGE_FRAMES_QUANTITY;
56
57 p_fsm->cur_result_gain_frame_id = 0;
58 p_fsm->pre_result_gain_frame_id = 0;
59
60 p_fsm->wb[0] = 527;
61 p_fsm->wb[1] = 271;
62 p_fsm->wb[2] = 271;
63 p_fsm->wb[3] = 436;
64 }
65
AWB_request_interrupt(AWB_fsm_ptr_t p_fsm,system_fw_interrupt_mask_t mask)66 void AWB_request_interrupt( AWB_fsm_ptr_t p_fsm, system_fw_interrupt_mask_t mask )
67 {
68 acamera_isp_interrupts_disable( ACAMERA_FSM2MGR_PTR( p_fsm ) );
69 p_fsm->mask.irq_mask |= mask;
70 acamera_isp_interrupts_enable( ACAMERA_FSM2MGR_PTR( p_fsm ) );
71 }
72
73
74 #if AWB_MODE_ID
get_awb_idx(uint32_t value)75 static uint32_t get_awb_idx( uint32_t value )
76 {
77 uint32_t res = 0;
78 // acamera awb scenes are always located in a certain order
79 // this order is
80 // {AWB_DAY_LIGHT}
81 // {AWB_CLOUDY}
82 // {AWB_INCANDESCENT}
83 // {AWB_FLOURESCENT}
84 // {AWB_TWILIGHT}
85 // {AWB_SHADE}
86 // {AWB_WARM_FLOURESCENT}
87 switch ( value ) {
88 case AWB_DAY_LIGHT:
89 res = 0;
90 break;
91 case AWB_CLOUDY:
92 res = 1;
93 break;
94 case AWB_INCANDESCENT:
95 res = 2;
96 break;
97 case AWB_FLOURESCENT:
98 res = 3;
99 break;
100 case AWB_TWILIGHT:
101 res = 4;
102 break;
103 case AWB_SHADE:
104 res = 5;
105 break;
106 case AWB_WARM_FLOURESCENT:
107 res = 6;
108 break;
109 default:
110 LOG( LOG_ERR, "Invalid AWB scene index. Please check your calibrations" );
111 break;
112 }
113 return res;
114 }
115 #endif
116
AWB_set_mode(AWB_fsm_ptr_t p_fsm,uint32_t mode)117 static int AWB_set_mode( AWB_fsm_ptr_t p_fsm, uint32_t mode )
118 {
119 int rc = 0;
120
121 #if AWB_MODE_ID
122 switch ( mode ) {
123 case AWB_MANUAL:
124 p_fsm->awb_enabled = 0;
125 ACAMERA_FSM2CTX_PTR( p_fsm )
126 ->stab.global_manual_awb = ( 1 );
127 p_fsm->mode = mode;
128 break;
129
130 case AWB_AUTO:
131 p_fsm->awb_enabled = 1;
132 ACAMERA_FSM2CTX_PTR( p_fsm )
133 ->stab.global_manual_awb = ( 0 );
134 p_fsm->mode = mode;
135 break;
136
137 case AWB_DAY_LIGHT:
138 case AWB_CLOUDY:
139 case AWB_INCANDESCENT:
140 case AWB_FLOURESCENT:
141 case AWB_TWILIGHT:
142 case AWB_SHADE:
143 case AWB_WARM_FLOURESCENT: {
144 modulation_entry_t *_calibration_awb_scene_presets = _GET_MOD_ENTRY16_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AWB_SCENE_PRESETS );
145 uint32_t i = get_awb_idx( mode );
146 p_fsm->awb_enabled = 0;
147 p_fsm->mode = mode;
148 // Then set the red and blue values
149 ACAMERA_FSM2CTX_PTR( p_fsm )
150 ->stab.global_manual_awb = ( 1 );
151 uint32_t cr = _calibration_awb_scene_presets[i].x;
152 uint32_t cb = _calibration_awb_scene_presets[i].y;
153 // Change 9 bit into 7 bit
154 ACAMERA_FSM2CTX_PTR( p_fsm )
155 ->stab.global_awb_red_gain = cr;
156 ACAMERA_FSM2CTX_PTR( p_fsm )
157 ->stab.global_awb_blue_gain = cb;
158 break;
159 }
160 default:
161 rc = -1;
162 break;
163 }
164 #endif
165
166 return rc;
167 }
168
AWB_fsm_init(void * fsm,fsm_init_param_t * init_param)169 void AWB_fsm_init( void *fsm, fsm_init_param_t *init_param )
170 {
171 AWB_fsm_t *p_fsm = (AWB_fsm_t *)fsm;
172 p_fsm->cmn.p_fsm_mgr = init_param->p_fsm_mgr;
173 p_fsm->cmn.isp_base = init_param->isp_base;
174 p_fsm->p_fsm_mgr = init_param->p_fsm_mgr;
175
176 AWB_fsm_clear( p_fsm );
177
178 awb_init( p_fsm );
179 awb_coeffs_write( p_fsm );
180 AWB_request_interrupt( p_fsm, ACAMERA_IRQ_MASK( ACAMERA_IRQ_AWB_STATS ) );
181 }
182
AWB_fsm_get_param(void * fsm,uint32_t param_id,void * input,uint32_t input_size,void * output,uint32_t output_size)183 int AWB_fsm_get_param( void *fsm, uint32_t param_id, void *input, uint32_t input_size, void *output, uint32_t output_size )
184 {
185 int rc = 0;
186 AWB_fsm_t *p_fsm = (AWB_fsm_t *)fsm;
187
188 switch ( param_id ) {
189 case FSM_PARAM_GET_AWB_INFO: {
190 if ( !output || output_size != sizeof( fsm_param_awb_info_t ) ) {
191 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
192 rc = -1;
193 break;
194 }
195
196 fsm_param_awb_info_t *p_info = (fsm_param_awb_info_t *)output;
197
198 system_memcpy( p_info->wb_log2, p_fsm->wb_log2, sizeof( p_info->wb_log2 ) );
199 system_memcpy( p_info->awb_warming, p_fsm->awb_warming, sizeof( p_info->awb_warming ) );
200
201 p_info->temperature_detected = p_fsm->temperature_detected;
202 p_info->p_high = p_fsm->p_high;
203 p_info->light_source_candidate = p_fsm->light_source_candidate;
204 p_info->avg_GR = p_fsm->avg_GR;
205 p_info->avg_GB = p_fsm->avg_GB;
206 p_info->rg_coef = p_fsm->rg_coef;
207 p_info->bg_coef = p_fsm->bg_coef;
208 p_info->result_gain_frame_id = p_fsm->pre_result_gain_frame_id;
209
210 break;
211 }
212
213 case FSM_PARAM_GET_AWB_MODE:
214 if ( !output || output_size != sizeof( uint32_t ) ) {
215 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
216 rc = -1;
217 break;
218 }
219
220 #if AWB_MODE_ID
221 if ( !ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_manual_awb ) {
222 *(uint32_t *)output = AWB_AUTO;
223 } else {
224 *(uint32_t *)output = p_fsm->mode;
225 }
226 #endif
227
228 break;
229
230 default:
231 rc = -1;
232 break;
233 }
234
235 return rc;
236 }
237
AWB_fsm_set_param(void * fsm,uint32_t param_id,void * input,uint32_t input_size)238 int AWB_fsm_set_param( void *fsm, uint32_t param_id, void *input, uint32_t input_size )
239 {
240 int rc = 0;
241 AWB_fsm_t *p_fsm = (AWB_fsm_t *)fsm;
242
243 switch ( param_id ) {
244 case FSM_PARAM_SET_AWB_NEW_PARAM: {
245 if ( !input || input_size != sizeof( sbuf_awb_t ) ) {
246 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
247 rc = -1;
248 break;
249 }
250
251 awb_set_new_param( p_fsm, (sbuf_awb_t *)input );
252
253 break;
254 }
255
256 case FSM_PARAM_SET_AWB_MODE:
257 if ( !input || input_size != sizeof( uint32_t ) ) {
258 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
259 rc = -1;
260 break;
261 }
262
263 rc = AWB_set_mode( p_fsm, *(uint32_t *)input );
264
265 break;
266
267 case FSM_PARAM_SET_AWB_INFO: {
268 if ( !input || input_size != sizeof( fsm_param_awb_info_t ) ) {
269 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
270 rc = -1;
271 break;
272 }
273
274 fsm_param_awb_info_t *p_info = (fsm_param_awb_info_t *)input;
275
276 if ( p_info->flag & AWB_INFO_TEMPERATURE_DETECTED ) {
277 p_fsm->temperature_detected = p_info->temperature_detected;
278 }
279
280 if ( p_info->flag & AWB_INFO_P_HIGH ) {
281 p_fsm->p_high = p_info->p_high;
282 }
283
284 if ( p_info->flag & AWB_INFO_LIGHT_SOURCE_CANDIDATE ) {
285 p_fsm->light_source_candidate = p_info->light_source_candidate;
286 }
287
288 break;
289 }
290
291 case FSM_PARAM_SET_AWB_ZONE_WEIGHT: {
292 if (!input || input_size == 0) {
293 LOG(LOG_ERR, "Invalid param. param id: %d.", param_id);
294 rc = -1;
295 break;
296 }
297
298 unsigned char *u_awb_wg = input;
299
300 rc = awb_set_zone_weight(p_fsm, u_awb_wg);
301 if (rc != 0)
302 LOG(LOG_ERR, "Failed to set ae zone weight");
303
304 break;
305 }
306 case FSM_PARAM_SET_AWB_PRESET:
307 if ( !input || input_size != sizeof( isp_awb_preset_t ) ) {
308 LOG( LOG_ERR, "Invalid param, param_id: %d.", param_id );
309 rc = -1;
310 break;
311 }
312
313 isp_awb_preset_t *p_new = (isp_awb_preset_t *)input;
314 p_fsm->wb_log2[0] = p_new->wb_log2[0];
315 p_fsm->wb_log2[1] = p_new->wb_log2[1];
316 p_fsm->wb_log2[2] = p_new->wb_log2[2];
317 p_fsm->wb_log2[3] = p_new->wb_log2[3];
318
319 p_fsm->wb[0] = p_new->wb[0];
320 p_fsm->wb[1] = p_new->wb[1];
321 p_fsm->wb[2] = p_new->wb[2];
322 p_fsm->wb[3] = p_new->wb[3];
323 acamera_isp_white_balance_gain_00_write( p_fsm->cmn.isp_base, p_fsm->wb[0]);
324 acamera_isp_white_balance_gain_01_write( p_fsm->cmn.isp_base, p_fsm->wb[1]);
325 acamera_isp_white_balance_gain_10_write( p_fsm->cmn.isp_base, p_fsm->wb[2]);
326 acamera_isp_white_balance_gain_11_write( p_fsm->cmn.isp_base, p_fsm->wb[3]);
327
328 break;
329 default:
330 rc = -1;
331 break;
332 }
333
334 return rc;
335 }
336
AWB_fsm_process_event(AWB_fsm_t * p_fsm,event_id_t event_id)337 uint8_t AWB_fsm_process_event( AWB_fsm_t *p_fsm, event_id_t event_id )
338 {
339 uint8_t b_event_processed = 0;
340 switch ( event_id ) {
341 default:
342 break;
343 case event_id_frame_end:
344 AWB_request_interrupt( p_fsm, ACAMERA_IRQ_MASK( ACAMERA_IRQ_AWB_STATS ) );
345 b_event_processed = 1;
346
347 break;
348
349 case event_id_awb_stats_ready:
350 AWB_request_interrupt( p_fsm, ACAMERA_IRQ_MASK( ACAMERA_IRQ_FRAME_END ) );
351 b_event_processed = 1;
352
353 break;
354
355 case event_id_awb_result_ready:
356 awb_update_ccm( p_fsm );
357 awb_normalise( p_fsm );
358 fsm_raise_event( p_fsm, event_id_WB_matrix_ready );
359 b_event_processed = 1;
360 break;
361 }
362
363 return b_event_processed;
364 }
365