1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Intel Camera Imaging ISP subsystem. 4 * Copyright (c) 2015, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 */ 15 16 #include "ia_css_types.h" 17 #include "sh_css_defs.h" 18 #ifndef IA_CSS_NO_DEBUG 19 #include "ia_css_debug.h" 20 #endif 21 #include "sh_css_frac.h" 22 #include "assert_support.h" 23 24 #include "bh/bh_2/ia_css_bh.host.h" 25 #include "ia_css_s3a.host.h" 26 27 const struct ia_css_3a_config default_3a_config = { 28 25559, 29 32768, 30 7209, 31 65535, 32 0, 33 65535, 34 {-3344, -6104, -19143, 19143, 6104, 3344, 0}, 35 {1027, 0, -9219, 16384, -9219, 1027, 0} 36 }; 37 38 static unsigned int s3a_raw_bit_depth; 39 40 void 41 ia_css_s3a_configure(unsigned int raw_bit_depth) 42 { 43 s3a_raw_bit_depth = raw_bit_depth; 44 } 45 46 static void 47 ia_css_ae_encode( 48 struct sh_css_isp_ae_params *to, 49 const struct ia_css_3a_config *from, 50 unsigned int size) 51 { 52 (void)size; 53 /* coefficients to calculate Y */ 54 to->y_coef_r = 55 uDIGIT_FITTING(from->ae_y_coef_r, 16, SH_CSS_AE_YCOEF_SHIFT); 56 to->y_coef_g = 57 uDIGIT_FITTING(from->ae_y_coef_g, 16, SH_CSS_AE_YCOEF_SHIFT); 58 to->y_coef_b = 59 uDIGIT_FITTING(from->ae_y_coef_b, 16, SH_CSS_AE_YCOEF_SHIFT); 60 } 61 62 static void 63 ia_css_awb_encode( 64 struct sh_css_isp_awb_params *to, 65 const struct ia_css_3a_config *from, 66 unsigned int size) 67 { 68 (void)size; 69 /* AWB level gate */ 70 to->lg_high_raw = 71 uDIGIT_FITTING(from->awb_lg_high_raw, 16, s3a_raw_bit_depth); 72 to->lg_low = 73 uDIGIT_FITTING(from->awb_lg_low, 16, SH_CSS_BAYER_BITS); 74 to->lg_high = 75 uDIGIT_FITTING(from->awb_lg_high, 16, SH_CSS_BAYER_BITS); 76 } 77 78 static void 79 ia_css_af_encode( 80 struct sh_css_isp_af_params *to, 81 const struct ia_css_3a_config *from, 82 unsigned int size) 83 { 84 unsigned int i; 85 (void)size; 86 87 /* af fir coefficients */ 88 for (i = 0; i < 7; ++i) { 89 to->fir1[i] = 90 sDIGIT_FITTING(from->af_fir1_coef[i], 15, 91 SH_CSS_AF_FIR_SHIFT); 92 to->fir2[i] = 93 sDIGIT_FITTING(from->af_fir2_coef[i], 15, 94 SH_CSS_AF_FIR_SHIFT); 95 } 96 } 97 98 void 99 ia_css_s3a_encode( 100 struct sh_css_isp_s3a_params *to, 101 const struct ia_css_3a_config *from, 102 unsigned int size) 103 { 104 (void)size; 105 106 ia_css_ae_encode(&to->ae, from, sizeof(to->ae)); 107 ia_css_awb_encode(&to->awb, from, sizeof(to->awb)); 108 ia_css_af_encode(&to->af, from, sizeof(to->af)); 109 } 110 111 #if 0 112 void 113 ia_css_process_s3a( 114 unsigned int pipe_id, 115 const struct ia_css_pipeline_stage *stage, 116 struct ia_css_isp_parameters *params) 117 { 118 short dmem_offset = stage->binary->info->mem_offsets->dmem.s3a; 119 120 assert(params); 121 122 if (dmem_offset >= 0) { 123 ia_css_s3a_encode((struct sh_css_isp_s3a_params *) 124 &stage->isp_mem_params[IA_CSS_ISP_DMEM0].address[dmem_offset], 125 ¶ms->s3a_config); 126 ia_css_bh_encode((struct sh_css_isp_bh_params *) 127 &stage->isp_mem_params[IA_CSS_ISP_DMEM0].address[dmem_offset], 128 ¶ms->s3a_config); 129 params->isp_params_changed = true; 130 params->isp_mem_params_changed[pipe_id][stage->stage_num][IA_CSS_ISP_DMEM0] = 131 true; 132 } 133 134 params->isp_params_changed = true; 135 } 136 #endif 137 138 #ifndef IA_CSS_NO_DEBUG 139 void 140 ia_css_ae_dump( 141 const struct sh_css_isp_ae_params *ae, 142 unsigned int level) 143 { 144 if (!ae) return; 145 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 146 "ae_y_coef_r", ae->y_coef_r); 147 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 148 "ae_y_coef_g", ae->y_coef_g); 149 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 150 "ae_y_coef_b", ae->y_coef_b); 151 } 152 153 void 154 ia_css_awb_dump( 155 const struct sh_css_isp_awb_params *awb, 156 unsigned int level) 157 { 158 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 159 "awb_lg_high_raw", awb->lg_high_raw); 160 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 161 "awb_lg_low", awb->lg_low); 162 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 163 "awb_lg_high", awb->lg_high); 164 } 165 166 void 167 ia_css_af_dump( 168 const struct sh_css_isp_af_params *af, 169 unsigned int level) 170 { 171 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 172 "af_fir1[0]", af->fir1[0]); 173 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 174 "af_fir1[1]", af->fir1[1]); 175 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 176 "af_fir1[2]", af->fir1[2]); 177 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 178 "af_fir1[3]", af->fir1[3]); 179 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 180 "af_fir1[4]", af->fir1[4]); 181 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 182 "af_fir1[5]", af->fir1[5]); 183 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 184 "af_fir1[6]", af->fir1[6]); 185 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 186 "af_fir2[0]", af->fir2[0]); 187 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 188 "af_fir2[1]", af->fir2[1]); 189 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 190 "af_fir2[2]", af->fir2[2]); 191 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 192 "af_fir2[3]", af->fir2[3]); 193 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 194 "af_fir2[4]", af->fir2[4]); 195 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 196 "af_fir2[5]", af->fir2[5]); 197 ia_css_debug_dtrace(level, "\t%-32s = %d\n", 198 "af_fir2[6]", af->fir2[6]); 199 } 200 201 void 202 ia_css_s3a_dump( 203 const struct sh_css_isp_s3a_params *s3a, 204 unsigned int level) 205 { 206 ia_css_debug_dtrace(level, "S3A Support:\n"); 207 ia_css_ae_dump(&s3a->ae, level); 208 ia_css_awb_dump(&s3a->awb, level); 209 ia_css_af_dump(&s3a->af, level); 210 } 211 212 void 213 ia_css_s3a_debug_dtrace( 214 const struct ia_css_3a_config *config, 215 unsigned int level) 216 { 217 ia_css_debug_dtrace(level, 218 "config.ae_y_coef_r=%d, config.ae_y_coef_g=%d, config.ae_y_coef_b=%d, config.awb_lg_high_raw=%d, config.awb_lg_low=%d, config.awb_lg_high=%d\n", 219 config->ae_y_coef_r, config->ae_y_coef_g, 220 config->ae_y_coef_b, config->awb_lg_high_raw, 221 config->awb_lg_low, config->awb_lg_high); 222 } 223 #endif 224 225 void 226 ia_css_s3a_hmem_decode( 227 struct ia_css_3a_statistics *host_stats, 228 const struct ia_css_bh_table *hmem_buf) 229 { 230 #if defined(HAS_NO_HMEM) 231 (void)host_stats; 232 (void)hmem_buf; 233 #else 234 struct ia_css_3a_rgby_output *out_ptr; 235 int i; 236 237 /* pixel counts(BQ) for 3A area */ 238 int count_for_3a; 239 int sum_r, diff; 240 241 assert(host_stats); 242 assert(host_stats->rgby_data); 243 assert(hmem_buf); 244 245 count_for_3a = host_stats->grid.width * host_stats->grid.height 246 * host_stats->grid.bqs_per_grid_cell 247 * host_stats->grid.bqs_per_grid_cell; 248 249 out_ptr = host_stats->rgby_data; 250 251 ia_css_bh_hmem_decode(out_ptr, hmem_buf); 252 253 /* Calculate sum of histogram of R, 254 which should not be less than count_for_3a */ 255 sum_r = 0; 256 for (i = 0; i < HMEM_UNIT_SIZE; i++) { 257 sum_r += out_ptr[i].r; 258 } 259 if (sum_r < count_for_3a) { 260 /* histogram is invalid */ 261 return; 262 } 263 264 /* Verify for sum of histogram of R/G/B/Y */ 265 #if 0 266 { 267 int sum_g = 0; 268 int sum_b = 0; 269 int sum_y = 0; 270 271 for (i = 0; i < HMEM_UNIT_SIZE; i++) { 272 sum_g += out_ptr[i].g; 273 sum_b += out_ptr[i].b; 274 sum_y += out_ptr[i].y; 275 } 276 if (sum_g != sum_r || sum_b != sum_r || sum_y != sum_r) { 277 /* histogram is invalid */ 278 return; 279 } 280 } 281 #endif 282 283 /* 284 * Limit the histogram area only to 3A area. 285 * In DSP, the histogram of 0 is incremented for pixels 286 * which are outside of 3A area. That amount should be subtracted here. 287 * hist[0] = hist[0] - ((sum of all hist[]) - (pixel count for 3A area)) 288 */ 289 diff = sum_r - count_for_3a; 290 out_ptr[0].r -= diff; 291 out_ptr[0].g -= diff; 292 out_ptr[0].b -= diff; 293 out_ptr[0].y -= diff; 294 #endif 295 } 296 297 void 298 ia_css_s3a_dmem_decode( 299 struct ia_css_3a_statistics *host_stats, 300 const struct ia_css_3a_output *isp_stats) 301 { 302 int isp_width, host_width, height, i; 303 struct ia_css_3a_output *host_ptr; 304 305 assert(host_stats); 306 assert(host_stats->data); 307 assert(isp_stats); 308 309 isp_width = host_stats->grid.aligned_width; 310 host_width = host_stats->grid.width; 311 height = host_stats->grid.height; 312 host_ptr = host_stats->data; 313 314 /* Getting 3A statistics from DMEM does not involve any 315 * transformation (like the VMEM version), we just copy the data 316 * using a different output width. */ 317 for (i = 0; i < height; i++) { 318 memcpy(host_ptr, isp_stats, host_width * sizeof(*host_ptr)); 319 isp_stats += isp_width; 320 host_ptr += host_width; 321 } 322 } 323 324 /* MW: this is an ISP function */ 325 static inline int 326 merge_hi_lo_14(unsigned short hi, unsigned short lo) 327 { 328 int val = (int)((((unsigned int)hi << 14) & 0xfffc000) | 329 ((unsigned int)lo & 0x3fff)); 330 return val; 331 } 332 333 void 334 ia_css_s3a_vmem_decode( 335 struct ia_css_3a_statistics *host_stats, 336 const u16 *isp_stats_hi, 337 const uint16_t *isp_stats_lo) 338 { 339 int out_width, out_height, chunk, rest, kmax, y, x, k, elm_start, elm, ofs; 340 const u16 *hi, *lo; 341 struct ia_css_3a_output *output; 342 343 assert(host_stats); 344 assert(host_stats->data); 345 assert(isp_stats_hi); 346 assert(isp_stats_lo); 347 348 output = host_stats->data; 349 out_width = host_stats->grid.width; 350 out_height = host_stats->grid.height; 351 hi = isp_stats_hi; 352 lo = isp_stats_lo; 353 354 chunk = ISP_VEC_NELEMS >> host_stats->grid.deci_factor_log2; 355 chunk = max(chunk, 1); 356 357 for (y = 0; y < out_height; y++) { 358 elm_start = y * ISP_S3ATBL_HI_LO_STRIDE; 359 rest = out_width; 360 x = 0; 361 while (x < out_width) { 362 kmax = (rest > chunk) ? chunk : rest; 363 ofs = y * out_width + x; 364 elm = elm_start + x * sizeof(*output) / sizeof(int32_t); 365 for (k = 0; k < kmax; k++, elm++) { 366 output[ofs + k].ae_y = merge_hi_lo_14( 367 hi[elm + chunk * 0], lo[elm + chunk * 0]); 368 output[ofs + k].awb_cnt = merge_hi_lo_14( 369 hi[elm + chunk * 1], lo[elm + chunk * 1]); 370 output[ofs + k].awb_gr = merge_hi_lo_14( 371 hi[elm + chunk * 2], lo[elm + chunk * 2]); 372 output[ofs + k].awb_r = merge_hi_lo_14( 373 hi[elm + chunk * 3], lo[elm + chunk * 3]); 374 output[ofs + k].awb_b = merge_hi_lo_14( 375 hi[elm + chunk * 4], lo[elm + chunk * 4]); 376 output[ofs + k].awb_gb = merge_hi_lo_14( 377 hi[elm + chunk * 5], lo[elm + chunk * 5]); 378 output[ofs + k].af_hpf1 = merge_hi_lo_14( 379 hi[elm + chunk * 6], lo[elm + chunk * 6]); 380 output[ofs + k].af_hpf2 = merge_hi_lo_14( 381 hi[elm + chunk * 7], lo[elm + chunk * 7]); 382 } 383 x += chunk; 384 rest -= chunk; 385 } 386 } 387 } 388