1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/device.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30
31#include "isp.h"
32#include "ispreg.h"
33#include "ispresizer.h"
34
35
36
37
38#define MIN_RESIZE_VALUE 64
39#define MID_RESIZE_VALUE 512
40#define MAX_RESIZE_VALUE 1024
41
42#define MIN_IN_WIDTH 32
43#define MIN_IN_HEIGHT 32
44#define MAX_IN_WIDTH_MEMORY_MODE 4095
45#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
46#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
47#define MAX_IN_HEIGHT 4095
48
49#define MIN_OUT_WIDTH 16
50#define MIN_OUT_HEIGHT 2
51#define MAX_OUT_HEIGHT 4095
52
53
54
55
56
57#define MAX_4TAP_OUT_WIDTH_ES1 1280
58#define MAX_7TAP_OUT_WIDTH_ES1 640
59#define MAX_4TAP_OUT_WIDTH_ES2 3312
60#define MAX_7TAP_OUT_WIDTH_ES2 1650
61#define MAX_4TAP_OUT_WIDTH_3630 4096
62#define MAX_7TAP_OUT_WIDTH_3630 2048
63
64
65
66
67#define RESIZE_DIVISOR 256
68#define DEFAULT_PHASE 1
69
70
71
72
73
74
75
76static const struct isprsz_coef filter_coefs = {
77
78 {
79 0x0000, 0x0100, 0x0000, 0x0000,
80 0x03FA, 0x00F6, 0x0010, 0x0000,
81 0x03F9, 0x00DB, 0x002C, 0x0000,
82 0x03FB, 0x00B3, 0x0053, 0x03FF,
83 0x03FD, 0x0082, 0x0084, 0x03FD,
84 0x03FF, 0x0053, 0x00B3, 0x03FB,
85 0x0000, 0x002C, 0x00DB, 0x03F9,
86 0x0000, 0x0010, 0x00F6, 0x03FA
87 },
88
89 {
90 0x0000, 0x0100, 0x0000, 0x0000,
91 0x03FA, 0x00F6, 0x0010, 0x0000,
92 0x03F9, 0x00DB, 0x002C, 0x0000,
93 0x03FB, 0x00B3, 0x0053, 0x03FF,
94 0x03FD, 0x0082, 0x0084, 0x03FD,
95 0x03FF, 0x0053, 0x00B3, 0x03FB,
96 0x0000, 0x002C, 0x00DB, 0x03F9,
97 0x0000, 0x0010, 0x00F6, 0x03FA
98 },
99
100 #define DUMMY 0
101 {
102 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
103 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
104 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
105 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
106 },
107
108 {
109 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
110 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
111 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
112 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
113 }
114
115
116
117
118 #undef DUMMY
119};
120
121
122
123
124
125
126
127
128
129static struct v4l2_mbus_framefmt *
130__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
131 unsigned int pad, enum v4l2_subdev_format_whence which)
132{
133 if (which == V4L2_SUBDEV_FORMAT_TRY)
134 return v4l2_subdev_get_try_format(fh, pad);
135 else
136 return &res->formats[pad];
137}
138
139
140
141
142
143
144
145static struct v4l2_rect *
146__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh,
147 enum v4l2_subdev_format_whence which)
148{
149 if (which == V4L2_SUBDEV_FORMAT_TRY)
150 return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK);
151 else
152 return &res->crop.request;
153}
154
155
156
157
158
159
160
161
162static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff,
163 const u16 *v_coeff)
164{
165 struct isp_device *isp = to_isp_device(res);
166 u32 startaddr_h, startaddr_v, tmp_h, tmp_v;
167 int i;
168
169 startaddr_h = ISPRSZ_HFILT10;
170 startaddr_v = ISPRSZ_VFILT10;
171
172 for (i = 0; i < COEFF_CNT; i += 2) {
173 tmp_h = h_coeff[i] |
174 (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT);
175 tmp_v = v_coeff[i] |
176 (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT);
177 isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h);
178 isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v);
179 startaddr_h += 4;
180 startaddr_v += 4;
181 }
182}
183
184
185
186
187
188
189
190
191
192
193static void resizer_set_bilinear(struct isp_res_device *res,
194 enum resizer_chroma_algo type)
195{
196 struct isp_device *isp = to_isp_device(res);
197
198 if (type == RSZ_BILINEAR)
199 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
200 ISPRSZ_CNT_CBILIN);
201 else
202 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
203 ISPRSZ_CNT_CBILIN);
204}
205
206
207
208
209
210
211static void resizer_set_ycpos(struct isp_res_device *res,
212 enum v4l2_mbus_pixelcode pixelcode)
213{
214 struct isp_device *isp = to_isp_device(res);
215
216 switch (pixelcode) {
217 case V4L2_MBUS_FMT_YUYV8_1X16:
218 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
219 ISPRSZ_CNT_YCPOS);
220 break;
221 case V4L2_MBUS_FMT_UYVY8_1X16:
222 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
223 ISPRSZ_CNT_YCPOS);
224 break;
225 default:
226 return;
227 }
228}
229
230
231
232
233
234
235
236
237
238static void resizer_set_phase(struct isp_res_device *res, u32 h_phase,
239 u32 v_phase)
240{
241 struct isp_device *isp = to_isp_device(res);
242 u32 rgval = 0;
243
244 rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
245 ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
246 rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK;
247 rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK;
248
249 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
250}
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274static void resizer_set_luma(struct isp_res_device *res,
275 struct resizer_luma_yenh *luma)
276{
277 struct isp_device *isp = to_isp_device(res);
278 u32 rgval = 0;
279
280 rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT)
281 & ISPRSZ_YENH_ALGO_MASK;
282 rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT)
283 & ISPRSZ_YENH_GAIN_MASK;
284 rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT)
285 & ISPRSZ_YENH_SLOP_MASK;
286 rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT)
287 & ISPRSZ_YENH_CORE_MASK;
288
289 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
290}
291
292
293
294
295
296
297
298
299
300static void resizer_set_source(struct isp_res_device *res,
301 enum resizer_input_entity source)
302{
303 struct isp_device *isp = to_isp_device(res);
304
305 if (source == RESIZER_INPUT_MEMORY)
306 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
307 ISPRSZ_CNT_INPSRC);
308 else
309 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
310 ISPRSZ_CNT_INPSRC);
311}
312
313
314
315
316
317
318
319
320static void resizer_set_ratio(struct isp_res_device *res,
321 const struct resizer_ratio *ratio)
322{
323 struct isp_device *isp = to_isp_device(res);
324 const u16 *h_filter, *v_filter;
325 u32 rgval = 0;
326
327 rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
328 ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
329 rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT)
330 & ISPRSZ_CNT_HRSZ_MASK;
331 rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT)
332 & ISPRSZ_CNT_VRSZ_MASK;
333 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
334
335
336 if (ratio->horz > MID_RESIZE_VALUE)
337 h_filter = &filter_coefs.h_filter_coef_7tap[0];
338 else
339 h_filter = &filter_coefs.h_filter_coef_4tap[0];
340
341
342 if (ratio->vert > MID_RESIZE_VALUE)
343 v_filter = &filter_coefs.v_filter_coef_7tap[0];
344 else
345 v_filter = &filter_coefs.v_filter_coef_4tap[0];
346
347 resizer_set_filters(res, h_filter, v_filter);
348}
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364static void resizer_set_output_size(struct isp_res_device *res,
365 u32 width, u32 height)
366{
367 struct isp_device *isp = to_isp_device(res);
368 u32 rgval = 0;
369
370 dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height);
371 rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT)
372 & ISPRSZ_OUT_SIZE_HORZ_MASK;
373 rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT)
374 & ISPRSZ_OUT_SIZE_VERT_MASK;
375 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
376}
377
378
379
380
381
382
383
384
385
386
387static void resizer_set_output_offset(struct isp_res_device *res, u32 offset)
388{
389 struct isp_device *isp = to_isp_device(res);
390
391 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
392}
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top)
410{
411 struct isp_device *isp = to_isp_device(res);
412 u32 rgval = 0;
413
414 rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT)
415 & ISPRSZ_IN_START_HORZ_ST_MASK;
416 rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT)
417 & ISPRSZ_IN_START_VERT_ST_MASK;
418
419 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
420}
421
422
423
424
425
426
427
428static void resizer_set_input_size(struct isp_res_device *res,
429 u32 width, u32 height)
430{
431 struct isp_device *isp = to_isp_device(res);
432 u32 rgval = 0;
433
434 dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height);
435
436 rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT)
437 & ISPRSZ_IN_SIZE_HORZ_MASK;
438 rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT)
439 & ISPRSZ_IN_SIZE_VERT_MASK;
440
441 isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
442}
443
444
445
446
447
448
449
450
451
452
453static void resizer_set_input_offset(struct isp_res_device *res, u32 offset)
454{
455 struct isp_device *isp = to_isp_device(res);
456
457 isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
458}
459
460
461
462
463
464
465static void resizer_set_intype(struct isp_res_device *res,
466 enum resizer_colors_type type)
467{
468 struct isp_device *isp = to_isp_device(res);
469
470 if (type == RSZ_COLOR8)
471 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
472 ISPRSZ_CNT_INPTYP);
473 else
474 isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
475 ISPRSZ_CNT_INPTYP);
476}
477
478
479
480
481
482
483
484static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr)
485{
486 struct isp_device *isp = to_isp_device(res);
487
488 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
489}
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514void omap3isp_resizer_max_rate(struct isp_res_device *res,
515 unsigned int *max_rate)
516{
517 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
518 const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE];
519 unsigned long limit = min(pipe->l3_ick, 200000000UL);
520 unsigned long clock;
521
522 clock = div_u64((u64)limit * res->crop.active.height, ofmt->height);
523 clock = min(clock, limit / 2);
524 *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width);
525}
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556static void resizer_adjust_bandwidth(struct isp_res_device *res)
557{
558 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
559 struct isp_device *isp = to_isp_device(res);
560 unsigned long l3_ick = pipe->l3_ick;
561 struct v4l2_fract *timeperframe;
562 unsigned int cycles_per_frame;
563 unsigned int requests_per_frame;
564 unsigned int cycles_per_request;
565 unsigned int granularity;
566 unsigned int minimum;
567 unsigned int maximum;
568 unsigned int value;
569
570 if (res->input != RESIZER_INPUT_MEMORY) {
571 isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
572 ISPSBL_SDR_REQ_RSZ_EXP_MASK);
573 return;
574 }
575
576 switch (isp->revision) {
577 case ISP_REVISION_1_0:
578 case ISP_REVISION_2_0:
579 default:
580 granularity = 1024;
581 break;
582
583 case ISP_REVISION_15_0:
584 granularity = 32;
585 break;
586 }
587
588
589
590
591
592 cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1,
593 pipe->max_rate);
594 minimum = DIV_ROUND_UP(cycles_per_request, granularity);
595
596
597
598
599
600
601 timeperframe = &pipe->max_timeperframe;
602
603 requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256)
604 * res->crop.active.height;
605 cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator,
606 timeperframe->denominator);
607 cycles_per_request = cycles_per_frame / requests_per_frame;
608
609 maximum = cycles_per_request / granularity;
610
611 value = max(minimum, maximum);
612
613 dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value);
614 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP,
615 ISPSBL_SDR_REQ_RSZ_EXP_MASK,
616 value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT);
617}
618
619
620
621
622
623
624int omap3isp_resizer_busy(struct isp_res_device *res)
625{
626 struct isp_device *isp = to_isp_device(res);
627
628 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
629 ISPRSZ_PCR_BUSY;
630}
631
632
633
634
635
636static void resizer_set_inaddr(struct isp_res_device *res, u32 addr)
637{
638 res->addr_base = addr;
639
640
641 if (res->crop_offset)
642 addr += res->crop_offset & ~0x1f;
643
644 __resizer_set_inaddr(res, addr);
645}
646
647
648
649
650
651
652
653static void resizer_set_outaddr(struct isp_res_device *res, u32 addr)
654{
655 struct isp_device *isp = to_isp_device(res);
656
657
658
659
660
661 isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
662 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
663}
664
665
666
667
668#define RSZ_PRINT_REGISTER(isp, name)\
669 dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \
670 isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name))
671
672static void resizer_print_status(struct isp_res_device *res)
673{
674 struct isp_device *isp = to_isp_device(res);
675
676 dev_dbg(isp->dev, "-------------Resizer Register dump----------\n");
677
678 RSZ_PRINT_REGISTER(isp, PCR);
679 RSZ_PRINT_REGISTER(isp, CNT);
680 RSZ_PRINT_REGISTER(isp, OUT_SIZE);
681 RSZ_PRINT_REGISTER(isp, IN_START);
682 RSZ_PRINT_REGISTER(isp, IN_SIZE);
683 RSZ_PRINT_REGISTER(isp, SDR_INADD);
684 RSZ_PRINT_REGISTER(isp, SDR_INOFF);
685 RSZ_PRINT_REGISTER(isp, SDR_OUTADD);
686 RSZ_PRINT_REGISTER(isp, SDR_OUTOFF);
687 RSZ_PRINT_REGISTER(isp, YENH);
688
689 dev_dbg(isp->dev, "--------------------------------------------\n");
690}
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794static void resizer_calc_ratios(struct isp_res_device *res,
795 struct v4l2_rect *input,
796 struct v4l2_mbus_framefmt *output,
797 struct resizer_ratio *ratio)
798{
799 struct isp_device *isp = to_isp_device(res);
800 const unsigned int spv = DEFAULT_PHASE;
801 const unsigned int sph = DEFAULT_PHASE;
802 unsigned int upscaled_width;
803 unsigned int upscaled_height;
804 unsigned int min_width;
805 unsigned int min_height;
806 unsigned int max_width;
807 unsigned int max_height;
808 unsigned int width_alignment;
809 unsigned int width;
810 unsigned int height;
811
812
813
814
815
816 min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1;
817 min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT);
818 max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1;
819 max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT);
820 output->height = clamp(output->height, min_height, max_height);
821
822 ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv)
823 / (output->height - 1);
824 if (ratio->vert > MID_RESIZE_VALUE)
825 ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv)
826 / (output->height - 1);
827 ratio->vert = clamp_t(unsigned int, ratio->vert,
828 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
829
830 if (ratio->vert <= MID_RESIZE_VALUE) {
831 upscaled_height = (output->height - 1) * ratio->vert
832 + 32 * spv + 16;
833 height = (upscaled_height >> 8) + 4;
834 } else {
835 upscaled_height = (output->height - 1) * ratio->vert
836 + 64 * spv + 32;
837 height = (upscaled_height >> 8) + 7;
838 }
839
840
841
842
843
844 min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1;
845 min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH);
846
847 if (ratio->vert <= MID_RESIZE_VALUE) {
848 switch (isp->revision) {
849 case ISP_REVISION_1_0:
850 max_width = MAX_4TAP_OUT_WIDTH_ES1;
851 break;
852
853 case ISP_REVISION_2_0:
854 default:
855 max_width = MAX_4TAP_OUT_WIDTH_ES2;
856 break;
857
858 case ISP_REVISION_15_0:
859 max_width = MAX_4TAP_OUT_WIDTH_3630;
860 break;
861 }
862 } else {
863 switch (isp->revision) {
864 case ISP_REVISION_1_0:
865 max_width = MAX_7TAP_OUT_WIDTH_ES1;
866 break;
867
868 case ISP_REVISION_2_0:
869 default:
870 max_width = MAX_7TAP_OUT_WIDTH_ES2;
871 break;
872
873 case ISP_REVISION_15_0:
874 max_width = MAX_7TAP_OUT_WIDTH_3630;
875 break;
876 }
877 }
878 max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64
879 + 1, max_width);
880
881
882
883
884
885
886
887
888 width_alignment = ratio->vert < 256 ? 8 : 2;
889 output->width = clamp(output->width, min_width,
890 max_width & ~(width_alignment - 1));
891 output->width = ALIGN(output->width, width_alignment);
892
893 ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph)
894 / (output->width - 1);
895 if (ratio->horz > MID_RESIZE_VALUE)
896 ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph)
897 / (output->width - 1);
898 ratio->horz = clamp_t(unsigned int, ratio->horz,
899 MIN_RESIZE_VALUE, MAX_RESIZE_VALUE);
900
901 if (ratio->horz <= MID_RESIZE_VALUE) {
902 upscaled_width = (output->width - 1) * ratio->horz
903 + 32 * sph + 16;
904 width = (upscaled_width >> 8) + 7;
905 } else {
906 upscaled_width = (output->width - 1) * ratio->horz
907 + 64 * sph + 32;
908 width = (upscaled_width >> 8) + 7;
909 }
910
911
912 input->left += (input->width - width) / 2;
913 input->top += (input->height - height) / 2;
914 input->width = width;
915 input->height = height;
916}
917
918
919
920
921
922
923
924
925static void resizer_set_crop_params(struct isp_res_device *res,
926 const struct v4l2_mbus_framefmt *input,
927 const struct v4l2_mbus_framefmt *output)
928{
929 resizer_set_ratio(res, &res->ratio);
930
931
932 if (res->ratio.horz >= RESIZE_DIVISOR)
933 resizer_set_bilinear(res, RSZ_THE_SAME);
934 else
935 resizer_set_bilinear(res, RSZ_BILINEAR);
936
937 resizer_adjust_bandwidth(res);
938
939 if (res->input == RESIZER_INPUT_MEMORY) {
940
941 res->crop_offset = (res->crop.active.top * input->width +
942 res->crop.active.left) * 2;
943
944
945
946
947 resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0);
948
949
950
951
952
953 __resizer_set_inaddr(res,
954 res->addr_base + (res->crop_offset & ~0x1f));
955 } else {
956
957
958
959
960
961 resizer_set_start(res, res->crop.active.left * 2,
962 res->crop.active.top);
963
964 __resizer_set_inaddr(res, 0);
965 resizer_set_input_offset(res, 0);
966 }
967
968
969 resizer_set_input_size(res, res->crop.active.width,
970 res->crop.active.height);
971}
972
973static void resizer_configure(struct isp_res_device *res)
974{
975 struct v4l2_mbus_framefmt *informat, *outformat;
976 struct resizer_luma_yenh luma = {0, 0, 0, 0};
977
978 resizer_set_source(res, res->input);
979
980 informat = &res->formats[RESZ_PAD_SINK];
981 outformat = &res->formats[RESZ_PAD_SOURCE];
982
983
984 if (res->input == RESIZER_INPUT_VP)
985 resizer_set_input_offset(res, 0);
986 else
987 resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2);
988
989
990 resizer_set_intype(res, RSZ_YUV422);
991 resizer_set_ycpos(res, informat->code);
992 resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE);
993 resizer_set_luma(res, &luma);
994
995
996 resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32));
997 resizer_set_output_size(res, outformat->width, outformat->height);
998
999 resizer_set_crop_params(res, informat, outformat);
1000}
1001
1002
1003
1004
1005
1006static void resizer_enable_oneshot(struct isp_res_device *res)
1007{
1008 struct isp_device *isp = to_isp_device(res);
1009
1010 isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR,
1011 ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT);
1012}
1013
1014void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res)
1015{
1016
1017
1018
1019
1020
1021
1022 if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
1023 res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1024 resizer_enable_oneshot(res);
1025 isp_video_dmaqueue_flags_clr(&res->video_out);
1026 }
1027}
1028
1029static void resizer_isr_buffer(struct isp_res_device *res)
1030{
1031 struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity);
1032 struct isp_buffer *buffer;
1033 int restart = 0;
1034
1035 if (res->state == ISP_PIPELINE_STREAM_STOPPED)
1036 return;
1037
1038
1039
1040
1041 buffer = omap3isp_video_buffer_next(&res->video_out, res->error);
1042 if (buffer != NULL) {
1043 resizer_set_outaddr(res, buffer->isp_addr);
1044 restart = 1;
1045 }
1046
1047 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;
1048
1049 if (res->input == RESIZER_INPUT_MEMORY) {
1050 buffer = omap3isp_video_buffer_next(&res->video_in, 0);
1051 if (buffer != NULL)
1052 resizer_set_inaddr(res, buffer->isp_addr);
1053 pipe->state |= ISP_PIPELINE_IDLE_INPUT;
1054 }
1055
1056 if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) {
1057 if (isp_pipeline_ready(pipe))
1058 omap3isp_pipeline_set_stream(pipe,
1059 ISP_PIPELINE_STREAM_SINGLESHOT);
1060 } else {
1061
1062
1063
1064 if (restart)
1065 resizer_enable_oneshot(res);
1066 }
1067
1068 res->error = 0;
1069}
1070
1071
1072
1073
1074
1075
1076
1077void omap3isp_resizer_isr(struct isp_res_device *res)
1078{
1079 struct v4l2_mbus_framefmt *informat, *outformat;
1080
1081 if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1082 return;
1083
1084 if (res->applycrop) {
1085 outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1086 V4L2_SUBDEV_FORMAT_ACTIVE);
1087 informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1088 V4L2_SUBDEV_FORMAT_ACTIVE);
1089 resizer_set_crop_params(res, informat, outformat);
1090 res->applycrop = 0;
1091 }
1092
1093 resizer_isr_buffer(res);
1094}
1095
1096
1097
1098
1099
1100static int resizer_video_queue(struct isp_video *video,
1101 struct isp_buffer *buffer)
1102{
1103 struct isp_res_device *res = &video->isp->isp_res;
1104
1105 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1106 resizer_set_inaddr(res, buffer->isp_addr);
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1121 resizer_set_outaddr(res, buffer->isp_addr);
1122
1123 return 0;
1124}
1125
1126static const struct isp_video_operations resizer_video_ops = {
1127 .queue = resizer_video_queue,
1128};
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1145{
1146 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1147 struct isp_video *video_out = &res->video_out;
1148 struct isp_device *isp = to_isp_device(res);
1149 struct device *dev = to_device(res);
1150
1151 if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1152 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1153 return 0;
1154
1155 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1156 resizer_configure(res);
1157 res->error = 0;
1158 resizer_print_status(res);
1159 }
1160
1161 switch (enable) {
1162 case ISP_PIPELINE_STREAM_CONTINUOUS:
1163 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1164 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1165 resizer_enable_oneshot(res);
1166 isp_video_dmaqueue_flags_clr(video_out);
1167 }
1168 break;
1169
1170 case ISP_PIPELINE_STREAM_SINGLESHOT:
1171 if (res->input == RESIZER_INPUT_MEMORY)
1172 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1173 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1174
1175 resizer_enable_oneshot(res);
1176 break;
1177
1178 case ISP_PIPELINE_STREAM_STOPPED:
1179 if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1180 &res->stopping))
1181 dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1182 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1183 OMAP3_ISP_SBL_RESIZER_WRITE);
1184 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1185 isp_video_dmaqueue_flags_clr(video_out);
1186 break;
1187 }
1188
1189 res->state = enable;
1190 return 0;
1191}
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1202 struct v4l2_subdev_crop *crop)
1203{
1204 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1205 struct v4l2_mbus_framefmt *format;
1206 struct resizer_ratio ratio;
1207
1208
1209 if (crop->pad != RESZ_PAD_SINK)
1210 return -EINVAL;
1211
1212 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1213 crop->rect = *__resizer_get_crop(res, fh, crop->which);
1214 resizer_calc_ratios(res, &crop->rect, format, &ratio);
1215
1216 return 0;
1217}
1218
1219
1220
1221
1222static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1223 const struct v4l2_mbus_framefmt *source,
1224 struct v4l2_rect *crop)
1225{
1226 const unsigned int spv = DEFAULT_PHASE;
1227 const unsigned int sph = DEFAULT_PHASE;
1228
1229
1230
1231
1232 unsigned int min_width =
1233 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1234 unsigned int min_height =
1235 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1236 unsigned int max_width =
1237 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1238 unsigned int max_height =
1239 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1240
1241 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1242 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1243
1244
1245 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1246 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1247 sink->width - crop->left);
1248 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1249 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1250 sink->height - crop->top);
1251}
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1262 struct v4l2_subdev_crop *crop)
1263{
1264 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1265 struct isp_device *isp = to_isp_device(res);
1266 struct v4l2_mbus_framefmt *format_sink, *format_source;
1267 struct resizer_ratio ratio;
1268
1269
1270 if (crop->pad != RESZ_PAD_SINK)
1271 return -EINVAL;
1272
1273 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1274 crop->which);
1275 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1276 crop->which);
1277
1278 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1279 crop->rect.left, crop->rect.top, crop->rect.width,
1280 crop->rect.height, crop->which);
1281
1282 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1283 format_sink->width, format_sink->height,
1284 format_source->width, format_source->height);
1285
1286 resizer_try_crop(format_sink, format_source, &crop->rect);
1287 *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1288 resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1289
1290 if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1291 return 0;
1292
1293 res->ratio = ratio;
1294 res->crop.active = crop->rect;
1295
1296
1297
1298
1299
1300 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1301 res->applycrop = 1;
1302
1303 return 0;
1304}
1305
1306
1307static const unsigned int resizer_formats[] = {
1308 V4L2_MBUS_FMT_UYVY8_1X16,
1309 V4L2_MBUS_FMT_YUYV8_1X16,
1310};
1311
1312static unsigned int resizer_max_in_width(struct isp_res_device *res)
1313{
1314 struct isp_device *isp = to_isp_device(res);
1315
1316 if (res->input == RESIZER_INPUT_MEMORY) {
1317 return MAX_IN_WIDTH_MEMORY_MODE;
1318 } else {
1319 if (isp->revision == ISP_REVISION_1_0)
1320 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1321 else
1322 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1323 }
1324}
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334static void resizer_try_format(struct isp_res_device *res,
1335 struct v4l2_subdev_fh *fh, unsigned int pad,
1336 struct v4l2_mbus_framefmt *fmt,
1337 enum v4l2_subdev_format_whence which)
1338{
1339 struct v4l2_mbus_framefmt *format;
1340 struct resizer_ratio ratio;
1341 struct v4l2_rect crop;
1342
1343 switch (pad) {
1344 case RESZ_PAD_SINK:
1345 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1346 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1347 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1348
1349 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1350 resizer_max_in_width(res));
1351 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1352 MAX_IN_HEIGHT);
1353 break;
1354
1355 case RESZ_PAD_SOURCE:
1356 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1357 fmt->code = format->code;
1358
1359 crop = *__resizer_get_crop(res, fh, which);
1360 resizer_calc_ratios(res, &crop, fmt, &ratio);
1361 break;
1362 }
1363
1364 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1365 fmt->field = V4L2_FIELD_NONE;
1366}
1367
1368
1369
1370
1371
1372
1373
1374
1375static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1376 struct v4l2_subdev_fh *fh,
1377 struct v4l2_subdev_mbus_code_enum *code)
1378{
1379 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1380 struct v4l2_mbus_framefmt *format;
1381
1382 if (code->pad == RESZ_PAD_SINK) {
1383 if (code->index >= ARRAY_SIZE(resizer_formats))
1384 return -EINVAL;
1385
1386 code->code = resizer_formats[code->index];
1387 } else {
1388 if (code->index != 0)
1389 return -EINVAL;
1390
1391 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1392 V4L2_SUBDEV_FORMAT_TRY);
1393 code->code = format->code;
1394 }
1395
1396 return 0;
1397}
1398
1399static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1400 struct v4l2_subdev_fh *fh,
1401 struct v4l2_subdev_frame_size_enum *fse)
1402{
1403 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1404 struct v4l2_mbus_framefmt format;
1405
1406 if (fse->index != 0)
1407 return -EINVAL;
1408
1409 format.code = fse->code;
1410 format.width = 1;
1411 format.height = 1;
1412 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1413 fse->min_width = format.width;
1414 fse->min_height = format.height;
1415
1416 if (format.code != fse->code)
1417 return -EINVAL;
1418
1419 format.code = fse->code;
1420 format.width = -1;
1421 format.height = -1;
1422 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1423 fse->max_width = format.width;
1424 fse->max_height = format.height;
1425
1426 return 0;
1427}
1428
1429
1430
1431
1432
1433
1434
1435
1436static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1437 struct v4l2_subdev_format *fmt)
1438{
1439 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1440 struct v4l2_mbus_framefmt *format;
1441
1442 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1443 if (format == NULL)
1444 return -EINVAL;
1445
1446 fmt->format = *format;
1447 return 0;
1448}
1449
1450
1451
1452
1453
1454
1455
1456
1457static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1458 struct v4l2_subdev_format *fmt)
1459{
1460 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1461 struct v4l2_mbus_framefmt *format;
1462 struct v4l2_rect *crop;
1463
1464 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1465 if (format == NULL)
1466 return -EINVAL;
1467
1468 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1469 *format = fmt->format;
1470
1471 if (fmt->pad == RESZ_PAD_SINK) {
1472
1473 crop = __resizer_get_crop(res, fh, fmt->which);
1474 crop->left = 0;
1475 crop->top = 0;
1476 crop->width = fmt->format.width;
1477 crop->height = fmt->format.height;
1478
1479
1480 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1481 fmt->which);
1482 *format = fmt->format;
1483 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1484 fmt->which);
1485 }
1486
1487 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1488
1489
1490
1491
1492 res->crop.active = res->crop.request;
1493 resizer_calc_ratios(res, &res->crop.active, format,
1494 &res->ratio);
1495 }
1496
1497 return 0;
1498}
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509static int resizer_init_formats(struct v4l2_subdev *sd,
1510 struct v4l2_subdev_fh *fh)
1511{
1512 struct v4l2_subdev_format format;
1513
1514 memset(&format, 0, sizeof(format));
1515 format.pad = RESZ_PAD_SINK;
1516 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1517 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1518 format.format.width = 4096;
1519 format.format.height = 4096;
1520 resizer_set_format(sd, fh, &format);
1521
1522 return 0;
1523}
1524
1525
1526static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1527 .s_stream = resizer_set_stream,
1528};
1529
1530
1531static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1532 .enum_mbus_code = resizer_enum_mbus_code,
1533 .enum_frame_size = resizer_enum_frame_size,
1534 .get_fmt = resizer_get_format,
1535 .set_fmt = resizer_set_format,
1536 .get_crop = resizer_g_crop,
1537 .set_crop = resizer_s_crop,
1538};
1539
1540
1541static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1542 .video = &resizer_v4l2_video_ops,
1543 .pad = &resizer_v4l2_pad_ops,
1544};
1545
1546
1547static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1548 .open = resizer_init_formats,
1549};
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563static int resizer_link_setup(struct media_entity *entity,
1564 const struct media_pad *local,
1565 const struct media_pad *remote, u32 flags)
1566{
1567 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1568 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1569
1570 switch (local->index | media_entity_type(remote->entity)) {
1571 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1572
1573 if (flags & MEDIA_LNK_FL_ENABLED) {
1574 if (res->input == RESIZER_INPUT_VP)
1575 return -EBUSY;
1576 res->input = RESIZER_INPUT_MEMORY;
1577 } else {
1578 if (res->input == RESIZER_INPUT_MEMORY)
1579 res->input = RESIZER_INPUT_NONE;
1580 }
1581 break;
1582
1583 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1584
1585 if (flags & MEDIA_LNK_FL_ENABLED) {
1586 if (res->input == RESIZER_INPUT_MEMORY)
1587 return -EBUSY;
1588 res->input = RESIZER_INPUT_VP;
1589 } else {
1590 if (res->input == RESIZER_INPUT_VP)
1591 res->input = RESIZER_INPUT_NONE;
1592 }
1593 break;
1594
1595 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1596
1597 break;
1598
1599 default:
1600 return -EINVAL;
1601 }
1602
1603 return 0;
1604}
1605
1606
1607static const struct media_entity_operations resizer_media_ops = {
1608 .link_setup = resizer_link_setup,
1609};
1610
1611
1612
1613
1614
1615
1616static int resizer_init_entities(struct isp_res_device *res)
1617{
1618 struct v4l2_subdev *sd = &res->subdev;
1619 struct media_pad *pads = res->pads;
1620 struct media_entity *me = &sd->entity;
1621 int ret;
1622
1623 res->input = RESIZER_INPUT_NONE;
1624
1625 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1626 sd->internal_ops = &resizer_v4l2_internal_ops;
1627 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1628 sd->grp_id = 1 << 16;
1629 v4l2_set_subdevdata(sd, res);
1630 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1631
1632 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1633 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1634
1635 me->ops = &resizer_media_ops;
1636 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1637 if (ret < 0)
1638 return ret;
1639
1640 resizer_init_formats(sd, NULL);
1641
1642 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1643 res->video_in.ops = &resizer_video_ops;
1644 res->video_in.isp = to_isp_device(res);
1645 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1646 res->video_in.bpl_alignment = 32;
1647 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1648 res->video_out.ops = &resizer_video_ops;
1649 res->video_out.isp = to_isp_device(res);
1650 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1651 res->video_out.bpl_alignment = 32;
1652
1653 ret = omap3isp_video_init(&res->video_in, "resizer");
1654 if (ret < 0)
1655 return ret;
1656
1657 ret = omap3isp_video_init(&res->video_out, "resizer");
1658 if (ret < 0)
1659 return ret;
1660
1661
1662 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1663 &res->subdev.entity, RESZ_PAD_SINK, 0);
1664 if (ret < 0)
1665 return ret;
1666
1667 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1668 &res->video_out.video.entity, 0, 0);
1669 if (ret < 0)
1670 return ret;
1671
1672 return 0;
1673}
1674
1675void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1676{
1677 media_entity_cleanup(&res->subdev.entity);
1678
1679 v4l2_device_unregister_subdev(&res->subdev);
1680 omap3isp_video_unregister(&res->video_in);
1681 omap3isp_video_unregister(&res->video_out);
1682}
1683
1684int omap3isp_resizer_register_entities(struct isp_res_device *res,
1685 struct v4l2_device *vdev)
1686{
1687 int ret;
1688
1689
1690 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1691 if (ret < 0)
1692 goto error;
1693
1694 ret = omap3isp_video_register(&res->video_in, vdev);
1695 if (ret < 0)
1696 goto error;
1697
1698 ret = omap3isp_video_register(&res->video_out, vdev);
1699 if (ret < 0)
1700 goto error;
1701
1702 return 0;
1703
1704error:
1705 omap3isp_resizer_unregister_entities(res);
1706 return ret;
1707}
1708
1709
1710
1711
1712
1713void omap3isp_resizer_cleanup(struct isp_device *isp)
1714{
1715}
1716
1717
1718
1719
1720
1721
1722int omap3isp_resizer_init(struct isp_device *isp)
1723{
1724 struct isp_res_device *res = &isp->isp_res;
1725 int ret;
1726
1727 init_waitqueue_head(&res->wait);
1728 atomic_set(&res->stopping, 0);
1729 ret = resizer_init_entities(res);
1730 if (ret < 0)
1731 goto out;
1732
1733out:
1734 if (ret)
1735 omap3isp_resizer_cleanup(isp);
1736
1737 return ret;
1738}
1739