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