Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / media / davinci_vpfe / dm365_resizer.c
1 /*
2  * Copyright (C) 2012 Texas Instruments Inc
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation version 2.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contributors:
18  *      Manjunath Hadli <manjunath.hadli@ti.com>
19  *      Prabhakar Lad <prabhakar.lad@ti.com>
20  *
21  *
22  * Resizer allows upscaling or downscaling a image to a desired
23  * resolution. There are 2 resizer modules. both operating on the
24  * same input image, but can have different output resolution.
25  */
26
27 #include "dm365_ipipe_hw.h"
28 #include "dm365_resizer.h"
29
30 #define MIN_IN_WIDTH            32
31 #define MIN_IN_HEIGHT           32
32 #define MAX_IN_WIDTH            4095
33 #define MAX_IN_HEIGHT           4095
34 #define MIN_OUT_WIDTH           16
35 #define MIN_OUT_HEIGHT          2
36
37 static const unsigned int resizer_input_formats[] = {
38         MEDIA_BUS_FMT_UYVY8_2X8,
39         MEDIA_BUS_FMT_Y8_1X8,
40         MEDIA_BUS_FMT_UV8_1X8,
41         MEDIA_BUS_FMT_SGRBG12_1X12,
42 };
43
44 static const unsigned int resizer_output_formats[] = {
45         MEDIA_BUS_FMT_UYVY8_2X8,
46         MEDIA_BUS_FMT_Y8_1X8,
47         MEDIA_BUS_FMT_UV8_1X8,
48         MEDIA_BUS_FMT_YDYUYDYV8_1X16,
49         MEDIA_BUS_FMT_SGRBG12_1X12,
50 };
51
52 /* resizer_calculate_line_length() - This function calculates the line length of
53  *                                   various image planes at the input and
54  *                                   output.
55  */
56 static void
57 resizer_calculate_line_length(u32 pix, int width, int height,
58                               int *line_len, int *line_len_c)
59 {
60         *line_len = 0;
61         *line_len_c = 0;
62
63         if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
64             pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
65                 *line_len = width << 1;
66         } else if (pix == MEDIA_BUS_FMT_Y8_1X8 ||
67                    pix == MEDIA_BUS_FMT_UV8_1X8) {
68                 *line_len = width;
69                 *line_len_c = width;
70         } else {
71                 /* YUV 420 */
72                 /* round width to upper 32 byte boundary */
73                 *line_len = width;
74                 *line_len_c = width;
75         }
76         /* adjust the line len to be a multiple of 32 */
77         *line_len += 31;
78         *line_len &= ~0x1f;
79         *line_len_c += 31;
80         *line_len_c &= ~0x1f;
81 }
82
83 static inline int
84 resizer_validate_output_image_format(struct device *dev,
85                                      struct v4l2_mbus_framefmt *format,
86                                      int *in_line_len, int *in_line_len_c)
87 {
88         if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 &&
89             format->code != MEDIA_BUS_FMT_Y8_1X8 &&
90             format->code != MEDIA_BUS_FMT_UV8_1X8 &&
91             format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 &&
92             format->code != MEDIA_BUS_FMT_SGRBG12_1X12) {
93                 dev_err(dev, "Invalid Mbus format, %d\n", format->code);
94                 return -EINVAL;
95         }
96         if (!format->width || !format->height) {
97                 dev_err(dev, "invalid width or height\n");
98                 return -EINVAL;
99         }
100         resizer_calculate_line_length(format->code, format->width,
101                 format->height, in_line_len, in_line_len_c);
102         return 0;
103 }
104
105 static void
106 resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass)
107 {
108         struct resizer_params *param = &resizer->config;
109
110         param->rsz_rsc_param[RSZ_A].cen = DISABLE;
111         param->rsz_rsc_param[RSZ_A].yen = DISABLE;
112         param->rsz_rsc_param[RSZ_A].v_phs_y = 0;
113         param->rsz_rsc_param[RSZ_A].v_phs_c = 0;
114         param->rsz_rsc_param[RSZ_A].v_dif = 256;
115         param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0;
116         param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0;
117         param->rsz_rsc_param[RSZ_A].h_phs = 0;
118         param->rsz_rsc_param[RSZ_A].h_dif = 256;
119         param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0;
120         param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0;
121         param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE;
122         param->rsz2rgb[RSZ_A].rgb_en = DISABLE;
123         param->rsz_en[RSZ_A] = ENABLE;
124         param->rsz_en[RSZ_B] = DISABLE;
125         if (bypass) {
126                 param->rsz_rsc_param[RSZ_A].i_vps = 0;
127                 param->rsz_rsc_param[RSZ_A].i_hps = 0;
128                 /* Raw Bypass */
129                 param->rsz_common.passthrough = BYPASS_ON;
130         }
131 }
132
133 static void
134 configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index,
135                              void *output_spec, unsigned char partial,
136                              unsigned flag)
137 {
138         struct resizer_params *param = &resizer->config;
139         struct v4l2_mbus_framefmt *outformat;
140         struct vpfe_rsz_output_spec *output;
141
142         if (index == RSZ_A &&
143             resizer->resizer_a.output == RESIZER_OUTPUT_NONE) {
144                 param->rsz_en[index] = DISABLE;
145                 return;
146         }
147         if (index == RSZ_B &&
148             resizer->resizer_b.output == RESIZER_OUTPUT_NONE) {
149                 param->rsz_en[index] = DISABLE;
150                 return;
151         }
152         output = output_spec;
153         param->rsz_en[index] = ENABLE;
154         if (partial) {
155                 param->rsz_rsc_param[index].h_flip = output->h_flip;
156                 param->rsz_rsc_param[index].v_flip = output->v_flip;
157                 param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
158                 param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
159                 param->rsz_rsc_param[index].v_lpf_int_y =
160                                                 output->v_lpf_int_y;
161                 param->rsz_rsc_param[index].v_lpf_int_c =
162                                                 output->v_lpf_int_c;
163                 param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
164                 param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
165                 param->rsz_rsc_param[index].h_lpf_int_y =
166                                                 output->h_lpf_int_y;
167                 param->rsz_rsc_param[index].h_lpf_int_c =
168                                                 output->h_lpf_int_c;
169                 param->rsz_rsc_param[index].dscale_en =
170                                                 output->en_down_scale;
171                 param->rsz_rsc_param[index].h_dscale_ave_sz =
172                                                 output->h_dscale_ave_sz;
173                 param->rsz_rsc_param[index].v_dscale_ave_sz =
174                                                 output->v_dscale_ave_sz;
175                 param->ext_mem_param[index].user_y_ofst =
176                                     (output->user_y_ofst + 31) & ~0x1f;
177                 param->ext_mem_param[index].user_c_ofst =
178                                     (output->user_c_ofst + 31) & ~0x1f;
179                 return;
180         }
181
182         if (index == RSZ_A)
183                 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
184         else
185                 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
186         param->rsz_rsc_param[index].o_vsz = outformat->height - 1;
187         param->rsz_rsc_param[index].o_hsz = outformat->width - 1;
188         param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y;
189         param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height;
190         param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c;
191         param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height;
192
193         if (!flag)
194                 return;
195         /* update common parameters */
196         param->rsz_rsc_param[index].h_flip = output->h_flip;
197         param->rsz_rsc_param[index].v_flip = output->v_flip;
198         param->rsz_rsc_param[index].v_typ_y = output->v_typ_y;
199         param->rsz_rsc_param[index].v_typ_c = output->v_typ_c;
200         param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y;
201         param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c;
202         param->rsz_rsc_param[index].h_typ_y = output->h_typ_y;
203         param->rsz_rsc_param[index].h_typ_c = output->h_typ_c;
204         param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y;
205         param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c;
206         param->rsz_rsc_param[index].dscale_en = output->en_down_scale;
207         param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz;
208         param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz;
209         param->ext_mem_param[index].user_y_ofst =
210                                         (output->user_y_ofst + 31) & ~0x1f;
211         param->ext_mem_param[index].user_c_ofst =
212                                         (output->user_c_ofst + 31) & ~0x1f;
213 }
214
215 /*
216  * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer
217  *                                    A or B. This is called after setting
218  *                                   the input size or output size.
219  * @resizer: Pointer to VPFE resizer subdevice.
220  * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
221  */
222 static void
223 resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index)
224 {
225         struct resizer_params *param = &resizer->config;
226         struct v4l2_mbus_framefmt *informat, *outformat;
227
228         informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
229
230         if (index == RSZ_A)
231                 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
232         else
233                 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
234
235         if (outformat->field != V4L2_FIELD_INTERLACED)
236                 param->rsz_rsc_param[index].v_dif =
237                         ((informat->height) * 256) / (outformat->height);
238         else
239                 param->rsz_rsc_param[index].v_dif =
240                         ((informat->height >> 1) * 256) / (outformat->height);
241         param->rsz_rsc_param[index].h_dif =
242                         ((informat->width) * 256) / (outformat->width);
243 }
244
245 void
246 static resizer_enable_422_420_conversion(struct resizer_params *param,
247                                          int index, bool en)
248 {
249         param->rsz_rsc_param[index].cen = en;
250         param->rsz_rsc_param[index].yen = en;
251 }
252
253 /* resizer_calculate_sdram_offsets() - This function calculates the offsets from
254  *                                     start of buffer for the C plane when
255  *                                     output format is YUV420SP. It also
256  *                                     calculates the offsets from the start of
257  *                                     the buffer when the image is flipped
258  *                                     vertically or horizontally for ycbcr/y/c
259  *                                     planes.
260  * @resizer: Pointer to resizer subdevice.
261  * @index: index RSZ_A-resizer-A RSZ_B-resizer-B.
262  */
263 static int
264 resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index)
265 {
266         struct resizer_params *param = &resizer->config;
267         struct v4l2_mbus_framefmt *outformat;
268         int bytesperpixel = 2;
269         int image_height;
270         int image_width;
271         int yuv_420 = 0;
272         int offset = 0;
273
274         if (index == RSZ_A)
275                 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
276         else
277                 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
278
279         image_height = outformat->height + 1;
280         image_width = outformat->width + 1;
281         param->ext_mem_param[index].c_offset = 0;
282         param->ext_mem_param[index].flip_ofst_y = 0;
283         param->ext_mem_param[index].flip_ofst_c = 0;
284         if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) {
285                 /* YUV 420 */
286                 yuv_420 = 1;
287                 bytesperpixel = 1;
288         }
289
290         if (param->rsz_rsc_param[index].h_flip)
291                 /* width * bytesperpixel - 1 */
292                 offset = (image_width * bytesperpixel) - 1;
293         if (param->rsz_rsc_param[index].v_flip)
294                 offset += (image_height - 1) *
295                         param->ext_mem_param[index].rsz_sdr_oft_y;
296         param->ext_mem_param[index].flip_ofst_y = offset;
297         if (!yuv_420)
298                 return 0;
299         offset = 0;
300         /* half height for c-plane */
301         if (param->rsz_rsc_param[index].h_flip)
302                 /* width * bytesperpixel - 1 */
303                 offset = image_width - 1;
304         if (param->rsz_rsc_param[index].v_flip)
305                 offset += (((image_height >> 1) - 1) *
306                            param->ext_mem_param[index].rsz_sdr_oft_c);
307         param->ext_mem_param[index].flip_ofst_c = offset;
308         param->ext_mem_param[index].c_offset =
309                       param->ext_mem_param[index].rsz_sdr_oft_y * image_height;
310         return 0;
311 }
312
313 static int resizer_configure_output_win(struct vpfe_resizer_device *resizer)
314 {
315         struct resizer_params *param = &resizer->config;
316         struct vpfe_rsz_output_spec output_specs;
317         struct v4l2_mbus_framefmt *outformat;
318         int line_len_c;
319         int line_len;
320         int ret;
321
322         outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
323
324         output_specs.vst_y = param->user_config.vst;
325         if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
326                 output_specs.vst_c = param->user_config.vst;
327
328         configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0);
329         resizer_calculate_line_length(outformat->code,
330                                       param->rsz_rsc_param[0].o_hsz + 1,
331                                       param->rsz_rsc_param[0].o_vsz + 1,
332                                       &line_len, &line_len_c);
333         param->ext_mem_param[0].rsz_sdr_oft_y = line_len;
334         param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c;
335         resizer_calculate_resize_ratios(resizer, RSZ_A);
336         if (param->rsz_en[RSZ_B])
337                 resizer_calculate_resize_ratios(resizer, RSZ_B);
338
339         if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
340                 resizer_enable_422_420_conversion(param, RSZ_A, ENABLE);
341         else
342                 resizer_enable_422_420_conversion(param, RSZ_A, DISABLE);
343
344         ret = resizer_calculate_sdram_offsets(resizer, RSZ_A);
345         if (!ret && param->rsz_en[RSZ_B])
346                 ret = resizer_calculate_sdram_offsets(resizer, RSZ_B);
347
348         if (ret)
349                 pr_err("Error in calculating sdram offsets\n");
350         return ret;
351 }
352
353 static int
354 resizer_calculate_down_scale_f_div_param(struct device *dev,
355                                          int input_width, int output_width,
356                                          struct resizer_scale_param *param)
357 {
358         /* rsz = R, input_width = H, output width = h in the equation */
359         unsigned int two_power;
360         unsigned int upper_h1;
361         unsigned int upper_h2;
362         unsigned int val1;
363         unsigned int val;
364         unsigned int rsz;
365         unsigned int h1;
366         unsigned int h2;
367         unsigned int o;
368         unsigned int n;
369
370         upper_h1 = input_width >> 1;
371         n = param->h_dscale_ave_sz;
372         /* 2 ^ (scale+1) */
373         two_power = 1 << (n + 1);
374         upper_h1 = (upper_h1 >> (n + 1)) << (n + 1);
375         upper_h2 = input_width - upper_h1;
376         if (upper_h2 % two_power) {
377                 dev_err(dev, "frame halves to be a multiple of 2 power n+1\n");
378                 return -EINVAL;
379         }
380         two_power = 1 << n;
381         rsz = (input_width << 8) / output_width;
382         val = rsz * two_power;
383         val = ((upper_h1 << 8) / val) + 1;
384         if (!(val % 2)) {
385                 h1 = val;
386         } else {
387                 val = upper_h1 << 8;
388                 val >>= n + 1;
389                 val -= rsz >> 1;
390                 val /= rsz << 1;
391                 val <<= 1;
392                 val += 2;
393                 h1 = val;
394         }
395         o = 10 + (two_power << 2);
396         if (((input_width << 7) / rsz) % 2)
397                 o += (((CEIL(rsz, 1024)) << 1) << n);
398         h2 = output_width - h1;
399         /* phi */
400         val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8);
401         /* skip */
402         val1 = ((val - 1024) >> 9) << 1;
403         param->f_div.num_passes = MAX_PASSES;
404         param->f_div.pass[0].o_hsz = h1 - 1;
405         param->f_div.pass[0].i_hps = 0;
406         param->f_div.pass[0].h_phs = 0;
407         param->f_div.pass[0].src_hps = 0;
408         param->f_div.pass[0].src_hsz = upper_h1 + o;
409         param->f_div.pass[1].o_hsz = h2 - 1;
410         param->f_div.pass[1].i_hps = 10 + (val1 * two_power);
411         param->f_div.pass[1].h_phs = (val - (val1 << 8));
412         param->f_div.pass[1].src_hps = upper_h1 - o;
413         param->f_div.pass[1].src_hsz = upper_h2 + o;
414
415         return 0;
416 }
417
418 static int
419 resizer_configure_common_in_params(struct vpfe_resizer_device *resizer)
420 {
421         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
422         struct resizer_params *param = &resizer->config;
423         struct vpfe_rsz_config_params *user_config;
424         struct v4l2_mbus_framefmt *informat;
425
426         informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
427         user_config = &resizer->config.user_config;
428         param->rsz_common.vps = param->user_config.vst;
429         param->rsz_common.hps = param->user_config.hst;
430
431         if (vpfe_ipipeif_decimation_enabled(vpfe_dev))
432                 param->rsz_common.hsz = (((informat->width - 1) *
433                         IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev));
434         else
435                 param->rsz_common.hsz = informat->width - 1;
436
437         if (informat->field == V4L2_FIELD_INTERLACED)
438                 param->rsz_common.vsz  = (informat->height - 1) >> 1;
439         else
440                 param->rsz_common.vsz  = informat->height - 1;
441
442         param->rsz_common.raw_flip = 0;
443
444         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF)
445                 param->rsz_common.source = IPIPEIF_DATA;
446         else
447                 param->rsz_common.source = IPIPE_DATA;
448
449         switch (informat->code) {
450         case MEDIA_BUS_FMT_UYVY8_2X8:
451                 param->rsz_common.src_img_fmt = RSZ_IMG_422;
452                 param->rsz_common.raw_flip = 0;
453                 break;
454
455         case MEDIA_BUS_FMT_Y8_1X8:
456                 param->rsz_common.src_img_fmt = RSZ_IMG_420;
457                 /* Select y */
458                 param->rsz_common.y_c = 0;
459                 param->rsz_common.raw_flip = 0;
460                 break;
461
462         case MEDIA_BUS_FMT_UV8_1X8:
463                 param->rsz_common.src_img_fmt = RSZ_IMG_420;
464                 /* Select y */
465                 param->rsz_common.y_c = 1;
466                 param->rsz_common.raw_flip = 0;
467                 break;
468
469         case MEDIA_BUS_FMT_SGRBG12_1X12:
470                 param->rsz_common.raw_flip = 1;
471                 break;
472
473         default:
474                 param->rsz_common.src_img_fmt = RSZ_IMG_422;
475                 param->rsz_common.source = IPIPE_DATA;
476         }
477
478         param->rsz_common.yuv_y_min = user_config->yuv_y_min;
479         param->rsz_common.yuv_y_max = user_config->yuv_y_max;
480         param->rsz_common.yuv_c_min = user_config->yuv_c_min;
481         param->rsz_common.yuv_c_max = user_config->yuv_c_max;
482         param->rsz_common.out_chr_pos = user_config->out_chr_pos;
483         param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even;
484
485         return 0;
486 }
487 static int
488 resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer)
489 {
490         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
491         struct resizer_params *param = &resizer->config;
492         struct vpfe_rsz_config_params *cont_config;
493         int line_len_c;
494         int line_len;
495         int ret;
496
497         if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) {
498                 dev_err(dev, "enable resizer - Resizer-A\n");
499                 return -EINVAL;
500         }
501
502         cont_config = &resizer->config.user_config;
503         param->rsz_en[RSZ_A] = ENABLE;
504         configure_resizer_out_params(resizer, RSZ_A,
505                                      &cont_config->output1, 1, 0);
506         param->rsz_en[RSZ_B] = DISABLE;
507         param->oper_mode = RESIZER_MODE_CONTINIOUS;
508
509         if (resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) {
510                 struct v4l2_mbus_framefmt *outformat2;
511
512                 param->rsz_en[RSZ_B] = ENABLE;
513                 outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
514                 ret = resizer_validate_output_image_format(dev, outformat2,
515                                 &line_len, &line_len_c);
516                 if (ret)
517                         return ret;
518                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
519                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
520                 configure_resizer_out_params(resizer, RSZ_B,
521                                                 &cont_config->output2, 0, 1);
522                 if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
523                         resizer_enable_422_420_conversion(param,
524                                                           RSZ_B, ENABLE);
525                 else
526                         resizer_enable_422_420_conversion(param,
527                                                           RSZ_B, DISABLE);
528         }
529         resizer_configure_common_in_params(resizer);
530         ret = resizer_configure_output_win(resizer);
531         if (ret)
532                 return ret;
533
534         param->rsz_common.passthrough = cont_config->bypass;
535         if (cont_config->bypass)
536                 resizer_configure_passthru(resizer, 1);
537
538         return 0;
539 }
540
541 static inline int
542 resizer_validate_input_image_format(struct device *dev,
543                                     u32 pix,
544                                     int width, int height, int *line_len)
545 {
546         int val;
547
548         if (pix != MEDIA_BUS_FMT_UYVY8_2X8 &&
549             pix != MEDIA_BUS_FMT_Y8_1X8 &&
550             pix != MEDIA_BUS_FMT_UV8_1X8 &&
551             pix != MEDIA_BUS_FMT_SGRBG12_1X12) {
552                 dev_err(dev,
553                 "resizer validate output: pix format not supported, %d\n", pix);
554                 return -EINVAL;
555         }
556
557         if (!width || !height) {
558                 dev_err(dev,
559                         "resizer validate input: invalid width or height\n");
560                 return -EINVAL;
561         }
562
563         if (pix == MEDIA_BUS_FMT_UV8_1X8)
564                 resizer_calculate_line_length(pix, width,
565                                               height, &val, line_len);
566         else
567                 resizer_calculate_line_length(pix, width,
568                                               height, line_len, &val);
569
570         return 0;
571 }
572
573 static int
574 resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en,
575                             unsigned char rsz, unsigned char frame_div_mode_en,
576                             int width)
577 {
578         if (dec_en && frame_div_mode_en) {
579                 dev_err(dev,
580                  "dec_en & frame_div_mode_en can not enabled simultaneously\n");
581                 return -EINVAL;
582         }
583
584         if (frame_div_mode_en) {
585                 dev_err(dev, "frame_div_mode mode not supported\n");
586                 return -EINVAL;
587         }
588
589         if (!dec_en)
590                 return 0;
591
592         if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) {
593                 dev_err(dev,
594                         "image width to be more than %d for decimation\n",
595                         VPFE_IPIPE_MAX_INPUT_WIDTH);
596                 return -EINVAL;
597         }
598
599         if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) {
600                 dev_err(dev, "rsz range is %d to %d\n",
601                         IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
602                 return -EINVAL;
603         }
604
605         return 0;
606 }
607
608 /* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame
609  *                                          division parameters for resizer.
610  *                                          in normal mode.
611  */
612 static int
613 resizer_calculate_normal_f_div_param(struct device *dev, int input_width,
614                 int output_width, struct resizer_scale_param *param)
615 {
616         /* rsz = R, input_width = H, output width = h in the equation */
617         unsigned int val1;
618         unsigned int rsz;
619         unsigned int val;
620         unsigned int h1;
621         unsigned int h2;
622         unsigned int o;
623
624         if (output_width > input_width) {
625                 dev_err(dev, "frame div mode is used for scale down only\n");
626                 return -EINVAL;
627         }
628
629         rsz = (input_width << 8) / output_width;
630         val = rsz << 1;
631         val = ((input_width << 8) / val) + 1;
632         o = 14;
633         if (!(val % 2)) {
634                 h1 = val;
635         } else {
636                 val = input_width << 7;
637                 val -= rsz >> 1;
638                 val /= rsz << 1;
639                 val <<= 1;
640                 val += 2;
641                 o += ((CEIL(rsz, 1024)) << 1);
642                 h1 = val;
643         }
644         h2 = output_width - h1;
645         /* phi */
646         val = (h1 * rsz) - (((input_width >> 1) - o) << 8);
647         /* skip */
648         val1 = ((val - 1024) >> 9) << 1;
649         param->f_div.num_passes = MAX_PASSES;
650         param->f_div.pass[0].o_hsz = h1 - 1;
651         param->f_div.pass[0].i_hps = 0;
652         param->f_div.pass[0].h_phs = 0;
653         param->f_div.pass[0].src_hps = 0;
654         param->f_div.pass[0].src_hsz = (input_width >> 2) + o;
655         param->f_div.pass[1].o_hsz = h2 - 1;
656         param->f_div.pass[1].i_hps = val1;
657         param->f_div.pass[1].h_phs = (val - (val1 << 8));
658         param->f_div.pass[1].src_hps = (input_width >> 2) - o;
659         param->f_div.pass[1].src_hsz = (input_width >> 2) + o;
660
661         return 0;
662 }
663
664 static int
665 resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
666 {
667         struct vpfe_rsz_config_params *config = &resizer->config.user_config;
668         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
669         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
670         struct v4l2_mbus_framefmt *outformat1, *outformat2;
671         struct resizer_params *param = &resizer->config;
672         struct v4l2_mbus_framefmt *informat;
673         int decimation;
674         int line_len_c;
675         int line_len;
676         int rsz;
677         int ret;
678
679         informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
680         outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
681         outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
682
683         decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev);
684         rsz = vpfe_ipipeif_get_rsz(vpfe_dev);
685         if (decimation && param->user_config.frame_div_mode_en) {
686                 dev_err(dev,
687                 "dec_en & frame_div_mode_en cannot enabled simultaneously\n");
688                 return -EINVAL;
689         }
690
691         ret = resizer_validate_decimation(dev, decimation, rsz,
692               param->user_config.frame_div_mode_en, informat->width);
693         if (ret)
694                 return -EINVAL;
695
696         ret = resizer_validate_input_image_format(dev, informat->code,
697                 informat->width, informat->height, &line_len);
698         if (ret)
699                 return -EINVAL;
700
701         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
702                 param->rsz_en[RSZ_A] = ENABLE;
703                 ret = resizer_validate_output_image_format(dev, outformat1,
704                                         &line_len, &line_len_c);
705                 if (ret)
706                         return ret;
707                 param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
708                 param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c;
709                 configure_resizer_out_params(resizer, RSZ_A,
710                                         &param->user_config.output1, 0, 1);
711
712                 if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12)
713                         param->rsz_common.raw_flip = 1;
714                 else
715                         param->rsz_common.raw_flip = 0;
716
717                 if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
718                         resizer_enable_422_420_conversion(param,
719                                                           RSZ_A, ENABLE);
720                 else
721                         resizer_enable_422_420_conversion(param,
722                                                           RSZ_A, DISABLE);
723         }
724
725         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
726                 param->rsz_en[RSZ_B] = ENABLE;
727                 ret = resizer_validate_output_image_format(dev, outformat2,
728                                 &line_len, &line_len_c);
729                 if (ret)
730                         return ret;
731                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
732                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
733                 configure_resizer_out_params(resizer, RSZ_B,
734                                         &param->user_config.output2, 0, 1);
735                 if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
736                         resizer_enable_422_420_conversion(param,
737                                                           RSZ_B, ENABLE);
738                 else
739                         resizer_enable_422_420_conversion(param,
740                                                           RSZ_B, DISABLE);
741         }
742
743         resizer_configure_common_in_params(resizer);
744         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
745                 resizer_calculate_resize_ratios(resizer, RSZ_A);
746                 resizer_calculate_sdram_offsets(resizer, RSZ_A);
747                 /* Overriding resize ratio calculation */
748                 if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
749                         param->rsz_rsc_param[RSZ_A].v_dif =
750                                 (((informat->height + 1) * 2) * 256) /
751                                 (param->rsz_rsc_param[RSZ_A].o_vsz + 1);
752                 }
753         }
754
755         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
756                 resizer_calculate_resize_ratios(resizer, RSZ_B);
757                 resizer_calculate_sdram_offsets(resizer, RSZ_B);
758                 /* Overriding resize ratio calculation */
759                 if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
760                         param->rsz_rsc_param[RSZ_B].v_dif =
761                                 (((informat->height + 1) * 2) * 256) /
762                                 (param->rsz_rsc_param[RSZ_B].o_vsz + 1);
763                 }
764         }
765         if (param->user_config.frame_div_mode_en &&
766                 param->rsz_en[RSZ_A]) {
767                 if (!param->rsz_rsc_param[RSZ_A].dscale_en)
768                         ret = resizer_calculate_normal_f_div_param(dev,
769                               informat->width,
770                               param->rsz_rsc_param[RSZ_A].o_vsz + 1,
771                               &param->rsz_rsc_param[RSZ_A]);
772                 else
773                         ret = resizer_calculate_down_scale_f_div_param(dev,
774                               informat->width,
775                               param->rsz_rsc_param[RSZ_A].o_vsz + 1,
776                               &param->rsz_rsc_param[RSZ_A]);
777                 if (ret)
778                         return -EINVAL;
779         }
780         if (param->user_config.frame_div_mode_en &&
781                 param->rsz_en[RSZ_B]) {
782                 if (!param->rsz_rsc_param[RSZ_B].dscale_en)
783                         ret = resizer_calculate_normal_f_div_param(dev,
784                               informat->width,
785                               param->rsz_rsc_param[RSZ_B].o_vsz + 1,
786                               &param->rsz_rsc_param[RSZ_B]);
787                 else
788                         ret = resizer_calculate_down_scale_f_div_param(dev,
789                               informat->width,
790                               param->rsz_rsc_param[RSZ_B].o_vsz + 1,
791                               &param->rsz_rsc_param[RSZ_B]);
792                 if (ret)
793                         return -EINVAL;
794         }
795         param->rsz_common.passthrough = config->bypass;
796         if (config->bypass)
797                 resizer_configure_passthru(resizer, 1);
798         return 0;
799 }
800
801 static void
802 resizer_set_defualt_configuration(struct vpfe_resizer_device *resizer)
803 {
804 #define  WIDTH_I 640
805 #define  HEIGHT_I 480
806 #define  WIDTH_O 640
807 #define  HEIGHT_O 480
808         const struct resizer_params rsz_default_config = {
809                 .oper_mode = RESIZER_MODE_ONE_SHOT,
810                 .rsz_common = {
811                         .vsz = HEIGHT_I - 1,
812                         .hsz = WIDTH_I - 1,
813                         .src_img_fmt = RSZ_IMG_422,
814                         .raw_flip = 1,  /* flip preserve Raw format */
815                         .source = IPIPE_DATA,
816                         .passthrough = BYPASS_OFF,
817                         .yuv_y_max = 255,
818                         .yuv_c_max = 255,
819                         .rsz_seq_crv = DISABLE,
820                         .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
821                 },
822                 .rsz_rsc_param = {
823                         {
824                                 .h_flip = DISABLE,
825                                 .v_flip = DISABLE,
826                                 .cen = DISABLE,
827                                 .yen = DISABLE,
828                                 .o_vsz = HEIGHT_O - 1,
829                                 .o_hsz = WIDTH_O - 1,
830                                 .v_dif = 256,
831                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
832                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
833                                 .h_dif = 256,
834                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
835                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
836                                 .h_dscale_ave_sz =
837                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
838                                 .v_dscale_ave_sz =
839                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
840                         },
841                         {
842                                 .h_flip = DISABLE,
843                                 .v_flip = DISABLE,
844                                 .cen = DISABLE,
845                                 .yen = DISABLE,
846                                 .o_vsz = HEIGHT_O - 1,
847                                 .o_hsz = WIDTH_O - 1,
848                                 .v_dif = 256,
849                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
850                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
851                                 .h_dif = 256,
852                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
853                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
854                                 .h_dscale_ave_sz =
855                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
856                                 .v_dscale_ave_sz =
857                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
858                         },
859                 },
860                 .rsz2rgb = {
861                         {
862                                 .rgb_en = DISABLE
863                         },
864                         {
865                                 .rgb_en = DISABLE
866                         }
867                 },
868                 .ext_mem_param = {
869                         {
870                                 .rsz_sdr_oft_y = WIDTH_O << 1,
871                                 .rsz_sdr_ptr_e_y = HEIGHT_O,
872                                 .rsz_sdr_oft_c = WIDTH_O,
873                                 .rsz_sdr_ptr_e_c = HEIGHT_O >> 1,
874                         },
875                         {
876                                 .rsz_sdr_oft_y = WIDTH_O << 1,
877                                 .rsz_sdr_ptr_e_y = HEIGHT_O,
878                                 .rsz_sdr_oft_c = WIDTH_O,
879                                 .rsz_sdr_ptr_e_c = HEIGHT_O,
880                         },
881                 },
882                 .rsz_en[0] = ENABLE,
883                 .rsz_en[1] = DISABLE,
884                 .user_config = {
885                         .output1 = {
886                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
887                                 .v_typ_c = VPFE_RSZ_INTP_CUBIC,
888                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
889                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
890                                 .h_dscale_ave_sz =
891                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
892                                 .v_dscale_ave_sz =
893                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
894                         },
895                         .output2 = {
896                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
897                                 .v_typ_c = VPFE_RSZ_INTP_CUBIC,
898                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
899                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
900                                 .h_dscale_ave_sz =
901                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
902                                 .v_dscale_ave_sz =
903                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
904                         },
905                         .yuv_y_max = 255,
906                         .yuv_c_max = 255,
907                         .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
908                 },
909         };
910         memcpy(&resizer->config, &rsz_default_config,
911                sizeof(struct resizer_params));
912 }
913
914 /*
915  * resizer_set_configuration() - set resizer config
916  * @resizer: vpfe resizer device pointer.
917  * @chan_config: resizer channel configuration.
918  */
919 static int
920 resizer_set_configuration(struct vpfe_resizer_device *resizer,
921                           struct vpfe_rsz_config *chan_config)
922 {
923         if (!chan_config->config)
924                 resizer_set_defualt_configuration(resizer);
925         else
926                 if (copy_from_user(&resizer->config.user_config,
927                     chan_config->config, sizeof(struct vpfe_rsz_config_params)))
928                         return -EFAULT;
929
930         return 0;
931 }
932
933 /*
934  * resizer_get_configuration() - get resizer config
935  * @resizer: vpfe resizer device pointer.
936  * @channel: image processor logical channel.
937  * @chan_config: resizer channel configuration.
938  */
939 static int
940 resizer_get_configuration(struct vpfe_resizer_device *resizer,
941                    struct vpfe_rsz_config *chan_config)
942 {
943         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
944
945         if (!chan_config->config) {
946                 dev_err(dev, "Resizer channel invalid pointer\n");
947                 return -EINVAL;
948         }
949
950         if (copy_to_user((void *)chan_config->config,
951            (void *)&resizer->config.user_config,
952            sizeof(struct vpfe_rsz_config_params))) {
953                 dev_err(dev, "resizer_get_configuration: Error in copy to user\n");
954                 return -EFAULT;
955         }
956
957         return 0;
958 }
959
960 /*
961  * VPFE video operations
962  */
963
964 /*
965  * resizer_a_video_out_queue() - RESIZER-A video out queue
966  * @vpfe_dev: vpfe device pointer.
967  * @addr: buffer address.
968  */
969 static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev,
970                                      unsigned long addr)
971 {
972         struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
973
974         return resizer_set_outaddr(resizer->base_addr,
975                                       &resizer->config, RSZ_A, addr);
976 }
977
978 /*
979  * resizer_b_video_out_queue() - RESIZER-B video out queue
980  * @vpfe_dev: vpfe device pointer.
981  * @addr: buffer address.
982  */
983 static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev,
984                                      unsigned long addr)
985 {
986         struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
987
988         return resizer_set_outaddr(resizer->base_addr,
989                                    &resizer->config, RSZ_B, addr);
990 }
991
992 static const struct vpfe_video_operations resizer_a_video_ops = {
993         .queue = resizer_a_video_out_queue,
994 };
995
996 static const struct vpfe_video_operations resizer_b_video_ops = {
997         .queue = resizer_b_video_out_queue,
998 };
999
1000 static void resizer_enable(struct vpfe_resizer_device *resizer, int en)
1001 {
1002         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1003         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1004         unsigned char val;
1005
1006         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1007                 return;
1008
1009         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF &&
1010            ipipeif_sink == IPIPEIF_INPUT_MEMORY) {
1011                 do {
1012                         val = regr_rsz(resizer->base_addr, RSZ_SRC_EN);
1013                 } while (val);
1014
1015                 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
1016                         do {
1017                                 val = regr_rsz(resizer->base_addr, RSZ_A);
1018                         } while (val);
1019                 }
1020                 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
1021                         do {
1022                                 val = regr_rsz(resizer->base_addr, RSZ_B);
1023                         } while (val);
1024                 }
1025         }
1026         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1027                 rsz_enable(resizer->base_addr, RSZ_A, en);
1028
1029         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1030                 rsz_enable(resizer->base_addr, RSZ_B, en);
1031 }
1032
1033
1034 /*
1035  * resizer_ss_isr() - resizer module single-shot buffer scheduling isr
1036  * @resizer: vpfe resizer device pointer.
1037  */
1038 static void resizer_ss_isr(struct vpfe_resizer_device *resizer)
1039 {
1040         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1041         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1042         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1043         struct vpfe_pipeline *pipe = &video_out->pipe;
1044         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1045         u32 val;
1046
1047         if (ipipeif_sink != IPIPEIF_INPUT_MEMORY)
1048                 return;
1049
1050         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1051                 val = vpss_dma_complete_interrupt();
1052                 if (val != 0 && val != 2)
1053                         return;
1054         }
1055
1056         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1057                 spin_lock(&video_out->dma_queue_lock);
1058                 vpfe_video_process_buffer_complete(video_out);
1059                 video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1060                 vpfe_video_schedule_next_buffer(video_out);
1061                 spin_unlock(&video_out->dma_queue_lock);
1062         }
1063
1064         /* If resizer B is enabled */
1065         if (pipe->output_num > 1 && resizer->resizer_b.output ==
1066             RESIZER_OUPUT_MEMORY) {
1067                 spin_lock(&video_out->dma_queue_lock);
1068                 vpfe_video_process_buffer_complete(video_out2);
1069                 video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1070                 vpfe_video_schedule_next_buffer(video_out2);
1071                 spin_unlock(&video_out2->dma_queue_lock);
1072         }
1073
1074         /* start HW if buffers are queued */
1075         if (vpfe_video_is_pipe_ready(pipe) &&
1076             resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1077                 resizer_enable(resizer, 1);
1078                 vpfe_ipipe_enable(vpfe_dev, 1);
1079                 vpfe_ipipeif_enable(vpfe_dev);
1080         }
1081 }
1082
1083 /*
1084  * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr
1085  * @resizer: vpfe resizer device pointer.
1086  */
1087 void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer)
1088 {
1089         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1090         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1091         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1092         struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe;
1093         enum v4l2_field field;
1094         int fid;
1095
1096         if (!video_out->started)
1097                 return;
1098
1099         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1100                 return;
1101
1102         field = video_out->fmt.fmt.pix.field;
1103         if (field == V4L2_FIELD_NONE) {
1104                 /* handle progressive frame capture */
1105                 if (video_out->cur_frm != video_out->next_frm) {
1106                         vpfe_video_process_buffer_complete(video_out);
1107                         if (pipe->output_num > 1)
1108                                 vpfe_video_process_buffer_complete(video_out2);
1109                 }
1110
1111                 video_out->skip_frame_count--;
1112                 if (!video_out->skip_frame_count) {
1113                         video_out->skip_frame_count =
1114                                 video_out->skip_frame_count_init;
1115                         rsz_src_enable(resizer->base_addr, 1);
1116                 } else {
1117                         rsz_src_enable(resizer->base_addr, 0);
1118                 }
1119                 return;
1120         }
1121
1122         /* handle interlaced frame capture */
1123         fid = vpfe_isif_get_fid(vpfe_dev);
1124
1125         /* switch the software maintained field id */
1126         video_out->field_id ^= 1;
1127         if (fid == video_out->field_id) {
1128                 /*
1129                  * we are in-sync here,continue.
1130                  * One frame is just being captured. If the
1131                  * next frame is available, release the current
1132                  * frame and move on
1133                  */
1134                 if (fid == 0 && video_out->cur_frm != video_out->next_frm) {
1135                         vpfe_video_process_buffer_complete(video_out);
1136                         if (pipe->output_num > 1)
1137                                 vpfe_video_process_buffer_complete(video_out2);
1138                 }
1139         } else if (fid == 0) {
1140                 /*
1141                 * out of sync. Recover from any hardware out-of-sync.
1142                 * May loose one frame
1143                 */
1144                 video_out->field_id = fid;
1145         }
1146 }
1147
1148 /*
1149  * vpfe_resizer_dma_isr() - resizer module dma isr
1150  * @resizer: vpfe resizer device pointer.
1151  */
1152 void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer)
1153 {
1154         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1155         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1156         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1157         struct vpfe_pipeline *pipe = &video_out->pipe;
1158         int schedule_capture = 0;
1159         enum v4l2_field field;
1160         int fid;
1161
1162         if (!video_out->started)
1163                 return;
1164
1165         if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) {
1166                 resizer_ss_isr(resizer);
1167                 return;
1168         }
1169
1170         field = video_out->fmt.fmt.pix.field;
1171         if (field == V4L2_FIELD_NONE) {
1172                 if (!list_empty(&video_out->dma_queue) &&
1173                         video_out->cur_frm == video_out->next_frm)
1174                         schedule_capture = 1;
1175         } else {
1176                 fid = vpfe_isif_get_fid(vpfe_dev);
1177                 if (fid == video_out->field_id) {
1178                         /* we are in-sync here,continue */
1179                         if (fid == 1 && !list_empty(&video_out->dma_queue) &&
1180                             video_out->cur_frm == video_out->next_frm)
1181                                 schedule_capture = 1;
1182                 }
1183         }
1184
1185         if (!schedule_capture)
1186                 return;
1187
1188         spin_lock(&video_out->dma_queue_lock);
1189         vpfe_video_schedule_next_buffer(video_out);
1190         spin_unlock(&video_out->dma_queue_lock);
1191         if (pipe->output_num > 1) {
1192                 spin_lock(&video_out2->dma_queue_lock);
1193                 vpfe_video_schedule_next_buffer(video_out2);
1194                 spin_unlock(&video_out2->dma_queue_lock);
1195         }
1196 }
1197
1198 /*
1199  * V4L2 subdev operations
1200  */
1201
1202 /*
1203  * resizer_ioctl() - Handle resizer module private ioctl's
1204  * @sd: pointer to v4l2 subdev structure
1205  * @cmd: configuration command
1206  * @arg: configuration argument
1207  */
1208 static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1209 {
1210         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1211         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
1212         struct vpfe_rsz_config *user_config;
1213         int ret = -ENOIOCTLCMD;
1214
1215         if (&resizer->crop_resizer.subdev != sd)
1216                 return ret;
1217
1218         switch (cmd) {
1219         case VIDIOC_VPFE_RSZ_S_CONFIG:
1220                 user_config = arg;
1221                 ret = resizer_set_configuration(resizer, user_config);
1222                 break;
1223
1224         case VIDIOC_VPFE_RSZ_G_CONFIG:
1225                 user_config = arg;
1226                 if (!user_config->config) {
1227                         dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n");
1228                         return -EINVAL;
1229                 }
1230                 ret = resizer_get_configuration(resizer, user_config);
1231                 break;
1232         }
1233         return ret;
1234 }
1235
1236 static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer)
1237 {
1238         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1239         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1240         u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1241         struct resizer_params *param = &resizer->config;
1242         int ret = 0;
1243
1244         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY ||
1245             resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) {
1246                 if (ipipeif_sink == IPIPEIF_INPUT_MEMORY &&
1247                     ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1248                         ret = resizer_configure_in_single_shot_mode(resizer);
1249                 else
1250                         ret =  resizer_configure_in_continious_mode(resizer);
1251                 if (ret)
1252                         return ret;
1253                 ret = config_rsz_hw(resizer, param);
1254         }
1255         return ret;
1256 }
1257
1258 /*
1259  * resizer_set_stream() - Enable/Disable streaming on resizer subdev
1260  * @sd: pointer to v4l2 subdev structure
1261  * @enable: 1 == Enable, 0 == Disable
1262  */
1263 static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1264 {
1265         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1266
1267         if (&resizer->crop_resizer.subdev != sd)
1268                 return 0;
1269
1270         if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY)
1271                 return 0;
1272
1273         switch (enable) {
1274         case 1:
1275                 if (resizer_do_hw_setup(resizer) < 0)
1276                         return -EINVAL;
1277                 resizer_enable(resizer, enable);
1278                 break;
1279
1280         case 0:
1281                 resizer_enable(resizer, enable);
1282                 break;
1283         }
1284
1285         return 0;
1286 }
1287
1288 /*
1289  * __resizer_get_format() - helper function for getting resizer format
1290  * @sd: pointer to subdev.
1291  * @cfg: V4L2 subdev pad config
1292  * @pad: pad number.
1293  * @which: wanted subdev format.
1294  * Retun wanted mbus frame format.
1295  */
1296 static struct v4l2_mbus_framefmt *
1297 __resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1298                      unsigned int pad, enum v4l2_subdev_format_whence which)
1299 {
1300         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1301
1302         if (which == V4L2_SUBDEV_FORMAT_TRY)
1303                 return v4l2_subdev_get_try_format(sd, cfg, pad);
1304         if (&resizer->crop_resizer.subdev == sd)
1305                 return &resizer->crop_resizer.formats[pad];
1306         if (&resizer->resizer_a.subdev == sd)
1307                 return &resizer->resizer_a.formats[pad];
1308         if (&resizer->resizer_b.subdev == sd)
1309                 return &resizer->resizer_b.formats[pad];
1310         return NULL;
1311 }
1312
1313 /*
1314  * resizer_try_format() - Handle try format by pad subdev method
1315  * @sd: pointer to subdev.
1316  * @cfg: V4L2 subdev pad config
1317  * @pad: pad num.
1318  * @fmt: pointer to v4l2 format structure.
1319  * @which: wanted subdev format.
1320  */
1321 static void
1322 resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1323         unsigned int pad, struct v4l2_mbus_framefmt *fmt,
1324         enum v4l2_subdev_format_whence which)
1325 {
1326         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1327         unsigned int max_out_height;
1328         unsigned int max_out_width;
1329         unsigned int i;
1330
1331         if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) ||
1332             (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) ||
1333             (&resizer->crop_resizer.subdev == sd &&
1334             (pad == RESIZER_CROP_PAD_SOURCE ||
1335             pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) {
1336                 for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) {
1337                         if (fmt->code == resizer_input_formats[i])
1338                                 break;
1339                 }
1340                 /* If not found, use UYVY as default */
1341                 if (i >= ARRAY_SIZE(resizer_input_formats))
1342                         fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1343
1344                 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1345                                         MAX_IN_WIDTH);
1346                 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1347                                 MAX_IN_HEIGHT);
1348         } else if (&resizer->resizer_a.subdev == sd &&
1349                    pad == RESIZER_PAD_SOURCE) {
1350                 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
1351                 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1352
1353                 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1354                         if (fmt->code == resizer_output_formats[i])
1355                                 break;
1356                 }
1357                 /* If not found, use UYVY as default */
1358                 if (i >= ARRAY_SIZE(resizer_output_formats))
1359                         fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1360
1361                 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1362                                         max_out_width);
1363                 fmt->width &= ~15;
1364                 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1365                                 max_out_height);
1366         } else if (&resizer->resizer_b.subdev == sd &&
1367                    pad == RESIZER_PAD_SOURCE) {
1368                 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B;
1369                 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1370
1371                 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1372                         if (fmt->code == resizer_output_formats[i])
1373                                 break;
1374                 }
1375                 /* If not found, use UYVY as default */
1376                 if (i >= ARRAY_SIZE(resizer_output_formats))
1377                         fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
1378
1379                 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1380                                         max_out_width);
1381                 fmt->width &= ~15;
1382                 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1383                                 max_out_height);
1384         }
1385 }
1386
1387 /*
1388  * resizer_set_format() - Handle set format by pads subdev method
1389  * @sd: pointer to v4l2 subdev structure
1390  * @cfg: V4L2 subdev pad config
1391  * @fmt: pointer to v4l2 subdev format structure
1392  * return -EINVAL or zero on success
1393  */
1394 static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1395                            struct v4l2_subdev_format *fmt)
1396 {
1397         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1398         struct v4l2_mbus_framefmt *format;
1399
1400         format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
1401         if (format == NULL)
1402                 return -EINVAL;
1403
1404         resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which);
1405         *format = fmt->format;
1406
1407         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1408                 return 0;
1409
1410         if (&resizer->crop_resizer.subdev == sd) {
1411                 if (fmt->pad == RESIZER_CROP_PAD_SINK) {
1412                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1413                 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE &&
1414                                 resizer->crop_resizer.output == RESIZER_A) {
1415                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1416                         resizer->crop_resizer.
1417                         formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format;
1418                 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 &&
1419                         resizer->crop_resizer.output2 == RESIZER_B) {
1420                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1421                         resizer->crop_resizer.
1422                         formats[RESIZER_CROP_PAD_SOURCE] = fmt->format;
1423                 } else {
1424                         return -EINVAL;
1425                 }
1426         } else if (&resizer->resizer_a.subdev == sd) {
1427                 if (fmt->pad == RESIZER_PAD_SINK)
1428                         resizer->resizer_a.formats[fmt->pad] = fmt->format;
1429                 else if (fmt->pad == RESIZER_PAD_SOURCE)
1430                         resizer->resizer_a.formats[fmt->pad] = fmt->format;
1431                 else
1432                         return -EINVAL;
1433         } else if (&resizer->resizer_b.subdev == sd) {
1434                 if (fmt->pad == RESIZER_PAD_SINK)
1435                         resizer->resizer_b.formats[fmt->pad] = fmt->format;
1436                 else if (fmt->pad == RESIZER_PAD_SOURCE)
1437                         resizer->resizer_b.formats[fmt->pad] = fmt->format;
1438                 else
1439                         return -EINVAL;
1440         } else {
1441                 return -EINVAL;
1442         }
1443
1444         return 0;
1445 }
1446
1447 /*
1448  * resizer_get_format() - Retrieve the video format on a pad
1449  * @sd: pointer to v4l2 subdev structure.
1450  * @cfg: V4L2 subdev pad config
1451  * @fmt: pointer to v4l2 subdev format structure
1452  * return -EINVAL or zero on success
1453  */
1454 static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
1455                            struct v4l2_subdev_format *fmt)
1456 {
1457         struct v4l2_mbus_framefmt *format;
1458
1459         format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which);
1460         if (format == NULL)
1461                 return -EINVAL;
1462
1463         fmt->format = *format;
1464
1465         return 0;
1466 }
1467
1468 /*
1469  * resizer_enum_frame_size() - enum frame sizes on pads
1470  * @sd: Pointer to subdevice.
1471  * @cfg: V4L2 subdev pad config
1472  * @code: pointer to v4l2_subdev_frame_size_enum structure.
1473  */
1474 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1475                                    struct v4l2_subdev_pad_config *cfg,
1476                                    struct v4l2_subdev_frame_size_enum *fse)
1477 {
1478         struct v4l2_mbus_framefmt format;
1479
1480         if (fse->index != 0)
1481                 return -EINVAL;
1482
1483         format.code = fse->code;
1484         format.width = 1;
1485         format.height = 1;
1486         resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
1487         fse->min_width = format.width;
1488         fse->min_height = format.height;
1489
1490         if (format.code != fse->code)
1491                 return -EINVAL;
1492
1493         format.code = fse->code;
1494         format.width = -1;
1495         format.height = -1;
1496         resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
1497         fse->max_width = format.width;
1498         fse->max_height = format.height;
1499
1500         return 0;
1501 }
1502
1503 /*
1504  * resizer_enum_mbus_code() - enum mbus codes for pads
1505  * @sd: Pointer to subdevice.
1506  * @cfg: V4L2 subdev pad config
1507  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1508  */
1509 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1510                                   struct v4l2_subdev_pad_config *cfg,
1511                                   struct v4l2_subdev_mbus_code_enum *code)
1512 {
1513         if (code->pad == RESIZER_PAD_SINK) {
1514                 if (code->index >= ARRAY_SIZE(resizer_input_formats))
1515                         return -EINVAL;
1516
1517                 code->code = resizer_input_formats[code->index];
1518         } else if (code->pad == RESIZER_PAD_SOURCE) {
1519                 if (code->index >= ARRAY_SIZE(resizer_output_formats))
1520                         return -EINVAL;
1521
1522                 code->code = resizer_output_formats[code->index];
1523         }
1524
1525         return 0;
1526 }
1527
1528 /*
1529  * resizer_init_formats() - Initialize formats on all pads
1530  * @sd: Pointer to subdevice.
1531  * @fh: V4L2 subdev file handle.
1532  *
1533  * Initialize all pad formats with default values. Try formats are
1534  * initialized on the file handle.
1535  */
1536 static int resizer_init_formats(struct v4l2_subdev *sd,
1537                                 struct v4l2_subdev_fh *fh)
1538 {
1539         __u32 which = V4L2_SUBDEV_FORMAT_TRY;
1540         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1541         struct v4l2_subdev_format format;
1542
1543         if (&resizer->crop_resizer.subdev == sd) {
1544                 memset(&format, 0, sizeof(format));
1545                 format.pad = RESIZER_CROP_PAD_SINK;
1546                 format.which = which;
1547                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1548                 format.format.width = MAX_IN_WIDTH;
1549                 format.format.height = MAX_IN_HEIGHT;
1550                 resizer_set_format(sd, fh->pad, &format);
1551
1552                 memset(&format, 0, sizeof(format));
1553                 format.pad = RESIZER_CROP_PAD_SOURCE;
1554                 format.which = which;
1555                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1556                 format.format.width = MAX_IN_WIDTH;
1557                 format.format.height = MAX_IN_WIDTH;
1558                 resizer_set_format(sd, fh->pad, &format);
1559
1560                 memset(&format, 0, sizeof(format));
1561                 format.pad = RESIZER_CROP_PAD_SOURCE2;
1562                 format.which = which;
1563                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1564                 format.format.width = MAX_IN_WIDTH;
1565                 format.format.height = MAX_IN_WIDTH;
1566                 resizer_set_format(sd, fh->pad, &format);
1567         } else if (&resizer->resizer_a.subdev == sd) {
1568                 memset(&format, 0, sizeof(format));
1569                 format.pad = RESIZER_PAD_SINK;
1570                 format.which = which;
1571                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1572                 format.format.width = MAX_IN_WIDTH;
1573                 format.format.height = MAX_IN_HEIGHT;
1574                 resizer_set_format(sd, fh->pad, &format);
1575
1576                 memset(&format, 0, sizeof(format));
1577                 format.pad = RESIZER_PAD_SOURCE;
1578                 format.which = which;
1579                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1580                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
1581                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1582                 resizer_set_format(sd, fh->pad, &format);
1583         } else if (&resizer->resizer_b.subdev == sd) {
1584                 memset(&format, 0, sizeof(format));
1585                 format.pad = RESIZER_PAD_SINK;
1586                 format.which = which;
1587                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1588                 format.format.width = MAX_IN_WIDTH;
1589                 format.format.height = MAX_IN_HEIGHT;
1590                 resizer_set_format(sd, fh->pad, &format);
1591
1592                 memset(&format, 0, sizeof(format));
1593                 format.pad = RESIZER_PAD_SOURCE;
1594                 format.which = which;
1595                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1596                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
1597                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1598                 resizer_set_format(sd, fh->pad, &format);
1599         }
1600
1601         return 0;
1602 }
1603
1604 /* subdev core operations */
1605 static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
1606         .ioctl = resizer_ioctl,
1607 };
1608
1609 /* subdev internal operations */
1610 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1611         .open = resizer_init_formats,
1612 };
1613
1614 /* subdev video operations */
1615 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1616         .s_stream = resizer_set_stream,
1617 };
1618
1619 /* subdev pad operations */
1620 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1621         .enum_mbus_code = resizer_enum_mbus_code,
1622         .enum_frame_size = resizer_enum_frame_size,
1623         .get_fmt = resizer_get_format,
1624         .set_fmt = resizer_set_format,
1625 };
1626
1627 /* subdev operations */
1628 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1629         .core = &resizer_v4l2_core_ops,
1630         .video = &resizer_v4l2_video_ops,
1631         .pad = &resizer_v4l2_pad_ops,
1632 };
1633
1634 /*
1635  * Media entity operations
1636  */
1637
1638 /*
1639  * resizer_link_setup() - Setup resizer connections
1640  * @entity: Pointer to media entity structure
1641  * @local: Pointer to local pad array
1642  * @remote: Pointer to remote pad array
1643  * @flags: Link flags
1644  * return -EINVAL or zero on success
1645  */
1646 static int resizer_link_setup(struct media_entity *entity,
1647                            const struct media_pad *local,
1648                            const struct media_pad *remote, u32 flags)
1649 {
1650         struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1651         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1652         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1653         u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1654         u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
1655
1656         if (&resizer->crop_resizer.subdev == sd) {
1657                 switch (local->index | media_entity_type(remote->entity)) {
1658                 case RESIZER_CROP_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1659                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1660                                 resizer->crop_resizer.input =
1661                                         RESIZER_CROP_INPUT_NONE;
1662                                 break;
1663                         }
1664
1665                         if (resizer->crop_resizer.input !=
1666                            RESIZER_CROP_INPUT_NONE)
1667                                 return -EBUSY;
1668                         if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1669                                 resizer->crop_resizer.input =
1670                                                 RESIZER_CROP_INPUT_IPIPEIF;
1671                         else if (ipipe_source == IPIPE_OUTPUT_RESIZER)
1672                                         resizer->crop_resizer.input =
1673                                                 RESIZER_CROP_INPUT_IPIPE;
1674                         else
1675                                 return -EINVAL;
1676                         break;
1677
1678                 case RESIZER_CROP_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1679                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1680                                 resizer->crop_resizer.output =
1681                                 RESIZER_CROP_OUTPUT_NONE;
1682                                 break;
1683                         }
1684                         if (resizer->crop_resizer.output !=
1685                             RESIZER_CROP_OUTPUT_NONE)
1686                                 return -EBUSY;
1687                         resizer->crop_resizer.output = RESIZER_A;
1688                         break;
1689
1690                 case RESIZER_CROP_PAD_SOURCE2 | MEDIA_ENT_T_V4L2_SUBDEV:
1691                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1692                                 resizer->crop_resizer.output2 =
1693                                         RESIZER_CROP_OUTPUT_NONE;
1694                                 break;
1695                         }
1696                         if (resizer->crop_resizer.output2 !=
1697                             RESIZER_CROP_OUTPUT_NONE)
1698                                 return -EBUSY;
1699                         resizer->crop_resizer.output2 = RESIZER_B;
1700                         break;
1701
1702                 default:
1703                         return -EINVAL;
1704                 }
1705         } else if (&resizer->resizer_a.subdev == sd) {
1706                 switch (local->index | media_entity_type(remote->entity)) {
1707                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1708                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1709                                 resizer->resizer_a.input = RESIZER_INPUT_NONE;
1710                                 break;
1711                         }
1712                         if (resizer->resizer_a.input != RESIZER_INPUT_NONE)
1713                                 return -EBUSY;
1714                         resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
1715                         break;
1716
1717                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1718                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1719                                 resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
1720                                 break;
1721                         }
1722                         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1723                                 return -EBUSY;
1724                         resizer->resizer_a.output = RESIZER_OUPUT_MEMORY;
1725                         break;
1726
1727                 default:
1728                         return -EINVAL;
1729                 }
1730         } else if (&resizer->resizer_b.subdev == sd) {
1731                 switch (local->index | media_entity_type(remote->entity)) {
1732                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1733                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1734                                 resizer->resizer_b.input = RESIZER_INPUT_NONE;
1735                                 break;
1736                         }
1737                         if (resizer->resizer_b.input != RESIZER_INPUT_NONE)
1738                                 return -EBUSY;
1739                         resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
1740                         break;
1741
1742                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1743                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1744                                 resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
1745                                 break;
1746                         }
1747                         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1748                                 return -EBUSY;
1749                         resizer->resizer_b.output = RESIZER_OUPUT_MEMORY;
1750                         break;
1751
1752                 default:
1753                         return -EINVAL;
1754                 }
1755         } else {
1756                 return -EINVAL;
1757         }
1758
1759         return 0;
1760 }
1761
1762 static const struct media_entity_operations resizer_media_ops = {
1763         .link_setup = resizer_link_setup,
1764 };
1765
1766 /*
1767  * vpfe_resizer_unregister_entities() - Unregister entity
1768  * @vpfe_rsz - pointer to resizer subdevice structure.
1769  */
1770 void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
1771 {
1772         /* unregister video devices */
1773         vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
1774         vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
1775
1776         /* unregister subdev */
1777         v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
1778         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
1779         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
1780         /* cleanup entity */
1781         media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
1782         media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
1783         media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
1784 }
1785
1786 /*
1787  * vpfe_resizer_register_entities() - Register entity
1788  * @resizer - pointer to resizer devive.
1789  * @vdev: pointer to v4l2 device structure.
1790  */
1791 int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
1792                                    struct v4l2_device *vdev)
1793 {
1794         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1795         unsigned int flags = 0;
1796         int ret;
1797
1798         /* Register the crop resizer subdev */
1799         ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev);
1800         if (ret < 0) {
1801                 pr_err("Failed to register crop resizer as v4l2-subdev\n");
1802                 return ret;
1803         }
1804         /* Register Resizer-A subdev */
1805         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev);
1806         if (ret < 0) {
1807                 pr_err("Failed to register resizer-a as v4l2-subdev\n");
1808                 return ret;
1809         }
1810         /* Register Resizer-B subdev */
1811         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev);
1812         if (ret < 0) {
1813                 pr_err("Failed to register resizer-b as v4l2-subdev\n");
1814                 return ret;
1815         }
1816         /* Register video-out device for resizer-a */
1817         ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev);
1818         if (ret) {
1819                 pr_err("Failed to register RSZ-A video-out device\n");
1820                 goto out_video_out2_register;
1821         }
1822         resizer->resizer_a.video_out.vpfe_dev = vpfe_dev;
1823
1824         /* Register video-out device for resizer-b */
1825         ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev);
1826         if (ret) {
1827                 pr_err("Failed to register RSZ-B video-out device\n");
1828                 goto out_video_out2_register;
1829         }
1830         resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
1831
1832         /* create link between Resizer Crop----> Resizer A*/
1833         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 1,
1834                                 &resizer->resizer_a.subdev.entity,
1835                                 0, flags);
1836         if (ret < 0)
1837                 goto out_create_link;
1838
1839         /* create link between Resizer Crop----> Resizer B*/
1840         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 2,
1841                                 &resizer->resizer_b.subdev.entity,
1842                                 0, flags);
1843         if (ret < 0)
1844                 goto out_create_link;
1845
1846         /* create link between Resizer A ----> video out */
1847         ret = media_entity_create_link(&resizer->resizer_a.subdev.entity, 1,
1848                 &resizer->resizer_a.video_out.video_dev.entity, 0, flags);
1849         if (ret < 0)
1850                 goto out_create_link;
1851
1852         /* create link between Resizer B ----> video out */
1853         ret = media_entity_create_link(&resizer->resizer_b.subdev.entity, 1,
1854                 &resizer->resizer_b.video_out.video_dev.entity, 0, flags);
1855         if (ret < 0)
1856                 goto out_create_link;
1857
1858         return 0;
1859
1860 out_create_link:
1861         vpfe_video_unregister(&resizer->resizer_b.video_out);
1862 out_video_out2_register:
1863         vpfe_video_unregister(&resizer->resizer_a.video_out);
1864         v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
1865         v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
1866         v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
1867         media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
1868         media_entity_cleanup(&resizer->resizer_a.subdev.entity);
1869         media_entity_cleanup(&resizer->resizer_b.subdev.entity);
1870         return ret;
1871 }
1872
1873 /*
1874  * vpfe_resizer_init() - resizer device initialization.
1875  * @vpfe_rsz - pointer to resizer device
1876  * @pdev: platform device pointer.
1877  */
1878 int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
1879                       struct platform_device *pdev)
1880 {
1881         struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev;
1882         struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0];
1883         struct media_entity *me = &sd->entity;
1884         static resource_size_t  res_len;
1885         struct resource *res;
1886         int ret;
1887
1888         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1889         if (!res)
1890                 return -ENOENT;
1891
1892         res_len = resource_size(res);
1893         res = request_mem_region(res->start, res_len, res->name);
1894         if (!res)
1895                 return -EBUSY;
1896
1897         vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len);
1898         if (!vpfe_rsz->base_addr)
1899                 return -EBUSY;
1900
1901         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1902         sd->internal_ops = &resizer_v4l2_internal_ops;
1903         strlcpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
1904         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1905         v4l2_set_subdevdata(sd, vpfe_rsz);
1906         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1907
1908         pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1909         pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1910         pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
1911
1912         vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE;
1913         vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE;
1914         vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
1915         vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
1916         me->ops = &resizer_media_ops;
1917         ret = media_entity_init(me, RESIZER_CROP_PADS_NUM, pads, 0);
1918         if (ret)
1919                 return ret;
1920
1921         sd = &vpfe_rsz->resizer_a.subdev;
1922         pads = &vpfe_rsz->resizer_a.pads[0];
1923         me = &sd->entity;
1924
1925         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1926         sd->internal_ops = &resizer_v4l2_internal_ops;
1927         strlcpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
1928         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1929         v4l2_set_subdevdata(sd, vpfe_rsz);
1930         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1931
1932         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1933         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1934
1935         vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE;
1936         vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
1937         vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
1938         me->ops = &resizer_media_ops;
1939         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1940         if (ret)
1941                 return ret;
1942
1943         sd = &vpfe_rsz->resizer_b.subdev;
1944         pads = &vpfe_rsz->resizer_b.pads[0];
1945         me = &sd->entity;
1946
1947         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1948         sd->internal_ops = &resizer_v4l2_internal_ops;
1949         strlcpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
1950         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1951         v4l2_set_subdevdata(sd, vpfe_rsz);
1952         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1953
1954         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1955         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1956
1957         vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE;
1958         vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
1959         vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
1960         me->ops = &resizer_media_ops;
1961         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1962         if (ret)
1963                 return ret;
1964
1965         vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops;
1966         vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1967         ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A");
1968         if (ret) {
1969                 pr_err("Failed to init RSZ video-out device\n");
1970                 return ret;
1971         }
1972         vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops;
1973         vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1974         ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B");
1975         if (ret) {
1976                 pr_err("Failed to init RSZ video-out2 device\n");
1977                 return ret;
1978         }
1979         memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params));
1980
1981         return 0;
1982 }
1983
1984 void
1985 vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
1986                      struct platform_device *pdev)
1987 {
1988         struct resource *res;
1989
1990         iounmap(vpfe_rsz->base_addr);
1991         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1992         if (res)
1993                 release_mem_region(res->start,
1994                                         resource_size(res));
1995 }