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 <linux/math.h> 17 #include <linux/slab.h> 18 19 #include <math_support.h> 20 #include "sh_css_param_shading.h" 21 #include "ia_css_shading.h" 22 #include "assert_support.h" 23 #include "sh_css_defs.h" 24 #include "sh_css_internal.h" 25 #include "ia_css_debug.h" 26 #include "ia_css_pipe_binarydesc.h" 27 28 #include "sh_css_hrt.h" 29 30 #include "platform_support.h" 31 32 /* Bilinear interpolation on shading tables: 33 * For each target point T, we calculate the 4 surrounding source points: 34 * ul (upper left), ur (upper right), ll (lower left) and lr (lower right). 35 * We then calculate the distances from the T to the source points: x0, x1, 36 * y0 and y1. 37 * We then calculate the value of T: 38 * dx0*dy0*Slr + dx0*dy1*Sur + dx1*dy0*Sll + dx1*dy1*Sul. 39 * We choose a grid size of 1x1 which means: 40 * dx1 = 1-dx0 41 * dy1 = 1-dy0 42 * 43 * Sul dx0 dx1 Sur 44 * .<----->|<------------->. 45 * ^ 46 * dy0| 47 * v T 48 * - . 49 * ^ 50 * | 51 * dy1| 52 * v 53 * . . 54 * Sll Slr 55 * 56 * Padding: 57 * The area that the ISP operates on can include padding both on the left 58 * and the right. We need to padd the shading table such that the shading 59 * values end up on the correct pixel values. This means we must padd the 60 * shading table to match the ISP padding. 61 * We can have 5 cases: 62 * 1. All 4 points fall in the left padding. 63 * 2. The left 2 points fall in the left padding. 64 * 3. All 4 points fall in the cropped (target) region. 65 * 4. The right 2 points fall in the right padding. 66 * 5. All 4 points fall in the right padding. 67 * Cases 1 and 5 are easy to handle: we simply use the 68 * value 1 in the shading table. 69 * Cases 2 and 4 require interpolation that takes into 70 * account how far into the padding area the pixels 71 * fall. We extrapolate the shading table into the 72 * padded area and then interpolate. 73 */ 74 static void 75 crop_and_interpolate(unsigned int cropped_width, 76 unsigned int cropped_height, 77 unsigned int left_padding, 78 int right_padding, 79 int top_padding, 80 const struct ia_css_shading_table *in_table, 81 struct ia_css_shading_table *out_table, 82 enum ia_css_sc_color color) 83 { 84 unsigned int i, j, 85 sensor_width, 86 sensor_height, 87 table_width, 88 table_height, 89 table_cell_h, 90 out_cell_size, 91 in_cell_size, 92 out_start_row, 93 padded_width; 94 int out_start_col, /* can be negative to indicate padded space */ 95 table_cell_w; 96 unsigned short *in_ptr, 97 *out_ptr; 98 99 assert(in_table); 100 assert(out_table); 101 102 sensor_width = in_table->sensor_width; 103 sensor_height = in_table->sensor_height; 104 table_width = in_table->width; 105 table_height = in_table->height; 106 in_ptr = in_table->data[color]; 107 out_ptr = out_table->data[color]; 108 109 padded_width = cropped_width + left_padding + right_padding; 110 out_cell_size = CEIL_DIV(padded_width, out_table->width - 1); 111 in_cell_size = CEIL_DIV(sensor_width, table_width - 1); 112 113 out_start_col = ((int)sensor_width - (int)cropped_width) / 2 - left_padding; 114 out_start_row = ((int)sensor_height - (int)cropped_height) / 2 - top_padding; 115 table_cell_w = (int)((table_width - 1) * in_cell_size); 116 table_cell_h = (table_height - 1) * in_cell_size; 117 118 for (i = 0; i < out_table->height; i++) { 119 int ty, src_y0, src_y1; 120 unsigned int sy0, sy1, dy0, dy1, divy; 121 122 /* 123 * calculate target point and make sure it falls within 124 * the table 125 */ 126 ty = out_start_row + i * out_cell_size; 127 128 /* calculate closest source points in shading table and 129 make sure they fall within the table */ 130 src_y0 = ty / (int)in_cell_size; 131 if (in_cell_size < out_cell_size) 132 src_y1 = (ty + out_cell_size) / in_cell_size; 133 else 134 src_y1 = src_y0 + 1; 135 src_y0 = clamp(src_y0, 0, (int)table_height - 1); 136 src_y1 = clamp(src_y1, 0, (int)table_height - 1); 137 ty = min(clamp(ty, 0, (int)sensor_height - 1), 138 (int)table_cell_h); 139 140 /* calculate closest source points for distance computation */ 141 sy0 = min(src_y0 * in_cell_size, sensor_height - 1); 142 sy1 = min(src_y1 * in_cell_size, sensor_height - 1); 143 /* calculate distance between source and target pixels */ 144 dy0 = ty - sy0; 145 dy1 = sy1 - ty; 146 divy = sy1 - sy0; 147 if (divy == 0) { 148 dy0 = 1; 149 divy = 1; 150 } 151 152 for (j = 0; j < out_table->width; j++, out_ptr++) { 153 int tx, src_x0, src_x1; 154 unsigned int sx0, sx1, dx0, dx1, divx; 155 unsigned short s_ul, s_ur, s_ll, s_lr; 156 157 /* calculate target point */ 158 tx = out_start_col + j * out_cell_size; 159 /* calculate closest source points. */ 160 src_x0 = tx / (int)in_cell_size; 161 if (in_cell_size < out_cell_size) { 162 src_x1 = (tx + out_cell_size) / 163 (int)in_cell_size; 164 } else { 165 src_x1 = src_x0 + 1; 166 } 167 /* if src points fall in padding, select closest ones.*/ 168 src_x0 = clamp(src_x0, 0, (int)table_width - 1); 169 src_x1 = clamp(src_x1, 0, (int)table_width - 1); 170 tx = min(clamp(tx, 0, (int)sensor_width - 1), 171 (int)table_cell_w); 172 /* 173 * calculate closest source points for distance 174 * computation 175 */ 176 sx0 = min(src_x0 * in_cell_size, sensor_width - 1); 177 sx1 = min(src_x1 * in_cell_size, sensor_width - 1); 178 /* 179 * calculate distances between source and target 180 * pixels 181 */ 182 dx0 = tx - sx0; 183 dx1 = sx1 - tx; 184 divx = sx1 - sx0; 185 /* if we're at the edge, we just use the closest 186 * point still in the grid. We make up for the divider 187 * in this case by setting the distance to 188 * out_cell_size, since it's actually 0. 189 */ 190 if (divx == 0) { 191 dx0 = 1; 192 divx = 1; 193 } 194 195 /* get source pixel values */ 196 s_ul = in_ptr[(table_width * src_y0) + src_x0]; 197 s_ur = in_ptr[(table_width * src_y0) + src_x1]; 198 s_ll = in_ptr[(table_width * src_y1) + src_x0]; 199 s_lr = in_ptr[(table_width * src_y1) + src_x1]; 200 201 *out_ptr = (unsigned short)((dx0 * dy0 * s_lr + dx0 * dy1 * s_ur + dx1 * dy0 * 202 s_ll + dx1 * dy1 * s_ul) / 203 (divx * divy)); 204 } 205 } 206 } 207 208 void 209 sh_css_params_shading_id_table_generate( 210 struct ia_css_shading_table **target_table, 211 unsigned int table_width, 212 unsigned int table_height) 213 { 214 /* initialize table with ones, shift becomes zero */ 215 unsigned int i, j; 216 struct ia_css_shading_table *result; 217 218 assert(target_table); 219 220 result = ia_css_shading_table_alloc(table_width, table_height); 221 if (!result) { 222 *target_table = NULL; 223 return; 224 } 225 226 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 227 for (j = 0; j < table_height * table_width; j++) 228 result->data[i][j] = 1; 229 } 230 result->fraction_bits = 0; 231 *target_table = result; 232 } 233 234 void 235 prepare_shading_table(const struct ia_css_shading_table *in_table, 236 unsigned int sensor_binning, 237 struct ia_css_shading_table **target_table, 238 const struct ia_css_binary *binary, 239 unsigned int bds_factor) 240 { 241 unsigned int input_width, input_height, table_width, table_height, i; 242 unsigned int left_padding, top_padding, left_cropping; 243 struct ia_css_shading_table *result; 244 struct u32_fract bds; 245 int right_padding; 246 247 assert(target_table); 248 assert(binary); 249 250 if (!in_table) { 251 sh_css_params_shading_id_table_generate(target_table, 252 binary->sctbl_width_per_color, 253 binary->sctbl_height); 254 return; 255 } 256 257 /* 258 * We use the ISP input resolution for the shading table because 259 * shading correction is performed in the bayer domain (before bayer 260 * down scaling). 261 */ 262 input_height = binary->in_frame_info.res.height; 263 input_width = binary->in_frame_info.res.width; 264 left_padding = binary->left_padding; 265 left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ? 266 binary->dvs_envelope.width : 2 * ISP_VEC_NELEMS; 267 268 sh_css_bds_factor_get_fract(bds_factor, &bds); 269 270 left_padding = (left_padding + binary->info->sp.pipeline.left_cropping) * 271 bds.numerator / bds.denominator - 272 binary->info->sp.pipeline.left_cropping; 273 right_padding = (binary->internal_frame_info.res.width - 274 binary->effective_in_frame_res.width * bds.denominator / 275 bds.numerator - left_cropping) * bds.numerator / bds.denominator; 276 top_padding = binary->info->sp.pipeline.top_cropping * bds.numerator / 277 bds.denominator - 278 binary->info->sp.pipeline.top_cropping; 279 280 /* 281 * We take into account the binning done by the sensor. We do this 282 * by cropping the non-binned part of the shading table and then 283 * increasing the size of a grid cell with this same binning factor. 284 */ 285 input_width <<= sensor_binning; 286 input_height <<= sensor_binning; 287 /* 288 * We also scale the padding by the same binning factor. This will 289 * make it much easier later on to calculate the padding of the 290 * shading table. 291 */ 292 left_padding <<= sensor_binning; 293 right_padding <<= sensor_binning; 294 top_padding <<= sensor_binning; 295 296 /* 297 * during simulation, the used resolution can exceed the sensor 298 * resolution, so we clip it. 299 */ 300 input_width = min(input_width, in_table->sensor_width); 301 input_height = min(input_height, in_table->sensor_height); 302 303 /* This prepare_shading_table() function is called only in legacy API (not in new API). 304 Then, the legacy shading table width and height should be used. */ 305 table_width = binary->sctbl_width_per_color; 306 table_height = binary->sctbl_height; 307 308 result = ia_css_shading_table_alloc(table_width, table_height); 309 if (!result) { 310 *target_table = NULL; 311 return; 312 } 313 result->sensor_width = in_table->sensor_width; 314 result->sensor_height = in_table->sensor_height; 315 result->fraction_bits = in_table->fraction_bits; 316 317 /* 318 * now we crop the original shading table and then interpolate to the 319 * requested resolution and decimation factor. 320 */ 321 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 322 crop_and_interpolate(input_width, input_height, 323 left_padding, right_padding, top_padding, 324 in_table, 325 result, i); 326 } 327 *target_table = result; 328 } 329 330 struct ia_css_shading_table * 331 ia_css_shading_table_alloc( 332 unsigned int width, 333 unsigned int height) 334 { 335 unsigned int i; 336 struct ia_css_shading_table *me; 337 338 IA_CSS_ENTER(""); 339 340 me = kmalloc(sizeof(*me), GFP_KERNEL); 341 if (!me) 342 return me; 343 344 me->width = width; 345 me->height = height; 346 me->sensor_width = 0; 347 me->sensor_height = 0; 348 me->fraction_bits = 0; 349 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 350 me->data[i] = 351 kvmalloc(width * height * sizeof(*me->data[0]), 352 GFP_KERNEL); 353 if (!me->data[i]) { 354 unsigned int j; 355 356 for (j = 0; j < i; j++) { 357 kvfree(me->data[j]); 358 me->data[j] = NULL; 359 } 360 kfree(me); 361 return NULL; 362 } 363 } 364 365 IA_CSS_LEAVE(""); 366 return me; 367 } 368 369 void 370 ia_css_shading_table_free(struct ia_css_shading_table *table) 371 { 372 unsigned int i; 373 374 if (!table) 375 return; 376 377 /* 378 * We only output logging when the table is not NULL, otherwise 379 * logs will give the impression that a table was freed. 380 */ 381 IA_CSS_ENTER(""); 382 383 for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { 384 if (table->data[i]) { 385 kvfree(table->data[i]); 386 table->data[i] = NULL; 387 } 388 } 389 kfree(table); 390 391 IA_CSS_LEAVE(""); 392 } 393