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