• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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