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_firmware_api.h"
21 #include "acamera_fw.h"
22 #include "acamera_math.h"
23 #include "acamera_command_api.h"
24
25 #include "acamera_aexp_hist_stats_mem_config.h"
26 #include "acamera_metering_stats_mem_config.h"
27
28 #include "acamera_math.h"
29 #include "ae_manual_fsm.h"
30
31 #include "sbuf.h"
32
33 #include <linux/vmalloc.h>
34 #include <asm/uaccess.h>
35 #include <linux/uaccess.h>
36
37 #define DEFAULT_AE_EXPOSURE_LOG2 2250000 //3390000
38
39 #ifdef LOG_MODULE
40 #undef LOG_MODULE
41 #define LOG_MODULE LOG_MODULE_AE_MANUAL
42 #endif
43
ae_roi_update(AE_fsm_ptr_t p_fsm)44 void ae_roi_update( AE_fsm_ptr_t p_fsm )
45 {
46 uint16_t horz_zones = acamera_isp_metering_hist_aexp_nodes_used_horiz_read( p_fsm->cmn.isp_base );
47 uint16_t vert_zones = acamera_isp_metering_hist_aexp_nodes_used_vert_read( p_fsm->cmn.isp_base );
48 uint16_t x, y;
49
50 uint16_t *ptr_ae_zone_whgh_h = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_HOR );
51 uint16_t *ptr_ae_zone_whgh_v = _GET_USHORT_PTR( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_VER );
52
53 uint8_t x_start = ( uint8_t )( ( ( ( p_fsm->roi >> 24 ) & 0xFF ) * horz_zones + 128 ) >> 8 );
54 uint8_t x_end = ( uint8_t )( ( ( ( p_fsm->roi >> 8 ) & 0xFF ) * horz_zones + 128 ) >> 8 );
55 uint8_t y_start = ( uint8_t )( ( ( ( p_fsm->roi >> 16 ) & 0xFF ) * vert_zones + 128 ) >> 8 );
56 uint8_t y_end = ( uint8_t )( ( ( ( p_fsm->roi >> 0 ) & 0xFF ) * vert_zones + 128 ) >> 8 );
57
58 uint8_t zone_size_x = x_end - x_start;
59 uint8_t zone_size_y = y_end - y_start;
60 uint32_t middle_x = zone_size_x * 256 / 2 + x_start * 256;
61 uint32_t middle_y = zone_size_y * 256 / 2 + y_start * 256;
62 uint16_t scale_x = 0;
63 uint16_t scale_y = 0;
64 uint32_t ae_zone_wght_hor_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_HOR );
65 uint32_t ae_zone_wght_ver_len = _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_VER );
66
67 if ( ae_zone_wght_hor_len ) {
68 scale_x = ( horz_zones - 1 ) * 256 / ae_zone_wght_hor_len + 1;
69 } else {
70 LOG( LOG_ERR, "ae_zone_wght_hor_len is zero" );
71 return;
72 }
73 if ( ae_zone_wght_ver_len ) {
74 scale_y = ( vert_zones - 1 ) * 256 / ae_zone_wght_ver_len + 1;
75 } else {
76 LOG( LOG_ERR, "ae_zone_wght_ver_len is zero" );
77 return;
78 }
79
80 uint16_t gaus_center_x = ( _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_HOR ) * scale_x / 2 );
81 uint16_t gaus_center_y = ( _GET_LEN( ACAMERA_FSM2CTX_PTR( p_fsm ), CALIBRATION_AE_ZONE_WGHT_VER ) * scale_y / 2 );
82
83 for ( y = 0; y < vert_zones; y++ ) {
84 uint8_t ae_coeff = 0;
85 for ( x = 0; x < horz_zones; x++ ) {
86 if ( y >= y_start && y <= y_end &&
87 x >= x_start && x <= x_end ) {
88
89 uint8_t index_y = ( y - y_start );
90 uint8_t index_x = ( x - x_start );
91 int32_t distance_x = ( index_x * 256 + 128 ) - middle_x;
92 int32_t distance_y = ( index_y * 256 + 128 ) - middle_y;
93 uint32_t coeff_x;
94 uint32_t coeff_y;
95
96 if ( ( x == x_end && x_start != x_end ) ||
97 ( y == y_end && y_start != y_end ) ) {
98 ae_coeff = 0;
99 } else {
100 coeff_x = ( gaus_center_x + distance_x * scale_x / 256 ) / 256;
101 if ( distance_x > 0 && ( distance_x & 0x80 ) )
102 coeff_x--;
103 coeff_y = ( gaus_center_y + distance_y * scale_y / 256 ) / 256;
104 if ( distance_y > 0 && ( distance_y & 0x80 ) )
105 coeff_y--;
106
107 coeff_x = ptr_ae_zone_whgh_h[coeff_x * 256 / scale_x];
108 coeff_y = ptr_ae_zone_whgh_v[coeff_y * 256 / scale_y];
109
110 ae_coeff = ( coeff_x * coeff_y ) >> 4;
111 if ( ae_coeff > 1 )
112 ae_coeff--;
113 }
114 } else {
115 ae_coeff = 0;
116 }
117 acamera_isp_metering_hist_aexp_zones_weight_write( p_fsm->cmn.isp_base, ISP_METERING_ZONES_MAX_H * y + x, ae_coeff );
118 }
119 }
120 }
121
122
ae_set_zone_weight(AE_fsm_ptr_t p_fsm,void * u_wg_ptr)123 int ae_set_zone_weight(AE_fsm_ptr_t p_fsm, void *u_wg_ptr)
124 {
125 int ret = -1;
126 unsigned long ae_wg_size = 0;
127 uint8_t *ae_wg = NULL;
128 int x = 0;
129 int y = 0;
130 uint8_t ae_coeff = 0;
131 uint32_t idx = 0;
132
133 if (p_fsm == NULL || u_wg_ptr == NULL) {
134 LOG(LOG_ERR, "Error invalid input param");
135 return ret;
136 }
137
138 ae_wg_size = ISP_METERING_ZONES_MAX_H * ISP_METERING_ZONES_MAX_V;
139 ae_wg = vmalloc(ae_wg_size);
140 if (ae_wg == NULL) {
141 LOG(LOG_ERR, "Failed to malloc mem");
142 return ret;
143 }
144
145 memset(ae_wg, 0, ae_wg_size);
146
147 if (copy_from_user(ae_wg, u_wg_ptr, ae_wg_size)) {
148 vfree(ae_wg);
149 LOG(LOG_ERR, "Failed to copy ae weight");
150 return ret;
151 }
152
153 for (y = 0; y < ISP_METERING_ZONES_MAX_V; y++) {
154 for (x = 0; x < ISP_METERING_ZONES_MAX_H; x++) {
155 idx = y * ISP_METERING_ZONES_MAX_H + x;
156 ae_coeff = ae_wg[idx];
157 acamera_isp_metering_hist_aexp_zones_weight_write(
158 p_fsm->cmn.isp_base, idx, ae_coeff);
159 }
160 }
161
162 vfree(ae_wg);
163
164 return 0;
165 }
166
ae_initialize(AE_fsm_ptr_t p_fsm)167 void ae_initialize( AE_fsm_ptr_t p_fsm )
168 {
169
170 #if FW_ZONE_AE
171 acamera_isp_metering_hist_thresh_0_1_write( p_fsm->cmn.isp_base, 0 );
172 acamera_isp_metering_hist_thresh_1_2_write( p_fsm->cmn.isp_base, 0 );
173 acamera_isp_metering_hist_thresh_3_4_write( p_fsm->cmn.isp_base, 0 );
174 acamera_isp_metering_hist_thresh_4_5_write( p_fsm->cmn.isp_base, 224 );
175 p_fsm->zone_weight[0] = 15;
176 #else
177 int i, j;
178 for ( i = 0; i < ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_VERT_DEFAULT; i++ )
179 for ( j = 0; j < ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_HORIZ_DEFAULT; j++ )
180 acamera_isp_metering_hist_aexp_zones_weight_write( p_fsm->cmn.isp_base, ISP_METERING_ZONES_MAX_H * i + j, 15 );
181 #endif
182 ae_roi_update( p_fsm );
183
184
185 //p_fsm->new_exposure_log2 = DEFAULT_AE_EXPOSURE_LOG2;
186
187 p_fsm->mask.repeat_irq_mask = ACAMERA_IRQ_MASK( ACAMERA_IRQ_AE_STATS );
188 AE_request_interrupt( p_fsm, p_fsm->mask.repeat_irq_mask );
189
190 // set default exposure value
191 ae_calculate_exposure( p_fsm );
192 }
193
ae_read_full_histogram_data(AE_fsm_ptr_t p_fsm)194 void ae_read_full_histogram_data( AE_fsm_ptr_t p_fsm )
195 {
196 int i;
197 int shift = 0;
198 uint32_t sum = 0;
199
200 sbuf_ae_t *p_sbuf_ae;
201 struct sbuf_item sbuf;
202 int fw_id = p_fsm->cmn.ctx_id;
203 fsm_param_mon_alg_flow_t ae_flow;
204
205 memset( &sbuf, 0, sizeof( sbuf ) );
206 sbuf.buf_type = SBUF_TYPE_AE;
207 sbuf.buf_status = SBUF_STATUS_DATA_EMPTY;
208
209 if ( sbuf_get_item( fw_id, &sbuf ) ) {
210 LOG( LOG_ERR, "Error: Failed to get sbuf, return." );
211 return;
212 }
213
214 p_sbuf_ae = (sbuf_ae_t *)sbuf.buf_base;
215 LOG( LOG_DEBUG, "Get sbuf ok, idx: %u, status: %u, addr: %p.", sbuf.buf_idx, sbuf.buf_status, sbuf.buf_base );
216
217 ae_flow.frame_id_tracking = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
218 p_sbuf_ae->frame_id = ae_flow.frame_id_tracking;
219
220 for ( i = 0; i < ISP_FULL_HISTOGRAM_SIZE; ++i ) {
221 uint32_t v = acamera_aexp_hist_stats_mem_array_data_read( p_fsm->cmn.isp_base, i );
222
223 shift = ( v >> 12 ) & 0xF;
224 v = v & 0xFFF;
225 if ( shift ) {
226 v = ( v | 0x1000 ) << ( shift - 1 );
227 }
228
229 /* some other FSMs(such as sharpening) in kern-FW also need AE stats data */
230 p_fsm->fullhist[i] = v;
231
232 sum += v;
233 }
234
235 p_fsm->fullhist_sum = sum;
236
237 /* NOTE: the size should match */
238 memcpy( p_sbuf_ae->stats_data, p_fsm->fullhist, sizeof( p_sbuf_ae->stats_data ) );
239 p_sbuf_ae->histogram_sum = sum;
240 LOG( LOG_DEBUG, "histsum: histogram_sum: %u.", p_sbuf_ae->histogram_sum );
241
242 /* read done, set the buffer back for future using */
243 sbuf.buf_status = SBUF_STATUS_DATA_DONE;
244
245 if ( sbuf_set_item( fw_id, &sbuf ) ) {
246 LOG( LOG_ERR, "Error: Failed to set sbuf, return." );
247 return;
248 }
249 LOG( LOG_DEBUG, "Set sbuf ok, idx: %u, status: %u, addr: %p.", sbuf.buf_idx, sbuf.buf_status, sbuf.buf_base );
250
251 ae_flow.frame_id_current = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
252 ae_flow.flow_state = MON_ALG_FLOW_STATE_INPUT_READY;
253 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_MON_AE_FLOW, &ae_flow, sizeof( ae_flow ) );
254
255 LOG( LOG_DEBUG, "AE flow: INPUT_READY: frame_id_tracking: %d, cur frame_id: %u.", ae_flow.frame_id_tracking, ae_flow.frame_id_current );
256
257 #if FW_ZONE_AE
258 int j;
259 for ( i = 0; i < ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_VERT_DEFAULT; i++ ) {
260 for ( j = 0; j < ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_HORIZ_DEFAULT; j++ ) {
261 p_fsm->hist4[i * ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_HORIZ_DEFAULT + j] = ( uint16_t )( acamera_metering_mem_array_data_read( p_fsm->cmn.isp_base, ( i * ACAMERA_ISP_METERING_HIST_AEXP_NODES_USED_HORIZ_DEFAULT + j ) * 2 + 1 ) >> 16 );
262 }
263 }
264 #endif
265 }
266
AE_fsm_process_interrupt(AE_fsm_const_ptr_t p_fsm,uint8_t irq_event)267 void AE_fsm_process_interrupt( AE_fsm_const_ptr_t p_fsm, uint8_t irq_event )
268 {
269 if ( acamera_fsm_util_is_irq_event_ignored( (fsm_irq_mask_t *)( &p_fsm->mask ), irq_event ) )
270 return;
271
272 switch ( irq_event ) {
273 case ACAMERA_IRQ_AE_STATS:
274 ae_read_full_histogram_data( (AE_fsm_ptr_t)p_fsm );
275 fsm_raise_event( p_fsm, event_id_ae_stats_ready );
276 break;
277 }
278 }
279
ae_set_new_param(AE_fsm_ptr_t p_fsm,sbuf_ae_t * p_sbuf_ae)280 void ae_set_new_param( AE_fsm_ptr_t p_fsm, sbuf_ae_t *p_sbuf_ae )
281 {
282 if ( p_sbuf_ae->frame_id == p_fsm->frame_id_tracking ) {
283 LOG( LOG_ERR, "Error: Same frame used twice, frame_id: %u.", p_sbuf_ae->frame_id );
284 return;
285 }
286
287 p_fsm->new_exposure_log2 = p_sbuf_ae->ae_exposure;
288 p_fsm->new_exposure_ratio = p_sbuf_ae->ae_exposure_ratio;
289 p_fsm->frame_id_tracking = p_sbuf_ae->frame_id;
290
291 if ( p_fsm->frame_id_tracking ) {
292 fsm_param_mon_alg_flow_t ae_flow;
293 ae_flow.frame_id_tracking = p_fsm->frame_id_tracking;
294 ae_flow.frame_id_current = acamera_fsm_util_get_cur_frame_id( &p_fsm->cmn );
295 ae_flow.flow_state = MON_ALG_FLOW_STATE_OUTPUT_READY;
296 acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_MON_AE_FLOW, &ae_flow, sizeof( ae_flow ) );
297
298 LOG( LOG_DEBUG, "AE flow: OUTPUT_READY: frame_id_tracking: %d, cur frame_id: %u.", ae_flow.frame_id_tracking, ae_flow.frame_id_current );
299 }
300
301 fsm_raise_event( p_fsm, event_id_ae_result_ready );
302 }
303
ae_calculate_exposure(AE_fsm_ptr_t p_fsm)304 int ae_calculate_exposure( AE_fsm_ptr_t p_fsm )
305 {
306 int rc = 0;
307
308 fsm_param_exposure_target_t exp_target;
309 exp_target.exposure_log2 = p_fsm->new_exposure_log2;
310 exp_target.exposure_ratio = p_fsm->new_exposure_ratio;
311 exp_target.frame_id_tracking = p_fsm->frame_id_tracking;
312
313 /* CMOS will skip exposure set operation in some conditions, so we need to check the apply result, ret 0 menas succeed */
314 if ( !acamera_fsm_mgr_set_param( p_fsm->cmn.p_fsm_mgr, FSM_PARAM_SET_EXPOSURE_TARGET, &exp_target, sizeof( exp_target ) ) ) {
315 p_fsm->exposure_log2 = p_fsm->new_exposure_log2;
316 p_fsm->exposure_ratio = p_fsm->new_exposure_ratio;
317
318 ACAMERA_FSM2CTX_PTR( p_fsm )
319 ->stab.global_exposure = ( acamera_math_exp2( p_fsm->new_exposure_log2, LOG2_GAIN_SHIFT, 6 ) );
320
321 // indicate we have new AE parameter, and should post event.
322 rc = 1;
323
324 LOG( LOG_INFO, "AE applied OK, exposure_log2 : %d, exposure_ratio: %u.", exp_target.exposure_log2, exp_target.exposure_ratio );
325 } else {
326 LOG( LOG_ERR, "AE applied failed, exposure_log2 : %d, exposure_ratio: %u.", exp_target.exposure_log2, exp_target.exposure_ratio );
327 }
328
329 return rc;
330 }
331