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