summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUmang Jain <umang.jain@ideasonboard.com>2021-05-10 22:59:43 +0530
committerUmang Jain <umang.jain@ideasonboard.com>2021-06-28 17:54:08 +0530
commit03d07648fe3ba288922609b5f310d159cc41001a (patch)
treeb1fbf8a057ae5fac96fcc11739422db1a706f1ee
parent12241d3b3be9ef911600194255904fbffeadc377 (diff)
stats: Create IPAIPU3Stats and import intel_skycam_statistics_convert()
This is will be used to convert statistics received from kernel to AIQ stats format. Specific 3a conversion functions will be added in IPAIP3Stats in subsequent commits. ipu3_stats_get_3a() will extract, memcpy each of 3A relevant structures. It's is intended just before setting the stats for next frame in AIQ::setStatistics(). It receives ipu3_uapi_stats_3a struct from the kernel. This API will be developed per parameter of ipu3_uapi_stats_3a struct in subsequent commit. IPAIPU3Stats will be responsible to take in the AIQ algorithms results set and hardware statistics as input and generate(and convert) AIQ consumable ia_aiq_statistics_input_param structure. Signed-off-by: Umang Jain <umang.jain@ideasonboard.com>
-rw-r--r--stats/ipa_ipu3_stats.cpp163
-rw-r--r--stats/ipa_ipu3_stats.h45
-rw-r--r--stats/ipu3_all_stats.cpp1015
-rw-r--r--stats/ipu3_all_stats.h56
-rw-r--r--stats/meson.build2
5 files changed, 1281 insertions, 0 deletions
diff --git a/stats/ipa_ipu3_stats.cpp b/stats/ipa_ipu3_stats.cpp
new file mode 100644
index 0000000..c14bd7e
--- /dev/null
+++ b/stats/ipa_ipu3_stats.cpp
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * IPAIPU3Stats.cpp: Generate statistics in IA AIQ consumable format.
+ */
+
+#include "ipa_ipu3_stats.h"
+
+#include <libcamera/base/log.h>
+
+#include "ipu3_all_stats.h"
+
+namespace libcamera::ipa::ipu3 {
+
+LOG_DEFINE_CATEGORY(IPAIPU3Stats)
+
+IPAIPU3Stats::IPAIPU3Stats()
+{
+ aiqStatsInputParams_ = {};
+
+ /* \todo: Is this fine here or we need separate helper? */
+ rgbsGridBuffPool_ = std::make_shared<SharedItemPool<ia_aiq_rgbs_grid>>("RgbsGridBuffPool");
+ afFilterBuffPool_ = std::make_shared<SharedItemPool<ia_aiq_af_grid>>("AfFilterBuffPool");
+#define PUBLIC_STATS_POOL_SIZE 9 /* comes from CrOS */
+ int ret = allocateStatBufferPools(PUBLIC_STATS_POOL_SIZE);
+ if (ret < 0)
+ LOG(IPAIPU3Stats, Error) << "Failed to allocate stats grid buffers";
+}
+
+IPAIPU3Stats::~IPAIPU3Stats()
+{
+ freeStatBufferPools();
+ rgbsGridBuffPool_.reset();
+ afFilterBuffPool_.reset();
+}
+
+ia_aiq_statistics_input_params *
+IPAIPU3Stats::getInputStatsParams(int frame, aiq::AiqResults *results,
+ const ipu3_uapi_stats_3a *stats)
+{
+ aiqStatsInputParams_.frame_id = frame;
+ aiqStatsInputParams_.frame_ae_parameters = results->ae();
+ aiqStatsInputParams_.frame_af_parameters = results->af();
+ aiqStatsInputParams_.awb_results = results->awb();
+ aiqStatsInputParams_.frame_pa_parameters = results->pa();
+ aiqStatsInputParams_.frame_sa_parameters = results->sa();
+ aiqStatsInputParams_.camera_orientation = ia_aiq_camera_orientation_unknown;
+
+ IPU3AllStats::ipu3_stats_all_stats outStats;
+ memset(&outStats, 0, sizeof(IPU3AllStats::ipu3_stats_all_stats));
+ IPU3AllStats::ipu3_stats_get_3a(&outStats, stats);
+
+ std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
+ std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;
+ int ret = afFilterBuffPool_->acquireItem(afGrid);
+ ret |= rgbsGridBuffPool_->acquireItem(rgbsGrid);
+ if (ret != 0 || afGrid.get() == nullptr || rgbsGrid.get() == nullptr) {
+ LOG(IPAIPU3Stats, Error) << "Failed to acquire 3A buffers from pools";
+ return nullptr;
+ }
+
+ IPU3AllStats::intel_skycam_statistics_convert(outStats.ia_css_4a_statistics,
+ rgbsGrid.get(), afGrid.get());
+
+ const ia_aiq_rgbs_grid *rgbsGridPtr = rgbsGrid.get();
+ const ia_aiq_af_grid *afGridPtr = afGrid.get();
+
+ aiqStatsInputParams_.num_rgbs_grids = 1;
+ aiqStatsInputParams_.rgbs_grids = &rgbsGridPtr;
+ aiqStatsInputParams_.num_af_grids = 1;
+ aiqStatsInputParams_.af_grids = &afGridPtr;
+
+ aiqStatsInputParams_.hdr_rgbs_grid = nullptr;
+ aiqStatsInputParams_.depth_grids = nullptr;
+
+ return &aiqStatsInputParams_;
+}
+
+int IPAIPU3Stats::allocateStatBufferPools(int numBufs)
+{
+ int ret = afFilterBuffPool_->init(numBufs);
+ ret |= rgbsGridBuffPool_->init(numBufs);
+ if (ret != 0) {
+ LOG(IPAIPU3Stats, Error) << "Failed to initialize 3A statistics pools";
+ freeStatBufferPools();
+ return -ENOMEM;
+ }
+#define IPU3_MAX_STATISTICS_WIDTH 80
+#define IPU3_MAX_STATISTICS_HEIGHT 60
+ int maxGridSize = IPU3_MAX_STATISTICS_WIDTH * IPU3_MAX_STATISTICS_HEIGHT;
+ std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
+ std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;
+
+ for (int allocated = 0; allocated < numBufs; allocated++) {
+ ret = afFilterBuffPool_->acquireItem(afGrid);
+ ret |= rgbsGridBuffPool_->acquireItem(rgbsGrid);
+
+ if (ret != 0 || afGrid.get() == nullptr ||
+ rgbsGrid.get() == nullptr) {
+ LOG(IPAIPU3Stats, Error) << "Failed to acquire memory from pools";
+ freeStatBufferPools();
+ return -ENOMEM;
+ }
+
+ rgbsGrid->blocks_ptr = new rgbs_grid_block[maxGridSize];
+ rgbsGrid->grid_height = 0;
+ rgbsGrid->grid_width = 0;
+
+ afGrid->filter_response_1 = new int[maxGridSize];
+ afGrid->filter_response_2 = new int[maxGridSize];
+ afGrid->block_height = 0;
+ afGrid->block_width = 0;
+ afGrid->grid_height = 0;
+ afGrid->grid_width = 0;
+ }
+
+ return 0;
+}
+
+void IPAIPU3Stats::freeStatBufferPools()
+{
+ if (!afFilterBuffPool_->isFull() || !rgbsGridBuffPool_->isFull()) {
+ /* We will leak if we errored out in allocateStatBufferPools*/
+ if (!afFilterBuffPool_->isFull())
+ LOG(IPAIPU3Stats, Warning) << "AfFilterBuffPool is leaking";
+ if (!rgbsGridBuffPool_->isFull())
+ LOG(IPAIPU3Stats, Warning) << "RgbsGridBuffPool is leaking";
+ }
+
+ int ret;
+ size_t availableItems = afFilterBuffPool_->availableItems();
+ std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;
+ for (size_t i = 0; i < availableItems; i++) {
+ ret = afFilterBuffPool_->acquireItem(afGrid);
+ if (ret == 0 && afGrid.get() != nullptr) {
+ delete[] afGrid->filter_response_1;
+ afGrid->filter_response_1 = nullptr;
+ delete[] afGrid->filter_response_2;
+ afGrid->filter_response_2 = nullptr;
+ } else {
+ LOG(IPAIPU3Stats, Warning)
+ << "Could not acquire AF filter response "
+ << i << "for deletion - leak?";
+ }
+ }
+
+ availableItems = rgbsGridBuffPool_->availableItems();
+ std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
+ for (size_t i = 0; i < availableItems; i++) {
+ ret = rgbsGridBuffPool_->acquireItem(rgbsGrid);
+ if (ret == 0 && rgbsGrid.get() != nullptr) {
+ delete[] rgbsGrid->blocks_ptr;
+ rgbsGrid->blocks_ptr = nullptr;
+ } else {
+ LOG(IPAIPU3Stats, Warning)
+ << "Could not acquire RGBS grid " << i
+ << "for deletion - leak?";
+ }
+ }
+}
+
+} /* namespace libcamera::ipa::ipu3 */
diff --git a/stats/ipa_ipu3_stats.h b/stats/ipa_ipu3_stats.h
new file mode 100644
index 0000000..4320024
--- /dev/null
+++ b/stats/ipa_ipu3_stats.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/*
+ * Copyright (C) 2017 Intel Corporation.
+ *
+ * IPAIPU3Stats.cpp: Generate statistics in IA AIQ consumable format.
+ */
+
+#include "aiq/aiq_results.h"
+
+#ifndef IPA_IPU3_STATS_H
+#define IPA_IPU3_STATS_H
+
+#include <ia_imaging/ia_aiq_types.h>
+#include <linux/intel-ipu3.h>
+
+#include "shared_item_pool.h"
+
+namespace libcamera::ipa::ipu3 {
+
+struct AiqResults;
+
+class IPAIPU3Stats
+{
+public:
+ IPAIPU3Stats();
+ ~IPAIPU3Stats();
+
+ ia_aiq_statistics_input_params *
+ getInputStatsParams(int frame,
+ aiq::AiqResults *results,
+ const ipu3_uapi_stats_3a *stats);
+
+private:
+ void freeStatBufferPools();
+ int allocateStatBufferPools(int numBufs);
+
+ ia_aiq_statistics_input_params aiqStatsInputParams_;
+ std::shared_ptr<SharedItemPool<ia_aiq_af_grid>> afFilterBuffPool_;
+ std::shared_ptr<SharedItemPool<ia_aiq_rgbs_grid>> rgbsGridBuffPool_;
+};
+
+} /* namespace libcamera::ipa::ipu3 */
+
+#endif /* IPA_IPU3_STATS_H */
+
diff --git a/stats/ipu3_all_stats.cpp b/stats/ipu3_all_stats.cpp
new file mode 100644
index 0000000..66444c7
--- /dev/null
+++ b/stats/ipu3_all_stats.cpp
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (C) 2017-2018 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * IPU3AllStats - Handle and convert statistics from kernel to AIQ interface
+ *
+ * This implementation is highly derived from ChromeOS:
+ * platform2/camera/hal/intel/ipu3/psl/ipu3/statsConverter/ipu-stats.cpp
+ */
+
+#include "ipu3_all_stats.h"
+
+#include <assert.h>
+#include <string.h>
+
+namespace libcamera::ipa::ipu3 {
+
+#define IA_CSS_ENTER(...) \
+ { \
+ }
+#define IA_CSS_LEAVE(...) \
+ { \
+ }
+#define IA_CSS_ENTER_PRIVATE(...) \
+ { \
+ }
+#define IA_CSS_LEAVE_PRIVATE(...) \
+ { \
+ }
+#define ia_css_debug_dtrace(...) \
+ { \
+ }
+
+typedef void *hrt_vaddress;
+
+#define CSS_ALIGN(d, a) d __attribute__((aligned(a)))
+
+#define HIVE_ISP_DDR_WORD_BITS 256
+#define HIVE_ISP_DDR_WORD_BYTES (HIVE_ISP_DDR_WORD_BITS / 8)
+#define RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES 2
+
+#define MAX_BUBBLE_SIZE 10
+#define AWB_MD_ITEM_SIZE_IN_BYTES 8
+#define AF_MD_ITEM_SIZE_IN_BYTES 4
+#define AWB_FR_MD_ITEM_SIZE_IN_BYTES 8
+#define AWB_MAX_NUM_OF_SETS 60
+#define AWB_SIZE_OF_ONE_SET_IN_BYTES 0x500
+#define AWB_SPARE_FOR_BUBBLES (MAX_BUBBLE_SIZE * RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES * AWB_MD_ITEM_SIZE_IN_BYTES)
+#define AF_MAX_NUM_OF_SETS 24
+#define AF_SIZE_OF_ONE_Y_TABLE_SET_IN_BYTES 0x80
+#define AF_SPARE_FOR_BUBBLES (MAX_BUBBLE_SIZE * RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES * AF_MD_ITEM_SIZE_IN_BYTES)
+#define AWB_FR_MAX_NUM_OF_SETS 24
+#define AWB_FR_SIZE_OF_ONE_BAYER_TBL_IN_BYTES 0x100
+#define AWB_FR_SPARE_FOR_BUBBLES (MAX_BUBBLE_SIZE * RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES * AWB_FR_MD_ITEM_SIZE_IN_BYTES)
+
+#define AE_PRIVATE_NUM_OF_HIST_BINS 256
+#define AE_PRIVATE_NUM_OF_COLORS 4
+
+#define AWB_MAX_BUFFER_SIZE (AWB_MAX_NUM_OF_SETS * (AWB_SIZE_OF_ONE_SET_IN_BYTES + AWB_SPARE_FOR_BUBBLES))
+#define AF_MAX_SIZE_OF_Y_TABLE (AF_MAX_NUM_OF_SETS * (AF_SIZE_OF_ONE_Y_TABLE_SET_IN_BYTES + AF_SPARE_FOR_BUBBLES) * \
+ RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES)
+#define AWB_FR_MAX_SIZE_OF_BAYER_TABLE (AWB_FR_MAX_NUM_OF_SETS * \
+ (AWB_FR_SIZE_OF_ONE_BAYER_TBL_IN_BYTES + AWB_FR_SPARE_FOR_BUBBLES) * \
+ RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES)
+
+struct bubble_info {
+ CSS_ALIGN(unsigned int num_of_stripes, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int num_sets, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int size_of_set, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int bubble_size, HIVE_ISP_DDR_WORD_BYTES);
+};
+
+struct stats_3a_bubble_info_per_stripe {
+ struct bubble_info awb_bubble_info[RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES];
+ struct bubble_info af_bubble_info[RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES];
+ struct bubble_info awb_fr_bubble_info[RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES];
+};
+
+struct ff_status {
+ CSS_ALIGN(unsigned int awb_en, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int ae_en, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int af_en, HIVE_ISP_DDR_WORD_BYTES);
+ CSS_ALIGN(unsigned int awb_fr_en, HIVE_ISP_DDR_WORD_BYTES);
+};
+
+typedef struct awb_fr_private_config_s {
+#if defined(__SP)
+ unsigned int config_overlay[7];
+#else
+ struct {
+ uint32_t grid_width : 6;
+ uint32_t rsvd_0 : 2;
+ uint32_t grid_height : 6;
+ uint32_t rsvd_1 : 2;
+ uint32_t block_width : 3;
+ uint32_t block_height : 3;
+ uint32_t grid_height_per_slice : 8;
+ uint32_t rsvd_2 : 2;
+ } bayer_grd_cfg;
+
+ struct {
+ uint32_t x_start : 12;
+ uint32_t revd_0 : 4;
+ uint32_t y_start : 12;
+ uint32_t rsvd_1 : 3;
+ uint32_t af_bayer_en : 1;
+ } bayer_grd_start;
+
+ struct {
+ uint32_t x_end : 12;
+ uint32_t rsvd_0 : 4;
+ uint32_t y_end : 12;
+ uint32_t rsvd_1 : 4;
+ } bayer_grd_end;
+
+ struct {
+ uint32_t A1 : 8;
+ uint32_t A2 : 8;
+ uint32_t A3 : 8;
+ uint32_t A4 : 8;
+ } bayer_coeff_0;
+
+ struct {
+ uint32_t A5 : 8;
+ uint32_t A6 : 8;
+ uint32_t rsvd_0 : 16;
+ } bayer_coeff_1;
+
+ struct {
+ uint32_t bayer_sign : 11;
+ uint32_t rsvd_0 : 21;
+ } bayer_sign_0;
+
+ struct {
+ uint32_t bayer_nf : 4;
+ uint32_t rsvd_0 : 28;
+ } nf;
+#endif
+} awb_fr_private_config_t;
+
+typedef struct {
+#if defined(__SP)
+ unsigned int config_overlay[3];
+#else
+ struct {
+ unsigned int grid_width : 6;
+ unsigned int spare0 : 2;
+ unsigned int grid_height : 6;
+ unsigned int spare1 : 2;
+ unsigned int block_width : 3;
+ unsigned int block_height : 3;
+ unsigned int grid_height_per_slice : 8; /* default value 1 */
+ unsigned int spare2 : 2;
+
+ } grd_cfg;
+
+ struct {
+ unsigned int x_start : 12; /* default 10 */
+ unsigned int spare0 : 4;
+ unsigned int y_start : 12; /* default 2 */
+ unsigned int spare1 : 3;
+ unsigned int en : 1; /* default: 1 */
+ } grd_start;
+
+ struct {
+ unsigned int x_end : 12;
+ unsigned int spare0 : 4;
+ unsigned int y_end : 12;
+ unsigned int spare1 : 4;
+ } grd_end;
+#endif
+} af_private_ff_af_grid_config_t;
+
+struct af_frame_size {
+ /* Represents the number of pixels in a row. NOF_Col == frame_width */
+ unsigned int nof_col : 16;
+ /* Represents the number of rows in a frame. NOF_Row == frame_height */
+ unsigned int nof_row : 16;
+};
+
+typedef struct {
+#if defined(__SP)
+
+ unsigned int config_overlay[11];
+
+#else
+
+ struct {
+ unsigned char A1;
+ unsigned char A2;
+ unsigned char A3;
+ unsigned char A4;
+ } y1_coeff_0;
+ struct {
+ unsigned char A5;
+ unsigned char A6;
+ unsigned char A7;
+ unsigned char A8;
+ } y1_coeff_1;
+ struct {
+ unsigned char A9;
+ unsigned char A10;
+ unsigned char A11;
+ unsigned char A12;
+ } y1_coeff_2;
+
+ unsigned int y1_sign_vec;
+
+ struct {
+ unsigned char A1;
+ unsigned char A2;
+ unsigned char A3;
+ unsigned char A4;
+ } y2_coeff_0;
+ struct {
+ unsigned char A5;
+ unsigned char A6;
+ unsigned char A7;
+ unsigned char A8;
+ } y2_coeff_1;
+ struct {
+ unsigned char A9;
+ unsigned char A10;
+ unsigned char A11;
+ unsigned char A12;
+ } y2_coeff_2;
+
+ unsigned int y2_sign_vec;
+
+ struct {
+ unsigned int y_gen_rate_gr : 6;
+ unsigned int spare0 : 2;
+ unsigned int y_gen_rate_r : 6;
+ unsigned int spare1 : 2;
+ unsigned int y_gen_rate_b : 6;
+ unsigned int spare2 : 2;
+ unsigned int y_gen_rate_gb : 6;
+ unsigned int spare3 : 2;
+ } y_calc;
+
+ struct {
+ unsigned int spare0 : 8;
+ unsigned int y1_nf : 4;
+ unsigned int spare1 : 4;
+ unsigned int y2_nf : 4;
+ unsigned int spare2 : 12;
+ } nf;
+
+ struct af_frame_size frame_size;
+
+#endif
+} af_private_ff_3a_fltr_rspns_config_t;
+
+/*
+ * this type is mirroring portions of the internal ff mmio,
+ * the portions are used for configuration
+ */
+
+typedef struct af_private_config_s {
+ CSS_ALIGN(af_private_ff_3a_fltr_rspns_config_t ff_3a_fltr_rspns_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(af_private_ff_af_grid_config_t y_grid_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+} af_private_config_t;
+
+// this type is mirroring the internal ff mmio
+typedef struct awb_private_config_s {
+#if defined(__SP)
+ // hivecc doesn't support the sizeof operator with bit-fields
+ // so we work around that with a separate definition for sp
+ unsigned int config_overlay[5];
+#else
+ struct {
+ unsigned int rgbs_thr_gr : 13;
+ unsigned int spr0 : 3;
+ unsigned int rgbs_thr_r : 13;
+ unsigned int spr1 : 3;
+ } rgbs_thrsh_0;
+
+ struct {
+ unsigned int rgbs_thr_gb : 13;
+ unsigned int spr0 : 3;
+ unsigned int rgbs_thr_b : 13;
+ unsigned int spr1 : 1;
+ unsigned int rgbs_en : 1; //controls generation of metat_data (like FF enable/disable) and not as discribed in HAS
+ unsigned int rgbs_incl_sat : 1;
+ } rgbs_thrsh_1;
+
+ struct {
+ unsigned int grid_width : 7;
+ unsigned int spr0 : 1;
+ unsigned int grid_height : 7;
+ unsigned int spr1 : 1;
+ unsigned int block_width : 3;
+ unsigned int block_height : 3;
+ unsigned int grid_height_per_slice : 8;
+ unsigned int spr2 : 2;
+ } rgbs_grd_cfg;
+
+ struct {
+ unsigned int x_start : 12;
+ unsigned int spr0 : 4;
+ unsigned int y_start : 12;
+ unsigned int spr1 : 4;
+ } rgbs_grd_start;
+
+ struct {
+ unsigned int x_end : 12;
+ unsigned int spr0 : 4;
+ unsigned int y_end : 12;
+ unsigned int spr1 : 4;
+ } rgbs_grd_end;
+#endif
+} awb_private_config_t;
+
+typedef struct ae_private_direct_config_s {
+#if defined(__SP)
+ unsigned int config_overlay[3];
+#else
+ unsigned int grid_width : 8;
+ unsigned int grid_height : 8;
+ unsigned int block_width : 4;
+ unsigned int block_height : 4;
+ unsigned int spare0 : 5;
+ unsigned int AE_En : 1;
+ unsigned int rst_hist_array : 1;
+ unsigned int done_rst_hist_array : 1;
+
+ unsigned int x_start : 12;
+ unsigned int spare1 : 4;
+ unsigned int y_start : 12;
+ unsigned int spare2 : 4;
+
+ unsigned int x_end : 12;
+ unsigned int spare3 : 4;
+ unsigned int y_end : 12;
+ unsigned int spare4 : 4;
+#endif
+} ae_private_direct_config_t;
+
+struct ia_css_4a_private_config {
+ CSS_ALIGN(struct awb_private_config_s awb_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct ae_private_direct_config_s ae_grd_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct af_private_config_s af_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct awb_fr_private_config_s awb_fr_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+};
+
+typedef struct {
+ unsigned int vals[AE_PRIVATE_NUM_OF_HIST_BINS * AE_PRIVATE_NUM_OF_COLORS];
+} ae_private_raw_buffer_t;
+
+typedef struct {
+ CSS_ALIGN(ae_private_raw_buffer_t buff,
+ HIVE_ISP_DDR_WORD_BYTES);
+} ae_private_raw_buffer_aligned_t;
+
+typedef struct {
+ unsigned char meta_data_buffer[AWB_MAX_BUFFER_SIZE];
+} awb_private_meta_data_t;
+
+/*
+ * the sp layer of fills this struct during frame processing
+ * it's allocated by another layer/component
+ * the address is communicated to the awb sp layer
+ * via a getter function
+ */
+typedef struct {
+ awb_private_meta_data_t meta_data;
+} awb_private_raw_buffer_t;
+
+typedef struct {
+ CSS_ALIGN(unsigned char y_table[AF_MAX_SIZE_OF_Y_TABLE], HIVE_ISP_DDR_WORD_BYTES);
+} af_private_meta_data_t;
+
+/*
+ * the sp layer of the af component fills this struct during frame processing
+ * it's allocated by another layer/component
+ * the address is communicated to the sp layer of the af component
+ * via a getter function
+ */
+typedef struct {
+ CSS_ALIGN(af_private_meta_data_t meta_data, HIVE_ISP_DDR_WORD_BYTES);
+} af_private_raw_buffer_t;
+
+typedef struct {
+ CSS_ALIGN(uint8_t bayer_table[AWB_FR_MAX_SIZE_OF_BAYER_TABLE], HIVE_ISP_DDR_WORD_BYTES);
+} awb_fr_private_meta_data_t;
+
+typedef struct {
+ awb_fr_private_meta_data_t meta_data;
+} awb_fr_private_raw_buffer_t;
+
+struct stats_4a_private_raw_buffer {
+ CSS_ALIGN(awb_private_raw_buffer_t awb_raw_buffer,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(ae_private_raw_buffer_aligned_t ae_raw_buffer[RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES],
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(af_private_raw_buffer_t af_raw_buffer,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(awb_fr_private_raw_buffer_t awb_fr_raw_buffer,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct ia_css_4a_private_config stats_4a_config,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(unsigned int ae_join_buffers,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct stats_3a_bubble_info_per_stripe stats_3a_bubble_per_stripe,
+ HIVE_ISP_DDR_WORD_BYTES);
+
+ CSS_ALIGN(struct ff_status stats_3a_status,
+ HIVE_ISP_DDR_WORD_BYTES);
+};
+
+static void ia_css_3a_join_ae_buffers(ae_public_raw_buffer_t *to,
+ ae_private_raw_buffer_aligned_t *ae_buff)
+{
+ unsigned int i = 0, j = 0;
+ unsigned int size = AE_PRIVATE_NUM_OF_HIST_BINS * AE_PRIVATE_NUM_OF_COLORS;
+ unsigned int color = 0;
+
+ IA_CSS_ENTER_PRIVATE("to=%p, from=%p", to, ae_buff);
+
+ for (i = 0; i < size; i++) {
+ color = i / AE_PRIVATE_NUM_OF_HIST_BINS;
+ j = i % AE_PRIVATE_NUM_OF_HIST_BINS;
+
+ switch (color) {
+ case 0: {
+ to->hist_R.vals[j] += ae_buff->buff.vals[i];
+ break;
+ }
+ case 1: {
+ to->hist_G.vals[j] += ae_buff->buff.vals[i];
+ break;
+ }
+ case 2: {
+ to->hist_B.vals[j] += ae_buff->buff.vals[i];
+ break;
+ }
+ case 3: {
+ to->hist_Y.vals[j] += ae_buff->buff.vals[i];
+ break;
+ }
+ default: {
+ assert(false);
+ break;
+ }
+ }
+ }
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+static void mmgr_load(void *src, void *dst, int len)
+{
+ /* Wrapper imported from ipu3 IPA in CrOS. Originally was MEMCPY_S.
+ * \todo: Check whether we need to use memcpy_s() instead? */
+ memcpy(dst, src, (size_t)(len));
+}
+
+static void ia_css_awb_grid_config_ddr_decode(struct awb_public_config_grid_config *to,
+ struct awb_private_config_s *from)
+{
+ IA_CSS_ENTER_PRIVATE("to=%p, from=%p", to, from);
+
+ to->grid_height = from->rgbs_grd_cfg.grid_height;
+ to->grid_width = from->rgbs_grd_cfg.grid_width;
+ to->grid_x_start = from->rgbs_grd_start.x_start;
+ to->grid_y_start = from->rgbs_grd_start.y_start;
+ to->grid_block_width = from->rgbs_grd_cfg.block_width;
+ to->grid_block_height = from->rgbs_grd_cfg.block_height;
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "\nW = %d, H = %d , BW = %d, BH = %d , X_S = %d, Y_S = %d \n",
+ to->grid_width,
+ to->grid_height,
+ to->grid_block_width,
+ to->grid_block_height,
+ to->grid_x_start,
+ to->grid_y_start);
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+static void
+ia_css_af_grid_config_ddr_decode(struct af_public_grid_config *to,
+ struct af_private_config_s *from)
+{
+ IA_CSS_ENTER_PRIVATE("to=%p, from=%p", to, from);
+
+ to->grid_width = from->y_grid_config.grd_cfg.grid_width;
+ to->grid_height = from->y_grid_config.grd_cfg.grid_height;
+ to->block_width = from->y_grid_config.grd_cfg.block_width;
+ to->block_height = from->y_grid_config.grd_cfg.block_height;
+ to->x_start = from->y_grid_config.grd_start.x_start;
+ to->y_start = from->y_grid_config.grd_start.y_start;
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "\nW = %d, H = %d , BW = %d, BH = %d , X = %d, Y = %d \n",
+ to->grid_width,
+ to->grid_height,
+ to->block_width,
+ to->block_height,
+ to->x_start,
+ to->y_start);
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+static void ia_css_awb_fr_grid_config_ddr_decode(struct awb_fr_public_grid_config *to,
+ struct awb_fr_private_config_s *from)
+{
+ IA_CSS_ENTER_PRIVATE("to=%p, from=%p", to, from);
+
+ to->grid_width = from->bayer_grd_cfg.grid_width;
+ to->grid_height = from->bayer_grd_cfg.grid_height;
+ to->block_width = from->bayer_grd_cfg.block_width;
+ to->block_height = from->bayer_grd_cfg.block_height;
+ to->x_start = from->bayer_grd_start.x_start;
+ to->y_start = from->bayer_grd_start.y_start;
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "\nW = %d, H = %d , BW = %d, BH = %d , X = %d, Y = %d \n",
+ to->grid_width,
+ to->grid_height,
+ to->block_width,
+ to->block_height,
+ to->x_start,
+ to->y_start);
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+static void
+ia_css_ae_grid_config_ddr_decode(struct ae_public_config_grid_config *to,
+ struct ae_private_direct_config_s *from)
+{
+ IA_CSS_ENTER_PRIVATE("to=%p, from=%p", to, from);
+
+ to->grid_width = from->grid_width;
+ to->grid_height = from->grid_height;
+ to->block_width = from->block_width;
+ to->block_height = from->block_height;
+ to->x_start = from->x_start;
+ to->y_start = from->y_start;
+
+ to->ae_en = from->AE_En;
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "\nW = %d, H = %d , BW = %d, BH = %d , X_S = %d, Y_S = %d , AE_EN = %d\n",
+ to->grid_width,
+ to->grid_height,
+ to->block_width,
+ to->block_height,
+ to->x_start,
+ to->y_start,
+ to->ae_en);
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+static void ia_css_3a_grid_config_ddr_decode(struct ia_css_2500_4a_config *to,
+ struct ia_css_4a_private_config *from)
+{
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_3a_grid_config_ddr_decode() enter\n");
+
+ ia_css_awb_grid_config_ddr_decode(&to->awb_grd_config,
+ &from->awb_config);
+
+ ia_css_af_grid_config_ddr_decode(&to->af_grd_config, &from->af_config);
+
+ ia_css_awb_fr_grid_config_ddr_decode(&to->awb_fr_grd_config,
+ &from->awb_fr_config);
+
+ ia_css_ae_grid_config_ddr_decode(&to->ae_grd_config,
+ &from->ae_grd_config);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_3a_grid_config_ddr_decode() leave\n");
+}
+
+/*
+ awb_debubble -
+ Removes bubbles btwn sets of stats caused by ACC
+ Due to striping support set size might differ
+ btwn the stripes but will stay consistent...
+ example:
+ statistics layout before of ia_css_3a_debubble:
+ | stats ... 0000 ... stats .... 000 ....|
+ statistics layout after of ia_css_3a_debubble:
+ | stats ... stats .... stats ...|
+*/
+static void awb_debubble(awb_public_raw_buffer_t *awb_raw_buffer,
+ struct bubble_info *awb_bubble_info)
+{
+ unsigned int num_sets, src_index, dst_index;
+ unsigned int num_of_stripes;
+ unsigned int i, set_size_w_bubble;
+
+ IA_CSS_ENTER_PRIVATE("buffer=%p, bubble info=%p",
+ awb_raw_buffer, awb_bubble_info);
+
+ num_of_stripes = awb_bubble_info[0].num_of_stripes;
+ if (num_of_stripes <= 1) {
+ awb_bubble_info[1] = awb_bubble_info[0];
+ }
+
+ for (i = 0; i < RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES; i++) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble info stripe %d:\n", i);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_of_stirpes = %d \n",
+ awb_bubble_info[0].num_of_stripes);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_sets = %d \n",
+ awb_bubble_info[i].num_sets);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "size_of_set = %d \n",
+ awb_bubble_info[i].size_of_set);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble_size = %d \n",
+ awb_bubble_info[i].bubble_size);
+ }
+
+ if (awb_bubble_info[0].bubble_size || awb_bubble_info[1].bubble_size) {
+ dst_index = awb_bubble_info[0].size_of_set;
+
+ set_size_w_bubble = awb_bubble_info[0].size_of_set +
+ awb_bubble_info[0].bubble_size;
+
+ src_index = set_size_w_bubble;
+
+ /* number of sets for s0 and s1 are identical */
+ if (num_of_stripes <= 1)
+ num_sets = awb_bubble_info[0].num_sets;
+ else {
+ if (awb_bubble_info[0].bubble_size) {
+ num_sets = awb_bubble_info[0].num_sets * 2;
+ } else {
+ num_sets = awb_bubble_info[1].num_sets * 2;
+ }
+ }
+ for (i = 1; i < num_sets; i++) {
+ memmove((void *)&awb_raw_buffer->rgb_table[dst_index],
+ (void *)&awb_raw_buffer->rgb_table[src_index],
+ (sizeof(awb_public_set_item_t) * awb_bubble_info[i % 2].size_of_set));
+
+ set_size_w_bubble = awb_bubble_info[i % 2].size_of_set +
+ awb_bubble_info[i % 2].bubble_size;
+
+ src_index += set_size_w_bubble;
+ dst_index += awb_bubble_info[i % 2].size_of_set;
+ }
+ }
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+/*
+ af_debubble-
+ Removes bubbles btwn sets of stats caused by ACC
+ Due to striping support set size might differ
+ btwn the stripes but will stay consistent...
+ example:
+ statistics layout before of ia_css_3a_debubble:
+ | stats ... 0000 ... stats .... 000 ....|
+ statistics layout after of ia_css_3a_debubble:
+ | stats ... stats .... stats ...|
+*/
+static void ia_css_af_debubble(af_public_raw_buffer_t *af_raw_buffer,
+ struct bubble_info *af_bubble_info)
+{
+ unsigned int num_sets, src_index, dst_index;
+ unsigned int num_of_stripes = 0;
+ unsigned int i, set_size_w_bubble;
+
+ IA_CSS_ENTER_PRIVATE("buffer=%p, bubble info=%p",
+ af_raw_buffer, af_bubble_info);
+
+ num_of_stripes = af_bubble_info[0].num_of_stripes;
+ if (num_of_stripes <= 1) {
+ af_bubble_info[1] = af_bubble_info[0];
+ }
+
+ for (i = 0; i < RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES; i++) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble info stripe %d:\n", i);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_of_stirpes = %d\n ",
+ af_bubble_info[0].num_of_stripes);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_sets = %d \n",
+ af_bubble_info[i].num_sets);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "size_of_set = %d \n",
+ af_bubble_info[i].size_of_set);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble_size = %d \n",
+ af_bubble_info[i].bubble_size);
+ }
+
+ if (af_bubble_info[0].bubble_size || af_bubble_info[1].bubble_size) {
+ dst_index = af_bubble_info[0].size_of_set;
+
+ set_size_w_bubble = af_bubble_info[0].size_of_set +
+ af_bubble_info[0].bubble_size;
+
+ src_index = set_size_w_bubble;
+
+ /* number of sets for s0 and s1 are identical */
+ if (num_of_stripes <= 1)
+ num_sets = af_bubble_info[0].num_sets;
+ else {
+ if (af_bubble_info[0].bubble_size) {
+ num_sets = af_bubble_info[0].num_sets * 2;
+ } else {
+ num_sets = af_bubble_info[1].num_sets * 2;
+ }
+ }
+
+ for (i = 1; i < num_sets; i++) {
+ memmove((void *)&af_raw_buffer->y_table[dst_index],
+ (void *)&af_raw_buffer->y_table[src_index],
+ (sizeof(af_public_y_item_t) * af_bubble_info[i % 2].size_of_set));
+
+ set_size_w_bubble = af_bubble_info[i % 2].size_of_set +
+ af_bubble_info[i % 2].bubble_size;
+
+ src_index += set_size_w_bubble;
+ dst_index += af_bubble_info[i % 2].size_of_set;
+ }
+ }
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+/* awb_fr_debubble-
+ * Removes bubbles btwn sets of stats caused by ACC
+ * Due to striping support set size might differ
+ * btwn the stripes but will stay consistent...
+ * example:
+ * statistics layout before of ia_css_3a_debubble:
+ * | stats ... 0000 ... stats .... 000 ....|
+ * statistics layout after of ia_css_3a_debubble:
+ * | stats ... stats .... stats ...|
+ */
+
+static void ia_css_awb_fr_debubble(awb_fr_public_raw_buffer_t *awb_fr_raw_buffer,
+ struct bubble_info *awb_fr_bubble_info)
+{
+ unsigned int num_sets, src_index, dst_index;
+ unsigned int num_of_stripes = 0;
+ unsigned int i, set_size_w_bubble;
+
+ IA_CSS_ENTER_PRIVATE("buffer=%p, bubble info=%p",
+ awb_fr_raw_buffer, awb_fr_bubble_info);
+
+ num_of_stripes = awb_fr_bubble_info[0].num_of_stripes;
+ if (num_of_stripes <= 1) {
+ awb_fr_bubble_info[1] = awb_fr_bubble_info[0];
+ }
+
+ for (i = 0; i < RES_MGR_PRIVATE_MAX_NUM_OF_STRIPES; i++) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble info stripe %d:\n", i);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_of_stirpes = %d\n",
+ awb_fr_bubble_info[0].num_of_stripes);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "num_sets = %d \n",
+ awb_fr_bubble_info[i].num_sets);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "size_of_set = %d \n",
+ awb_fr_bubble_info[i].size_of_set);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "bubble_size = %d \n",
+ awb_fr_bubble_info[i].bubble_size);
+ }
+
+ if (awb_fr_bubble_info[0].bubble_size || awb_fr_bubble_info[1].bubble_size) {
+ dst_index = awb_fr_bubble_info[0].size_of_set;
+
+ set_size_w_bubble = awb_fr_bubble_info[0].size_of_set +
+ awb_fr_bubble_info[0].bubble_size;
+
+ src_index = set_size_w_bubble;
+
+ // number of sets for s0 and s1 are identical
+ if (num_of_stripes <= 1)
+ num_sets = awb_fr_bubble_info[0].num_sets;
+ else {
+ if (awb_fr_bubble_info[0].bubble_size) {
+ num_sets = awb_fr_bubble_info[0].num_sets * 2;
+ } else {
+ num_sets = awb_fr_bubble_info[1].num_sets * 2;
+ }
+ }
+
+ for (i = 1; i < num_sets; i++) {
+ memmove((void *)&awb_fr_raw_buffer->bayer_table[dst_index],
+ (void *)&awb_fr_raw_buffer->bayer_table[src_index],
+ (sizeof(awb_fr_public_bayer_item_t) * awb_fr_bubble_info[i % 2].size_of_set));
+
+ set_size_w_bubble = awb_fr_bubble_info[i % 2].size_of_set +
+ awb_fr_bubble_info[i % 2].bubble_size;
+
+ src_index += set_size_w_bubble;
+ dst_index += awb_fr_bubble_info[i % 2].size_of_set;
+ }
+ }
+
+ IA_CSS_LEAVE_PRIVATE("");
+}
+
+/*
+ ia_css_3a_debubble -
+ Removes bubbles btwn sets of stats caused by ACC
+ Due to striping support set size might differ
+ btwn the stripes but will stay consistent...
+ example:
+ statistics layout before of ia_css_3a_debubble:
+ | stats ... 0000 ... stats .... 000 ....|
+ statistics layout after of ia_css_3a_debubble:
+ | stats ... stats .... stats ...|
+*/
+static void ia_css_3a_debubble(struct stats_4a_public_raw_buffer *meta_data,
+ struct stats_3a_bubble_info_per_stripe *bubble_info,
+ struct ff_status *stats_enable)
+{
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_3a_debubble() enter\n");
+
+ if (stats_enable->awb_en) {
+ awb_debubble(&meta_data->awb_raw_buffer,
+ bubble_info->awb_bubble_info);
+ }
+ if (stats_enable->af_en) {
+ ia_css_af_debubble(&meta_data->af_raw_buffer,
+ bubble_info->af_bubble_info);
+ }
+ if (stats_enable->awb_fr_en) {
+ ia_css_awb_fr_debubble(&meta_data->awb_fr_raw_buffer,
+ bubble_info->awb_fr_bubble_info);
+ }
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_3a_debubble() leave\n");
+}
+
+void IPU3AllStats::ipu3_stats_init_3a(struct ipu3_stats_all_stats *all_stats)
+{
+ all_stats->ia_css_4a_statistics.data =
+ &all_stats->stats_4a_public_raw_buffer;
+ all_stats->ia_css_4a_statistics.stats_4a_config =
+ &all_stats->ia_css_2500_4a_config;
+}
+
+void IPU3AllStats::ipu3_stats_get_3a([[maybe_unused]] struct ipu3_stats_all_stats *all_stats,
+ [[maybe_unused]] const struct ipu3_uapi_stats_3a *isp_stats)
+{
+ /* extract, memcpy and debubble each of 3A stats */
+ struct ia_css_4a_statistics *host_stats = &all_stats->ia_css_4a_statistics;
+ struct ia_css_4a_private_config stats_config;
+ struct stats_3a_bubble_info_per_stripe stats_bubble_info;
+ struct ff_status stats_enable;
+ ae_private_raw_buffer_aligned_t ae_raw_buffer_s;
+ unsigned int ae_join_buffers;
+
+ hrt_vaddress af_ddr_addr = (hrt_vaddress)(long int)&(((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->af_raw_buffer);
+
+ hrt_vaddress awb_ddr_addr = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->awb_raw_buffer;
+
+ hrt_vaddress awb_fr_ddr_addr = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->awb_fr_raw_buffer;
+
+ hrt_vaddress ae_buff_0_ddr_addr = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->ae_raw_buffer[0];
+ hrt_vaddress ae_buff_1_ddr_addr = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->ae_raw_buffer[1];
+
+ hrt_vaddress ae_pp_info_addr = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->ae_join_buffers;
+
+ hrt_vaddress stats_bubble_info_addr = (hrt_vaddress) & (isp_stats->stats_3a_bubble_per_stripe);
+
+ hrt_vaddress stats_config_addr = (hrt_vaddress) & (isp_stats->stats_4a_config);
+
+ hrt_vaddress stats_3a_enable = (hrt_vaddress)(long int)&((struct stats_4a_private_raw_buffer *)(long int)isp_stats)->stats_3a_status;
+
+ ipu3_stats_init_3a(all_stats);
+
+ /* load grid configuration */
+ mmgr_load(stats_config_addr,
+ (void *)&(stats_config),
+ sizeof(struct ia_css_4a_private_config));
+
+ /* load bubble info */
+ mmgr_load(stats_bubble_info_addr, (void *)&(stats_bubble_info),
+ sizeof(struct stats_3a_bubble_info_per_stripe));
+
+ /* load ae post processing info */
+ mmgr_load(ae_pp_info_addr,
+ (void *)&(ae_join_buffers),
+ sizeof(unsigned int));
+
+ /* load metadata */
+ mmgr_load(af_ddr_addr,
+ (void *)&(host_stats->data->af_raw_buffer),
+ sizeof(af_public_raw_buffer_t));
+
+ mmgr_load(awb_ddr_addr,
+ (void *)&(host_stats->data->awb_raw_buffer),
+ sizeof(awb_public_raw_buffer_t));
+
+ mmgr_load(awb_fr_ddr_addr,
+ (void *)&(host_stats->data->awb_fr_raw_buffer),
+ sizeof(awb_fr_public_raw_buffer_t));
+
+ mmgr_load(ae_buff_0_ddr_addr,
+ (void *)&(host_stats->data->ae_raw_buffer),
+ sizeof(ae_public_raw_buffer_t));
+
+ mmgr_load(stats_3a_enable,
+ (void *)&(stats_enable),
+ sizeof(struct ff_status));
+
+ if (ae_join_buffers == 1) {
+ mmgr_load(ae_buff_1_ddr_addr,
+ (void *)&(ae_raw_buffer_s),
+ sizeof(ae_private_raw_buffer_aligned_t));
+ }
+
+ /* for striping might need to combine buffers of ae */
+ if (ae_join_buffers == 1)
+ ia_css_3a_join_ae_buffers(&host_stats->data->ae_raw_buffer,
+ &ae_raw_buffer_s);
+
+ /* decode must be prior to debubbling! */
+ ia_css_3a_grid_config_ddr_decode(host_stats->stats_4a_config,
+ &stats_config);
+ ia_css_3a_debubble(host_stats->data, &stats_bubble_info, &stats_enable);
+}
+
+ia_err
+IPU3AllStats::intel_skycam_statistics_convert(const ia_css_4a_statistics &statistics,
+ ia_aiq_rgbs_grid *out_rgbs_grid,
+ ia_aiq_af_grid *out_af_grid)
+{
+ if (!out_rgbs_grid || !out_af_grid) {
+ return ia_err_data;
+ }
+
+ // AWB (RGBS) grid.
+ out_rgbs_grid->grid_width = statistics.stats_4a_config->awb_grd_config.grid_width;
+ out_rgbs_grid->grid_height = statistics.stats_4a_config->awb_grd_config.grid_height;
+
+ for (int i = 0; i < out_rgbs_grid->grid_width * out_rgbs_grid->grid_height; ++i) {
+ out_rgbs_grid->blocks_ptr[i].avg_r = statistics.data->awb_raw_buffer.rgb_table[i].R_avg;
+ out_rgbs_grid->blocks_ptr[i].avg_b = statistics.data->awb_raw_buffer.rgb_table[i].B_avg;
+ out_rgbs_grid->blocks_ptr[i].avg_gb = statistics.data->awb_raw_buffer.rgb_table[i].Gb_avg;
+ out_rgbs_grid->blocks_ptr[i].avg_gr = statistics.data->awb_raw_buffer.rgb_table[i].Gr_avg;
+ out_rgbs_grid->blocks_ptr[i].sat = statistics.data->awb_raw_buffer.rgb_table[i].sat_ratio;
+ }
+
+ // AF (aka F response) grid.
+ out_af_grid->grid_width = statistics.stats_4a_config->af_grd_config.grid_width;
+ out_af_grid->grid_height = statistics.stats_4a_config->af_grd_config.grid_height;
+
+ // The AIQ block expects block dimensions specified in BQ's, while
+ // SkyCam uses log2 of pixel count.
+ out_af_grid->block_width = 1 << (statistics.stats_4a_config->af_grd_config.block_width - 1);
+ out_af_grid->block_height = 1 << (statistics.stats_4a_config->af_grd_config.block_height - 1);
+
+ for (int i = 0; i < out_af_grid->grid_width * out_af_grid->grid_height; ++i) {
+ out_af_grid->filter_response_1[i] = statistics.data->af_raw_buffer.y_table[i].y1_avg;
+ out_af_grid->filter_response_2[i] = statistics.data->af_raw_buffer.y_table[i].y2_avg;
+ }
+
+ return ia_err_none;
+}
+
+} // namespace libcamera::ipa::ipu3
+
diff --git a/stats/ipu3_all_stats.h b/stats/ipu3_all_stats.h
new file mode 100644
index 0000000..3e5a336
--- /dev/null
+++ b/stats/ipu3_all_stats.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017-2018 Intel Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * IPU3AllStats - Handle and convert statistics from kernel to AIQ interface
+ *
+ * This implementation is highly derived from ChromeOS:
+ * platform2/camera/hal/intel/ipu3/psl/ipu3/statsConverter/ipu-stats.cpp
+ */
+
+#ifndef IPU3_ALL_STATS_H
+#define IPU3_ALL_STATS_H
+
+#include <ia_imaging/ia_aiq_types.h>
+#include <ia_imaging/stats_3a_public.h>
+
+#include <linux/intel-ipu3.h>
+
+namespace libcamera::ipa::ipu3 {
+
+class IPU3AllStats
+{
+public:
+ struct ipu3_stats_all_stats {
+ struct ia_css_4a_statistics ia_css_4a_statistics;
+ struct stats_4a_public_raw_buffer stats_4a_public_raw_buffer;
+ struct ia_css_2500_4a_config ia_css_2500_4a_config;
+ };
+
+ static void
+ ipu3_stats_get_3a(struct ipu3_stats_all_stats *all_stats,
+ const struct ipu3_uapi_stats_3a *isp_stats);
+
+ static ia_err
+ intel_skycam_statistics_convert(const ia_css_4a_statistics &statistics,
+ ia_aiq_rgbs_grid *out_rgbs_grid,
+ ia_aiq_af_grid *out_af_grid);
+private:
+ static void ipu3_stats_init_3a(struct ipu3_stats_all_stats *all_stats);
+};
+
+} /* namespace libcamera::ipa::ipu3 */
+
+#endif /* IPU3_ALL_STATS_H */
+
diff --git a/stats/meson.build b/stats/meson.build
index 9707630..74ce657 100644
--- a/stats/meson.build
+++ b/stats/meson.build
@@ -1,6 +1,8 @@
# SPDX-License-Identifier: CC0-1.0
ipu3_ipa_files += files([
+ 'ipa_ipu3_stats.cpp',
+ 'ipu3_all_stats.cpp',
'shared_item_pool.cpp',
])