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
22 #include "acamera_math.h"
23
24 #include "acamera_mesh_shading_mem_config.h"
25
26 #include "acamera_math.h"
27 #include "acamera_command_api.h"
28 #include "color_matrix_fsm.h"
29
30 #ifndef AWB_LIGHT_SOURCE_A
31 #define AWB_LIGHT_SOURCE_A 0x01
32 #endif
33
34 #ifndef AWB_LIGHT_SOURCE_D40
35 #define AWB_LIGHT_SOURCE_D40 0x02
36 #endif
37
38 #ifndef AWB_LIGHT_SOURCE_D50
39 #define AWB_LIGHT_SOURCE_D50 0x03
40 #endif
41
42
43 #define SHADING_SET_TABLE
44
45 #define OV_08835_MESH_SHADING_LS_A_BANK 0
46 #define OV_08835_MESH_SHADING_LS_D40_BANK 1
47 #define OV_08835_MESH_SHADING_LS_D50_BANK 2
48
49
50 // threshold for the LSC table hysterisis.
51 #define AWB_DLS_LIGHT_SOURCE_D40_D50_BORDER_low ( ( AWB_LIGHT_SOURCE_D50_TEMPERATURE + AWB_LIGHT_SOURCE_D40_TEMPERATURE ) >> 1 ) - 200
52 #define AWB_DLS_LIGHT_SOURCE_D40_D50_BORDER_high ( ( AWB_LIGHT_SOURCE_D40_TEMPERATURE + AWB_LIGHT_SOURCE_D50_TEMPERATURE ) >> 1 ) + 200
53 #define AWB_DLS_LIGHT_SOURCE_A_D40_BORDER_low ( ( AWB_LIGHT_SOURCE_A_TEMPERATURE + AWB_LIGHT_SOURCE_D40_TEMPERATURE ) >> 1 ) - 200
54 #define AWB_DLS_LIGHT_SOURCE_A_D40_BORDER_high ( ( AWB_LIGHT_SOURCE_D40_TEMPERATURE + AWB_LIGHT_SOURCE_A_TEMPERATURE ) >> 1 ) + 200
55 //==============Math Functions========================================================
56
57 #ifdef LOG_MODULE
58 #undef LOG_MODULE
59 #define LOG_MODULE LOG_MODULE_COLOR_MATRIX
60 #endif
61
matrix_matrix_multiply(int16_t * a1,int16_t * a2,int16_t * result,int dim1,int dim2,int dim3)62 static void matrix_matrix_multiply( int16_t *a1, int16_t *a2, int16_t *result, int dim1, int dim2, int dim3 )
63 {
64 int i, j, k;
65
66 for ( i = 0; i < dim1; ++i ) {
67 for ( j = 0; j < dim3; ++j ) {
68 int32_t temp = 0;
69 for ( k = 0; k < dim2; ++k )
70 temp += ( ( (int32_t)a1[i * dim2 + k] * a2[k * dim3 + j] ) >> 8 );
71 result[i * dim3 + j] = (int16_t)temp;
72 }
73 }
74 }
75
76
color_matrix_complement_to_direct(int16_t v)77 uint16_t color_matrix_complement_to_direct( int16_t v )
78 {
79 uint16_t result;
80
81 if ( v >= 0 )
82 result = v;
83 else {
84 result = -v;
85 result |= ( 1 << 12 );
86 }
87 return result;
88 }
89
color_matrix_direct_to_complement(uint16_t v)90 int16_t color_matrix_direct_to_complement( uint16_t v )
91 {
92 int16_t result;
93 result = v & ( ~( 1 << 15 ) );
94 if ( v & ( 1 << 15 ) )
95 result = -result;
96
97 return result;
98 }
99
100 //==============Saturation Related Functions========================================================
101
saturation_modulate_strength(color_matrix_fsm_ptr_t p_fsm)102 void saturation_modulate_strength( color_matrix_fsm_ptr_t p_fsm )
103 {
104 uint16_t strength;
105 int32_t total_gain = 0;
106
107 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_CMOS_TOTAL_GAIN, NULL, 0, &total_gain, sizeof( total_gain ) );
108
109 uint16_t log2_gain = total_gain >> ( LOG2_GAIN_SHIFT - 8 );
110 uint32_t ccm_saturation_table_idx = CALIBRATION_SATURATION_STRENGTH;
111 modulation_entry_t *ccm_saturation_table = _GET_MOD_ENTRY16_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), ccm_saturation_table_idx );
112 uint32_t ccm_saturation_table_len = _GET_ROWS( ACAMERA_FSM2CTX_PTR( p_fsm ), ccm_saturation_table_idx );
113 strength = acamera_calc_modulation_u16( log2_gain, ccm_saturation_table, ccm_saturation_table_len );
114 ACAMERA_FSM2CTX_PTR( p_fsm )
115 ->stab.global_saturation_target = ( strength );
116 }
117
118
color_mat_calculate_saturation_matrix(int16_t * saturation_matrix,uint8_t saturation)119 static void color_mat_calculate_saturation_matrix( int16_t *saturation_matrix, uint8_t saturation )
120 {
121 const int16_t identity[9] = {0x0100, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0100};
122 const int16_t black_white[9] = {0x004c, 0x0096, 0x001d, 0x004c, 0x0096, 0x001d, 0x004c, 0x0096, 0x001d};
123 int i;
124 int16_t alpha;
125 // (1 - saturation)
126 alpha = (int16_t)0x100 - ( (uint16_t)saturation << 1 );
127
128 for ( i = 0; i < 9; ++i ) {
129 int16_t result;
130 // (1. - saturation) * _black_white
131 result = ( (int32_t)alpha * black_white[i] + 0x80 ) >> 8;
132 // += (saturation * _identity)
133 result = result + ( ( (int32_t)identity[i] * ( (uint16_t)saturation << 1 ) + 0x80 ) >> 8 );
134 saturation_matrix[i] = result;
135 }
136 }
137
138 //==============Mesh Shading Related Functions========================================================
139
mesh_shading_modulate_strength(color_matrix_fsm_ptr_t p_fsm)140 static void mesh_shading_modulate_strength( color_matrix_fsm_ptr_t p_fsm )
141 {
142 int32_t total_gain = 0;
143
144 if ( ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_manual_shading == 0 ) {
145 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_CMOS_TOTAL_GAIN, NULL, 0, &total_gain, sizeof( total_gain ) );
146 uint16_t log2_gain = total_gain >> ( LOG2_GAIN_SHIFT - 8 );
147 uint16_t strength = acamera_calc_modulation_u16( log2_gain, _GET_MOD_ENTRY16_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_MESH_SHADING_STRENGTH ), _GET_ROWS( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_MESH_SHADING_STRENGTH ) );
148 acamera_isp_mesh_shading_mesh_strength_write( p_fsm->cmn.isp_base, strength );
149 }
150 }
151
152
153 // mode - one of linear, native, fs_lin or fs_hdr. see EWDRModeID enum.
color_matrix_shading_mesh_reload(color_matrix_fsm_ptr_t p_fsm)154 void color_matrix_shading_mesh_reload( color_matrix_fsm_ptr_t p_fsm )
155 {
156 int i, j, k, p;
157 uint8_t *mesh_page[4][3] = {{NULL, NULL, NULL}, {NULL, NULL, NULL}, {NULL, NULL, NULL}};
158
159 uint8_t mirror = !acamera_isp_top_bypass_mirror_read( p_fsm->cmn.isp_base );
160
161
162 // assume that all mesh tables have identical size
163 uint32_t mesh_size = _GET_COLS( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_A_R );
164
165
166 // determine the shading size. assume the tables have identical dimentions NxN
167 uint32_t dim = acamera_sqrt32(mesh_size);
168
169
170 //for mesh shading light switching
171 //acamera_isp_top_bypass_mesh_shading_write( p_fsm->cmn.isp_base, 0 );
172 acamera_isp_mesh_shading_mesh_page_r_write( p_fsm->cmn.isp_base, 0x0 );
173 acamera_isp_mesh_shading_mesh_page_g_write( p_fsm->cmn.isp_base, 0x1 );
174 acamera_isp_mesh_shading_mesh_page_b_write( p_fsm->cmn.isp_base, 0x2 );
175 acamera_isp_mesh_shading_mesh_width_write( p_fsm->cmn.isp_base, dim-1 );
176 acamera_isp_mesh_shading_mesh_height_write( p_fsm->cmn.isp_base, dim-1 );
177 //acamera_isp_mesh_shading_mesh_scale_write( p_fsm->cmn.isp_base, 1 );
178 acamera_isp_mesh_shading_mesh_alpha_mode_write( p_fsm->cmn.isp_base, 2 );
179
180
181 mesh_page[0][0] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_A_R );
182
183 mesh_page[0][1] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_A_G );
184
185 mesh_page[0][2] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_A_B );
186
187 mesh_page[1][0] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_TL84_R );
188
189 mesh_page[1][1] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_TL84_G );
190
191 mesh_page[1][2] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_TL84_B );
192
193 mesh_page[2][0] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_R );
194
195 mesh_page[2][1] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_G );
196
197 mesh_page[2][2] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_B );
198
199 mesh_page[3][0] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_R );
200
201 mesh_page[3][1] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_G );
202
203 mesh_page[3][2] = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_LS_D65_B );
204 for ( i = 0; i < 3; ++i ) {
205 for ( j = 0; j < dim; ++j ) {
206 for ( k = 0; k < dim; ++k ) {
207 p = mirror ? ( dim - 1 - k ) : k; // for mirror images shading must be mirrored
208 acamera_mesh_shading_mem_array_data_write( p_fsm->cmn.isp_base, i * 32 * 32 + j * 32 + p, ( (uint32_t)mesh_page[0][i][j * dim + k] << 0 ) +
209 ( (uint32_t)mesh_page[1][i][j * dim + k] << 8 ) +
210 ( (uint32_t)mesh_page[2][i][j * dim + k] << 16 ) +
211 ( (uint32_t)mesh_page[3][i][j * dim + k] << 24 ) );
212 }
213 }
214 }
215
216 acamera_isp_mesh_shading_enable_write( p_fsm->cmn.isp_base, 1 );
217 acamera_isp_mesh_shading_mesh_show_write( p_fsm->cmn.isp_base, 0 );
218 }
219
220
221 //==============Color Matrix Related Functions========================================================
color_matrix_recalculate(color_matrix_fsm_t * p_fsm)222 void color_matrix_recalculate( color_matrix_fsm_t *p_fsm )
223 {
224 uint32_t saturation;
225 int i;
226 // Saturation matrix
227 if ( ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_manual_saturation == 0 ) // Do not update values if manual mode
228 {
229 saturation_modulate_strength( p_fsm );
230 }
231
232 saturation = ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_saturation_target;
233 color_mat_calculate_saturation_matrix( p_fsm->color_saturation_matrix, (uint8_t)saturation );
234 // New colour management:
235 matrix_matrix_multiply( p_fsm->color_saturation_matrix, p_fsm->color_correction_matrix, p_fsm->color_matrix, 3, 3, 3 );
236
237 for ( i = 0; i < 9; ++i ) {
238 p_fsm->color_matrix[i] = color_matrix_complement_to_direct( p_fsm->color_matrix[i] );
239 }
240 }
241
write_CCM_to_purple_fringe(color_matrix_fsm_t * p_fsm)242 static void write_CCM_to_purple_fringe( color_matrix_fsm_t *p_fsm )
243 {
244 int16_t ccm_coeff[9];
245 int16_t *pf_ccm;
246
247 switch ( p_fsm->light_source_ccm ) {
248 case AWB_LIGHT_SOURCE_A:
249 pf_ccm = p_fsm->color_matrix_A;
250 break;
251 case AWB_LIGHT_SOURCE_D40:
252 pf_ccm = p_fsm->color_matrix_D40;
253 break;
254 case AWB_LIGHT_SOURCE_D50:
255 pf_ccm = p_fsm->color_matrix_D50;
256 break;
257 default:
258 pf_ccm = p_fsm->color_matrix_one;
259 break;
260 }
261
262 //convert from s7p8 to s4p8
263 int i;
264 for ( i = 0; i < 9; ++i ) {
265 if ( pf_ccm[i] < 0 ) {
266 ccm_coeff[i] = 4096 - ( pf_ccm[i] );
267 } else {
268 ccm_coeff[i] = pf_ccm[i];
269 }
270 }
271
272 acamera_isp_pf_correction_ccm_coeff_rr_write( p_fsm->cmn.isp_base, ccm_coeff[0] );
273 acamera_isp_pf_correction_ccm_coeff_rg_write( p_fsm->cmn.isp_base, ccm_coeff[1] );
274 acamera_isp_pf_correction_ccm_coeff_rb_write( p_fsm->cmn.isp_base, ccm_coeff[2] );
275 acamera_isp_pf_correction_ccm_coeff_gr_write( p_fsm->cmn.isp_base, ccm_coeff[3] );
276 acamera_isp_pf_correction_ccm_coeff_gg_write( p_fsm->cmn.isp_base, ccm_coeff[4] );
277 acamera_isp_pf_correction_ccm_coeff_gb_write( p_fsm->cmn.isp_base, ccm_coeff[5] );
278 acamera_isp_pf_correction_ccm_coeff_br_write( p_fsm->cmn.isp_base, ccm_coeff[6] );
279 acamera_isp_pf_correction_ccm_coeff_bg_write( p_fsm->cmn.isp_base, ccm_coeff[7] );
280 acamera_isp_pf_correction_ccm_coeff_bb_write( p_fsm->cmn.isp_base, ccm_coeff[8] );
281 }
282
283
color_matrix_setup(int16_t * p_matrix,uint16_t CCM_R_R,uint16_t CCM_R_G,uint16_t CCM_R_B,uint16_t CCM_G_R,uint16_t CCM_G_G,uint16_t CCM_G_B,uint16_t CCM_B_R,uint16_t CCM_B_G,uint16_t CCM_B_B)284 void color_matrix_setup( int16_t *p_matrix, uint16_t CCM_R_R, uint16_t CCM_R_G, uint16_t CCM_R_B, uint16_t CCM_G_R, uint16_t CCM_G_G, uint16_t CCM_G_B, uint16_t CCM_B_R, uint16_t CCM_B_G, uint16_t CCM_B_B )
285 {
286 p_matrix[0] = color_matrix_direct_to_complement( CCM_R_R );
287 p_matrix[1] = color_matrix_direct_to_complement( CCM_R_G );
288 p_matrix[2] = color_matrix_direct_to_complement( CCM_R_B );
289
290 p_matrix[3] = color_matrix_direct_to_complement( CCM_G_R );
291 p_matrix[4] = color_matrix_direct_to_complement( CCM_G_G );
292 p_matrix[5] = color_matrix_direct_to_complement( CCM_G_B );
293
294 p_matrix[6] = color_matrix_direct_to_complement( CCM_B_R );
295 p_matrix[7] = color_matrix_direct_to_complement( CCM_B_G );
296 p_matrix[8] = color_matrix_direct_to_complement( CCM_B_B );
297 }
298
299
color_matrix_initialize(color_matrix_fsm_t * p_fsm)300 void color_matrix_initialize( color_matrix_fsm_t *p_fsm )
301 {
302 #if FW_DO_INITIALIZATION
303 color_matrix_change_CCMs( p_fsm );
304
305 p_fsm->manual_saturation_enabled = 0;
306 p_fsm->saturation_target = CM_SATURATION_TARGET;
307 ACAMERA_FSM2CTX_PTR( p_fsm )
308 ->stab.global_saturation_target = ( p_fsm->saturation_target );
309
310 uint32_t mode = 0;
311 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_WDR_MODE, NULL, 0, &mode, sizeof( mode ) );
312
313 color_matrix_shading_mesh_reload( p_fsm );
314 p_fsm->shading_alpha = 0;
315 p_fsm->shading_direction = 2; //0 ->inc 1->dec 2->do nothing
316 p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_D50;
317
318 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
319 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
320 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
321
322 acamera_isp_mesh_shading_mesh_alpha_r_write( p_fsm->cmn.isp_base, 0 );
323 acamera_isp_mesh_shading_mesh_alpha_g_write( p_fsm->cmn.isp_base, 0 );
324 acamera_isp_mesh_shading_mesh_alpha_b_write( p_fsm->cmn.isp_base, 0 );
325
326 p_fsm->temperature_threshold[0] = 3000;
327 p_fsm->temperature_threshold[1] = 3900;
328 p_fsm->temperature_threshold[2] = 4100;
329 p_fsm->temperature_threshold[3] = 4900;
330 p_fsm->temperature_threshold[4] = 2999;
331 p_fsm->temperature_threshold[5] = 3899;
332 p_fsm->temperature_threshold[6] = 4099;
333 p_fsm->temperature_threshold[7] = 4899;
334
335 ACAMERA_FSM2CTX_PTR( p_fsm )
336 ->stab.global_manual_saturation = ( 0 );
337
338 #endif // FW_DO_INITIALIZATION
339 }
340
color_matrix_write(color_matrix_fsm_t * p_fsm)341 void color_matrix_write( color_matrix_fsm_t *p_fsm )
342 {
343 if ( p_fsm->manual_CCM ) {
344 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
345 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
346 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
347 acamera_isp_mesh_shading_mesh_alpha_r_write( p_fsm->cmn.isp_base, 0 );
348 acamera_isp_mesh_shading_mesh_alpha_g_write( p_fsm->cmn.isp_base, 0 );
349 acamera_isp_mesh_shading_mesh_alpha_b_write( p_fsm->cmn.isp_base, 0 );
350
351 acamera_isp_ccm_coefft_r_r_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[0] );
352 acamera_isp_ccm_coefft_r_g_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[1] );
353 acamera_isp_ccm_coefft_r_b_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[2] );
354 acamera_isp_ccm_coefft_g_r_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[3] );
355 acamera_isp_ccm_coefft_g_g_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[4] );
356 acamera_isp_ccm_coefft_g_b_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[5] );
357 acamera_isp_ccm_coefft_b_r_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[6] );
358 acamera_isp_ccm_coefft_b_g_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[7] );
359 acamera_isp_ccm_coefft_b_b_write( p_fsm->cmn.isp_base, p_fsm->manual_color_matrix[8] );
360
361 } else {
362
363 acamera_isp_ccm_coefft_r_r_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[0] );
364 acamera_isp_ccm_coefft_r_g_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[1] );
365 acamera_isp_ccm_coefft_r_b_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[2] );
366 acamera_isp_ccm_coefft_g_r_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[3] );
367 acamera_isp_ccm_coefft_g_g_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[4] );
368 acamera_isp_ccm_coefft_g_b_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[5] );
369 acamera_isp_ccm_coefft_b_r_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[6] );
370 acamera_isp_ccm_coefft_b_g_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[7] );
371 acamera_isp_ccm_coefft_b_b_write( p_fsm->cmn.isp_base, p_fsm->color_matrix[8] );
372 }
373 }
374
375
color_matrix_update(color_matrix_fsm_t * p_fsm)376 void color_matrix_update( color_matrix_fsm_t *p_fsm )
377 {
378 // For CCM switching
379 if ( p_fsm->light_source_change_frames_left != 0 ) {
380 int16_t *p_ccm_prev;
381 int16_t *p_ccm_cur = p_fsm->color_correction_matrix;
382 int16_t *p_ccm_target;
383 int16_t delta;
384
385 switch ( p_fsm->light_source_ccm_previous ) {
386 case AWB_LIGHT_SOURCE_A:
387 p_ccm_prev = p_fsm->color_matrix_A;
388 break;
389 case AWB_LIGHT_SOURCE_D40:
390 p_ccm_prev = p_fsm->color_matrix_D40;
391 break;
392 case AWB_LIGHT_SOURCE_D50:
393 p_ccm_prev = p_fsm->color_matrix_D50;
394 break;
395 default:
396 p_ccm_prev = p_fsm->color_matrix_one;
397 break;
398 }
399
400 switch ( p_fsm->light_source_ccm ) {
401 case AWB_LIGHT_SOURCE_A:
402 p_ccm_target = p_fsm->color_matrix_A;
403 break;
404 case AWB_LIGHT_SOURCE_D40:
405 p_ccm_target = p_fsm->color_matrix_D40;
406 break;
407 case AWB_LIGHT_SOURCE_D50:
408 p_ccm_target = p_fsm->color_matrix_D50;
409 break;
410 default:
411 p_ccm_target = p_fsm->color_matrix_one;
412 break;
413 }
414 int i;
415 for ( i = 0; i < 9; ++i ) {
416 // smooth transition
417 // using curr += (target - curr)/frames_left causes no movement in first half
418 // for small movements
419 if ( p_fsm->light_source_change_frames > 1 ) {
420 delta = ( ( p_ccm_target[i] - p_ccm_prev[i] ) * ( p_fsm->light_source_change_frames - p_fsm->light_source_change_frames_left ) ) / ( p_fsm->light_source_change_frames - 1 ); // division by zero is checked
421 p_ccm_cur[i] = p_ccm_prev[i] + delta;
422 }
423 }
424 }
425
426 if ( ACAMERA_FSM2CTX_PTR( p_fsm )->stab.global_manual_shading == 0 ) {
427 fsm_param_awb_info_t wb_info;
428 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_AWB_INFO, NULL, 0, &wb_info, sizeof( wb_info ) );
429
430 //uint32_t fixed_table = 0;
431 // if temp less < 3250 go to A
432 // LSC is completely based on alpha blending and the AWB color temp.
433
434 if ( ( wb_info.temperature_detected < p_fsm->temperature_threshold[0] ) ) //0->1
435 {
436 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
437 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
438 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
439 p_fsm->shading_alpha = 0;
440 p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_A;
441
442 }
443 // if current temp between 4100 and 3900 use D40
444 else if ( ( wb_info.temperature_detected > p_fsm->temperature_threshold[1] ) && ( wb_info.temperature_detected < p_fsm->temperature_threshold[2] ) ) //1->2
445 {
446 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
447 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
448 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
449 p_fsm->shading_direction = 1; //0 ->inc 1->dec
450 p_fsm->shading_alpha = 0;
451 p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_D40;
452
453 }
454 // if current temp > 4900 go to d65
455 else if ( ( wb_info.temperature_detected > p_fsm->temperature_threshold[3] ) ) //2->1
456 {
457 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
458 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
459 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D50_BANK );
460 p_fsm->shading_direction = 0; //0 ->inc 1->dec
461 p_fsm->shading_alpha = 0;
462 p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_D50;
463
464 }
465
466 // if prev if d50 and current temp < 3700 go to d40
467 else if ( ( wb_info.temperature_detected > p_fsm->temperature_threshold[4] ) && ( wb_info.temperature_detected < p_fsm->temperature_threshold[5] ) ) //2->0
468 {
469 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
470 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
471 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_A_BANK );
472
473 if ( p_fsm->temperature_threshold[5] != p_fsm->temperature_threshold[4] )
474 p_fsm->shading_alpha = ( 255 * ( wb_info.temperature_detected - p_fsm->temperature_threshold[4] ) ) / ( p_fsm->temperature_threshold[5] - p_fsm->temperature_threshold[4] ); // division by zero is checked
475 //p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_D40;
476
477 }
478 // if current temp > 4750 go to d65
479 else if ( ( wb_info.temperature_detected > p_fsm->temperature_threshold[6] ) && ( wb_info.temperature_detected < p_fsm->temperature_threshold[7] ) ) //2->1
480 {
481 acamera_isp_mesh_shading_mesh_alpha_bank_r_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
482 acamera_isp_mesh_shading_mesh_alpha_bank_g_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
483 acamera_isp_mesh_shading_mesh_alpha_bank_b_write( p_fsm->cmn.isp_base, OV_08835_MESH_SHADING_LS_D40_BANK );
484
485 if ( p_fsm->temperature_threshold[7] != p_fsm->temperature_threshold[6] )
486 p_fsm->shading_alpha = ( 255 * ( wb_info.temperature_detected - p_fsm->temperature_threshold[6] ) ) / ( p_fsm->temperature_threshold[7] - p_fsm->temperature_threshold[6] ); // division by zero is checked
487 //p_fsm->shading_source_previous = AWB_LIGHT_SOURCE_D50;
488 }
489 acamera_isp_mesh_shading_mesh_alpha_r_write( p_fsm->cmn.isp_base, p_fsm->shading_alpha );
490 acamera_isp_mesh_shading_mesh_alpha_g_write( p_fsm->cmn.isp_base, p_fsm->shading_alpha );
491 acamera_isp_mesh_shading_mesh_alpha_b_write( p_fsm->cmn.isp_base, p_fsm->shading_alpha );
492 }
493
494 //this will put the ccm into the right format used in purple fringe and write to registers
495 //Write CCM before it is modified by saturation modulation
496 write_CCM_to_purple_fringe( p_fsm );
497
498 color_matrix_recalculate( p_fsm );
499 color_matrix_write( p_fsm );
500 mesh_shading_modulate_strength( p_fsm );
501
502 if ( p_fsm->light_source_change_frames_left > 0 ) {
503 p_fsm->light_source_change_frames_left--;
504 }
505 }
506
color_matrix_change_CCMs(color_matrix_fsm_t * p_fsm)507 void color_matrix_change_CCMs( color_matrix_fsm_t *p_fsm )
508 {
509 uint8_t i;
510 uint16_t *p_mtrx;
511 // For CCM switching
512
513
514 p_mtrx = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_MT_ABSOLUTE_LS_A_CCM );
515 color_matrix_setup( &p_fsm->color_matrix_A[0], p_mtrx[0], p_mtrx[1], p_mtrx[2], p_mtrx[3], p_mtrx[4], p_mtrx[5], p_mtrx[6], p_mtrx[7], p_mtrx[8] );
516 p_mtrx = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_MT_ABSOLUTE_LS_D40_CCM );
517 color_matrix_setup( &p_fsm->color_matrix_D40[0], p_mtrx[0], p_mtrx[1], p_mtrx[2], p_mtrx[3], p_mtrx[4], p_mtrx[5], p_mtrx[6], p_mtrx[7], p_mtrx[8] );
518 p_mtrx = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_MT_ABSOLUTE_LS_D50_CCM );
519 color_matrix_setup( &p_fsm->color_matrix_D50[0], p_mtrx[0], p_mtrx[1], p_mtrx[2], p_mtrx[3], p_mtrx[4], p_mtrx[5], p_mtrx[6], p_mtrx[7], p_mtrx[8] );
520 color_matrix_setup( p_fsm->color_matrix_one, 256, 0, 0, 0, 256, 0, 0, 0, 256 );
521
522
523 if ( p_fsm->light_source_change_frames_left != 0 ) {
524 // In CCM switching
525 // call CCM switcher to update CCM
526 // (note: this does mean CCM switching takes one frame less than normal)
527 color_matrix_update( p_fsm );
528 } else {
529 // Not moving, update current CCMs
530
531 int16_t *p_ccm_next;
532
533 switch ( p_fsm->light_source_ccm ) {
534 case AWB_LIGHT_SOURCE_A:
535 p_ccm_next = p_fsm->color_matrix_A;
536 break;
537 case AWB_LIGHT_SOURCE_D40:
538 p_ccm_next = p_fsm->color_matrix_D40;
539 break;
540 case AWB_LIGHT_SOURCE_D50:
541 p_ccm_next = p_fsm->color_matrix_D50;
542 break;
543 default:
544 p_ccm_next = p_fsm->color_matrix_one;
545 break;
546 }
547
548 for ( i = 0; i < 9; i++ ) {
549 p_fsm->color_correction_matrix[i] = p_ccm_next[i];
550 }
551 }
552 }
553