1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2010 - 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 "system_global.h"
17 #include <linux/kernel.h>
18 
19 
20 #include "ia_css_ifmtr.h"
21 #include <math_support.h>
22 #include "sh_css_internal.h"
23 #include "input_formatter.h"
24 #include "assert_support.h"
25 #include "sh_css_sp.h"
26 #include "isp/modes/interface/input_buf.isp.h"
27 
28 /************************************************************
29  * Static functions declarations
30  ************************************************************/
31 static int ifmtr_start_column(
32     const struct ia_css_stream_config *config,
33     unsigned int bin_in,
34     unsigned int *start_column);
35 
36 static int ifmtr_input_start_line(
37     const struct ia_css_stream_config *config,
38     unsigned int bin_in,
39     unsigned int *start_line);
40 
41 static void ifmtr_set_if_blocking_mode(
42     const input_formatter_cfg_t *const config_a,
43     const input_formatter_cfg_t *const config_b);
44 
45 /************************************************************
46  * Public functions
47  ************************************************************/
48 
49 /* ISP expects GRBG bayer order, we skip one line and/or one row
50  * to correct in case the input bayer order is different.
51  */
ia_css_ifmtr_lines_needed_for_bayer_order(const struct ia_css_stream_config * config)52 unsigned int ia_css_ifmtr_lines_needed_for_bayer_order(
53     const struct ia_css_stream_config *config)
54 {
55 	assert(config);
56 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR)
57 	    || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
58 		return 1;
59 
60 	return 0;
61 }
62 
ia_css_ifmtr_columns_needed_for_bayer_order(const struct ia_css_stream_config * config)63 unsigned int ia_css_ifmtr_columns_needed_for_bayer_order(
64     const struct ia_css_stream_config *config)
65 {
66 	assert(config);
67 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB)
68 	    || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
69 		return 1;
70 
71 	return 0;
72 }
73 
ia_css_ifmtr_configure(struct ia_css_stream_config * config,struct ia_css_binary * binary)74 int ia_css_ifmtr_configure(struct ia_css_stream_config *config,
75 				       struct ia_css_binary *binary)
76 {
77 	unsigned int start_line, start_column = 0,
78 				 cropped_height,
79 				 cropped_width,
80 				 num_vectors,
81 				 buffer_height = 2,
82 				 buffer_width,
83 				 two_ppc,
84 				 vmem_increment = 0,
85 				 deinterleaving = 0,
86 				 deinterleaving_b = 0,
87 				 width_a = 0,
88 				 width_b = 0,
89 				 bits_per_pixel,
90 				 vectors_per_buffer,
91 				 vectors_per_line = 0,
92 				 buffers_per_line = 0,
93 				 buf_offset_a = 0,
94 				 buf_offset_b = 0,
95 				 line_width = 0,
96 				 width_b_factor = 1, start_column_b,
97 				 left_padding = 0;
98 	input_formatter_cfg_t if_a_config, if_b_config;
99 	enum atomisp_input_format input_format;
100 	int err = 0;
101 	u8 if_config_index;
102 
103 	/* Determine which input formatter config set is targeted. */
104 	/* Index is equal to the CSI-2 port used. */
105 	enum mipi_port_id port;
106 
107 	if (binary) {
108 		cropped_height = binary->in_frame_info.res.height;
109 		cropped_width = binary->in_frame_info.res.width;
110 		/* This should correspond to the input buffer definition for
111 		ISP binaries in input_buf.isp.h */
112 		if (binary->info->sp.enable.continuous &&
113 		    binary->info->sp.pipeline.mode != IA_CSS_BINARY_MODE_COPY)
114 			buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
115 		else
116 			buffer_width = binary->info->sp.input.max_width;
117 		input_format = binary->input_format;
118 	} else {
119 		/* sp raw copy pipe (IA_CSS_PIPE_MODE_COPY): binary is NULL */
120 		cropped_height = config->input_config.input_res.height;
121 		cropped_width = config->input_config.input_res.width;
122 		buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
123 		input_format = config->input_config.format;
124 	}
125 	two_ppc = config->pixels_per_clock == 2;
126 	if (config->mode == IA_CSS_INPUT_MODE_SENSOR
127 	    || config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
128 		port = config->source.port.port;
129 		if_config_index = (uint8_t)(port - MIPI_PORT0_ID);
130 	} else if (config->mode == IA_CSS_INPUT_MODE_MEMORY) {
131 		if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED;
132 	} else {
133 		if_config_index = 0;
134 	}
135 
136 	assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS
137 	       || if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED);
138 
139 	/* TODO: check to see if input is RAW and if current mode interprets
140 	 * RAW data in any particular bayer order. copy binary with output
141 	 * format other than raw should not result in dropping lines and/or
142 	 * columns.
143 	 */
144 	err = ifmtr_input_start_line(config, cropped_height, &start_line);
145 	if (err)
146 		return err;
147 	err = ifmtr_start_column(config, cropped_width, &start_column);
148 	if (err)
149 		return err;
150 
151 	if (config->left_padding == -1)
152 		if (!binary)
153 			/* sp raw copy pipe: set left_padding value */
154 			left_padding = 0;
155 		else
156 			left_padding = binary->left_padding;
157 	else
158 		left_padding = 2 * ISP_VEC_NELEMS - config->left_padding;
159 
160 	if (left_padding) {
161 		num_vectors = CEIL_DIV(cropped_width + left_padding,
162 				       ISP_VEC_NELEMS);
163 	} else {
164 		num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
165 		num_vectors *= buffer_height;
166 		/* todo: in case of left padding,
167 		   num_vectors is vectors per line,
168 		   otherwise vectors per line * buffer_height. */
169 	}
170 
171 	start_column_b = start_column;
172 
173 	bits_per_pixel = input_formatter_get_alignment(INPUT_FORMATTER0_ID)
174 			 * 8 / ISP_VEC_NELEMS;
175 	switch (input_format) {
176 	case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
177 		if (two_ppc) {
178 			vmem_increment = 1;
179 			deinterleaving = 1;
180 			deinterleaving_b = 1;
181 			/* half lines */
182 			width_a = cropped_width * deinterleaving / 2;
183 			width_b_factor = 2;
184 			/* full lines */
185 			width_b = width_a * width_b_factor;
186 			buffer_width *= deinterleaving * 2;
187 			/* Patch from bayer to yuv */
188 			num_vectors *= deinterleaving;
189 			buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
190 			vectors_per_line = num_vectors / buffer_height;
191 			/* Even lines are half size */
192 			line_width = vectors_per_line *
193 				     input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
194 				     2;
195 			start_column /= 2;
196 		} else {
197 			vmem_increment = 1;
198 			deinterleaving = 3;
199 			width_a = cropped_width * deinterleaving / 2;
200 			buffer_width = buffer_width * deinterleaving / 2;
201 			/* Patch from bayer to yuv */
202 			num_vectors = num_vectors / 2 * deinterleaving;
203 			start_column = start_column * deinterleaving / 2;
204 		}
205 		break;
206 	case ATOMISP_INPUT_FORMAT_YUV420_8:
207 	case ATOMISP_INPUT_FORMAT_YUV420_10:
208 	case ATOMISP_INPUT_FORMAT_YUV420_16:
209 		if (two_ppc) {
210 			vmem_increment = 1;
211 			deinterleaving = 1;
212 			width_a = width_b = cropped_width * deinterleaving / 2;
213 			buffer_width *= deinterleaving * 2;
214 			num_vectors *= deinterleaving;
215 			buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
216 			vectors_per_line = num_vectors / buffer_height;
217 			/* Even lines are half size */
218 			line_width = vectors_per_line *
219 				     input_formatter_get_alignment(INPUT_FORMATTER0_ID) /
220 				     2;
221 			start_column *= deinterleaving;
222 			start_column /= 2;
223 			start_column_b = start_column;
224 		} else {
225 			vmem_increment = 1;
226 			deinterleaving = 1;
227 			width_a = cropped_width * deinterleaving;
228 			buffer_width *= deinterleaving * 2;
229 			num_vectors *= deinterleaving;
230 			start_column *= deinterleaving;
231 		}
232 		break;
233 	case ATOMISP_INPUT_FORMAT_YUV422_8:
234 	case ATOMISP_INPUT_FORMAT_YUV422_10:
235 	case ATOMISP_INPUT_FORMAT_YUV422_16:
236 		if (two_ppc) {
237 			vmem_increment = 1;
238 			deinterleaving = 1;
239 			width_a = width_b = cropped_width * deinterleaving;
240 			buffer_width *= deinterleaving * 2;
241 			num_vectors *= deinterleaving;
242 			start_column *= deinterleaving;
243 			buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
244 			start_column_b = start_column;
245 		} else {
246 			vmem_increment = 1;
247 			deinterleaving = 2;
248 			width_a = cropped_width * deinterleaving;
249 			buffer_width *= deinterleaving;
250 			num_vectors *= deinterleaving;
251 			start_column *= deinterleaving;
252 		}
253 		break;
254 	case ATOMISP_INPUT_FORMAT_RGB_444:
255 	case ATOMISP_INPUT_FORMAT_RGB_555:
256 	case ATOMISP_INPUT_FORMAT_RGB_565:
257 	case ATOMISP_INPUT_FORMAT_RGB_666:
258 	case ATOMISP_INPUT_FORMAT_RGB_888:
259 		num_vectors *= 2;
260 		if (two_ppc) {
261 			deinterleaving = 2;	/* BR in if_a, G in if_b */
262 			deinterleaving_b = 1;	/* BR in if_a, G in if_b */
263 			buffers_per_line = 4;
264 			start_column_b = start_column;
265 			start_column *= deinterleaving;
266 			start_column_b *= deinterleaving_b;
267 		} else {
268 			deinterleaving = 3;	/* BGR */
269 			buffers_per_line = 3;
270 			start_column *= deinterleaving;
271 		}
272 		vmem_increment = 1;
273 		width_a = cropped_width * deinterleaving;
274 		width_b = cropped_width * deinterleaving_b;
275 		buffer_width *= buffers_per_line;
276 		/* Patch from bayer to rgb */
277 		num_vectors = num_vectors / 2 * deinterleaving;
278 		buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS;
279 		break;
280 	case ATOMISP_INPUT_FORMAT_RAW_6:
281 	case ATOMISP_INPUT_FORMAT_RAW_7:
282 	case ATOMISP_INPUT_FORMAT_RAW_8:
283 	case ATOMISP_INPUT_FORMAT_RAW_10:
284 	case ATOMISP_INPUT_FORMAT_RAW_12:
285 		if (two_ppc) {
286 			int crop_col = (start_column % 2) == 1;
287 
288 			vmem_increment = 2;
289 			deinterleaving = 1;
290 			width_a = width_b = cropped_width / 2;
291 
292 			/* When two_ppc is enabled AND we need to crop one extra
293 			 * column, if_a crops by one extra and we swap the
294 			 * output offsets to interleave the bayer pattern in
295 			 * the correct order.
296 			 */
297 			buf_offset_a   = crop_col ? 1 : 0;
298 			buf_offset_b   = crop_col ? 0 : 1;
299 			start_column_b = start_column / 2;
300 			start_column   = start_column / 2 + crop_col;
301 		} else {
302 			vmem_increment = 1;
303 			deinterleaving = 2;
304 			if ((!binary) || (config->continuous && binary
305 					  && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)) {
306 				/* !binary -> sp raw copy pipe, no deinterleaving */
307 				deinterleaving = 1;
308 			}
309 			width_a = cropped_width;
310 			/* Must be multiple of deinterleaving */
311 			num_vectors = CEIL_MUL(num_vectors, deinterleaving);
312 		}
313 		buffer_height *= 2;
314 		if ((!binary) || config->continuous)
315 			/* !binary -> sp raw copy pipe */
316 			buffer_height *= 2;
317 		vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS);
318 		vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving);
319 		break;
320 	case ATOMISP_INPUT_FORMAT_RAW_14:
321 	case ATOMISP_INPUT_FORMAT_RAW_16:
322 		if (two_ppc) {
323 			num_vectors *= 2;
324 			vmem_increment = 1;
325 			deinterleaving = 2;
326 			width_a = width_b = cropped_width;
327 			/* B buffer is one line further */
328 			buf_offset_b = buffer_width / ISP_VEC_NELEMS;
329 			bits_per_pixel *= 2;
330 		} else {
331 			vmem_increment = 1;
332 			deinterleaving = 2;
333 			width_a = cropped_width;
334 			start_column /= deinterleaving;
335 		}
336 		buffer_height *= 2;
337 		break;
338 	case ATOMISP_INPUT_FORMAT_BINARY_8:
339 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT1:
340 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT2:
341 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT3:
342 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT4:
343 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT5:
344 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT6:
345 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT7:
346 	case ATOMISP_INPUT_FORMAT_GENERIC_SHORT8:
347 	case ATOMISP_INPUT_FORMAT_YUV420_8_SHIFT:
348 	case ATOMISP_INPUT_FORMAT_YUV420_10_SHIFT:
349 	case ATOMISP_INPUT_FORMAT_EMBEDDED:
350 	case ATOMISP_INPUT_FORMAT_USER_DEF1:
351 	case ATOMISP_INPUT_FORMAT_USER_DEF2:
352 	case ATOMISP_INPUT_FORMAT_USER_DEF3:
353 	case ATOMISP_INPUT_FORMAT_USER_DEF4:
354 	case ATOMISP_INPUT_FORMAT_USER_DEF5:
355 	case ATOMISP_INPUT_FORMAT_USER_DEF6:
356 	case ATOMISP_INPUT_FORMAT_USER_DEF7:
357 	case ATOMISP_INPUT_FORMAT_USER_DEF8:
358 		break;
359 	}
360 	if (width_a == 0)
361 		return -EINVAL;
362 
363 	if (two_ppc)
364 		left_padding /= 2;
365 
366 	/* Default values */
367 	if (left_padding)
368 		vectors_per_line = num_vectors;
369 	if (!vectors_per_line) {
370 		vectors_per_line = CEIL_MUL(num_vectors / buffer_height,
371 					    deinterleaving);
372 		line_width = 0;
373 	}
374 	if (!line_width)
375 		line_width = vectors_per_line *
376 			     input_formatter_get_alignment(INPUT_FORMATTER0_ID);
377 	if (!buffers_per_line)
378 		buffers_per_line = deinterleaving;
379 	line_width = CEIL_MUL(line_width,
380 			      input_formatter_get_alignment(INPUT_FORMATTER0_ID)
381 			      * vmem_increment);
382 
383 	vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS;
384 
385 	if_a_config.start_line = start_line;
386 	if_a_config.start_column = start_column;
387 	if_a_config.left_padding = left_padding / deinterleaving;
388 	if_a_config.cropped_height = cropped_height;
389 	if_a_config.cropped_width = width_a;
390 	if_a_config.deinterleaving = deinterleaving;
391 	if_a_config.buf_vecs = vectors_per_buffer;
392 	if_a_config.buf_start_index = buf_offset_a;
393 	if_a_config.buf_increment = vmem_increment;
394 	if_a_config.buf_eol_offset =
395 	    buffer_width * bits_per_pixel / 8 - line_width;
396 	if_a_config.is_yuv420_format =
397 	    (input_format == ATOMISP_INPUT_FORMAT_YUV420_8)
398 	    || (input_format == ATOMISP_INPUT_FORMAT_YUV420_10)
399 	    || (input_format == ATOMISP_INPUT_FORMAT_YUV420_16);
400 	if_a_config.block_no_reqs = (config->mode != IA_CSS_INPUT_MODE_SENSOR);
401 
402 	if (two_ppc) {
403 		if (deinterleaving_b) {
404 			deinterleaving = deinterleaving_b;
405 			width_b = cropped_width * deinterleaving;
406 			buffer_width *= deinterleaving;
407 			/* Patch from bayer to rgb */
408 			num_vectors = num_vectors / 2 *
409 				      deinterleaving * width_b_factor;
410 			vectors_per_line = num_vectors / buffer_height;
411 			line_width = vectors_per_line *
412 				     input_formatter_get_alignment(INPUT_FORMATTER0_ID);
413 		}
414 		if_b_config.start_line = start_line;
415 		if_b_config.start_column = start_column_b;
416 		if_b_config.left_padding = left_padding / deinterleaving;
417 		if_b_config.cropped_height = cropped_height;
418 		if_b_config.cropped_width = width_b;
419 		if_b_config.deinterleaving = deinterleaving;
420 		if_b_config.buf_vecs = vectors_per_buffer;
421 		if_b_config.buf_start_index = buf_offset_b;
422 		if_b_config.buf_increment = vmem_increment;
423 		if_b_config.buf_eol_offset =
424 		    buffer_width * bits_per_pixel / 8 - line_width;
425 		if_b_config.is_yuv420_format =
426 		    input_format == ATOMISP_INPUT_FORMAT_YUV420_8
427 		    || input_format == ATOMISP_INPUT_FORMAT_YUV420_10
428 		    || input_format == ATOMISP_INPUT_FORMAT_YUV420_16;
429 		if_b_config.block_no_reqs =
430 		    (config->mode != IA_CSS_INPUT_MODE_SENSOR);
431 
432 		if (if_config_index != SH_CSS_IF_CONFIG_NOT_NEEDED) {
433 			assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
434 
435 			ifmtr_set_if_blocking_mode(&if_a_config, &if_b_config);
436 			/* Set the ifconfigs to SP group */
437 			sh_css_sp_set_if_configs(&if_a_config, &if_b_config,
438 						 if_config_index);
439 		}
440 	} else {
441 		if (if_config_index != SH_CSS_IF_CONFIG_NOT_NEEDED) {
442 			assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS);
443 
444 			ifmtr_set_if_blocking_mode(&if_a_config, NULL);
445 			/* Set the ifconfigs to SP group */
446 			sh_css_sp_set_if_configs(&if_a_config, NULL,
447 						 if_config_index);
448 		}
449 	}
450 
451 	return 0;
452 }
453 
454 bool ifmtr_set_if_blocking_mode_reset = true;
455 
456 /************************************************************
457  * Static functions
458  ************************************************************/
ifmtr_set_if_blocking_mode(const input_formatter_cfg_t * const config_a,const input_formatter_cfg_t * const config_b)459 static void ifmtr_set_if_blocking_mode(
460     const input_formatter_cfg_t *const config_a,
461     const input_formatter_cfg_t *const config_b)
462 {
463 	int i;
464 	bool block[] = { false, false, false, false };
465 
466 	assert(N_INPUT_FORMATTER_ID <= (ARRAY_SIZE(block)));
467 
468 	block[INPUT_FORMATTER0_ID] = (bool)config_a->block_no_reqs;
469 	if (config_b)
470 		block[INPUT_FORMATTER1_ID] = (bool)config_b->block_no_reqs;
471 
472 	/* TODO: next could cause issues when streams are started after
473 	 * eachother. */
474 	/*IF should not be reconfigured/reset from host */
475 	if (ifmtr_set_if_blocking_mode_reset) {
476 		ifmtr_set_if_blocking_mode_reset = false;
477 		for (i = 0; i < N_INPUT_FORMATTER_ID; i++) {
478 			input_formatter_ID_t id = (input_formatter_ID_t)i;
479 
480 			input_formatter_rst(id);
481 			input_formatter_set_fifo_blocking_mode(id, block[id]);
482 		}
483 	}
484 
485 	return;
486 }
487 
ifmtr_start_column(const struct ia_css_stream_config * config,unsigned int bin_in,unsigned int * start_column)488 static int ifmtr_start_column(
489     const struct ia_css_stream_config *config,
490     unsigned int bin_in,
491     unsigned int *start_column)
492 {
493 	unsigned int in = config->input_config.input_res.width, start,
494 		     for_bayer = ia_css_ifmtr_columns_needed_for_bayer_order(config);
495 
496 	if (bin_in + 2 * for_bayer > in)
497 		return -EINVAL;
498 
499 	/* On the hardware, we want to use the middle of the input, so we
500 	 * divide the start column by 2. */
501 	start = (in - bin_in) / 2;
502 	/* in case the number of extra columns is 2 or odd, we round the start
503 	 * column down */
504 	start &= ~0x1;
505 
506 	/* now we add the one column (if needed) to correct for the bayer
507 	 * order).
508 	 */
509 	start += for_bayer;
510 	*start_column = start;
511 	return 0;
512 }
513 
ifmtr_input_start_line(const struct ia_css_stream_config * config,unsigned int bin_in,unsigned int * start_line)514 static int ifmtr_input_start_line(
515     const struct ia_css_stream_config *config,
516     unsigned int bin_in,
517     unsigned int *start_line)
518 {
519 	unsigned int in = config->input_config.input_res.height, start,
520 		     for_bayer = ia_css_ifmtr_lines_needed_for_bayer_order(config);
521 
522 	if (bin_in + 2 * for_bayer > in)
523 		return -EINVAL;
524 
525 	/* On the hardware, we want to use the middle of the input, so we
526 	 * divide the start line by 2. On the simulator, we cannot handle extra
527 	 * lines at the end of the frame.
528 	 */
529 	start = (in - bin_in) / 2;
530 	/* in case the number of extra lines is 2 or odd, we round the start
531 	 * line down.
532 	 */
533 	start &= ~0x1;
534 
535 	/* now we add the one line (if needed) to correct for the bayer order */
536 	start += for_bayer;
537 	*start_line = start;
538 	return 0;
539 }
540 
541