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);
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);
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
1069
1070
1071
1072
1073
1074
1075void omap3isp_resizer_isr(struct isp_res_device *res)
1076{
1077 struct v4l2_mbus_framefmt *informat, *outformat;
1078
1079 if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping))
1080 return;
1081
1082 if (res->applycrop) {
1083 outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE,
1084 V4L2_SUBDEV_FORMAT_ACTIVE);
1085 informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK,
1086 V4L2_SUBDEV_FORMAT_ACTIVE);
1087 resizer_set_crop_params(res, informat, outformat);
1088 res->applycrop = 0;
1089 }
1090
1091 resizer_isr_buffer(res);
1092}
1093
1094
1095
1096
1097
1098static int resizer_video_queue(struct isp_video *video,
1099 struct isp_buffer *buffer)
1100{
1101 struct isp_res_device *res = &video->isp->isp_res;
1102
1103 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
1104 resizer_set_inaddr(res, buffer->isp_addr);
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1119 resizer_set_outaddr(res, buffer->isp_addr);
1120
1121 return 0;
1122}
1123
1124static const struct isp_video_operations resizer_video_ops = {
1125 .queue = resizer_video_queue,
1126};
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
1143{
1144 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1145 struct isp_video *video_out = &res->video_out;
1146 struct isp_device *isp = to_isp_device(res);
1147 struct device *dev = to_device(res);
1148
1149 if (res->state == ISP_PIPELINE_STREAM_STOPPED) {
1150 if (enable == ISP_PIPELINE_STREAM_STOPPED)
1151 return 0;
1152
1153 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1154 resizer_configure(res);
1155 resizer_print_status(res);
1156 }
1157
1158 switch (enable) {
1159 case ISP_PIPELINE_STREAM_CONTINUOUS:
1160 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1161 if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) {
1162 resizer_enable_oneshot(res);
1163 isp_video_dmaqueue_flags_clr(video_out);
1164 }
1165 break;
1166
1167 case ISP_PIPELINE_STREAM_SINGLESHOT:
1168 if (res->input == RESIZER_INPUT_MEMORY)
1169 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ);
1170 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE);
1171
1172 resizer_enable_oneshot(res);
1173 break;
1174
1175 case ISP_PIPELINE_STREAM_STOPPED:
1176 if (omap3isp_module_sync_idle(&sd->entity, &res->wait,
1177 &res->stopping))
1178 dev_dbg(dev, "%s: module stop timeout.\n", sd->name);
1179 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ |
1180 OMAP3_ISP_SBL_RESIZER_WRITE);
1181 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER);
1182 isp_video_dmaqueue_flags_clr(video_out);
1183 break;
1184 }
1185
1186 res->state = enable;
1187 return 0;
1188}
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1199 struct v4l2_subdev_crop *crop)
1200{
1201 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1202 struct v4l2_mbus_framefmt *format;
1203 struct resizer_ratio ratio;
1204
1205
1206 if (crop->pad != RESZ_PAD_SINK)
1207 return -EINVAL;
1208
1209 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
1210 crop->rect = *__resizer_get_crop(res, fh, crop->which);
1211 resizer_calc_ratios(res, &crop->rect, format, &ratio);
1212
1213 return 0;
1214}
1215
1216
1217
1218
1219static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1220 const struct v4l2_mbus_framefmt *source,
1221 struct v4l2_rect *crop)
1222{
1223 const unsigned int spv = DEFAULT_PHASE;
1224 const unsigned int sph = DEFAULT_PHASE;
1225
1226
1227
1228
1229 unsigned int min_width =
1230 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1231 unsigned int min_height =
1232 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1233 unsigned int max_width =
1234 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1235 unsigned int max_height =
1236 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1237
1238 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1239 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1240
1241
1242 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1243 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1244 sink->width - crop->left);
1245 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1246 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1247 sink->height - crop->top);
1248}
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1259 struct v4l2_subdev_crop *crop)
1260{
1261 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1262 struct isp_device *isp = to_isp_device(res);
1263 struct v4l2_mbus_framefmt *format_sink, *format_source;
1264 struct resizer_ratio ratio;
1265
1266
1267 if (crop->pad != RESZ_PAD_SINK)
1268 return -EINVAL;
1269
1270 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1271 crop->which);
1272 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1273 crop->which);
1274
1275 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1276 crop->rect.left, crop->rect.top, crop->rect.width,
1277 crop->rect.height, crop->which);
1278
1279 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1280 format_sink->width, format_sink->height,
1281 format_source->width, format_source->height);
1282
1283 resizer_try_crop(format_sink, format_source, &crop->rect);
1284 *__resizer_get_crop(res, fh, crop->which) = crop->rect;
1285 resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
1286
1287 if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
1288 return 0;
1289
1290 res->ratio = ratio;
1291 res->crop.active = crop->rect;
1292
1293
1294
1295
1296
1297 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1298 res->applycrop = 1;
1299
1300 return 0;
1301}
1302
1303
1304static const unsigned int resizer_formats[] = {
1305 V4L2_MBUS_FMT_UYVY8_1X16,
1306 V4L2_MBUS_FMT_YUYV8_1X16,
1307};
1308
1309static unsigned int resizer_max_in_width(struct isp_res_device *res)
1310{
1311 struct isp_device *isp = to_isp_device(res);
1312
1313 if (res->input == RESIZER_INPUT_MEMORY) {
1314 return MAX_IN_WIDTH_MEMORY_MODE;
1315 } else {
1316 if (isp->revision == ISP_REVISION_1_0)
1317 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1318 else
1319 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1320 }
1321}
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331static void resizer_try_format(struct isp_res_device *res,
1332 struct v4l2_subdev_fh *fh, unsigned int pad,
1333 struct v4l2_mbus_framefmt *fmt,
1334 enum v4l2_subdev_format_whence which)
1335{
1336 struct v4l2_mbus_framefmt *format;
1337 struct resizer_ratio ratio;
1338 struct v4l2_rect crop;
1339
1340 switch (pad) {
1341 case RESZ_PAD_SINK:
1342 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1343 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1344 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1345
1346 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1347 resizer_max_in_width(res));
1348 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1349 MAX_IN_HEIGHT);
1350 break;
1351
1352 case RESZ_PAD_SOURCE:
1353 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1354 fmt->code = format->code;
1355
1356 crop = *__resizer_get_crop(res, fh, which);
1357 resizer_calc_ratios(res, &crop, fmt, &ratio);
1358 break;
1359 }
1360
1361 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1362 fmt->field = V4L2_FIELD_NONE;
1363}
1364
1365
1366
1367
1368
1369
1370
1371
1372static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1373 struct v4l2_subdev_fh *fh,
1374 struct v4l2_subdev_mbus_code_enum *code)
1375{
1376 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1377 struct v4l2_mbus_framefmt *format;
1378
1379 if (code->pad == RESZ_PAD_SINK) {
1380 if (code->index >= ARRAY_SIZE(resizer_formats))
1381 return -EINVAL;
1382
1383 code->code = resizer_formats[code->index];
1384 } else {
1385 if (code->index != 0)
1386 return -EINVAL;
1387
1388 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1389 V4L2_SUBDEV_FORMAT_TRY);
1390 code->code = format->code;
1391 }
1392
1393 return 0;
1394}
1395
1396static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1397 struct v4l2_subdev_fh *fh,
1398 struct v4l2_subdev_frame_size_enum *fse)
1399{
1400 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1401 struct v4l2_mbus_framefmt format;
1402
1403 if (fse->index != 0)
1404 return -EINVAL;
1405
1406 format.code = fse->code;
1407 format.width = 1;
1408 format.height = 1;
1409 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1410 fse->min_width = format.width;
1411 fse->min_height = format.height;
1412
1413 if (format.code != fse->code)
1414 return -EINVAL;
1415
1416 format.code = fse->code;
1417 format.width = -1;
1418 format.height = -1;
1419 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1420 fse->max_width = format.width;
1421 fse->max_height = format.height;
1422
1423 return 0;
1424}
1425
1426
1427
1428
1429
1430
1431
1432
1433static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1434 struct v4l2_subdev_format *fmt)
1435{
1436 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1437 struct v4l2_mbus_framefmt *format;
1438
1439 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1440 if (format == NULL)
1441 return -EINVAL;
1442
1443 fmt->format = *format;
1444 return 0;
1445}
1446
1447
1448
1449
1450
1451
1452
1453
1454static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1455 struct v4l2_subdev_format *fmt)
1456{
1457 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1458 struct v4l2_mbus_framefmt *format;
1459 struct v4l2_rect *crop;
1460
1461 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1462 if (format == NULL)
1463 return -EINVAL;
1464
1465 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1466 *format = fmt->format;
1467
1468 if (fmt->pad == RESZ_PAD_SINK) {
1469
1470 crop = __resizer_get_crop(res, fh, fmt->which);
1471 crop->left = 0;
1472 crop->top = 0;
1473 crop->width = fmt->format.width;
1474 crop->height = fmt->format.height;
1475
1476
1477 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1478 fmt->which);
1479 *format = fmt->format;
1480 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1481 fmt->which);
1482 }
1483
1484 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1485
1486
1487
1488
1489 res->crop.active = res->crop.request;
1490 resizer_calc_ratios(res, &res->crop.active, format,
1491 &res->ratio);
1492 }
1493
1494 return 0;
1495}
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506static int resizer_init_formats(struct v4l2_subdev *sd,
1507 struct v4l2_subdev_fh *fh)
1508{
1509 struct v4l2_subdev_format format;
1510
1511 memset(&format, 0, sizeof(format));
1512 format.pad = RESZ_PAD_SINK;
1513 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1514 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1515 format.format.width = 4096;
1516 format.format.height = 4096;
1517 resizer_set_format(sd, fh, &format);
1518
1519 return 0;
1520}
1521
1522
1523static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1524 .s_stream = resizer_set_stream,
1525};
1526
1527
1528static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1529 .enum_mbus_code = resizer_enum_mbus_code,
1530 .enum_frame_size = resizer_enum_frame_size,
1531 .get_fmt = resizer_get_format,
1532 .set_fmt = resizer_set_format,
1533 .get_crop = resizer_g_crop,
1534 .set_crop = resizer_s_crop,
1535};
1536
1537
1538static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1539 .video = &resizer_v4l2_video_ops,
1540 .pad = &resizer_v4l2_pad_ops,
1541};
1542
1543
1544static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1545 .open = resizer_init_formats,
1546};
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560static int resizer_link_setup(struct media_entity *entity,
1561 const struct media_pad *local,
1562 const struct media_pad *remote, u32 flags)
1563{
1564 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1565 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1566
1567 switch (local->index | media_entity_type(remote->entity)) {
1568 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1569
1570 if (flags & MEDIA_LNK_FL_ENABLED) {
1571 if (res->input == RESIZER_INPUT_VP)
1572 return -EBUSY;
1573 res->input = RESIZER_INPUT_MEMORY;
1574 } else {
1575 if (res->input == RESIZER_INPUT_MEMORY)
1576 res->input = RESIZER_INPUT_NONE;
1577 }
1578 break;
1579
1580 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1581
1582 if (flags & MEDIA_LNK_FL_ENABLED) {
1583 if (res->input == RESIZER_INPUT_MEMORY)
1584 return -EBUSY;
1585 res->input = RESIZER_INPUT_VP;
1586 } else {
1587 if (res->input == RESIZER_INPUT_VP)
1588 res->input = RESIZER_INPUT_NONE;
1589 }
1590 break;
1591
1592 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1593
1594 break;
1595
1596 default:
1597 return -EINVAL;
1598 }
1599
1600 return 0;
1601}
1602
1603
1604static const struct media_entity_operations resizer_media_ops = {
1605 .link_setup = resizer_link_setup,
1606};
1607
1608void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1609{
1610 v4l2_device_unregister_subdev(&res->subdev);
1611 omap3isp_video_unregister(&res->video_in);
1612 omap3isp_video_unregister(&res->video_out);
1613}
1614
1615int omap3isp_resizer_register_entities(struct isp_res_device *res,
1616 struct v4l2_device *vdev)
1617{
1618 int ret;
1619
1620
1621 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1622 if (ret < 0)
1623 goto error;
1624
1625 ret = omap3isp_video_register(&res->video_in, vdev);
1626 if (ret < 0)
1627 goto error;
1628
1629 ret = omap3isp_video_register(&res->video_out, vdev);
1630 if (ret < 0)
1631 goto error;
1632
1633 return 0;
1634
1635error:
1636 omap3isp_resizer_unregister_entities(res);
1637 return ret;
1638}
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649static int resizer_init_entities(struct isp_res_device *res)
1650{
1651 struct v4l2_subdev *sd = &res->subdev;
1652 struct media_pad *pads = res->pads;
1653 struct media_entity *me = &sd->entity;
1654 int ret;
1655
1656 res->input = RESIZER_INPUT_NONE;
1657
1658 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1659 sd->internal_ops = &resizer_v4l2_internal_ops;
1660 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1661 sd->grp_id = 1 << 16;
1662 v4l2_set_subdevdata(sd, res);
1663 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1664
1665 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1666 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1667
1668 me->ops = &resizer_media_ops;
1669 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1670 if (ret < 0)
1671 return ret;
1672
1673 resizer_init_formats(sd, NULL);
1674
1675 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1676 res->video_in.ops = &resizer_video_ops;
1677 res->video_in.isp = to_isp_device(res);
1678 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1679 res->video_in.bpl_alignment = 32;
1680 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1681 res->video_out.ops = &resizer_video_ops;
1682 res->video_out.isp = to_isp_device(res);
1683 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1684 res->video_out.bpl_alignment = 32;
1685
1686 ret = omap3isp_video_init(&res->video_in, "resizer");
1687 if (ret < 0)
1688 goto error_video_in;
1689
1690 ret = omap3isp_video_init(&res->video_out, "resizer");
1691 if (ret < 0)
1692 goto error_video_out;
1693
1694
1695 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1696 &res->subdev.entity, RESZ_PAD_SINK, 0);
1697 if (ret < 0)
1698 goto error_link;
1699
1700 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1701 &res->video_out.video.entity, 0, 0);
1702 if (ret < 0)
1703 goto error_link;
1704
1705 return 0;
1706
1707error_link:
1708 omap3isp_video_cleanup(&res->video_out);
1709error_video_out:
1710 omap3isp_video_cleanup(&res->video_in);
1711error_video_in:
1712 media_entity_cleanup(&res->subdev.entity);
1713 return ret;
1714}
1715
1716
1717
1718
1719
1720
1721int omap3isp_resizer_init(struct isp_device *isp)
1722{
1723 struct isp_res_device *res = &isp->isp_res;
1724
1725 init_waitqueue_head(&res->wait);
1726 atomic_set(&res->stopping, 0);
1727 return resizer_init_entities(res);
1728}
1729
1730void omap3isp_resizer_cleanup(struct isp_device *isp)
1731{
1732 struct isp_res_device *res = &isp->isp_res;
1733
1734 omap3isp_video_cleanup(&res->video_in);
1735 omap3isp_video_cleanup(&res->video_out);
1736 media_entity_cleanup(&res->subdev.entity);
1737}
1738