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