Linux 3.18-rc3
[cascardo/linux.git] / 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         V4L2_MBUS_FMT_UYVY8_2X8,
39         V4L2_MBUS_FMT_Y8_1X8,
40         V4L2_MBUS_FMT_UV8_1X8,
41         V4L2_MBUS_FMT_SGRBG12_1X12,
42 };
43
44 static const unsigned int resizer_output_formats[] = {
45         V4L2_MBUS_FMT_UYVY8_2X8,
46         V4L2_MBUS_FMT_Y8_1X8,
47         V4L2_MBUS_FMT_UV8_1X8,
48         V4L2_MBUS_FMT_YDYUYDYV8_1X16,
49         V4L2_MBUS_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(enum v4l2_mbus_pixelcode pix, int width,
58                       int height, int *line_len, int *line_len_c)
59 {
60         *line_len = 0;
61         *line_len_c = 0;
62
63         if (pix == V4L2_MBUS_FMT_UYVY8_2X8 ||
64             pix == V4L2_MBUS_FMT_SGRBG12_1X12) {
65                 *line_len = width << 1;
66         } else if (pix == V4L2_MBUS_FMT_Y8_1X8 ||
67                    pix == V4L2_MBUS_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 != V4L2_MBUS_FMT_UYVY8_2X8 &&
89             format->code != V4L2_MBUS_FMT_Y8_1X8 &&
90             format->code != V4L2_MBUS_FMT_UV8_1X8 &&
91             format->code != V4L2_MBUS_FMT_YDYUYDYV8_1X16 &&
92             format->code != V4L2_MBUS_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 = (struct vpfe_rsz_output_spec *)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 == V4L2_MBUS_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 == V4L2_MBUS_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 == V4L2_MBUS_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 V4L2_MBUS_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 V4L2_MBUS_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 V4L2_MBUS_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 V4L2_MBUS_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 == V4L2_MBUS_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                                     enum v4l2_mbus_pixelcode pix,
544                                     int width, int height, int *line_len)
545 {
546         int val;
547
548         if (pix != V4L2_MBUS_FMT_UYVY8_2X8 &&
549             pix != V4L2_MBUS_FMT_Y8_1X8 &&
550             pix != V4L2_MBUS_FMT_UV8_1X8 &&
551             pix != V4L2_MBUS_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 == V4L2_MBUS_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 == V4L2_MBUS_FMT_SGRBG12_1X12)
713                         param->rsz_common.raw_flip = 1;
714                 else
715                         param->rsz_common.raw_flip = 0;
716
717                 if (outformat1->code == V4L2_MBUS_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 == V4L2_MBUS_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 == V4L2_MBUS_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 == V4L2_MBUS_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         memset(&resizer->config, 0, sizeof(struct resizer_params));
911         memcpy(&resizer->config, &rsz_default_config,
912                sizeof(struct resizer_params));
913 }
914
915 /*
916  * resizer_set_configuration() - set resizer config
917  * @resizer: vpfe resizer device pointer.
918  * @chan_config: resizer channel configuration.
919  */
920 static int
921 resizer_set_configuration(struct vpfe_resizer_device *resizer,
922                           struct vpfe_rsz_config *chan_config)
923 {
924         if (!chan_config->config)
925                 resizer_set_defualt_configuration(resizer);
926         else
927                 if (copy_from_user(&resizer->config.user_config,
928                     chan_config->config, sizeof(struct vpfe_rsz_config_params)))
929                         return -EFAULT;
930
931         return 0;
932 }
933
934 /*
935  * resizer_get_configuration() - get resizer config
936  * @resizer: vpfe resizer device pointer.
937  * @channel: image processor logical channel.
938  * @chan_config: resizer channel configuration.
939  */
940 static int
941 resizer_get_configuration(struct vpfe_resizer_device *resizer,
942                    struct vpfe_rsz_config *chan_config)
943 {
944         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
945
946         if (!chan_config->config) {
947                 dev_err(dev, "Resizer channel invalid pointer\n");
948                 return -EINVAL;
949         }
950
951         if (copy_to_user((void *)chan_config->config,
952            (void *)&resizer->config.user_config,
953            sizeof(struct vpfe_rsz_config_params))) {
954                 dev_err(dev, "resizer_get_configuration: Error in copy to user\n");
955                 return -EFAULT;
956         }
957
958         return 0;
959 }
960
961 /*
962  * VPFE video operations
963  */
964
965 /*
966  * resizer_a_video_out_queue() - RESIZER-A video out queue
967  * @vpfe_dev: vpfe device pointer.
968  * @addr: buffer address.
969  */
970 static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev,
971                                      unsigned long addr)
972 {
973         struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
974
975         return resizer_set_outaddr(resizer->base_addr,
976                                       &resizer->config, RSZ_A, addr);
977 }
978
979 /*
980  * resizer_b_video_out_queue() - RESIZER-B video out queue
981  * @vpfe_dev: vpfe device pointer.
982  * @addr: buffer address.
983  */
984 static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev,
985                                      unsigned long addr)
986 {
987         struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer;
988
989         return resizer_set_outaddr(resizer->base_addr,
990                                    &resizer->config, RSZ_B, addr);
991 }
992
993 static const struct vpfe_video_operations resizer_a_video_ops = {
994         .queue = resizer_a_video_out_queue,
995 };
996
997 static const struct vpfe_video_operations resizer_b_video_ops = {
998         .queue = resizer_b_video_out_queue,
999 };
1000
1001 static void resizer_enable(struct vpfe_resizer_device *resizer, int en)
1002 {
1003         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1004         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1005         unsigned char val;
1006
1007         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1008                 return;
1009
1010         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF &&
1011            ipipeif_sink == IPIPEIF_INPUT_MEMORY) {
1012                 do {
1013                         val = regr_rsz(resizer->base_addr, RSZ_SRC_EN);
1014                 } while (val);
1015
1016                 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
1017                         do {
1018                                 val = regr_rsz(resizer->base_addr, RSZ_A);
1019                         } while (val);
1020                 }
1021                 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
1022                         do {
1023                                 val = regr_rsz(resizer->base_addr, RSZ_B);
1024                         } while (val);
1025                 }
1026         }
1027         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1028                 rsz_enable(resizer->base_addr, RSZ_A, en);
1029
1030         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1031                 rsz_enable(resizer->base_addr, RSZ_B, en);
1032 }
1033
1034
1035 /*
1036  * resizer_ss_isr() - resizer module single-shot buffer scheduling isr
1037  * @resizer: vpfe resizer device pointer.
1038  */
1039 static void resizer_ss_isr(struct vpfe_resizer_device *resizer)
1040 {
1041         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1042         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1043         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1044         struct vpfe_pipeline *pipe = &video_out->pipe;
1045         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1046         u32 val;
1047
1048         if (ipipeif_sink != IPIPEIF_INPUT_MEMORY)
1049                 return;
1050
1051         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1052                 val = vpss_dma_complete_interrupt();
1053                 if (val != 0 && val != 2)
1054                         return;
1055         }
1056
1057         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1058                 spin_lock(&video_out->dma_queue_lock);
1059                 vpfe_video_process_buffer_complete(video_out);
1060                 video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1061                 vpfe_video_schedule_next_buffer(video_out);
1062                 spin_unlock(&video_out->dma_queue_lock);
1063         }
1064
1065         /* If resizer B is enabled */
1066         if (pipe->output_num > 1 && resizer->resizer_b.output ==
1067             RESIZER_OUPUT_MEMORY) {
1068                 spin_lock(&video_out->dma_queue_lock);
1069                 vpfe_video_process_buffer_complete(video_out2);
1070                 video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED;
1071                 vpfe_video_schedule_next_buffer(video_out2);
1072                 spin_unlock(&video_out2->dma_queue_lock);
1073         }
1074
1075         /* start HW if buffers are queued */
1076         if (vpfe_video_is_pipe_ready(pipe) &&
1077             resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) {
1078                 resizer_enable(resizer, 1);
1079                 vpfe_ipipe_enable(vpfe_dev, 1);
1080                 vpfe_ipipeif_enable(vpfe_dev);
1081         }
1082 }
1083
1084 /*
1085  * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr
1086  * @resizer: vpfe resizer device pointer.
1087  */
1088 void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer)
1089 {
1090         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1091         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1092         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1093         struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe;
1094         enum v4l2_field field;
1095         int fid;
1096
1097         if (!video_out->started)
1098                 return;
1099
1100         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE)
1101                 return;
1102
1103         field = video_out->fmt.fmt.pix.field;
1104         if (field == V4L2_FIELD_NONE) {
1105                 /* handle progressive frame capture */
1106                 if (video_out->cur_frm != video_out->next_frm) {
1107                         vpfe_video_process_buffer_complete(video_out);
1108                         if (pipe->output_num > 1)
1109                                 vpfe_video_process_buffer_complete(video_out2);
1110                 }
1111
1112                 video_out->skip_frame_count--;
1113                 if (!video_out->skip_frame_count) {
1114                         video_out->skip_frame_count =
1115                                 video_out->skip_frame_count_init;
1116                         rsz_src_enable(resizer->base_addr, 1);
1117                 } else {
1118                         rsz_src_enable(resizer->base_addr, 0);
1119                 }
1120                 return;
1121         }
1122
1123         /* handle interlaced frame capture */
1124         fid = vpfe_isif_get_fid(vpfe_dev);
1125
1126         /* switch the software maintained field id */
1127         video_out->field_id ^= 1;
1128         if (fid == video_out->field_id) {
1129                 /*
1130                  * we are in-sync here,continue.
1131                  * One frame is just being captured. If the
1132                  * next frame is available, release the current
1133                  * frame and move on
1134                  */
1135                 if (fid == 0 && video_out->cur_frm != video_out->next_frm) {
1136                         vpfe_video_process_buffer_complete(video_out);
1137                         if (pipe->output_num > 1)
1138                                 vpfe_video_process_buffer_complete(video_out2);
1139                 }
1140         } else if (fid == 0) {
1141                 /*
1142                 * out of sync. Recover from any hardware out-of-sync.
1143                 * May loose one frame
1144                 */
1145                 video_out->field_id = fid;
1146         }
1147 }
1148
1149 /*
1150  * vpfe_resizer_dma_isr() - resizer module dma isr
1151  * @resizer: vpfe resizer device pointer.
1152  */
1153 void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer)
1154 {
1155         struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out;
1156         struct vpfe_video_device *video_out = &resizer->resizer_a.video_out;
1157         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1158         struct vpfe_pipeline *pipe = &video_out->pipe;
1159         int schedule_capture = 0;
1160         enum v4l2_field field;
1161         int fid;
1162
1163         if (!video_out->started)
1164                 return;
1165
1166         if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) {
1167                 resizer_ss_isr(resizer);
1168                 return;
1169         }
1170
1171         field = video_out->fmt.fmt.pix.field;
1172         if (field == V4L2_FIELD_NONE) {
1173                 if (!list_empty(&video_out->dma_queue) &&
1174                         video_out->cur_frm == video_out->next_frm)
1175                         schedule_capture = 1;
1176         } else {
1177                 fid = vpfe_isif_get_fid(vpfe_dev);
1178                 if (fid == video_out->field_id) {
1179                         /* we are in-sync here,continue */
1180                         if (fid == 1 && !list_empty(&video_out->dma_queue) &&
1181                             video_out->cur_frm == video_out->next_frm)
1182                                 schedule_capture = 1;
1183                 }
1184         }
1185
1186         if (!schedule_capture)
1187                 return;
1188
1189         spin_lock(&video_out->dma_queue_lock);
1190         vpfe_video_schedule_next_buffer(video_out);
1191         spin_unlock(&video_out->dma_queue_lock);
1192         if (pipe->output_num > 1) {
1193                 spin_lock(&video_out2->dma_queue_lock);
1194                 vpfe_video_schedule_next_buffer(video_out2);
1195                 spin_unlock(&video_out2->dma_queue_lock);
1196         }
1197 }
1198
1199 /*
1200  * V4L2 subdev operations
1201  */
1202
1203 /*
1204  * resizer_ioctl() - Handle resizer module private ioctl's
1205  * @sd: pointer to v4l2 subdev structure
1206  * @cmd: configuration command
1207  * @arg: configuration argument
1208  */
1209 static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
1210 {
1211         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1212         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
1213         struct vpfe_rsz_config *user_config;
1214         int ret = -ENOIOCTLCMD;
1215
1216         if (&resizer->crop_resizer.subdev != sd)
1217                 return ret;
1218
1219         switch (cmd) {
1220         case VIDIOC_VPFE_RSZ_S_CONFIG:
1221                 user_config = (struct vpfe_rsz_config *)arg;
1222                 ret = resizer_set_configuration(resizer, user_config);
1223                 break;
1224
1225         case VIDIOC_VPFE_RSZ_G_CONFIG:
1226                 user_config = (struct vpfe_rsz_config *)arg;
1227                 if (!user_config->config) {
1228                         dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n");
1229                         return -EINVAL;
1230                 }
1231                 ret = resizer_get_configuration(resizer, user_config);
1232                 break;
1233         }
1234         return ret;
1235 }
1236
1237 static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer)
1238 {
1239         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1240         u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input;
1241         u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1242         struct resizer_params *param = &resizer->config;
1243         int ret = 0;
1244
1245         if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY ||
1246             resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) {
1247                 if (ipipeif_sink == IPIPEIF_INPUT_MEMORY &&
1248                     ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1249                         ret = resizer_configure_in_single_shot_mode(resizer);
1250                 else
1251                         ret =  resizer_configure_in_continious_mode(resizer);
1252                 if (ret)
1253                         return ret;
1254                 ret = config_rsz_hw(resizer, param);
1255         }
1256         return ret;
1257 }
1258
1259 /*
1260  * resizer_set_stream() - Enable/Disable streaming on resizer subdev
1261  * @sd: pointer to v4l2 subdev structure
1262  * @enable: 1 == Enable, 0 == Disable
1263  */
1264 static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1265 {
1266         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1267
1268         if (&resizer->crop_resizer.subdev != sd)
1269                 return 0;
1270
1271         if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY)
1272                 return 0;
1273
1274         switch (enable) {
1275         case 1:
1276                 if (resizer_do_hw_setup(resizer) < 0)
1277                         return -EINVAL;
1278                 resizer_enable(resizer, enable);
1279                 break;
1280
1281         case 0:
1282                 resizer_enable(resizer, enable);
1283                 break;
1284         }
1285
1286         return 0;
1287 }
1288
1289 /*
1290  * __resizer_get_format() - helper function for getting resizer format
1291  * @sd: pointer to subdev.
1292  * @fh: V4L2 subdev file handle.
1293  * @pad: pad number.
1294  * @which: wanted subdev format.
1295  * Retun wanted mbus frame format.
1296  */
1297 static struct v4l2_mbus_framefmt *
1298 __resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1299                      unsigned int pad, enum v4l2_subdev_format_whence which)
1300 {
1301         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1302
1303         if (which == V4L2_SUBDEV_FORMAT_TRY)
1304                 return v4l2_subdev_get_try_format(fh, pad);
1305         if (&resizer->crop_resizer.subdev == sd)
1306                 return &resizer->crop_resizer.formats[pad];
1307         if (&resizer->resizer_a.subdev == sd)
1308                 return &resizer->resizer_a.formats[pad];
1309         if (&resizer->resizer_b.subdev == sd)
1310                 return &resizer->resizer_b.formats[pad];
1311         return NULL;
1312 }
1313
1314 /*
1315  * resizer_try_format() - Handle try format by pad subdev method
1316  * @sd: pointer to subdev.
1317  * @fh: V4L2 subdev file handle.
1318  * @pad: pad num.
1319  * @fmt: pointer to v4l2 format structure.
1320  * @which: wanted subdev format.
1321  */
1322 static void
1323 resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1324         unsigned int pad, struct v4l2_mbus_framefmt *fmt,
1325         enum v4l2_subdev_format_whence which)
1326 {
1327         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1328         unsigned int max_out_height;
1329         unsigned int max_out_width;
1330         unsigned int i;
1331
1332         if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) ||
1333             (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) ||
1334             (&resizer->crop_resizer.subdev == sd &&
1335             (pad == RESIZER_CROP_PAD_SOURCE ||
1336             pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) {
1337                 for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) {
1338                         if (fmt->code == resizer_input_formats[i])
1339                                 break;
1340                 }
1341                 /* If not found, use UYVY as default */
1342                 if (i >= ARRAY_SIZE(resizer_input_formats))
1343                         fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
1344
1345                 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1346                                         MAX_IN_WIDTH);
1347                 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1348                                 MAX_IN_HEIGHT);
1349         } else if (&resizer->resizer_a.subdev == sd &&
1350                    pad == RESIZER_PAD_SOURCE) {
1351                 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A;
1352                 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1353
1354                 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1355                         if (fmt->code == resizer_output_formats[i])
1356                                 break;
1357                 }
1358                 /* If not found, use UYVY as default */
1359                 if (i >= ARRAY_SIZE(resizer_output_formats))
1360                         fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
1361
1362                 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1363                                         max_out_width);
1364                 fmt->width &= ~15;
1365                 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1366                                 max_out_height);
1367         } else if (&resizer->resizer_b.subdev == sd &&
1368                    pad == RESIZER_PAD_SOURCE) {
1369                 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B;
1370                 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1371
1372                 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) {
1373                         if (fmt->code == resizer_output_formats[i])
1374                                 break;
1375                 }
1376                 /* If not found, use UYVY as default */
1377                 if (i >= ARRAY_SIZE(resizer_output_formats))
1378                         fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
1379
1380                 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
1381                                         max_out_width);
1382                 fmt->width &= ~15;
1383                 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT,
1384                                 max_out_height);
1385         }
1386 }
1387
1388 /*
1389  * resizer_set_format() - Handle set format by pads subdev method
1390  * @sd: pointer to v4l2 subdev structure
1391  * @fh: V4L2 subdev file handle
1392  * @fmt: pointer to v4l2 subdev format structure
1393  * return -EINVAL or zero on success
1394  */
1395 static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1396                            struct v4l2_subdev_format *fmt)
1397 {
1398         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1399         struct v4l2_mbus_framefmt *format;
1400
1401         format = __resizer_get_format(sd, fh, fmt->pad, fmt->which);
1402         if (format == NULL)
1403                 return -EINVAL;
1404
1405         resizer_try_format(sd, fh, fmt->pad, &fmt->format, fmt->which);
1406         *format = fmt->format;
1407
1408         if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
1409                 return 0;
1410
1411         if (&resizer->crop_resizer.subdev == sd) {
1412                 if (fmt->pad == RESIZER_CROP_PAD_SINK) {
1413                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1414                 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE &&
1415                                 resizer->crop_resizer.output == RESIZER_A) {
1416                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1417                         resizer->crop_resizer.
1418                         formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format;
1419                 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 &&
1420                         resizer->crop_resizer.output2 == RESIZER_B) {
1421                         resizer->crop_resizer.formats[fmt->pad] = fmt->format;
1422                         resizer->crop_resizer.
1423                         formats[RESIZER_CROP_PAD_SOURCE] = fmt->format;
1424                 } else {
1425                         return -EINVAL;
1426                 }
1427         } else if (&resizer->resizer_a.subdev == sd) {
1428                 if (fmt->pad == RESIZER_PAD_SINK)
1429                         resizer->resizer_a.formats[fmt->pad] = fmt->format;
1430                 else if (fmt->pad == RESIZER_PAD_SOURCE)
1431                         resizer->resizer_a.formats[fmt->pad] = fmt->format;
1432                 else
1433                         return -EINVAL;
1434         } else if (&resizer->resizer_b.subdev == sd) {
1435                 if (fmt->pad == RESIZER_PAD_SINK)
1436                         resizer->resizer_b.formats[fmt->pad] = fmt->format;
1437                 else if (fmt->pad == RESIZER_PAD_SOURCE)
1438                         resizer->resizer_b.formats[fmt->pad] = fmt->format;
1439                 else
1440                         return -EINVAL;
1441         } else {
1442                 return -EINVAL;
1443         }
1444
1445         return 0;
1446 }
1447
1448 /*
1449  * resizer_get_format() - Retrieve the video format on a pad
1450  * @sd: pointer to v4l2 subdev structure.
1451  * @fh: V4L2 subdev file handle.
1452  * @fmt: pointer to v4l2 subdev format structure
1453  * return -EINVAL or zero on success
1454  */
1455 static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1456                            struct v4l2_subdev_format *fmt)
1457 {
1458         struct v4l2_mbus_framefmt *format;
1459
1460         format = __resizer_get_format(sd, fh, fmt->pad, fmt->which);
1461         if (format == NULL)
1462                 return -EINVAL;
1463
1464         fmt->format = *format;
1465
1466         return 0;
1467 }
1468
1469 /*
1470  * resizer_enum_frame_size() - enum frame sizes on pads
1471  * @sd: Pointer to subdevice.
1472  * @fh: V4L2 subdev file handle.
1473  * @code: pointer to v4l2_subdev_frame_size_enum structure.
1474  */
1475 static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1476                                    struct v4l2_subdev_fh *fh,
1477                                    struct v4l2_subdev_frame_size_enum *fse)
1478 {
1479         struct v4l2_mbus_framefmt format;
1480
1481         if (fse->index != 0)
1482                 return -EINVAL;
1483
1484         format.code = fse->code;
1485         format.width = 1;
1486         format.height = 1;
1487         resizer_try_format(sd, fh, fse->pad, &format,
1488                             V4L2_SUBDEV_FORMAT_TRY);
1489         fse->min_width = format.width;
1490         fse->min_height = format.height;
1491
1492         if (format.code != fse->code)
1493                 return -EINVAL;
1494
1495         format.code = fse->code;
1496         format.width = -1;
1497         format.height = -1;
1498         resizer_try_format(sd, fh, fse->pad, &format,
1499                            V4L2_SUBDEV_FORMAT_TRY);
1500         fse->max_width = format.width;
1501         fse->max_height = format.height;
1502
1503         return 0;
1504 }
1505
1506 /*
1507  * resizer_enum_mbus_code() - enum mbus codes for pads
1508  * @sd: Pointer to subdevice.
1509  * @fh: V4L2 subdev file handle
1510  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1511  */
1512 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1513                                   struct v4l2_subdev_fh *fh,
1514                                   struct v4l2_subdev_mbus_code_enum *code)
1515 {
1516         if (code->pad == RESIZER_PAD_SINK) {
1517                 if (code->index >= ARRAY_SIZE(resizer_input_formats))
1518                         return -EINVAL;
1519
1520                 code->code = resizer_input_formats[code->index];
1521         } else if (code->pad == RESIZER_PAD_SOURCE) {
1522                 if (code->index >= ARRAY_SIZE(resizer_output_formats))
1523                         return -EINVAL;
1524
1525                 code->code = resizer_output_formats[code->index];
1526         }
1527
1528         return 0;
1529 }
1530
1531 /*
1532  * resizer_init_formats() - Initialize formats on all pads
1533  * @sd: Pointer to subdevice.
1534  * @fh: V4L2 subdev file handle.
1535  *
1536  * Initialize all pad formats with default values. If fh is not NULL, try
1537  * formats are initialized on the file handle. Otherwise active formats are
1538  * initialized on the device.
1539  */
1540 static int resizer_init_formats(struct v4l2_subdev *sd,
1541                                 struct v4l2_subdev_fh *fh)
1542 {
1543         __u32 which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1544         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1545         struct v4l2_subdev_format format;
1546
1547         if (&resizer->crop_resizer.subdev == sd) {
1548                 memset(&format, 0, sizeof(format));
1549                 format.pad = RESIZER_CROP_PAD_SINK;
1550                 format.which = which;
1551                 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
1552                 format.format.width = MAX_IN_WIDTH;
1553                 format.format.height = MAX_IN_HEIGHT;
1554                 resizer_set_format(sd, fh, &format);
1555
1556                 memset(&format, 0, sizeof(format));
1557                 format.pad = RESIZER_CROP_PAD_SOURCE;
1558                 format.which = which;
1559                 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
1560                 format.format.width = MAX_IN_WIDTH;
1561                 format.format.height = MAX_IN_WIDTH;
1562                 resizer_set_format(sd, fh, &format);
1563
1564                 memset(&format, 0, sizeof(format));
1565                 format.pad = RESIZER_CROP_PAD_SOURCE2;
1566                 format.which = which;
1567                 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
1568                 format.format.width = MAX_IN_WIDTH;
1569                 format.format.height = MAX_IN_WIDTH;
1570                 resizer_set_format(sd, fh, &format);
1571         } else if (&resizer->resizer_a.subdev == sd) {
1572                 memset(&format, 0, sizeof(format));
1573                 format.pad = RESIZER_PAD_SINK;
1574                 format.which = which;
1575                 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
1576                 format.format.width = MAX_IN_WIDTH;
1577                 format.format.height = MAX_IN_HEIGHT;
1578                 resizer_set_format(sd, fh, &format);
1579
1580                 memset(&format, 0, sizeof(format));
1581                 format.pad = RESIZER_PAD_SOURCE;
1582                 format.which = which;
1583                 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
1584                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
1585                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1586                 resizer_set_format(sd, fh, &format);
1587         } else if (&resizer->resizer_b.subdev == sd) {
1588                 memset(&format, 0, sizeof(format));
1589                 format.pad = RESIZER_PAD_SINK;
1590                 format.which = which;
1591                 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
1592                 format.format.width = MAX_IN_WIDTH;
1593                 format.format.height = MAX_IN_HEIGHT;
1594                 resizer_set_format(sd, fh, &format);
1595
1596                 memset(&format, 0, sizeof(format));
1597                 format.pad = RESIZER_PAD_SOURCE;
1598                 format.which = which;
1599                 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
1600                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
1601                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1602                 resizer_set_format(sd, fh, &format);
1603         }
1604
1605         return 0;
1606 }
1607
1608 /* subdev core operations */
1609 static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
1610         .ioctl = resizer_ioctl,
1611 };
1612
1613 /* subdev internal operations */
1614 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1615         .open = resizer_init_formats,
1616 };
1617
1618 /* subdev video operations */
1619 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1620         .s_stream = resizer_set_stream,
1621 };
1622
1623 /* subdev pad operations */
1624 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1625         .enum_mbus_code = resizer_enum_mbus_code,
1626         .enum_frame_size = resizer_enum_frame_size,
1627         .get_fmt = resizer_get_format,
1628         .set_fmt = resizer_set_format,
1629 };
1630
1631 /* subdev operations */
1632 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1633         .core = &resizer_v4l2_core_ops,
1634         .video = &resizer_v4l2_video_ops,
1635         .pad = &resizer_v4l2_pad_ops,
1636 };
1637
1638 /*
1639  * Media entity operations
1640  */
1641
1642 /*
1643  * resizer_link_setup() - Setup resizer connections
1644  * @entity: Pointer to media entity structure
1645  * @local: Pointer to local pad array
1646  * @remote: Pointer to remote pad array
1647  * @flags: Link flags
1648  * return -EINVAL or zero on success
1649  */
1650 static int resizer_link_setup(struct media_entity *entity,
1651                            const struct media_pad *local,
1652                            const struct media_pad *remote, u32 flags)
1653 {
1654         struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1655         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1656         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1657         u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1658         u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
1659
1660         if (&resizer->crop_resizer.subdev == sd) {
1661                 switch (local->index | media_entity_type(remote->entity)) {
1662                 case RESIZER_CROP_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1663                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1664                                 resizer->crop_resizer.input =
1665                                         RESIZER_CROP_INPUT_NONE;
1666                                 break;
1667                         }
1668
1669                         if (resizer->crop_resizer.input !=
1670                            RESIZER_CROP_INPUT_NONE)
1671                                 return -EBUSY;
1672                         if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1673                                 resizer->crop_resizer.input =
1674                                                 RESIZER_CROP_INPUT_IPIPEIF;
1675                         else if (ipipe_source == IPIPE_OUTPUT_RESIZER)
1676                                         resizer->crop_resizer.input =
1677                                                 RESIZER_CROP_INPUT_IPIPE;
1678                         else
1679                                 return -EINVAL;
1680                         break;
1681
1682                 case RESIZER_CROP_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1683                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1684                                 resizer->crop_resizer.output =
1685                                 RESIZER_CROP_OUTPUT_NONE;
1686                                 break;
1687                         }
1688                         if (resizer->crop_resizer.output !=
1689                             RESIZER_CROP_OUTPUT_NONE)
1690                                 return -EBUSY;
1691                         resizer->crop_resizer.output = RESIZER_A;
1692                         break;
1693
1694                 case RESIZER_CROP_PAD_SOURCE2 | MEDIA_ENT_T_V4L2_SUBDEV:
1695                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1696                                 resizer->crop_resizer.output2 =
1697                                         RESIZER_CROP_OUTPUT_NONE;
1698                                 break;
1699                         }
1700                         if (resizer->crop_resizer.output2 !=
1701                             RESIZER_CROP_OUTPUT_NONE)
1702                                 return -EBUSY;
1703                         resizer->crop_resizer.output2 = RESIZER_B;
1704                         break;
1705
1706                 default:
1707                         return -EINVAL;
1708                 }
1709         } else if (&resizer->resizer_a.subdev == sd) {
1710                 switch (local->index | media_entity_type(remote->entity)) {
1711                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1712                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1713                                 resizer->resizer_a.input = RESIZER_INPUT_NONE;
1714                                 break;
1715                         }
1716                         if (resizer->resizer_a.input != RESIZER_INPUT_NONE)
1717                                 return -EBUSY;
1718                         resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
1719                         break;
1720
1721                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1722                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1723                                 resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
1724                                 break;
1725                         }
1726                         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1727                                 return -EBUSY;
1728                         resizer->resizer_a.output = RESIZER_OUPUT_MEMORY;
1729                         break;
1730
1731                 default:
1732                         return -EINVAL;
1733                 }
1734         } else if (&resizer->resizer_b.subdev == sd) {
1735                 switch (local->index | media_entity_type(remote->entity)) {
1736                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1737                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1738                                 resizer->resizer_b.input = RESIZER_INPUT_NONE;
1739                                 break;
1740                         }
1741                         if (resizer->resizer_b.input != RESIZER_INPUT_NONE)
1742                                 return -EBUSY;
1743                         resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
1744                         break;
1745
1746                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1747                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1748                                 resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
1749                                 break;
1750                         }
1751                         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1752                                 return -EBUSY;
1753                         resizer->resizer_b.output = RESIZER_OUPUT_MEMORY;
1754                         break;
1755
1756                 default:
1757                         return -EINVAL;
1758                 }
1759         } else {
1760                 return -EINVAL;
1761         }
1762
1763         return 0;
1764 }
1765
1766 static const struct media_entity_operations resizer_media_ops = {
1767         .link_setup = resizer_link_setup,
1768 };
1769
1770 /*
1771  * vpfe_resizer_unregister_entities() - Unregister entity
1772  * @vpfe_rsz - pointer to resizer subdevice structure.
1773  */
1774 void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
1775 {
1776         /* unregister video devices */
1777         vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
1778         vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
1779
1780         /* unregister subdev */
1781         v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
1782         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
1783         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
1784         /* cleanup entity */
1785         media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
1786         media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
1787         media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
1788 }
1789
1790 /*
1791  * vpfe_resizer_register_entities() - Register entity
1792  * @resizer - pointer to resizer devive.
1793  * @vdev: pointer to v4l2 device structure.
1794  */
1795 int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
1796                                    struct v4l2_device *vdev)
1797 {
1798         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1799         unsigned int flags = 0;
1800         int ret;
1801
1802         /* Register the crop resizer subdev */
1803         ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev);
1804         if (ret < 0) {
1805                 pr_err("Failed to register crop resizer as v4l2-subdev\n");
1806                 return ret;
1807         }
1808         /* Register Resizer-A subdev */
1809         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev);
1810         if (ret < 0) {
1811                 pr_err("Failed to register resizer-a as v4l2-subdev\n");
1812                 return ret;
1813         }
1814         /* Register Resizer-B subdev */
1815         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev);
1816         if (ret < 0) {
1817                 pr_err("Failed to register resizer-b as v4l2-subdev\n");
1818                 return ret;
1819         }
1820         /* Register video-out device for resizer-a */
1821         ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev);
1822         if (ret) {
1823                 pr_err("Failed to register RSZ-A video-out device\n");
1824                 goto out_video_out2_register;
1825         }
1826         resizer->resizer_a.video_out.vpfe_dev = vpfe_dev;
1827
1828         /* Register video-out device for resizer-b */
1829         ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev);
1830         if (ret) {
1831                 pr_err("Failed to register RSZ-B video-out device\n");
1832                 goto out_video_out2_register;
1833         }
1834         resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
1835
1836         /* create link between Resizer Crop----> Resizer A*/
1837         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 1,
1838                                 &resizer->resizer_a.subdev.entity,
1839                                 0, flags);
1840         if (ret < 0)
1841                 goto out_create_link;
1842
1843         /* create link between Resizer Crop----> Resizer B*/
1844         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 2,
1845                                 &resizer->resizer_b.subdev.entity,
1846                                 0, flags);
1847         if (ret < 0)
1848                 goto out_create_link;
1849
1850         /* create link between Resizer A ----> video out */
1851         ret = media_entity_create_link(&resizer->resizer_a.subdev.entity, 1,
1852                 &resizer->resizer_a.video_out.video_dev.entity, 0, flags);
1853         if (ret < 0)
1854                 goto out_create_link;
1855
1856         /* create link between Resizer B ----> video out */
1857         ret = media_entity_create_link(&resizer->resizer_b.subdev.entity, 1,
1858                 &resizer->resizer_b.video_out.video_dev.entity, 0, flags);
1859         if (ret < 0)
1860                 goto out_create_link;
1861
1862         return 0;
1863
1864 out_create_link:
1865         vpfe_video_unregister(&resizer->resizer_b.video_out);
1866 out_video_out2_register:
1867         vpfe_video_unregister(&resizer->resizer_a.video_out);
1868         v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
1869         v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
1870         v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
1871         media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
1872         media_entity_cleanup(&resizer->resizer_a.subdev.entity);
1873         media_entity_cleanup(&resizer->resizer_b.subdev.entity);
1874         return ret;
1875 }
1876
1877 /*
1878  * vpfe_resizer_init() - resizer device initialization.
1879  * @vpfe_rsz - pointer to resizer device
1880  * @pdev: platform device pointer.
1881  */
1882 int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
1883                       struct platform_device *pdev)
1884 {
1885         struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev;
1886         struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0];
1887         struct media_entity *me = &sd->entity;
1888         static resource_size_t  res_len;
1889         struct resource *res;
1890         int ret;
1891
1892         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1893         if (!res)
1894                 return -ENOENT;
1895
1896         res_len = resource_size(res);
1897         res = request_mem_region(res->start, res_len, res->name);
1898         if (!res)
1899                 return -EBUSY;
1900
1901         vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len);
1902         if (!vpfe_rsz->base_addr)
1903                 return -EBUSY;
1904
1905         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1906         sd->internal_ops = &resizer_v4l2_internal_ops;
1907         strlcpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
1908         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1909         v4l2_set_subdevdata(sd, vpfe_rsz);
1910         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1911
1912         pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1913         pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1914         pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
1915
1916         vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE;
1917         vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE;
1918         vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
1919         vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
1920         me->ops = &resizer_media_ops;
1921         ret = media_entity_init(me, RESIZER_CROP_PADS_NUM, pads, 0);
1922         if (ret)
1923                 return ret;
1924
1925         sd = &vpfe_rsz->resizer_a.subdev;
1926         pads = &vpfe_rsz->resizer_a.pads[0];
1927         me = &sd->entity;
1928
1929         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1930         sd->internal_ops = &resizer_v4l2_internal_ops;
1931         strlcpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
1932         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1933         v4l2_set_subdevdata(sd, vpfe_rsz);
1934         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1935
1936         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1937         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1938
1939         vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE;
1940         vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
1941         vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
1942         me->ops = &resizer_media_ops;
1943         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1944         if (ret)
1945                 return ret;
1946
1947         sd = &vpfe_rsz->resizer_b.subdev;
1948         pads = &vpfe_rsz->resizer_b.pads[0];
1949         me = &sd->entity;
1950
1951         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1952         sd->internal_ops = &resizer_v4l2_internal_ops;
1953         strlcpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
1954         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1955         v4l2_set_subdevdata(sd, vpfe_rsz);
1956         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1957
1958         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1959         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1960
1961         vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE;
1962         vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
1963         vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
1964         me->ops = &resizer_media_ops;
1965         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1966         if (ret)
1967                 return ret;
1968
1969         vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops;
1970         vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1971         ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A");
1972         if (ret) {
1973                 pr_err("Failed to init RSZ video-out device\n");
1974                 return ret;
1975         }
1976         vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops;
1977         vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1978         ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B");
1979         if (ret) {
1980                 pr_err("Failed to init RSZ video-out2 device\n");
1981                 return ret;
1982         }
1983         memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params));
1984
1985         return 0;
1986 }
1987
1988 void
1989 vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
1990                      struct platform_device *pdev)
1991 {
1992         struct resource *res;
1993
1994         iounmap(vpfe_rsz->base_addr);
1995         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1996         if (res)
1997                 release_mem_region(res->start,
1998                                         resource_size(res));
1999 }