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
crop_and_interpolate(unsigned int cropped_width,unsigned int cropped_height,unsigned int left_padding,int right_padding,int top_padding,const struct ia_css_shading_table * in_table,struct ia_css_shading_table * out_table,enum ia_css_sc_color color)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
sh_css_params_shading_id_table_generate(struct ia_css_shading_table ** target_table,unsigned int table_width,unsigned int table_height)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
prepare_shading_table(const struct ia_css_shading_table * in_table,unsigned int sensor_binning,struct ia_css_shading_table ** target_table,const struct ia_css_binary * binary,unsigned int bds_factor)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 *
ia_css_shading_table_alloc(unsigned int width,unsigned int height)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
ia_css_shading_table_free(struct ia_css_shading_table * table)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