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 "acamera.h"
22 #include "acamera_command_api.h"
23 #include "acamera_math.h"
24
25 #include "isp_config_seq.h"
26 #include "acamera_sbus_api.h"
27
28 #include "acamera_fr_gamma_rgb_mem_config.h"
29
30 #if ISP_HAS_DS1
31 #include "acamera_ds1_gamma_rgb_mem_config.h"
32 #endif
33
34 #include "acamera_isp_config.h"
35
36
37 #include "general_fsm.h"
38
39 #include "acamera_ca_correction_filter_mem_config.h"
40 #include "acamera_ca_correction_mesh_mem_config.h"
41
42 #include "acamera_lut3d_mem_config.h"
43
44
45 #if defined( CALIBRATION_DECOMPANDER0_MEM )
46 #include "acamera_decompander0_mem_config.h"
47 #endif
48
49 #if defined( CALIBRATION_DECOMPANDER1_MEM )
50 #include "acamera_decompander1_mem_config.h"
51 #endif
52
53 #if defined( CALIBRATION_SHADING_RADIAL_R )
54 #include "acamera_radial_shading_mem_config.h"
55 #endif
56
57 #ifdef LOG_MODULE
58 #undef LOG_MODULE
59 #define LOG_MODULE LOG_MODULE_GENERAL
60 #endif
61
62 #define CAC_MEM_LUT_LEN 4096
63
64 #define BIT_SHIFT( v, s ) ( ( s > 0 ) ? ( v << s ) : ( v >> ( -s ) ) )
65
66 typedef uint16_t( CAC_MEM_LUT_T )[][10];
67
signed_bitshift(int32_t val,int32_t shift)68 static int32_t signed_bitshift( int32_t val, int32_t shift )
69 {
70 int32_t out_val = 0;
71 uint8_t val_sign = val < 0;
72
73 val = (val > 0) ? val : -val;
74
75 if ( val_sign ) {
76 out_val = -BIT_SHIFT( val, shift );
77 } else {
78 out_val = BIT_SHIFT( val, shift );
79 }
80
81 return out_val;
82 }
83
general_cac_memory_lut_reload(general_fsm_ptr_t p_fsm)84 static void general_cac_memory_lut_reload( general_fsm_ptr_t p_fsm )
85 {
86 uint32_t cac_mem_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CA_CORRECTION_MEM );
87 const CAC_MEM_LUT_T *p_calibration_ca_model = (const CAC_MEM_LUT_T *)_GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CA_CORRECTION_MEM );
88 const uint16_t *p_calibration_cac_cfg = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CA_CORRECTION );
89
90 uint16_t calibration_ca_min_correction = p_calibration_cac_cfg[0];
91 uint16_t calibration_ca_mesh_width = p_calibration_cac_cfg[1];
92 uint16_t calibration_ca_mesh_height = p_calibration_cac_cfg[2];
93
94 uint8_t cfa_pattern = acamera_isp_top_cfa_pattern_read( p_fsm->cmn.isp_base );
95
96 uint8_t line_offset = calibration_ca_mesh_width;
97 uint16_t plane_offset = calibration_ca_mesh_width * calibration_ca_mesh_height;
98
99 int32_t ca_model[10] = {0};
100 int32_t mesh_vars[9] = {0};
101 uint16_t component;
102 uint8_t term;
103 uint8_t plane_count;
104 uint32_t plane_offset_val;
105 uint8_t x;
106 uint8_t y;
107 uint16_t vh_shift;
108 uint16_t lut_index = 0;
109
110 if ( CAC_MEM_LUT_LEN != ( ACAMERA_CA_CORRECTION_MESH_MEM_SIZE >> 2 ) ) {
111 LOG( LOG_CRIT, "cac_mem_lut size mismatch, hw_size: %d, expected: %d.", ( ACAMERA_CA_CORRECTION_MESH_MEM_SIZE >> 2 ), CAC_MEM_LUT_LEN );
112 return;
113 }
114
115 // configure mesh size and reset the table
116 acamera_isp_ca_correction_mesh_width_write( p_fsm->cmn.isp_base, calibration_ca_mesh_width );
117 acamera_isp_ca_correction_mesh_height_write( p_fsm->cmn.isp_base, calibration_ca_mesh_height );
118 acamera_isp_ca_correction_line_offset_write( p_fsm->cmn.isp_base, calibration_ca_mesh_width );
119 acamera_isp_ca_correction_plane_offset_write( p_fsm->cmn.isp_base, calibration_ca_mesh_width * calibration_ca_mesh_height );
120
121 // reset to 0
122 for ( lut_index = 0; lut_index < CAC_MEM_LUT_LEN; lut_index++ ) {
123 acamera_ca_correction_mesh_mem_array_data_write( p_fsm->cmn.isp_base, lut_index, 0 );
124 }
125
126 switch ( cfa_pattern ) {
127 case 0: // RGGB
128 plane_count = 2;
129 break;
130 case 1: // RCCC
131 plane_count = 1;
132 break;
133 default: // RGBIr
134 plane_count = 3;
135 break;
136 }
137
138 LOG( LOG_DEBUG, "cfa_pattern: %d, plane_count: %d, cac_mem_len: %d", cfa_pattern, plane_count, cac_mem_len );
139
140 for ( component = 0; component < plane_count * 2; component++ ) {
141 // Generate s15.0 ca_model (int32) from u16.0 ca_model_u (uint16)
142 for ( term = 0; term < 10; term++ ) {
143 if ( ( *p_calibration_ca_model )[component][term] < 32768 )
144 ca_model[term] = ( *p_calibration_ca_model )[component][term];
145 else
146 ca_model[term] = ( *p_calibration_ca_model )[component][term] - 65536;
147 }
148
149 plane_offset_val = plane_offset * ( component>>1 );
150 vh_shift = ( component % 2 ) * 8;
151
152 for ( x = 0; x < calibration_ca_mesh_width; x++ ) {
153 for ( y = 0; y < calibration_ca_mesh_height; y++ ) {
154 int32_t z32 = 0;
155 int16_t z16 = 0;
156 int16_t z_norm = 0;
157 int32_t product = 0;
158 uint8_t z_sign = 0;
159 uint32_t zu32 = 0;
160 uint8_t lut_shift = 0;
161 uint32_t old_value = 0;
162 uint32_t new_value = 0;
163
164 // Apply model - this polynomial:
165 // z = b0*x^3 + b1*x^2*y + b2*x*y^2 + b3*y^3 + b4*x^2 + b5*x*y + b6*y^2 + b7*x + b8*y +b9
166
167 // mesh_vars(:,1:4) are u18.0, coeffs(1:4) are s-10.23 so product is s8.23
168 // mesh_vars(:,5:7) are u12.0, coeffs(5:7) are s-3.17 so product is s9.17
169 // mesh_vars(:,8:9) are u6.0, coeffs(8:9) are s2.11 so product is s8.11
170 // mesh_vars(:,10) are u1.0, coeffs(10) is s6.5 so product is s6.5
171
172 mesh_vars[8] = y;
173 mesh_vars[7] = x;
174 mesh_vars[6] = y * y;
175 mesh_vars[5] = x * y;
176 mesh_vars[4] = x * x;
177 mesh_vars[3] = mesh_vars[6] * y;
178 mesh_vars[2] = mesh_vars[5] * y;
179 mesh_vars[1] = mesh_vars[4] * y;
180 mesh_vars[0] = mesh_vars[4] * x;
181
182 for ( term = 0; term < 4; term++ ) {
183 product = mesh_vars[term] * ca_model[term];
184 product = signed_bitshift( product, -4 );
185 z32 = z32 + product;
186 }
187
188 // Drop precision to match next set of coefficients
189 z32 = signed_bitshift( z32, -2 );
190
191 for ( term = 4; term < 7; term++ ) {
192 product = mesh_vars[term] * ca_model[term];
193 z32 = z32 + product;
194 }
195
196 // Drop precision to match next set of coefficients
197 z32 = signed_bitshift( z32, -6 );
198
199 for ( term = 7; term < 9; term++ ) {
200 product = mesh_vars[term] * ca_model[term];
201 z32 = z32 + product;
202 }
203
204 // Drop precision to match error model (precision of coeff 10 is also set to match this)
205 z32 = signed_bitshift( z32, -4 );
206
207 z32 = z32 + ca_model[9];
208
209 // Clip to s4.7 range
210 z32 = MAX( z32, -2048 );
211 z32 = MIN( z32, 2047 );
212
213 // Cast z from int32 to int16 here. Its size is only 12 bits.
214 z16 = (int16_t)z32;
215
216 // Apply periodic linear approximation of error model
217 // z = z - 0.1*sin(pi*z)
218 // Approximation between is z = z+0.25z_norm
219
220 // z_norm is equivalent position of z within linear range of +/-0.5
221 if ( ( z16 + 128 ) < 0 ) {
222 z_norm = ( ( z16 + 128 ) % 256 ) - 128;
223 z_norm = 256 + z_norm;
224 } else {
225 z_norm = ( ( z16 + 128 ) % 256 ) - 128;
226 }
227
228 if ( z_norm < -64 ) {
229 z_norm = -128 - z_norm;
230 } else if ( z_norm > 64 ) {
231 z_norm = 128 - z_norm;
232 }
233
234 // Shift by -2 is like multiplying by 0.25z_norm
235 z_norm = signed_bitshift( z_norm, -2 );
236 z16 = z16 - z_norm;
237
238 z16 = signed_bitshift( z16, -2 );
239
240 // Now manipulate z to the format of the mesh (u4.4, 2s complement)
241
242 z_sign = z16 < 0;
243
244 // Round z to 4 bits precision
245 z16 = (z16>0) ? z16 : -z16;
246 z16 = ( z16 % 2 ) + ( z16>>1 );
247
248 // Apply ca_min_correction (clip small corrections to 0)
249 if ( z16 <= calibration_ca_min_correction ) {
250 z_sign = 0;
251 z16 = 0;
252 }
253
254 if ( z16 > 127 ) {
255 z16 = 127;
256 }
257
258 // Convert to 2s complement
259 if ( z_sign ) {
260 z16 = 256 - z16;
261 }
262
263 // Cast z from int16 to uint32 here
264 zu32 = (uint32_t)z16;
265
266 // Work out which LUT entry this z value should be placed in
267 lut_index = plane_offset_val + y * line_offset + x;
268
269 // Shift increases by 16 bits for odd entries
270 lut_shift = vh_shift + ( lut_index % 2 ) * 16;
271
272 // Find location within half sized array (2 blocks per register)
273 lut_index = ( lut_index>>1 );
274
275 // Clip to size of LUT (in case of error)
276 lut_index = lut_index & 4095;
277
278 old_value = acamera_ca_correction_mesh_mem_array_data_read( p_fsm->cmn.isp_base, lut_index );
279 new_value = old_value + BIT_SHIFT( zu32, lut_shift );
280 acamera_ca_correction_mesh_mem_array_data_write( p_fsm->cmn.isp_base, lut_index, new_value );
281 }
282 }
283 }
284
285 acamera_isp_ca_correction_mesh_reload_write( p_fsm->cmn.isp_base, 0 );
286 acamera_isp_ca_correction_mesh_reload_write( p_fsm->cmn.isp_base, 1 );
287 acamera_isp_ca_correction_mesh_reload_write( p_fsm->cmn.isp_base, 0 );
288
289 return;
290 }
291
acamera_reload_isp_calibratons(general_fsm_ptr_t p_fsm)292 void acamera_reload_isp_calibratons( general_fsm_ptr_t p_fsm )
293 {
294 int32_t i = 0;
295 (void)i; // no unused warninig
296
297 //temp lut to test new FS module
298 #if ISP_WDR_SWITCH == 0
299 uint32_t mode = p_fsm->wdr_mode;
300 if ( mode != WDR_MODE_LINEAR ) {
301 LOG( LOG_ERR, "Failed to apply wdr switch. Firmware doesn't support WDR mode." );
302 }
303 #endif
304
305 const uint16_t *gamma_lut = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA );
306 const uint32_t gamma_lut_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA );
307
308 uint32_t exp_gamma_size = ( ( ACAMERA_FR_GAMMA_RGB_MEM_SIZE / ( ACAMERA_FR_GAMMA_RGB_MEM_ARRAY_DATA_DATASIZE >> 3 ) >> 1 ) + 1 );
309
310 if ( gamma_lut_len != exp_gamma_size )
311 LOG( LOG_CRIT, "wrong elements number in gamma_rgb -> current size %d but expected %d", (int)gamma_lut_len, (int)exp_gamma_size );
312
313 for ( i = 0; i < gamma_lut_len; i++ ) {
314 acamera_fr_gamma_rgb_mem_array_data_write( p_fsm->cmn.isp_base, i, gamma_lut[i] );
315 #if ISP_HAS_DS1
316 acamera_ds1_gamma_rgb_mem_array_data_write( p_fsm->cmn.isp_base, i, gamma_lut[i] );
317 #endif
318 }
319
320 const uint8_t *demosaic_lut = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DEMOSAIC );
321
322 for ( i = 0; i < _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DEMOSAIC ); i++ ) {
323 acamera_isp_demosaic_rgb_noise_profile_lut_weight_lut_write( p_fsm->cmn.isp_base, i, demosaic_lut[i] );
324 }
325
326 const uint8_t *np_lut_wdr = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_WDR_NP_LUT );
327 const uint8_t *np_lut = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_NOISE_PROFILE );
328
329 for ( i = 0; i < _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_NOISE_PROFILE ); i++ ) {
330
331 acamera_isp_sinter_noise_profile_lut_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut[i] );
332 acamera_isp_temper_noise_profile_lut_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut[i] );
333
334 acamera_isp_frame_stitch_np_lut_vs_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut_wdr[i] );
335 acamera_isp_frame_stitch_np_lut_s_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut_wdr[i] );
336 acamera_isp_frame_stitch_np_lut_m_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut_wdr[i] );
337 acamera_isp_frame_stitch_np_lut_l_weight_lut_write( p_fsm->cmn.isp_base, i, np_lut_wdr[i] );
338 }
339
340 #if ISP_HAS_COLOR_MATRIX_FSM
341 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_SHADING_MESH_RELOAD, NULL, 0 );
342
343 {
344 // this wdr_switch is called when change resolution happens.
345 // we need to reload ccm matrix in the case when several set of
346 // settings are supported for each resolution
347 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_CCM_CHANGE, NULL, 0 );
348 }
349 #endif
350
351 #if defined( ISP_HAS_IRIDIX_FSM ) || defined( ISP_HAS_IRIDIX8_FSM )
352 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_IRIDIX_INIT, NULL, 0 );
353 #endif
354
355 // Load purple fringe
356 const uint8_t *lut_pf = _GET_UCHAR_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_PF_RADIAL_LUT );
357 for ( i = 0; i < _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_PF_RADIAL_LUT ); i++ ) {
358 acamera_isp_pf_correction_shading_shading_lut_write( p_fsm->cmn.isp_base, i, lut_pf[i] );
359 }
360
361 const uint16_t *p_pf_radial_params = (uint16_t *)_GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_PF_RADIAL_PARAMS );
362 acamera_isp_pf_correction_center_x_write( p_fsm->cmn.isp_base, p_pf_radial_params[0] );
363 acamera_isp_pf_correction_center_y_write( p_fsm->cmn.isp_base, p_pf_radial_params[1] );
364 acamera_isp_pf_correction_off_center_mult_write( p_fsm->cmn.isp_base, p_pf_radial_params[2] );
365
366 #if defined( ACAMERA_CA_CORRECTION_FILTER_MEM_ARRAY_DATA_DEFAULT )
367 uint32_t ca_filter_mem_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CA_FILTER_MEM );
368 const uint32_t *p_ca_filter_mem = _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CA_FILTER_MEM );
369 for ( i = 0; i < ca_filter_mem_len; i++ ) {
370 acamera_ca_correction_filter_mem_array_data_write( p_fsm->cmn.isp_base, i, p_ca_filter_mem[i] );
371 }
372 #endif
373
374 if ( acamera_isp_isp_global_parameter_status_cac_read( p_fsm->cmn.isp_base ) == 0 ) {
375 #if defined( ACAMERA_CA_CORRECTION_MESH_MEM_ARRAY_DATA_DEFAULT )
376 general_cac_memory_lut_reload( p_fsm );
377 #endif
378 }
379
380 if ( acamera_isp_isp_global_parameter_status_lut_3d_read( p_fsm->cmn.isp_base ) == 0 ) {
381 #if defined( ACAMERA_LUT3D_MEM_ARRAY_DATA_DEFAULT )
382 uint32_t lut3d_mem_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_LUT3D_MEM );
383 const uint32_t *p_lut3d_mem = _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_LUT3D_MEM );
384 for ( i = 0; i < lut3d_mem_len; i++ ) {
385 acamera_lut3d_mem_array_data_write( p_fsm->cmn.isp_base, i, p_lut3d_mem[i] );
386 }
387 #endif
388 }
389
390 #if defined( CALIBRATION_DECOMPANDER0_MEM )
391 for ( i = 0; i < _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DECOMPANDER0_MEM ); i++ ) {
392 acamera_decompander0_mem_array_data_write( p_fsm->cmn.isp_base, i, _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DECOMPANDER0_MEM )[i] );
393 }
394 #endif
395
396 #if defined( CALIBRATION_DECOMPANDER1_MEM )
397 for ( i = 0; i < _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DECOMPANDER1_MEM ); i++ ) {
398 acamera_decompander1_mem_array_data_write( p_fsm->cmn.isp_base, i, _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_DECOMPANDER1_MEM )[i] );
399 }
400 #endif
401
402 #if defined( CALIBRATION_SHADING_RADIAL_R ) && defined( CALIBRATION_SHADING_RADIAL_G ) && defined( CALIBRATION_SHADING_RADIAL_B )
403 uint32_t len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_R );
404 uint16_t * p_lut = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_R );
405 uint32_t bank_offset = 0;
406 for ( i = 0; i < len; i++ ) {
407 acamera_radial_shading_mem_array_data_write( p_fsm->cmn.isp_base, bank_offset + i, p_lut[i] );
408 }
409
410 len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_G );
411 p_lut = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_G );
412 bank_offset += 256;
413 for ( i = 0; i < len; i++ ) {
414 acamera_radial_shading_mem_array_data_write( p_fsm->cmn.isp_base, bank_offset + i, p_lut[i] );
415 }
416
417 len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_B );
418 p_lut = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_B );
419 bank_offset += 256;
420 for ( i = 0; i < len; i++ ) {
421 acamera_radial_shading_mem_array_data_write( p_fsm->cmn.isp_base, bank_offset + i, p_lut[i] );
422 }
423 #endif
424
425 #if defined(CALIBRATION_SHADING_RADIAL_CENTRE_AND_MULT)
426 uint16_t len_cm = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_CENTRE_AND_MULT );
427 uint16_t *radial_shading_lut_cm = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_SHADING_RADIAL_CENTRE_AND_MULT );
428
429 if ( len_cm == 16 ) {
430 //R
431 acamera_isp_radial_shading_centerr_x_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[0] );
432 acamera_isp_radial_shading_centerr_y_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[1] );
433 acamera_isp_radial_shading_off_center_multrx_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[2] );
434 acamera_isp_radial_shading_off_center_multry_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[3] );
435 //G
436 acamera_isp_radial_shading_centerg_x_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[4] );
437 acamera_isp_radial_shading_centerg_y_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[5] );
438 acamera_isp_radial_shading_off_center_multgx_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[6] );
439 acamera_isp_radial_shading_off_center_multgy_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[7] );
440 //B
441 acamera_isp_radial_shading_centerb_x_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[8] );
442 acamera_isp_radial_shading_centerb_y_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[9] );
443 acamera_isp_radial_shading_off_center_multbx_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[10] );
444 acamera_isp_radial_shading_off_center_multby_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[11] );
445 //IR
446 acamera_isp_radial_shading_centerir_x_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[12] );
447 acamera_isp_radial_shading_centerir_y_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[13] );
448 acamera_isp_radial_shading_off_center_multirx_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[14] );
449 acamera_isp_radial_shading_off_center_multiry_write( p_fsm->cmn.isp_base, radial_shading_lut_cm[15] );
450 } else {
451 LOG( LOG_ERR, "CALIBRATION_SHADING_RADIAL_CENTRE_AND_MULT has wrong size %d but expected 16", len_cm );
452 }
453 #endif
454
455 p_fsm->gamma2_enable = _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_THRESHOLD )[0];
456 #if FW_HAS_CUSTOM_SETTINGS
457 // the custom initialization may be required for a context
458 const acam_reg_t *p_custom_settings_context = (const acam_reg_t *)_GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_CUSTOM_SETTINGS_CONTEXT );
459 acamera_load_sw_sequence( ACAMERA_FSM2CTX_PTR( p_fsm )->settings.isp_base, &p_custom_settings_context, 0 );
460 #endif
461 }
462
463
general_fsm_process_interrupt(general_fsm_const_ptr_t p_fsm,uint8_t irq_event)464 void general_fsm_process_interrupt( general_fsm_const_ptr_t p_fsm, uint8_t irq_event )
465 {
466 if ( acamera_fsm_util_is_irq_event_ignored( (fsm_irq_mask_t *)( &p_fsm->mask ), irq_event ) )
467 return;
468 switch ( irq_event ) {
469 case ACAMERA_IRQ_FRAME_START:
470 general_frame_start( (general_fsm_ptr_t)p_fsm );
471 break;
472 case ACAMERA_IRQ_FRAME_END:
473 general_frame_end( (general_fsm_ptr_t)p_fsm );
474 break;
475 }
476 }
477
general_set_wdr_mode(general_fsm_ptr_t p_fsm)478 void general_set_wdr_mode( general_fsm_ptr_t p_fsm )
479 {
480 #if ISP_BINARY_SEQUENCE == 0 //remove compile error
481 (void)seq_table;
482 #endif
483
484 if(p_fsm->p_fsm_mgr == NULL)
485 return;
486
487 switch ( p_fsm->wdr_mode ) {
488 case WDR_MODE_LINEAR:
489 #ifdef SENSOR_ISP_SEQUENCE_DEFAULT_LINEAR
490 LOG( LOG_CRIT, "Setting Linear Binary Sequence\n" );
491 acamera_load_sw_sequence( p_fsm->cmn.isp_base, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_LINEAR );
492 #endif
493
494 #if defined( SENSOR_ISP_SEQUENCE_DEFAULT_FPGA_LINEAR ) && ISP_HAS_FPGA_WRAPPER
495 LOG( LOG_CRIT, "Setting Linear Binary Sequence for FPGA\n" );
496 acamera_load_isp_sequence( 0, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_FPGA_LINEAR );
497 #endif
498 break;
499
500 case WDR_MODE_FS_LIN: {
501
502 #if defined( SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_2EXP ) || defined( SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_3EXP ) || defined( SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_4EXP )
503 if ( 2 == p_fsm->cur_exp_number ) {
504 acamera_load_sw_sequence( p_fsm->cmn.isp_base, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_2EXP );
505 LOG( LOG_CRIT, "Setting FS_Lin_2Exp Binary Sequence." );
506 } else if ( 3 == p_fsm->cur_exp_number ) {
507 acamera_load_sw_sequence( p_fsm->cmn.isp_base, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_3EXP );
508 LOG( LOG_CRIT, "Setting FS_Lin_3Exp Binary Sequence." );
509 } else if ( 4 == p_fsm->cur_exp_number ) {
510 acamera_load_sw_sequence( p_fsm->cmn.isp_base, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_FS_LIN_4EXP );
511 LOG( LOG_CRIT, "Setting FS_Lin_4Exp Binary Sequence." );
512 }
513 #endif
514
515 #if defined( SENSOR_ISP_SEQUENCE_DEFAULT_FPGA_FS_LIN ) && ISP_HAS_FPGA_WRAPPER
516 LOG( LOG_CRIT, "Setting FS Lin Binary Sequence for FPGA\n" );
517 acamera_load_isp_sequence( 0, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_FPGA_FS_LIN );
518 #endif
519 break;
520 }
521
522 case WDR_MODE_NATIVE:
523 #ifdef SENSOR_ISP_SEQUENCE_DEFAULT_NATIVE
524 acamera_load_sw_sequence( p_fsm->cmn.isp_base, ACAMERA_FSM2CTX_PTR( p_fsm )->isp_sequence, SENSOR_ISP_SEQUENCE_DEFAULT_NATIVE );
525 #endif
526 break;
527 }
528 }
529
general_initialize(general_fsm_ptr_t p_fsm)530 void general_initialize( general_fsm_ptr_t p_fsm )
531 {
532
533 // initialize isp sbus to get access to isp memory
534 // in api function REGISTERS_SOURCE_ID
535 acamera_sbus_init( &p_fsm->isp_sbus, sbus_isp );
536 p_fsm->isp_sbus.mask = SBUS_MASK_SAMPLE_8BITS | SBUS_MASK_ADDR_16BITS | SBUS_MASK_SAMPLE_32BITS;
537
538 // API related
539 #ifdef COLOR_MODE_ID
540 p_fsm->api_color_mode = NORMAL;
541 #endif
542 #ifdef SCENE_MODE_ID
543 p_fsm->api_scene_mode = AUTO;
544 #endif
545
546 #if defined REGISTERS_SOURCE_ID && defined SENSOR
547 p_fsm->api_reg_source = SENSOR;
548 #endif
549
550 p_fsm->gamma2_enable = 0;
551
552 general_set_wdr_mode( p_fsm );
553
554 p_fsm->mask.repeat_irq_mask = ACAMERA_IRQ_MASK( ACAMERA_IRQ_FRAME_START ) | ACAMERA_IRQ_MASK( ACAMERA_IRQ_FRAME_END );
555 // Finally request interrupts
556 general_request_interrupt( p_fsm, p_fsm->mask.repeat_irq_mask );
557 }
558
559 #if ISP_WDR_SWITCH
560
adjust_exposure(general_fsm_ptr_t p_fsm,int32_t corr)561 static void adjust_exposure( general_fsm_ptr_t p_fsm, int32_t corr )
562 {
563 #if defined( ISP_HAS_CMOS_FSM )
564 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_CMOS_ADJUST_EXP, &corr, sizeof( corr ) );
565
566 #if defined( ISP_HAS_AE_BALANCED_FSM )
567 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_AE_ADJUST_EXP, &corr, sizeof( corr ) );
568 #endif
569
570 fsm_param_ae_info_t ae_info;
571 fsm_param_exposure_target_t exp;
572
573 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_AE_INFO, NULL, 0, &ae_info, sizeof( ae_info ) );
574
575 exp.exposure_log2 = ae_info.exposure_log2;
576 exp.exposure_ratio = ae_info.exposure_ratio;
577 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_EXPOSURE_TARGET, &exp, sizeof( exp ) );
578
579 acamera_fsm_mgr_raise_event( ACAMERA_FSM2MGR_PTR( p_fsm ), event_id_exposure_changed );
580 #endif // ISP_HAS_CMOS_FSM
581 }
582
583 #endif
584
general_dynamic_gamma_update(general_fsm_ptr_t p_fsm)585 void general_dynamic_gamma_update( general_fsm_ptr_t p_fsm)
586 {
587 // update gamma here
588 const uint16_t *gamma_ev1 = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_EV1 );
589 const uint16_t *gamma_ev2 = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_EV2 );
590 if (gamma_ev1 == NULL || gamma_ev2 == NULL)
591 return;
592 const uint32_t gamma_len_ev1 = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_EV1 );
593 const uint32_t gamma_len_ev2 = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_EV2 );
594
595 uint32_t expected_gamma_size = ( ( ACAMERA_FR_GAMMA_RGB_MEM_SIZE / ( ACAMERA_FR_GAMMA_RGB_MEM_ARRAY_DATA_DATASIZE >> 3 ) >> 1 ) + 1 );
596
597 if ( (gamma_len_ev1 == expected_gamma_size) && (gamma_len_ev2 == expected_gamma_size) ) {
598 fsm_param_ae_info_t ae_info;
599 uint32_t i = 0;
600 // get current exposure value
601 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_AE_INFO, NULL, 0, &ae_info, sizeof( ae_info ) );
602 uint32_t exposure_log2 = ae_info.exposure_log2;
603 uint32_t ev1_thresh = _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_THRESHOLD )[1] ;
604 uint32_t ev2_thresh = _GET_UINT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_GAMMA_THRESHOLD )[2] ;
605
606 modulation_entry_32_t p_table[2];
607 p_table[0].x = ev1_thresh;
608 p_table[1].x = ev2_thresh;
609 // Use EV1 gamma curve if EV < EV1_THRESHOLD
610 // Use EV2 gamma curve if EV > EV2_THRESHOLD
611 // Do alpha blending between EV1 and EV2 when EV1_THRESHOLD < EV < EV2_THRESHOLD
612 for ( i = 0; i < expected_gamma_size; i++ ) {
613 p_table[0].y = gamma_ev1[i];
614 p_table[1].y = gamma_ev2[i];
615 // do alpha blending between two gammas for bin [i]
616 uint16_t gamma_bin = acamera_calc_modulation_u32( exposure_log2, p_table, 2);
617 LOG( LOG_DEBUG, "Gamma update: ev %d, ev1 %d, ev2 %d, ref_gamma_ev1 %d, ref_gamma_ev2 %d, result %d", exposure_log2, ev1_thresh, ev2_thresh, gamma_ev1[i], gamma_ev2[i], gamma_bin );
618 // update the hardware gamma curve for fr and ds
619 acamera_fr_gamma_rgb_mem_array_data_write( p_fsm->cmn.isp_base, i, gamma_bin );
620 #if ISP_HAS_DS1
621 acamera_ds1_gamma_rgb_mem_array_data_write( p_fsm->cmn.isp_base, i, gamma_bin );
622 #endif
623 }
624 } else {
625 // wrong gamma lut size
626 LOG( LOG_ERR, "wrong elements number in gamma_rgb_ev1 or ev2 -> ev1 size %d, ev2 size, expected %d", (int)gamma_len_ev1, (int)gamma_len_ev2, (int)expected_gamma_size );
627 }
628 }
629
general_frame_start(general_fsm_ptr_t p_fsm)630 void general_frame_start( general_fsm_ptr_t p_fsm )
631 {
632 if ( p_fsm->gamma2_enable )
633 general_dynamic_gamma_update(p_fsm);
634
635 #if ISP_WDR_SWITCH
636
637 if ( p_fsm->wdr_auto_mode ) {
638 fsm_param_ae_hist_info_t ae_hist_info;
639 // init to NULL in case no AE configured and caused wrong access via wild pointer
640 ae_hist_info.fullhist = NULL;
641
642 acamera_fsm_mgr_get_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_GET_AE_HIST_INFO, NULL, 0, &ae_hist_info, sizeof( ae_hist_info ) );
643
644 int i;
645 uint32_t exposure_edge = 0;
646 for ( i = ISP_FULL_HISTOGRAM_SIZE - 10; i < ISP_FULL_HISTOGRAM_SIZE; i++ ) {
647 exposure_edge += ae_hist_info.fullhist[i];
648 }
649 if ( p_fsm->wdr_mode == WDR_MODE_LINEAR ) {
650 for ( i = 0; i < 10; i++ ) {
651 exposure_edge += ae_hist_info.fullhist[i];
652 }
653 exposure_edge = exposure_edge * 1000 / ae_hist_info.fullhist_sum;
654 if ( exposure_edge > WDR_SWITCH_THRESHOLD + WDR_SWITCH_THRESHOLD_HISTERESIS ) {
655 if ( ++p_fsm->wdr_mode_frames > WDR_SWITCH_FRAMES ) {
656 p_fsm->wdr_mode_req = WDR_AUTO_SWITCH_TO;
657 p_fsm->wdr_mode_frames = 0;
658
659 adjust_exposure( p_fsm, -WDR_SWITCH_EXPOSURE_CORRECTION );
660 }
661 } else {
662 p_fsm->wdr_mode_frames = 0;
663 }
664 } else {
665 for ( i = 0; i < 50; i++ ) // in HDR mode histogramm is square rooted, so 10 is equal to 50 ~= (10/256)^2*256
666 {
667 exposure_edge += ae_hist_info.fullhist[i];
668 }
669 exposure_edge = exposure_edge * 1000 / ae_hist_info.fullhist_sum;
670 if ( exposure_edge <= WDR_SWITCH_THRESHOLD - WDR_SWITCH_THRESHOLD_HISTERESIS ) {
671 if ( ++p_fsm->wdr_mode_frames > WDR_SWITCH_FRAMES ) {
672 p_fsm->wdr_mode_req = WDR_MODE_LINEAR;
673 p_fsm->wdr_mode_frames = 0;
674
675 adjust_exposure( p_fsm, WDR_SWITCH_EXPOSURE_CORRECTION );
676 }
677 } else {
678 p_fsm->wdr_mode_frames = 0;
679 }
680 }
681 }
682 #endif
683 }
684
general_frame_end(general_fsm_ptr_t p_fsm)685 void general_frame_end( general_fsm_ptr_t p_fsm )
686 {
687 #if ISP_WDR_SWITCH
688
689 // Called on frame end
690 if ( p_fsm->wdr_mode_req != p_fsm->wdr_mode ) {
691 p_fsm->wdr_mode = p_fsm->wdr_mode_req;
692
693 general_set_wdr_mode( p_fsm );
694
695 p_fsm->wdr_mode_frames = 0;
696 }
697 #endif
698 }
699
general_calc_fe_lut_output(general_fsm_ptr_t p_fsm,uint16_t val)700 uint32_t general_calc_fe_lut_output( general_fsm_ptr_t p_fsm, uint16_t val )
701 {
702 // calculation the output of the FE LUT(s) for input {val}
703 uint32_t result = val;
704 #if ISP_WDR_SWITCH
705 // New switching system
706 result = val;
707 #else
708
709 // Standard old system - just use sqrt
710 result = acamera_sqrt32( val );
711 #endif
712 return result;
713 }
714
general_calc_fe_lut_input(general_fsm_ptr_t p_fsm,uint16_t val)715 uint32_t general_calc_fe_lut_input( general_fsm_ptr_t p_fsm, uint16_t val )
716 {
717 // calculation the input of the FE LUT(s) for output {val}
718 #if ISP_WDR_SWITCH
719 return val;
720 #else
721 // Standard old system - just use sqrt
722 return val * val;
723 #endif
724 }
725