These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[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         memset(&output_specs, 0x0, sizeof(struct vpfe_rsz_output_spec));
325         output_specs.vst_y = param->user_config.vst;
326         if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
327                 output_specs.vst_c = param->user_config.vst;
328
329         configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0);
330         resizer_calculate_line_length(outformat->code,
331                                       param->rsz_rsc_param[0].o_hsz + 1,
332                                       param->rsz_rsc_param[0].o_vsz + 1,
333                                       &line_len, &line_len_c);
334         param->ext_mem_param[0].rsz_sdr_oft_y = line_len;
335         param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c;
336         resizer_calculate_resize_ratios(resizer, RSZ_A);
337         if (param->rsz_en[RSZ_B])
338                 resizer_calculate_resize_ratios(resizer, RSZ_B);
339
340         if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
341                 resizer_enable_422_420_conversion(param, RSZ_A, ENABLE);
342         else
343                 resizer_enable_422_420_conversion(param, RSZ_A, DISABLE);
344
345         ret = resizer_calculate_sdram_offsets(resizer, RSZ_A);
346         if (!ret && param->rsz_en[RSZ_B])
347                 ret = resizer_calculate_sdram_offsets(resizer, RSZ_B);
348
349         if (ret)
350                 pr_err("Error in calculating sdram offsets\n");
351         return ret;
352 }
353
354 static int
355 resizer_calculate_down_scale_f_div_param(struct device *dev,
356                                          int input_width, int output_width,
357                                          struct resizer_scale_param *param)
358 {
359         /* rsz = R, input_width = H, output width = h in the equation */
360         unsigned int two_power;
361         unsigned int upper_h1;
362         unsigned int upper_h2;
363         unsigned int val1;
364         unsigned int val;
365         unsigned int rsz;
366         unsigned int h1;
367         unsigned int h2;
368         unsigned int o;
369         unsigned int n;
370
371         upper_h1 = input_width >> 1;
372         n = param->h_dscale_ave_sz;
373         /* 2 ^ (scale+1) */
374         two_power = 1 << (n + 1);
375         upper_h1 = (upper_h1 >> (n + 1)) << (n + 1);
376         upper_h2 = input_width - upper_h1;
377         if (upper_h2 % two_power) {
378                 dev_err(dev, "frame halves to be a multiple of 2 power n+1\n");
379                 return -EINVAL;
380         }
381         two_power = 1 << n;
382         rsz = (input_width << 8) / output_width;
383         val = rsz * two_power;
384         val = ((upper_h1 << 8) / val) + 1;
385         if (!(val % 2)) {
386                 h1 = val;
387         } else {
388                 val = upper_h1 << 8;
389                 val >>= n + 1;
390                 val -= rsz >> 1;
391                 val /= rsz << 1;
392                 val <<= 1;
393                 val += 2;
394                 h1 = val;
395         }
396         o = 10 + (two_power << 2);
397         if (((input_width << 7) / rsz) % 2)
398                 o += (((CEIL(rsz, 1024)) << 1) << n);
399         h2 = output_width - h1;
400         /* phi */
401         val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8);
402         /* skip */
403         val1 = ((val - 1024) >> 9) << 1;
404         param->f_div.num_passes = MAX_PASSES;
405         param->f_div.pass[0].o_hsz = h1 - 1;
406         param->f_div.pass[0].i_hps = 0;
407         param->f_div.pass[0].h_phs = 0;
408         param->f_div.pass[0].src_hps = 0;
409         param->f_div.pass[0].src_hsz = upper_h1 + o;
410         param->f_div.pass[1].o_hsz = h2 - 1;
411         param->f_div.pass[1].i_hps = 10 + (val1 * two_power);
412         param->f_div.pass[1].h_phs = (val - (val1 << 8));
413         param->f_div.pass[1].src_hps = upper_h1 - o;
414         param->f_div.pass[1].src_hsz = upper_h2 + o;
415
416         return 0;
417 }
418
419 static int
420 resizer_configure_common_in_params(struct vpfe_resizer_device *resizer)
421 {
422         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
423         struct resizer_params *param = &resizer->config;
424         struct vpfe_rsz_config_params *user_config;
425         struct v4l2_mbus_framefmt *informat;
426
427         informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
428         user_config = &resizer->config.user_config;
429         param->rsz_common.vps = param->user_config.vst;
430         param->rsz_common.hps = param->user_config.hst;
431
432         if (vpfe_ipipeif_decimation_enabled(vpfe_dev))
433                 param->rsz_common.hsz = (((informat->width - 1) *
434                         IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev));
435         else
436                 param->rsz_common.hsz = informat->width - 1;
437
438         if (informat->field == V4L2_FIELD_INTERLACED)
439                 param->rsz_common.vsz  = (informat->height - 1) >> 1;
440         else
441                 param->rsz_common.vsz  = informat->height - 1;
442
443         param->rsz_common.raw_flip = 0;
444
445         if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF)
446                 param->rsz_common.source = IPIPEIF_DATA;
447         else
448                 param->rsz_common.source = IPIPE_DATA;
449
450         switch (informat->code) {
451         case MEDIA_BUS_FMT_UYVY8_2X8:
452                 param->rsz_common.src_img_fmt = RSZ_IMG_422;
453                 param->rsz_common.raw_flip = 0;
454                 break;
455
456         case MEDIA_BUS_FMT_Y8_1X8:
457                 param->rsz_common.src_img_fmt = RSZ_IMG_420;
458                 /* Select y */
459                 param->rsz_common.y_c = 0;
460                 param->rsz_common.raw_flip = 0;
461                 break;
462
463         case MEDIA_BUS_FMT_UV8_1X8:
464                 param->rsz_common.src_img_fmt = RSZ_IMG_420;
465                 /* Select y */
466                 param->rsz_common.y_c = 1;
467                 param->rsz_common.raw_flip = 0;
468                 break;
469
470         case MEDIA_BUS_FMT_SGRBG12_1X12:
471                 param->rsz_common.raw_flip = 1;
472                 break;
473
474         default:
475                 param->rsz_common.src_img_fmt = RSZ_IMG_422;
476                 param->rsz_common.source = IPIPE_DATA;
477         }
478
479         param->rsz_common.yuv_y_min = user_config->yuv_y_min;
480         param->rsz_common.yuv_y_max = user_config->yuv_y_max;
481         param->rsz_common.yuv_c_min = user_config->yuv_c_min;
482         param->rsz_common.yuv_c_max = user_config->yuv_c_max;
483         param->rsz_common.out_chr_pos = user_config->out_chr_pos;
484         param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even;
485
486         return 0;
487 }
488 static int
489 resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer)
490 {
491         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
492         struct resizer_params *param = &resizer->config;
493         struct vpfe_rsz_config_params *cont_config;
494         int line_len_c;
495         int line_len;
496         int ret;
497
498         if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) {
499                 dev_err(dev, "enable resizer - Resizer-A\n");
500                 return -EINVAL;
501         }
502
503         cont_config = &resizer->config.user_config;
504         param->rsz_en[RSZ_A] = ENABLE;
505         configure_resizer_out_params(resizer, RSZ_A,
506                                      &cont_config->output1, 1, 0);
507         param->rsz_en[RSZ_B] = DISABLE;
508         param->oper_mode = RESIZER_MODE_CONTINIOUS;
509
510         if (resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) {
511                 struct v4l2_mbus_framefmt *outformat2;
512
513                 param->rsz_en[RSZ_B] = ENABLE;
514                 outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
515                 ret = resizer_validate_output_image_format(dev, outformat2,
516                                 &line_len, &line_len_c);
517                 if (ret)
518                         return ret;
519                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
520                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
521                 configure_resizer_out_params(resizer, RSZ_B,
522                                                 &cont_config->output2, 0, 1);
523                 if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
524                         resizer_enable_422_420_conversion(param,
525                                                           RSZ_B, ENABLE);
526                 else
527                         resizer_enable_422_420_conversion(param,
528                                                           RSZ_B, DISABLE);
529         }
530         resizer_configure_common_in_params(resizer);
531         ret = resizer_configure_output_win(resizer);
532         if (ret)
533                 return ret;
534
535         param->rsz_common.passthrough = cont_config->bypass;
536         if (cont_config->bypass)
537                 resizer_configure_passthru(resizer, 1);
538
539         return 0;
540 }
541
542 static inline int
543 resizer_validate_input_image_format(struct device *dev,
544                                     u32 pix,
545                                     int width, int height, int *line_len)
546 {
547         int val;
548
549         if (pix != MEDIA_BUS_FMT_UYVY8_2X8 &&
550             pix != MEDIA_BUS_FMT_Y8_1X8 &&
551             pix != MEDIA_BUS_FMT_UV8_1X8 &&
552             pix != MEDIA_BUS_FMT_SGRBG12_1X12) {
553                 dev_err(dev,
554                 "resizer validate output: pix format not supported, %d\n", pix);
555                 return -EINVAL;
556         }
557
558         if (!width || !height) {
559                 dev_err(dev,
560                         "resizer validate input: invalid width or height\n");
561                 return -EINVAL;
562         }
563
564         if (pix == MEDIA_BUS_FMT_UV8_1X8)
565                 resizer_calculate_line_length(pix, width,
566                                               height, &val, line_len);
567         else
568                 resizer_calculate_line_length(pix, width,
569                                               height, line_len, &val);
570
571         return 0;
572 }
573
574 static int
575 resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en,
576                             unsigned char rsz, unsigned char frame_div_mode_en,
577                             int width)
578 {
579         if (dec_en && frame_div_mode_en) {
580                 dev_err(dev,
581                  "dec_en & frame_div_mode_en can not enabled simultaneously\n");
582                 return -EINVAL;
583         }
584
585         if (frame_div_mode_en) {
586                 dev_err(dev, "frame_div_mode mode not supported\n");
587                 return -EINVAL;
588         }
589
590         if (!dec_en)
591                 return 0;
592
593         if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) {
594                 dev_err(dev,
595                         "image width to be more than %d for decimation\n",
596                         VPFE_IPIPE_MAX_INPUT_WIDTH);
597                 return -EINVAL;
598         }
599
600         if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) {
601                 dev_err(dev, "rsz range is %d to %d\n",
602                         IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX);
603                 return -EINVAL;
604         }
605
606         return 0;
607 }
608
609 /* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame
610  *                                          division parameters for resizer.
611  *                                          in normal mode.
612  */
613 static int
614 resizer_calculate_normal_f_div_param(struct device *dev, int input_width,
615                 int output_width, struct resizer_scale_param *param)
616 {
617         /* rsz = R, input_width = H, output width = h in the equation */
618         unsigned int val1;
619         unsigned int rsz;
620         unsigned int val;
621         unsigned int h1;
622         unsigned int h2;
623         unsigned int o;
624
625         if (output_width > input_width) {
626                 dev_err(dev, "frame div mode is used for scale down only\n");
627                 return -EINVAL;
628         }
629
630         rsz = (input_width << 8) / output_width;
631         val = rsz << 1;
632         val = ((input_width << 8) / val) + 1;
633         o = 14;
634         if (!(val % 2)) {
635                 h1 = val;
636         } else {
637                 val = input_width << 7;
638                 val -= rsz >> 1;
639                 val /= rsz << 1;
640                 val <<= 1;
641                 val += 2;
642                 o += ((CEIL(rsz, 1024)) << 1);
643                 h1 = val;
644         }
645         h2 = output_width - h1;
646         /* phi */
647         val = (h1 * rsz) - (((input_width >> 1) - o) << 8);
648         /* skip */
649         val1 = ((val - 1024) >> 9) << 1;
650         param->f_div.num_passes = MAX_PASSES;
651         param->f_div.pass[0].o_hsz = h1 - 1;
652         param->f_div.pass[0].i_hps = 0;
653         param->f_div.pass[0].h_phs = 0;
654         param->f_div.pass[0].src_hps = 0;
655         param->f_div.pass[0].src_hsz = (input_width >> 2) + o;
656         param->f_div.pass[1].o_hsz = h2 - 1;
657         param->f_div.pass[1].i_hps = val1;
658         param->f_div.pass[1].h_phs = (val - (val1 << 8));
659         param->f_div.pass[1].src_hps = (input_width >> 2) - o;
660         param->f_div.pass[1].src_hsz = (input_width >> 2) + o;
661
662         return 0;
663 }
664
665 static int
666 resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
667 {
668         struct vpfe_rsz_config_params *config = &resizer->config.user_config;
669         struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev;
670         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
671         struct v4l2_mbus_framefmt *outformat1, *outformat2;
672         struct resizer_params *param = &resizer->config;
673         struct v4l2_mbus_framefmt *informat;
674         int decimation;
675         int line_len_c;
676         int line_len;
677         int rsz;
678         int ret;
679
680         informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK];
681         outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
682         outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE];
683
684         decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev);
685         rsz = vpfe_ipipeif_get_rsz(vpfe_dev);
686         if (decimation && param->user_config.frame_div_mode_en) {
687                 dev_err(dev,
688                 "dec_en & frame_div_mode_en cannot enabled simultaneously\n");
689                 return -EINVAL;
690         }
691
692         ret = resizer_validate_decimation(dev, decimation, rsz,
693               param->user_config.frame_div_mode_en, informat->width);
694         if (ret)
695                 return -EINVAL;
696
697         ret = resizer_validate_input_image_format(dev, informat->code,
698                 informat->width, informat->height, &line_len);
699         if (ret)
700                 return -EINVAL;
701
702         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
703                 param->rsz_en[RSZ_A] = ENABLE;
704                 ret = resizer_validate_output_image_format(dev, outformat1,
705                                         &line_len, &line_len_c);
706                 if (ret)
707                         return ret;
708                 param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len;
709                 param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c;
710                 configure_resizer_out_params(resizer, RSZ_A,
711                                         &param->user_config.output1, 0, 1);
712
713                 if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12)
714                         param->rsz_common.raw_flip = 1;
715                 else
716                         param->rsz_common.raw_flip = 0;
717
718                 if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
719                         resizer_enable_422_420_conversion(param,
720                                                           RSZ_A, ENABLE);
721                 else
722                         resizer_enable_422_420_conversion(param,
723                                                           RSZ_A, DISABLE);
724         }
725
726         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
727                 param->rsz_en[RSZ_B] = ENABLE;
728                 ret = resizer_validate_output_image_format(dev, outformat2,
729                                 &line_len, &line_len_c);
730                 if (ret)
731                         return ret;
732                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len;
733                 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
734                 configure_resizer_out_params(resizer, RSZ_B,
735                                         &param->user_config.output2, 0, 1);
736                 if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
737                         resizer_enable_422_420_conversion(param,
738                                                           RSZ_B, ENABLE);
739                 else
740                         resizer_enable_422_420_conversion(param,
741                                                           RSZ_B, DISABLE);
742         }
743
744         resizer_configure_common_in_params(resizer);
745         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) {
746                 resizer_calculate_resize_ratios(resizer, RSZ_A);
747                 resizer_calculate_sdram_offsets(resizer, RSZ_A);
748                 /* Overriding resize ratio calculation */
749                 if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
750                         param->rsz_rsc_param[RSZ_A].v_dif =
751                                 (((informat->height + 1) * 2) * 256) /
752                                 (param->rsz_rsc_param[RSZ_A].o_vsz + 1);
753                 }
754         }
755
756         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) {
757                 resizer_calculate_resize_ratios(resizer, RSZ_B);
758                 resizer_calculate_sdram_offsets(resizer, RSZ_B);
759                 /* Overriding resize ratio calculation */
760                 if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
761                         param->rsz_rsc_param[RSZ_B].v_dif =
762                                 (((informat->height + 1) * 2) * 256) /
763                                 (param->rsz_rsc_param[RSZ_B].o_vsz + 1);
764                 }
765         }
766         if (param->user_config.frame_div_mode_en &&
767                 param->rsz_en[RSZ_A]) {
768                 if (!param->rsz_rsc_param[RSZ_A].dscale_en)
769                         ret = resizer_calculate_normal_f_div_param(dev,
770                               informat->width,
771                               param->rsz_rsc_param[RSZ_A].o_vsz + 1,
772                               &param->rsz_rsc_param[RSZ_A]);
773                 else
774                         ret = resizer_calculate_down_scale_f_div_param(dev,
775                               informat->width,
776                               param->rsz_rsc_param[RSZ_A].o_vsz + 1,
777                               &param->rsz_rsc_param[RSZ_A]);
778                 if (ret)
779                         return -EINVAL;
780         }
781         if (param->user_config.frame_div_mode_en &&
782                 param->rsz_en[RSZ_B]) {
783                 if (!param->rsz_rsc_param[RSZ_B].dscale_en)
784                         ret = resizer_calculate_normal_f_div_param(dev,
785                               informat->width,
786                               param->rsz_rsc_param[RSZ_B].o_vsz + 1,
787                               &param->rsz_rsc_param[RSZ_B]);
788                 else
789                         ret = resizer_calculate_down_scale_f_div_param(dev,
790                               informat->width,
791                               param->rsz_rsc_param[RSZ_B].o_vsz + 1,
792                               &param->rsz_rsc_param[RSZ_B]);
793                 if (ret)
794                         return -EINVAL;
795         }
796         param->rsz_common.passthrough = config->bypass;
797         if (config->bypass)
798                 resizer_configure_passthru(resizer, 1);
799         return 0;
800 }
801
802 static void
803 resizer_set_defualt_configuration(struct vpfe_resizer_device *resizer)
804 {
805 #define  WIDTH_I 640
806 #define  HEIGHT_I 480
807 #define  WIDTH_O 640
808 #define  HEIGHT_O 480
809         const struct resizer_params rsz_default_config = {
810                 .oper_mode = RESIZER_MODE_ONE_SHOT,
811                 .rsz_common = {
812                         .vsz = HEIGHT_I - 1,
813                         .hsz = WIDTH_I - 1,
814                         .src_img_fmt = RSZ_IMG_422,
815                         .raw_flip = 1,  /* flip preserve Raw format */
816                         .source = IPIPE_DATA,
817                         .passthrough = BYPASS_OFF,
818                         .yuv_y_max = 255,
819                         .yuv_c_max = 255,
820                         .rsz_seq_crv = DISABLE,
821                         .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
822                 },
823                 .rsz_rsc_param = {
824                         {
825                                 .h_flip = DISABLE,
826                                 .v_flip = DISABLE,
827                                 .cen = DISABLE,
828                                 .yen = DISABLE,
829                                 .o_vsz = HEIGHT_O - 1,
830                                 .o_hsz = WIDTH_O - 1,
831                                 .v_dif = 256,
832                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
833                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
834                                 .h_dif = 256,
835                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
836                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
837                                 .h_dscale_ave_sz =
838                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
839                                 .v_dscale_ave_sz =
840                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
841                         },
842                         {
843                                 .h_flip = DISABLE,
844                                 .v_flip = DISABLE,
845                                 .cen = DISABLE,
846                                 .yen = DISABLE,
847                                 .o_vsz = HEIGHT_O - 1,
848                                 .o_hsz = WIDTH_O - 1,
849                                 .v_dif = 256,
850                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
851                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
852                                 .h_dif = 256,
853                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
854                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
855                                 .h_dscale_ave_sz =
856                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
857                                 .v_dscale_ave_sz =
858                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
859                         },
860                 },
861                 .rsz2rgb = {
862                         {
863                                 .rgb_en = DISABLE
864                         },
865                         {
866                                 .rgb_en = DISABLE
867                         }
868                 },
869                 .ext_mem_param = {
870                         {
871                                 .rsz_sdr_oft_y = WIDTH_O << 1,
872                                 .rsz_sdr_ptr_e_y = HEIGHT_O,
873                                 .rsz_sdr_oft_c = WIDTH_O,
874                                 .rsz_sdr_ptr_e_c = HEIGHT_O >> 1,
875                         },
876                         {
877                                 .rsz_sdr_oft_y = WIDTH_O << 1,
878                                 .rsz_sdr_ptr_e_y = HEIGHT_O,
879                                 .rsz_sdr_oft_c = WIDTH_O,
880                                 .rsz_sdr_ptr_e_c = HEIGHT_O,
881                         },
882                 },
883                 .rsz_en[0] = ENABLE,
884                 .rsz_en[1] = DISABLE,
885                 .user_config = {
886                         .output1 = {
887                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
888                                 .v_typ_c = VPFE_RSZ_INTP_CUBIC,
889                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
890                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
891                                 .h_dscale_ave_sz =
892                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
893                                 .v_dscale_ave_sz =
894                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
895                         },
896                         .output2 = {
897                                 .v_typ_y = VPFE_RSZ_INTP_CUBIC,
898                                 .v_typ_c = VPFE_RSZ_INTP_CUBIC,
899                                 .h_typ_y = VPFE_RSZ_INTP_CUBIC,
900                                 .h_typ_c = VPFE_RSZ_INTP_CUBIC,
901                                 .h_dscale_ave_sz =
902                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
903                                 .v_dscale_ave_sz =
904                                         VPFE_IPIPE_DWN_SCALE_1_OVER_2,
905                         },
906                         .yuv_y_max = 255,
907                         .yuv_c_max = 255,
908                         .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE,
909                 },
910         };
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 = arg;
1222                 ret = resizer_set_configuration(resizer, user_config);
1223                 break;
1224
1225         case VIDIOC_VPFE_RSZ_G_CONFIG:
1226                 user_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  * @cfg: V4L2 subdev pad config
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_pad_config *cfg,
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(sd, cfg, 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  * @cfg: V4L2 subdev pad config
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_pad_config *cfg,
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 = MEDIA_BUS_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 = MEDIA_BUS_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 = MEDIA_BUS_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  * @cfg: V4L2 subdev pad config
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_pad_config *cfg,
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, cfg, fmt->pad, fmt->which);
1402         if (format == NULL)
1403                 return -EINVAL;
1404
1405         resizer_try_format(sd, cfg, 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  * @cfg: V4L2 subdev pad config
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_pad_config *cfg,
1456                            struct v4l2_subdev_format *fmt)
1457 {
1458         struct v4l2_mbus_framefmt *format;
1459
1460         format = __resizer_get_format(sd, cfg, 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  * @cfg: V4L2 subdev pad config
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_pad_config *cfg,
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, cfg, fse->pad, &format, fse->which);
1488         fse->min_width = format.width;
1489         fse->min_height = format.height;
1490
1491         if (format.code != fse->code)
1492                 return -EINVAL;
1493
1494         format.code = fse->code;
1495         format.width = -1;
1496         format.height = -1;
1497         resizer_try_format(sd, cfg, fse->pad, &format, fse->which);
1498         fse->max_width = format.width;
1499         fse->max_height = format.height;
1500
1501         return 0;
1502 }
1503
1504 /*
1505  * resizer_enum_mbus_code() - enum mbus codes for pads
1506  * @sd: Pointer to subdevice.
1507  * @cfg: V4L2 subdev pad config
1508  * @code: pointer to v4l2_subdev_mbus_code_enum structure
1509  */
1510 static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1511                                   struct v4l2_subdev_pad_config *cfg,
1512                                   struct v4l2_subdev_mbus_code_enum *code)
1513 {
1514         if (code->pad == RESIZER_PAD_SINK) {
1515                 if (code->index >= ARRAY_SIZE(resizer_input_formats))
1516                         return -EINVAL;
1517
1518                 code->code = resizer_input_formats[code->index];
1519         } else if (code->pad == RESIZER_PAD_SOURCE) {
1520                 if (code->index >= ARRAY_SIZE(resizer_output_formats))
1521                         return -EINVAL;
1522
1523                 code->code = resizer_output_formats[code->index];
1524         }
1525
1526         return 0;
1527 }
1528
1529 /*
1530  * resizer_init_formats() - Initialize formats on all pads
1531  * @sd: Pointer to subdevice.
1532  * @fh: V4L2 subdev file handle.
1533  *
1534  * Initialize all pad formats with default values. Try formats are
1535  * initialized on the file handle.
1536  */
1537 static int resizer_init_formats(struct v4l2_subdev *sd,
1538                                 struct v4l2_subdev_fh *fh)
1539 {
1540         __u32 which = V4L2_SUBDEV_FORMAT_TRY;
1541         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1542         struct v4l2_subdev_format format;
1543
1544         if (&resizer->crop_resizer.subdev == sd) {
1545                 memset(&format, 0, sizeof(format));
1546                 format.pad = RESIZER_CROP_PAD_SINK;
1547                 format.which = which;
1548                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1549                 format.format.width = MAX_IN_WIDTH;
1550                 format.format.height = MAX_IN_HEIGHT;
1551                 resizer_set_format(sd, fh->pad, &format);
1552
1553                 memset(&format, 0, sizeof(format));
1554                 format.pad = RESIZER_CROP_PAD_SOURCE;
1555                 format.which = which;
1556                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1557                 format.format.width = MAX_IN_WIDTH;
1558                 format.format.height = MAX_IN_WIDTH;
1559                 resizer_set_format(sd, fh->pad, &format);
1560
1561                 memset(&format, 0, sizeof(format));
1562                 format.pad = RESIZER_CROP_PAD_SOURCE2;
1563                 format.which = which;
1564                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1565                 format.format.width = MAX_IN_WIDTH;
1566                 format.format.height = MAX_IN_WIDTH;
1567                 resizer_set_format(sd, fh->pad, &format);
1568         } else if (&resizer->resizer_a.subdev == sd) {
1569                 memset(&format, 0, sizeof(format));
1570                 format.pad = RESIZER_PAD_SINK;
1571                 format.which = which;
1572                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1573                 format.format.width = MAX_IN_WIDTH;
1574                 format.format.height = MAX_IN_HEIGHT;
1575                 resizer_set_format(sd, fh->pad, &format);
1576
1577                 memset(&format, 0, sizeof(format));
1578                 format.pad = RESIZER_PAD_SOURCE;
1579                 format.which = which;
1580                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1581                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
1582                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
1583                 resizer_set_format(sd, fh->pad, &format);
1584         } else if (&resizer->resizer_b.subdev == sd) {
1585                 memset(&format, 0, sizeof(format));
1586                 format.pad = RESIZER_PAD_SINK;
1587                 format.which = which;
1588                 format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
1589                 format.format.width = MAX_IN_WIDTH;
1590                 format.format.height = MAX_IN_HEIGHT;
1591                 resizer_set_format(sd, fh->pad, &format);
1592
1593                 memset(&format, 0, sizeof(format));
1594                 format.pad = RESIZER_PAD_SOURCE;
1595                 format.which = which;
1596                 format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
1597                 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
1598                 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
1599                 resizer_set_format(sd, fh->pad, &format);
1600         }
1601
1602         return 0;
1603 }
1604
1605 /* subdev core operations */
1606 static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = {
1607         .ioctl = resizer_ioctl,
1608 };
1609
1610 /* subdev internal operations */
1611 static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1612         .open = resizer_init_formats,
1613 };
1614
1615 /* subdev video operations */
1616 static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1617         .s_stream = resizer_set_stream,
1618 };
1619
1620 /* subdev pad operations */
1621 static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1622         .enum_mbus_code = resizer_enum_mbus_code,
1623         .enum_frame_size = resizer_enum_frame_size,
1624         .get_fmt = resizer_get_format,
1625         .set_fmt = resizer_set_format,
1626 };
1627
1628 /* subdev operations */
1629 static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1630         .core = &resizer_v4l2_core_ops,
1631         .video = &resizer_v4l2_video_ops,
1632         .pad = &resizer_v4l2_pad_ops,
1633 };
1634
1635 /*
1636  * Media entity operations
1637  */
1638
1639 /*
1640  * resizer_link_setup() - Setup resizer connections
1641  * @entity: Pointer to media entity structure
1642  * @local: Pointer to local pad array
1643  * @remote: Pointer to remote pad array
1644  * @flags: Link flags
1645  * return -EINVAL or zero on success
1646  */
1647 static int resizer_link_setup(struct media_entity *entity,
1648                            const struct media_pad *local,
1649                            const struct media_pad *remote, u32 flags)
1650 {
1651         struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1652         struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd);
1653         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1654         u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output;
1655         u16 ipipe_source = vpfe_dev->vpfe_ipipe.output;
1656
1657         if (&resizer->crop_resizer.subdev == sd) {
1658                 switch (local->index | media_entity_type(remote->entity)) {
1659                 case RESIZER_CROP_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1660                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1661                                 resizer->crop_resizer.input =
1662                                         RESIZER_CROP_INPUT_NONE;
1663                                 break;
1664                         }
1665
1666                         if (resizer->crop_resizer.input !=
1667                            RESIZER_CROP_INPUT_NONE)
1668                                 return -EBUSY;
1669                         if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER)
1670                                 resizer->crop_resizer.input =
1671                                                 RESIZER_CROP_INPUT_IPIPEIF;
1672                         else if (ipipe_source == IPIPE_OUTPUT_RESIZER)
1673                                         resizer->crop_resizer.input =
1674                                                 RESIZER_CROP_INPUT_IPIPE;
1675                         else
1676                                 return -EINVAL;
1677                         break;
1678
1679                 case RESIZER_CROP_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
1680                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1681                                 resizer->crop_resizer.output =
1682                                 RESIZER_CROP_OUTPUT_NONE;
1683                                 break;
1684                         }
1685                         if (resizer->crop_resizer.output !=
1686                             RESIZER_CROP_OUTPUT_NONE)
1687                                 return -EBUSY;
1688                         resizer->crop_resizer.output = RESIZER_A;
1689                         break;
1690
1691                 case RESIZER_CROP_PAD_SOURCE2 | MEDIA_ENT_T_V4L2_SUBDEV:
1692                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1693                                 resizer->crop_resizer.output2 =
1694                                         RESIZER_CROP_OUTPUT_NONE;
1695                                 break;
1696                         }
1697                         if (resizer->crop_resizer.output2 !=
1698                             RESIZER_CROP_OUTPUT_NONE)
1699                                 return -EBUSY;
1700                         resizer->crop_resizer.output2 = RESIZER_B;
1701                         break;
1702
1703                 default:
1704                         return -EINVAL;
1705                 }
1706         } else if (&resizer->resizer_a.subdev == sd) {
1707                 switch (local->index | media_entity_type(remote->entity)) {
1708                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1709                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1710                                 resizer->resizer_a.input = RESIZER_INPUT_NONE;
1711                                 break;
1712                         }
1713                         if (resizer->resizer_a.input != RESIZER_INPUT_NONE)
1714                                 return -EBUSY;
1715                         resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER;
1716                         break;
1717
1718                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1719                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1720                                 resizer->resizer_a.output = RESIZER_OUTPUT_NONE;
1721                                 break;
1722                         }
1723                         if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE)
1724                                 return -EBUSY;
1725                         resizer->resizer_a.output = RESIZER_OUPUT_MEMORY;
1726                         break;
1727
1728                 default:
1729                         return -EINVAL;
1730                 }
1731         } else if (&resizer->resizer_b.subdev == sd) {
1732                 switch (local->index | media_entity_type(remote->entity)) {
1733                 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1734                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1735                                 resizer->resizer_b.input = RESIZER_INPUT_NONE;
1736                                 break;
1737                         }
1738                         if (resizer->resizer_b.input != RESIZER_INPUT_NONE)
1739                                 return -EBUSY;
1740                         resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER;
1741                         break;
1742
1743                 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1744                         if (!(flags & MEDIA_LNK_FL_ENABLED)) {
1745                                 resizer->resizer_b.output = RESIZER_OUTPUT_NONE;
1746                                 break;
1747                         }
1748                         if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE)
1749                                 return -EBUSY;
1750                         resizer->resizer_b.output = RESIZER_OUPUT_MEMORY;
1751                         break;
1752
1753                 default:
1754                         return -EINVAL;
1755                 }
1756         } else {
1757                 return -EINVAL;
1758         }
1759
1760         return 0;
1761 }
1762
1763 static const struct media_entity_operations resizer_media_ops = {
1764         .link_setup = resizer_link_setup,
1765 };
1766
1767 /*
1768  * vpfe_resizer_unregister_entities() - Unregister entity
1769  * @vpfe_rsz - pointer to resizer subdevice structure.
1770  */
1771 void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz)
1772 {
1773         /* unregister video devices */
1774         vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out);
1775         vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out);
1776
1777         /* unregister subdev */
1778         v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev);
1779         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev);
1780         v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev);
1781         /* cleanup entity */
1782         media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity);
1783         media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity);
1784         media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity);
1785 }
1786
1787 /*
1788  * vpfe_resizer_register_entities() - Register entity
1789  * @resizer - pointer to resizer devive.
1790  * @vdev: pointer to v4l2 device structure.
1791  */
1792 int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer,
1793                                    struct v4l2_device *vdev)
1794 {
1795         struct vpfe_device *vpfe_dev = to_vpfe_device(resizer);
1796         unsigned int flags = 0;
1797         int ret;
1798
1799         /* Register the crop resizer subdev */
1800         ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev);
1801         if (ret < 0) {
1802                 pr_err("Failed to register crop resizer as v4l2-subdev\n");
1803                 return ret;
1804         }
1805         /* Register Resizer-A subdev */
1806         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev);
1807         if (ret < 0) {
1808                 pr_err("Failed to register resizer-a as v4l2-subdev\n");
1809                 return ret;
1810         }
1811         /* Register Resizer-B subdev */
1812         ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev);
1813         if (ret < 0) {
1814                 pr_err("Failed to register resizer-b as v4l2-subdev\n");
1815                 return ret;
1816         }
1817         /* Register video-out device for resizer-a */
1818         ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev);
1819         if (ret) {
1820                 pr_err("Failed to register RSZ-A video-out device\n");
1821                 goto out_video_out2_register;
1822         }
1823         resizer->resizer_a.video_out.vpfe_dev = vpfe_dev;
1824
1825         /* Register video-out device for resizer-b */
1826         ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev);
1827         if (ret) {
1828                 pr_err("Failed to register RSZ-B video-out device\n");
1829                 goto out_video_out2_register;
1830         }
1831         resizer->resizer_b.video_out.vpfe_dev = vpfe_dev;
1832
1833         /* create link between Resizer Crop----> Resizer A*/
1834         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 1,
1835                                 &resizer->resizer_a.subdev.entity,
1836                                 0, flags);
1837         if (ret < 0)
1838                 goto out_create_link;
1839
1840         /* create link between Resizer Crop----> Resizer B*/
1841         ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 2,
1842                                 &resizer->resizer_b.subdev.entity,
1843                                 0, flags);
1844         if (ret < 0)
1845                 goto out_create_link;
1846
1847         /* create link between Resizer A ----> video out */
1848         ret = media_entity_create_link(&resizer->resizer_a.subdev.entity, 1,
1849                 &resizer->resizer_a.video_out.video_dev.entity, 0, flags);
1850         if (ret < 0)
1851                 goto out_create_link;
1852
1853         /* create link between Resizer B ----> video out */
1854         ret = media_entity_create_link(&resizer->resizer_b.subdev.entity, 1,
1855                 &resizer->resizer_b.video_out.video_dev.entity, 0, flags);
1856         if (ret < 0)
1857                 goto out_create_link;
1858
1859         return 0;
1860
1861 out_create_link:
1862         vpfe_video_unregister(&resizer->resizer_b.video_out);
1863 out_video_out2_register:
1864         vpfe_video_unregister(&resizer->resizer_a.video_out);
1865         v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev);
1866         v4l2_device_unregister_subdev(&resizer->resizer_a.subdev);
1867         v4l2_device_unregister_subdev(&resizer->resizer_b.subdev);
1868         media_entity_cleanup(&resizer->crop_resizer.subdev.entity);
1869         media_entity_cleanup(&resizer->resizer_a.subdev.entity);
1870         media_entity_cleanup(&resizer->resizer_b.subdev.entity);
1871         return ret;
1872 }
1873
1874 /*
1875  * vpfe_resizer_init() - resizer device initialization.
1876  * @vpfe_rsz - pointer to resizer device
1877  * @pdev: platform device pointer.
1878  */
1879 int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz,
1880                       struct platform_device *pdev)
1881 {
1882         struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev;
1883         struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0];
1884         struct media_entity *me = &sd->entity;
1885         static resource_size_t  res_len;
1886         struct resource *res;
1887         int ret;
1888
1889         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1890         if (!res)
1891                 return -ENOENT;
1892
1893         res_len = resource_size(res);
1894         res = request_mem_region(res->start, res_len, res->name);
1895         if (!res)
1896                 return -EBUSY;
1897
1898         vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len);
1899         if (!vpfe_rsz->base_addr)
1900                 return -EBUSY;
1901
1902         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1903         sd->internal_ops = &resizer_v4l2_internal_ops;
1904         strlcpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name));
1905         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1906         v4l2_set_subdevdata(sd, vpfe_rsz);
1907         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1908
1909         pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1910         pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1911         pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE;
1912
1913         vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE;
1914         vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE;
1915         vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE;
1916         vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz;
1917         me->ops = &resizer_media_ops;
1918         ret = media_entity_init(me, RESIZER_CROP_PADS_NUM, pads, 0);
1919         if (ret)
1920                 return ret;
1921
1922         sd = &vpfe_rsz->resizer_a.subdev;
1923         pads = &vpfe_rsz->resizer_a.pads[0];
1924         me = &sd->entity;
1925
1926         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1927         sd->internal_ops = &resizer_v4l2_internal_ops;
1928         strlcpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name));
1929         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1930         v4l2_set_subdevdata(sd, vpfe_rsz);
1931         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1932
1933         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1934         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1935
1936         vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE;
1937         vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE;
1938         vpfe_rsz->resizer_a.rsz_device = vpfe_rsz;
1939         me->ops = &resizer_media_ops;
1940         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1941         if (ret)
1942                 return ret;
1943
1944         sd = &vpfe_rsz->resizer_b.subdev;
1945         pads = &vpfe_rsz->resizer_b.pads[0];
1946         me = &sd->entity;
1947
1948         v4l2_subdev_init(sd, &resizer_v4l2_ops);
1949         sd->internal_ops = &resizer_v4l2_internal_ops;
1950         strlcpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name));
1951         sd->grp_id = 1 << 16;   /* group ID for davinci subdevs */
1952         v4l2_set_subdevdata(sd, vpfe_rsz);
1953         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1954
1955         pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1956         pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1957
1958         vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE;
1959         vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE;
1960         vpfe_rsz->resizer_b.rsz_device = vpfe_rsz;
1961         me->ops = &resizer_media_ops;
1962         ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
1963         if (ret)
1964                 return ret;
1965
1966         vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops;
1967         vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1968         ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A");
1969         if (ret) {
1970                 pr_err("Failed to init RSZ video-out device\n");
1971                 return ret;
1972         }
1973         vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops;
1974         vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1975         ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B");
1976         if (ret) {
1977                 pr_err("Failed to init RSZ video-out2 device\n");
1978                 return ret;
1979         }
1980         memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params));
1981
1982         return 0;
1983 }
1984
1985 void
1986 vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
1987                      struct platform_device *pdev)
1988 {
1989         struct resource *res;
1990
1991         iounmap(vpfe_rsz->base_addr);
1992         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
1993         if (res)
1994                 release_mem_region(res->start,
1995                                         resource_size(res));
1996 }