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