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