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
1193static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
1194 const struct v4l2_mbus_framefmt *source,
1195 struct v4l2_rect *crop)
1196{
1197 const unsigned int spv = DEFAULT_PHASE;
1198 const unsigned int sph = DEFAULT_PHASE;
1199
1200
1201
1202
1203 unsigned int min_width =
1204 ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7;
1205 unsigned int min_height =
1206 ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4;
1207 unsigned int max_width =
1208 ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7;
1209 unsigned int max_height =
1210 ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7;
1211
1212 crop->width = clamp_t(u32, crop->width, min_width, max_width);
1213 crop->height = clamp_t(u32, crop->height, min_height, max_height);
1214
1215
1216 crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH);
1217 crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH,
1218 sink->width - crop->left);
1219 crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT);
1220 crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT,
1221 sink->height - crop->top);
1222}
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234static int resizer_get_selection(struct v4l2_subdev *sd,
1235 struct v4l2_subdev_fh *fh,
1236 struct v4l2_subdev_selection *sel)
1237{
1238 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1239 struct v4l2_mbus_framefmt *format_source;
1240 struct v4l2_mbus_framefmt *format_sink;
1241 struct resizer_ratio ratio;
1242
1243 if (sel->pad != RESZ_PAD_SINK)
1244 return -EINVAL;
1245
1246 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1247 sel->which);
1248 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1249 sel->which);
1250
1251 switch (sel->target) {
1252 case V4L2_SEL_TGT_CROP_BOUNDS:
1253 sel->r.left = 0;
1254 sel->r.top = 0;
1255 sel->r.width = INT_MAX;
1256 sel->r.height = INT_MAX;
1257
1258 resizer_try_crop(format_sink, format_source, &sel->r);
1259 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1260 break;
1261
1262 case V4L2_SEL_TGT_CROP:
1263 sel->r = *__resizer_get_crop(res, fh, sel->which);
1264 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1265 break;
1266
1267 default:
1268 return -EINVAL;
1269 }
1270
1271 return 0;
1272}
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287static int resizer_set_selection(struct v4l2_subdev *sd,
1288 struct v4l2_subdev_fh *fh,
1289 struct v4l2_subdev_selection *sel)
1290{
1291 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1292 struct isp_device *isp = to_isp_device(res);
1293 struct v4l2_mbus_framefmt *format_sink, *format_source;
1294 struct resizer_ratio ratio;
1295
1296 if (sel->target != V4L2_SEL_TGT_CROP ||
1297 sel->pad != RESZ_PAD_SINK)
1298 return -EINVAL;
1299
1300 format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1301 sel->which);
1302 format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1303 sel->which);
1304
1305 dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
1306 sel->r.left, sel->r.top, sel->r.width, sel->r.height,
1307 sel->which);
1308
1309 dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
1310 format_sink->width, format_sink->height,
1311 format_source->width, format_source->height);
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321 resizer_try_crop(format_sink, format_source, &sel->r);
1322 *__resizer_get_crop(res, fh, sel->which) = sel->r;
1323 resizer_calc_ratios(res, &sel->r, format_source, &ratio);
1324
1325 if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
1326 return 0;
1327
1328 res->ratio = ratio;
1329 res->crop.active = sel->r;
1330
1331
1332
1333
1334
1335 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1336 res->applycrop = 1;
1337
1338 return 0;
1339}
1340
1341
1342static const unsigned int resizer_formats[] = {
1343 V4L2_MBUS_FMT_UYVY8_1X16,
1344 V4L2_MBUS_FMT_YUYV8_1X16,
1345};
1346
1347static unsigned int resizer_max_in_width(struct isp_res_device *res)
1348{
1349 struct isp_device *isp = to_isp_device(res);
1350
1351 if (res->input == RESIZER_INPUT_MEMORY) {
1352 return MAX_IN_WIDTH_MEMORY_MODE;
1353 } else {
1354 if (isp->revision == ISP_REVISION_1_0)
1355 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1356 else
1357 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1358 }
1359}
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369static void resizer_try_format(struct isp_res_device *res,
1370 struct v4l2_subdev_fh *fh, unsigned int pad,
1371 struct v4l2_mbus_framefmt *fmt,
1372 enum v4l2_subdev_format_whence which)
1373{
1374 struct v4l2_mbus_framefmt *format;
1375 struct resizer_ratio ratio;
1376 struct v4l2_rect crop;
1377
1378 switch (pad) {
1379 case RESZ_PAD_SINK:
1380 if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
1381 fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
1382 fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
1383
1384 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1385 resizer_max_in_width(res));
1386 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1387 MAX_IN_HEIGHT);
1388 break;
1389
1390 case RESZ_PAD_SOURCE:
1391 format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which);
1392 fmt->code = format->code;
1393
1394 crop = *__resizer_get_crop(res, fh, which);
1395 resizer_calc_ratios(res, &crop, fmt, &ratio);
1396 break;
1397 }
1398
1399 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1400 fmt->field = V4L2_FIELD_NONE;
1401}
1402
1403
1404
1405
1406
1407
1408
1409
1410static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1411 struct v4l2_subdev_fh *fh,
1412 struct v4l2_subdev_mbus_code_enum *code)
1413{
1414 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1415 struct v4l2_mbus_framefmt *format;
1416
1417 if (code->pad == RESZ_PAD_SINK) {
1418 if (code->index >= ARRAY_SIZE(resizer_formats))
1419 return -EINVAL;
1420
1421 code->code = resizer_formats[code->index];
1422 } else {
1423 if (code->index != 0)
1424 return -EINVAL;
1425
1426 format = __resizer_get_format(res, fh, RESZ_PAD_SINK,
1427 V4L2_SUBDEV_FORMAT_TRY);
1428 code->code = format->code;
1429 }
1430
1431 return 0;
1432}
1433
1434static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1435 struct v4l2_subdev_fh *fh,
1436 struct v4l2_subdev_frame_size_enum *fse)
1437{
1438 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1439 struct v4l2_mbus_framefmt format;
1440
1441 if (fse->index != 0)
1442 return -EINVAL;
1443
1444 format.code = fse->code;
1445 format.width = 1;
1446 format.height = 1;
1447 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1448 fse->min_width = format.width;
1449 fse->min_height = format.height;
1450
1451 if (format.code != fse->code)
1452 return -EINVAL;
1453
1454 format.code = fse->code;
1455 format.width = -1;
1456 format.height = -1;
1457 resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
1458 fse->max_width = format.width;
1459 fse->max_height = format.height;
1460
1461 return 0;
1462}
1463
1464
1465
1466
1467
1468
1469
1470
1471static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1472 struct v4l2_subdev_format *fmt)
1473{
1474 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1475 struct v4l2_mbus_framefmt *format;
1476
1477 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1478 if (format == NULL)
1479 return -EINVAL;
1480
1481 fmt->format = *format;
1482 return 0;
1483}
1484
1485
1486
1487
1488
1489
1490
1491
1492static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
1493 struct v4l2_subdev_format *fmt)
1494{
1495 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1496 struct v4l2_mbus_framefmt *format;
1497 struct v4l2_rect *crop;
1498
1499 format = __resizer_get_format(res, fh, fmt->pad, fmt->which);
1500 if (format == NULL)
1501 return -EINVAL;
1502
1503 resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which);
1504 *format = fmt->format;
1505
1506 if (fmt->pad == RESZ_PAD_SINK) {
1507
1508 crop = __resizer_get_crop(res, fh, fmt->which);
1509 crop->left = 0;
1510 crop->top = 0;
1511 crop->width = fmt->format.width;
1512 crop->height = fmt->format.height;
1513
1514
1515 format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
1516 fmt->which);
1517 *format = fmt->format;
1518 resizer_try_format(res, fh, RESZ_PAD_SOURCE, format,
1519 fmt->which);
1520 }
1521
1522 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1523
1524
1525
1526
1527 res->crop.active = res->crop.request;
1528 resizer_calc_ratios(res, &res->crop.active, format,
1529 &res->ratio);
1530 }
1531
1532 return 0;
1533}
1534
1535static int resizer_link_validate(struct v4l2_subdev *sd,
1536 struct media_link *link,
1537 struct v4l2_subdev_format *source_fmt,
1538 struct v4l2_subdev_format *sink_fmt)
1539{
1540 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1541 struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
1542
1543 omap3isp_resizer_max_rate(res, &pipe->max_rate);
1544
1545 return v4l2_subdev_link_validate_default(sd, link,
1546 source_fmt, sink_fmt);
1547}
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558static int resizer_init_formats(struct v4l2_subdev *sd,
1559 struct v4l2_subdev_fh *fh)
1560{
1561 struct v4l2_subdev_format format;
1562
1563 memset(&format, 0, sizeof(format));
1564 format.pad = RESZ_PAD_SINK;
1565 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1566 format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
1567 format.format.width = 4096;
1568 format.format.height = 4096;
1569 resizer_set_format(sd, fh, &format);
1570
1571 return 0;
1572}
1573
1574
1575static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1576 .s_stream = resizer_set_stream,
1577};
1578
1579
1580static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1581 .enum_mbus_code = resizer_enum_mbus_code,
1582 .enum_frame_size = resizer_enum_frame_size,
1583 .get_fmt = resizer_get_format,
1584 .set_fmt = resizer_set_format,
1585 .get_selection = resizer_get_selection,
1586 .set_selection = resizer_set_selection,
1587 .link_validate = resizer_link_validate,
1588};
1589
1590
1591static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1592 .video = &resizer_v4l2_video_ops,
1593 .pad = &resizer_v4l2_pad_ops,
1594};
1595
1596
1597static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1598 .open = resizer_init_formats,
1599};
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613static int resizer_link_setup(struct media_entity *entity,
1614 const struct media_pad *local,
1615 const struct media_pad *remote, u32 flags)
1616{
1617 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1618 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1619
1620 switch (local->index | media_entity_type(remote->entity)) {
1621 case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE:
1622
1623 if (flags & MEDIA_LNK_FL_ENABLED) {
1624 if (res->input == RESIZER_INPUT_VP)
1625 return -EBUSY;
1626 res->input = RESIZER_INPUT_MEMORY;
1627 } else {
1628 if (res->input == RESIZER_INPUT_MEMORY)
1629 res->input = RESIZER_INPUT_NONE;
1630 }
1631 break;
1632
1633 case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
1634
1635 if (flags & MEDIA_LNK_FL_ENABLED) {
1636 if (res->input == RESIZER_INPUT_MEMORY)
1637 return -EBUSY;
1638 res->input = RESIZER_INPUT_VP;
1639 } else {
1640 if (res->input == RESIZER_INPUT_VP)
1641 res->input = RESIZER_INPUT_NONE;
1642 }
1643 break;
1644
1645 case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
1646
1647 break;
1648
1649 default:
1650 return -EINVAL;
1651 }
1652
1653 return 0;
1654}
1655
1656
1657static const struct media_entity_operations resizer_media_ops = {
1658 .link_setup = resizer_link_setup,
1659 .link_validate = v4l2_subdev_link_validate,
1660};
1661
1662void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1663{
1664 v4l2_device_unregister_subdev(&res->subdev);
1665 omap3isp_video_unregister(&res->video_in);
1666 omap3isp_video_unregister(&res->video_out);
1667}
1668
1669int omap3isp_resizer_register_entities(struct isp_res_device *res,
1670 struct v4l2_device *vdev)
1671{
1672 int ret;
1673
1674
1675 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1676 if (ret < 0)
1677 goto error;
1678
1679 ret = omap3isp_video_register(&res->video_in, vdev);
1680 if (ret < 0)
1681 goto error;
1682
1683 ret = omap3isp_video_register(&res->video_out, vdev);
1684 if (ret < 0)
1685 goto error;
1686
1687 return 0;
1688
1689error:
1690 omap3isp_resizer_unregister_entities(res);
1691 return ret;
1692}
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703static int resizer_init_entities(struct isp_res_device *res)
1704{
1705 struct v4l2_subdev *sd = &res->subdev;
1706 struct media_pad *pads = res->pads;
1707 struct media_entity *me = &sd->entity;
1708 int ret;
1709
1710 res->input = RESIZER_INPUT_NONE;
1711
1712 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1713 sd->internal_ops = &resizer_v4l2_internal_ops;
1714 strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1715 sd->grp_id = 1 << 16;
1716 v4l2_set_subdevdata(sd, res);
1717 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1718
1719 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
1720 | MEDIA_PAD_FL_MUST_CONNECT;
1721 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1722
1723 me->ops = &resizer_media_ops;
1724 ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0);
1725 if (ret < 0)
1726 return ret;
1727
1728 resizer_init_formats(sd, NULL);
1729
1730 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1731 res->video_in.ops = &resizer_video_ops;
1732 res->video_in.isp = to_isp_device(res);
1733 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1734 res->video_in.bpl_alignment = 32;
1735 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1736 res->video_out.ops = &resizer_video_ops;
1737 res->video_out.isp = to_isp_device(res);
1738 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1739 res->video_out.bpl_alignment = 32;
1740
1741 ret = omap3isp_video_init(&res->video_in, "resizer");
1742 if (ret < 0)
1743 goto error_video_in;
1744
1745 ret = omap3isp_video_init(&res->video_out, "resizer");
1746 if (ret < 0)
1747 goto error_video_out;
1748
1749 res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
1750
1751
1752 ret = media_entity_create_link(&res->video_in.video.entity, 0,
1753 &res->subdev.entity, RESZ_PAD_SINK, 0);
1754 if (ret < 0)
1755 goto error_link;
1756
1757 ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE,
1758 &res->video_out.video.entity, 0, 0);
1759 if (ret < 0)
1760 goto error_link;
1761
1762 return 0;
1763
1764error_link:
1765 omap3isp_video_cleanup(&res->video_out);
1766error_video_out:
1767 omap3isp_video_cleanup(&res->video_in);
1768error_video_in:
1769 media_entity_cleanup(&res->subdev.entity);
1770 return ret;
1771}
1772
1773
1774
1775
1776
1777
1778int omap3isp_resizer_init(struct isp_device *isp)
1779{
1780 struct isp_res_device *res = &isp->isp_res;
1781
1782 init_waitqueue_head(&res->wait);
1783 atomic_set(&res->stopping, 0);
1784 return resizer_init_entities(res);
1785}
1786
1787void omap3isp_resizer_cleanup(struct isp_device *isp)
1788{
1789 struct isp_res_device *res = &isp->isp_res;
1790
1791 omap3isp_video_cleanup(&res->video_in);
1792 omap3isp_video_cleanup(&res->video_out);
1793 media_entity_cleanup(&res->subdev.entity);
1794}
1795