• 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_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