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