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