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