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