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 		/* calculate target point and make sure it falls within
122 		   the table */
123 		ty = out_start_row + i * out_cell_size;
124 
125 		/* calculate closest source points in shading table and
126 		   make sure they fall within the table */
127 		src_y0 = ty / (int)in_cell_size;
128 		if (in_cell_size < out_cell_size)
129 			src_y1 = (ty + out_cell_size) / in_cell_size;
130 		else
131 			src_y1 = src_y0 + 1;
132 		src_y0 = clamp(src_y0, 0, (int)table_height - 1);
133 		src_y1 = clamp(src_y1, 0, (int)table_height - 1);
134 		ty = min(clamp(ty, 0, (int)sensor_height - 1),
135 			 (int)table_cell_h);
136 
137 		/* calculate closest source points for distance computation */
138 		sy0 = min(src_y0 * in_cell_size, sensor_height - 1);
139 		sy1 = min(src_y1 * in_cell_size, sensor_height - 1);
140 		/* calculate distance between source and target pixels */
141 		dy0 = ty - sy0;
142 		dy1 = sy1 - ty;
143 		divy = sy1 - sy0;
144 		if (divy == 0) {
145 			dy0 = 1;
146 			divy = 1;
147 		}
148 
149 		for (j = 0; j < out_table->width; j++, out_ptr++) {
150 			int tx, src_x0, src_x1;
151 			unsigned int sx0, sx1, dx0, dx1, divx;
152 			unsigned short s_ul, s_ur, s_ll, s_lr;
153 
154 			/* calculate target point */
155 			tx = out_start_col + j * out_cell_size;
156 			/* calculate closest source points. */
157 			src_x0 = tx / (int)in_cell_size;
158 			if (in_cell_size < out_cell_size) {
159 				src_x1 = (tx + out_cell_size) /
160 					 (int)in_cell_size;
161 			} else {
162 				src_x1 = src_x0 + 1;
163 			}
164 			/* if src points fall in padding, select closest ones.*/
165 			src_x0 = clamp(src_x0, 0, (int)table_width - 1);
166 			src_x1 = clamp(src_x1, 0, (int)table_width - 1);
167 			tx = min(clamp(tx, 0, (int)sensor_width - 1),
168 				 (int)table_cell_w);
169 			/* calculate closest source points for distance
170 			   computation */
171 			sx0 = min(src_x0 * in_cell_size, sensor_width - 1);
172 			sx1 = min(src_x1 * in_cell_size, sensor_width - 1);
173 			/* calculate distances between source and target
174 			   pixels */
175 			dx0 = tx - sx0;
176 			dx1 = sx1 - tx;
177 			divx = sx1 - sx0;
178 			/* if we're at the edge, we just use the closest
179 			   point still in the grid. We make up for the divider
180 			   in this case by setting the distance to
181 			   out_cell_size, since it's actually 0. */
182 			if (divx == 0) {
183 				dx0 = 1;
184 				divx = 1;
185 			}
186 
187 			/* get source pixel values */
188 			s_ul = in_ptr[(table_width * src_y0) + src_x0];
189 			s_ur = in_ptr[(table_width * src_y0) + src_x1];
190 			s_ll = in_ptr[(table_width * src_y1) + src_x0];
191 			s_lr = in_ptr[(table_width * src_y1) + src_x1];
192 
193 			*out_ptr = (unsigned short)((dx0 * dy0 * s_lr + dx0 * dy1 * s_ur + dx1 * dy0 *
194 						     s_ll + dx1 * dy1 * s_ul) /
195 						    (divx * divy));
196 		}
197 	}
198 }
199 
200 void
201 sh_css_params_shading_id_table_generate(
202     struct ia_css_shading_table **target_table,
203     unsigned int table_width,
204     unsigned int table_height)
205 {
206 	/* initialize table with ones, shift becomes zero */
207 	unsigned int i, j;
208 	struct ia_css_shading_table *result;
209 
210 	assert(target_table);
211 
212 	result = ia_css_shading_table_alloc(table_width, table_height);
213 	if (!result) {
214 		*target_table = NULL;
215 		return;
216 	}
217 
218 	for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
219 		for (j = 0; j < table_height * table_width; j++)
220 			result->data[i][j] = 1;
221 	}
222 	result->fraction_bits = 0;
223 	*target_table = result;
224 }
225 
226 void
227 prepare_shading_table(const struct ia_css_shading_table *in_table,
228 		      unsigned int sensor_binning,
229 		      struct ia_css_shading_table **target_table,
230 		      const struct ia_css_binary *binary,
231 		      unsigned int bds_factor)
232 {
233 	unsigned int input_width,
234 		 input_height,
235 		 table_width,
236 		 table_height,
237 		 left_padding,
238 		 top_padding,
239 		 padded_width,
240 		 left_cropping,
241 		 i;
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_legacy_width_per_color,
253 							binary->sctbl_legacy_height);
254 		return;
255 	}
256 
257 	padded_width = binary->in_frame_info.padded_width;
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 #if defined(USE_INPUT_SYSTEM_VERSION_2401)
262 	padded_width = CEIL_MUL(binary->effective_in_frame_res.width + 2 *
263 				ISP_VEC_NELEMS,
264 				2 * ISP_VEC_NELEMS);
265 #endif
266 	input_height  = binary->in_frame_info.res.height;
267 	input_width   = binary->in_frame_info.res.width;
268 	left_padding  = binary->left_padding;
269 	left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ?
270 			binary->dvs_envelope.width : 2 * ISP_VEC_NELEMS;
271 
272 	sh_css_bds_factor_get_numerator_denominator
273 	(bds_factor, &bds_numerator, &bds_denominator);
274 
275 	left_padding  = (left_padding + binary->info->sp.pipeline.left_cropping) *
276 			bds_numerator / bds_denominator -
277 			binary->info->sp.pipeline.left_cropping;
278 	right_padding = (binary->internal_frame_info.res.width -
279 			 binary->effective_in_frame_res.width * bds_denominator /
280 			 bds_numerator - left_cropping) * bds_numerator / bds_denominator;
281 	top_padding = binary->info->sp.pipeline.top_cropping * bds_numerator /
282 		      bds_denominator -
283 		      binary->info->sp.pipeline.top_cropping;
284 
285 #if !defined(USE_WINDOWS_BINNING_FACTOR)
286 	/* @deprecated{This part of the code will be replaced by the code
287 	 * in the #else section below to make the calculation same across
288 	 * all platforms.
289 	 * Android and Windows platforms interpret the binning_factor parameter
290 	 * differently. In Android, the binning factor is expressed in the form
291 	 * 2^N * 2^N, whereas in Windows platform, the binning factor is N*N}
292 	 */
293 
294 	/* We take into account the binning done by the sensor. We do this
295 	   by cropping the non-binned part of the shading table and then
296 	   increasing the size of a grid cell with this same binning factor. */
297 	input_width  <<= sensor_binning;
298 	input_height <<= sensor_binning;
299 	/* We also scale the padding by the same binning factor. This will
300 	   make it much easier later on to calculate the padding of the
301 	   shading table. */
302 	left_padding  <<= sensor_binning;
303 	right_padding <<= sensor_binning;
304 	top_padding   <<= sensor_binning;
305 #else
306 	input_width   *= sensor_binning;
307 	input_height  *= sensor_binning;
308 	left_padding  *= sensor_binning;
309 	right_padding *= sensor_binning;
310 	top_padding   *= sensor_binning;
311 #endif /*USE_WINDOWS_BINNING_FACTOR*/
312 
313 	/* during simulation, the used resolution can exceed the sensor
314 	   resolution, so we clip it. */
315 	input_width  = min(input_width,  in_table->sensor_width);
316 	input_height = min(input_height, in_table->sensor_height);
317 
318 	/* This prepare_shading_table() function is called only in legacy API (not in new API).
319 	   Then, the legacy shading table width and height should be used. */
320 	table_width  = binary->sctbl_legacy_width_per_color;
321 	table_height = binary->sctbl_legacy_height;
322 
323 	result = ia_css_shading_table_alloc(table_width, table_height);
324 	if (!result) {
325 		*target_table = NULL;
326 		return;
327 	}
328 	result->sensor_width  = in_table->sensor_width;
329 	result->sensor_height = in_table->sensor_height;
330 	result->fraction_bits = in_table->fraction_bits;
331 
332 	/* now we crop the original shading table and then interpolate to the
333 	   requested resolution and decimation factor. */
334 	for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
335 		crop_and_interpolate(input_width, input_height,
336 				     left_padding, right_padding, top_padding,
337 				     in_table,
338 				     result, i);
339 	}
340 	*target_table = result;
341 }
342 
343 struct ia_css_shading_table *
344 ia_css_shading_table_alloc(
345     unsigned int width,
346     unsigned int height)
347 {
348 	unsigned int i;
349 	struct ia_css_shading_table *me;
350 
351 	IA_CSS_ENTER("");
352 
353 	me = kmalloc(sizeof(*me), GFP_KERNEL);
354 	if (!me)
355 		return me;
356 
357 	me->width         = width;
358 	me->height        = height;
359 	me->sensor_width  = 0;
360 	me->sensor_height = 0;
361 	me->fraction_bits = 0;
362 	for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
363 		me->data[i] =
364 		    kvmalloc(width * height * sizeof(*me->data[0]),
365 			     GFP_KERNEL);
366 		if (!me->data[i]) {
367 			unsigned int j;
368 
369 			for (j = 0; j < i; j++) {
370 				kvfree(me->data[j]);
371 				me->data[j] = NULL;
372 			}
373 			kfree(me);
374 			return NULL;
375 		}
376 	}
377 
378 	IA_CSS_LEAVE("");
379 	return me;
380 }
381 
382 void
383 ia_css_shading_table_free(struct ia_css_shading_table *table)
384 {
385 	unsigned int i;
386 
387 	if (!table)
388 		return;
389 
390 	/* We only output logging when the table is not NULL, otherwise
391 	 * logs will give the impression that a table was freed.
392 	 * */
393 	IA_CSS_ENTER("");
394 
395 	for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) {
396 		if (table->data[i]) {
397 			kvfree(table->data[i]);
398 			table->data[i] = NULL;
399 		}
400 	}
401 	kfree(table);
402 
403 	IA_CSS_LEAVE("");
404 }
405