1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/device.h>
15#include <linux/mm.h>
16#include <linux/module.h>
17
18#include "isp.h"
19#include "ispreg.h"
20#include "ispresizer.h"
21
22
23
24
25#define MIN_RESIZE_VALUE 64
26#define MID_RESIZE_VALUE 512
27#define MAX_RESIZE_VALUE 1024
28
29#define MIN_IN_WIDTH 32
30#define MIN_IN_HEIGHT 32
31#define MAX_IN_WIDTH_MEMORY_MODE 4095
32#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280
33#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095
34#define MAX_IN_HEIGHT 4095
35
36#define MIN_OUT_WIDTH 16
37#define MIN_OUT_HEIGHT 2
38#define MAX_OUT_HEIGHT 4095
39
40
41
42
43
44#define MAX_4TAP_OUT_WIDTH_ES1 1280
45#define MAX_7TAP_OUT_WIDTH_ES1 640
46#define MAX_4TAP_OUT_WIDTH_ES2 3312
47#define MAX_7TAP_OUT_WIDTH_ES2 1650
48#define MAX_4TAP_OUT_WIDTH_3630 4096
49#define MAX_7TAP_OUT_WIDTH_3630 2048
50
51
52
53
54#define RESIZE_DIVISOR 256
55#define DEFAULT_PHASE 1
56
57
58
59
60
61
62
63static const struct isprsz_coef filter_coefs = {
64
65 {
66 0x0000, 0x0100, 0x0000, 0x0000,
67 0x03FA, 0x00F6, 0x0010, 0x0000,
68 0x03F9, 0x00DB, 0x002C, 0x0000,
69 0x03FB, 0x00B3, 0x0053, 0x03FF,
70 0x03FD, 0x0082, 0x0084, 0x03FD,
71 0x03FF, 0x0053, 0x00B3, 0x03FB,
72 0x0000, 0x002C, 0x00DB, 0x03F9,
73 0x0000, 0x0010, 0x00F6, 0x03FA
74 },
75
76 {
77 0x0000, 0x0100, 0x0000, 0x0000,
78 0x03FA, 0x00F6, 0x0010, 0x0000,
79 0x03F9, 0x00DB, 0x002C, 0x0000,
80 0x03FB, 0x00B3, 0x0053, 0x03FF,
81 0x03FD, 0x0082, 0x0084, 0x03FD,
82 0x03FF, 0x0053, 0x00B3, 0x03FB,
83 0x0000, 0x002C, 0x00DB, 0x03F9,
84 0x0000, 0x0010, 0x00F6, 0x03FA
85 },
86
87 #define DUMMY 0
88 {
89 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
90 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
91 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
92 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
93 },
94
95 {
96 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY,
97 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY,
98 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY,
99 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY
100 }
101
102
103
104
105 #undef DUMMY
106};
107
108
109
110
111
112
113
114
115
116static struct v4l2_mbus_framefmt *
117__resizer_get_format(struct isp_res_device *res,
118 struct v4l2_subdev_state *sd_state,
119 unsigned int pad, enum v4l2_subdev_format_whence which)
120{
121 if (which == V4L2_SUBDEV_FORMAT_TRY)
122 return v4l2_subdev_get_try_format(&res->subdev, sd_state, pad);
123 else
124 return &res->formats[pad];
125}
126
127
128
129
130
131
132
133static struct v4l2_rect *
134__resizer_get_crop(struct isp_res_device *res,
135 struct v4l2_subdev_state *sd_state,
136 enum v4l2_subdev_format_whence which)
137{
138 if (which == V4L2_SUBDEV_FORMAT_TRY)
139 return v4l2_subdev_get_try_crop(&res->subdev, sd_state,
140 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_state *sd_state,
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, sd_state, RESZ_PAD_SINK,
1238 sel->which);
1239 format_source = __resizer_get_format(res, sd_state, 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, sd_state, 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_state *sd_state,
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, sd_state, RESZ_PAD_SINK,
1294 sel->which);
1295 format_source = *__resizer_get_format(res, sd_state, 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, sd_state, 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, sd_state, RESZ_PAD_SOURCE,
1324 sel->which) =
1325 format_source;
1326 return 0;
1327 }
1328
1329
1330
1331
1332
1333 spin_lock_irqsave(&res->lock, flags);
1334
1335 *__resizer_get_format(res, sd_state, RESZ_PAD_SOURCE, sel->which) =
1336 format_source;
1337
1338 res->ratio = ratio;
1339 res->crop.active = sel->r;
1340
1341 if (res->state != ISP_PIPELINE_STREAM_STOPPED)
1342 res->applycrop = 1;
1343
1344 spin_unlock_irqrestore(&res->lock, flags);
1345
1346 return 0;
1347}
1348
1349
1350static const unsigned int resizer_formats[] = {
1351 MEDIA_BUS_FMT_UYVY8_1X16,
1352 MEDIA_BUS_FMT_YUYV8_1X16,
1353};
1354
1355static unsigned int resizer_max_in_width(struct isp_res_device *res)
1356{
1357 struct isp_device *isp = to_isp_device(res);
1358
1359 if (res->input == RESIZER_INPUT_MEMORY) {
1360 return MAX_IN_WIDTH_MEMORY_MODE;
1361 } else {
1362 if (isp->revision == ISP_REVISION_1_0)
1363 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1;
1364 else
1365 return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
1366 }
1367}
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377static void resizer_try_format(struct isp_res_device *res,
1378 struct v4l2_subdev_state *sd_state,
1379 unsigned int pad,
1380 struct v4l2_mbus_framefmt *fmt,
1381 enum v4l2_subdev_format_whence which)
1382{
1383 struct v4l2_mbus_framefmt *format;
1384 struct resizer_ratio ratio;
1385 struct v4l2_rect crop;
1386
1387 switch (pad) {
1388 case RESZ_PAD_SINK:
1389 if (fmt->code != MEDIA_BUS_FMT_YUYV8_1X16 &&
1390 fmt->code != MEDIA_BUS_FMT_UYVY8_1X16)
1391 fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
1392
1393 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
1394 resizer_max_in_width(res));
1395 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT,
1396 MAX_IN_HEIGHT);
1397 break;
1398
1399 case RESZ_PAD_SOURCE:
1400 format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
1401 which);
1402 fmt->code = format->code;
1403
1404 crop = *__resizer_get_crop(res, sd_state, which);
1405 resizer_calc_ratios(res, &crop, fmt, &ratio);
1406 break;
1407 }
1408
1409 fmt->colorspace = V4L2_COLORSPACE_JPEG;
1410 fmt->field = V4L2_FIELD_NONE;
1411}
1412
1413
1414
1415
1416
1417
1418
1419
1420static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
1421 struct v4l2_subdev_state *sd_state,
1422 struct v4l2_subdev_mbus_code_enum *code)
1423{
1424 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1425 struct v4l2_mbus_framefmt *format;
1426
1427 if (code->pad == RESZ_PAD_SINK) {
1428 if (code->index >= ARRAY_SIZE(resizer_formats))
1429 return -EINVAL;
1430
1431 code->code = resizer_formats[code->index];
1432 } else {
1433 if (code->index != 0)
1434 return -EINVAL;
1435
1436 format = __resizer_get_format(res, sd_state, RESZ_PAD_SINK,
1437 code->which);
1438 code->code = format->code;
1439 }
1440
1441 return 0;
1442}
1443
1444static int resizer_enum_frame_size(struct v4l2_subdev *sd,
1445 struct v4l2_subdev_state *sd_state,
1446 struct v4l2_subdev_frame_size_enum *fse)
1447{
1448 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1449 struct v4l2_mbus_framefmt format;
1450
1451 if (fse->index != 0)
1452 return -EINVAL;
1453
1454 format.code = fse->code;
1455 format.width = 1;
1456 format.height = 1;
1457 resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
1458 fse->min_width = format.width;
1459 fse->min_height = format.height;
1460
1461 if (format.code != fse->code)
1462 return -EINVAL;
1463
1464 format.code = fse->code;
1465 format.width = -1;
1466 format.height = -1;
1467 resizer_try_format(res, sd_state, fse->pad, &format, fse->which);
1468 fse->max_width = format.width;
1469 fse->max_height = format.height;
1470
1471 return 0;
1472}
1473
1474
1475
1476
1477
1478
1479
1480
1481static int resizer_get_format(struct v4l2_subdev *sd,
1482 struct v4l2_subdev_state *sd_state,
1483 struct v4l2_subdev_format *fmt)
1484{
1485 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1486 struct v4l2_mbus_framefmt *format;
1487
1488 format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
1489 if (format == NULL)
1490 return -EINVAL;
1491
1492 fmt->format = *format;
1493 return 0;
1494}
1495
1496
1497
1498
1499
1500
1501
1502
1503static int resizer_set_format(struct v4l2_subdev *sd,
1504 struct v4l2_subdev_state *sd_state,
1505 struct v4l2_subdev_format *fmt)
1506{
1507 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1508 struct v4l2_mbus_framefmt *format;
1509 struct v4l2_rect *crop;
1510
1511 format = __resizer_get_format(res, sd_state, fmt->pad, fmt->which);
1512 if (format == NULL)
1513 return -EINVAL;
1514
1515 resizer_try_format(res, sd_state, fmt->pad, &fmt->format, fmt->which);
1516 *format = fmt->format;
1517
1518 if (fmt->pad == RESZ_PAD_SINK) {
1519
1520 crop = __resizer_get_crop(res, sd_state, fmt->which);
1521 crop->left = 0;
1522 crop->top = 0;
1523 crop->width = fmt->format.width;
1524 crop->height = fmt->format.height;
1525
1526
1527 format = __resizer_get_format(res, sd_state, RESZ_PAD_SOURCE,
1528 fmt->which);
1529 *format = fmt->format;
1530 resizer_try_format(res, sd_state, RESZ_PAD_SOURCE, format,
1531 fmt->which);
1532 }
1533
1534 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1535
1536
1537
1538
1539 res->crop.active = res->crop.request;
1540 resizer_calc_ratios(res, &res->crop.active, format,
1541 &res->ratio);
1542 }
1543
1544 return 0;
1545}
1546
1547static int resizer_link_validate(struct v4l2_subdev *sd,
1548 struct media_link *link,
1549 struct v4l2_subdev_format *source_fmt,
1550 struct v4l2_subdev_format *sink_fmt)
1551{
1552 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1553 struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
1554
1555 omap3isp_resizer_max_rate(res, &pipe->max_rate);
1556
1557 return v4l2_subdev_link_validate_default(sd, link,
1558 source_fmt, sink_fmt);
1559}
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570static int resizer_init_formats(struct v4l2_subdev *sd,
1571 struct v4l2_subdev_fh *fh)
1572{
1573 struct v4l2_subdev_format format;
1574
1575 memset(&format, 0, sizeof(format));
1576 format.pad = RESZ_PAD_SINK;
1577 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
1578 format.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
1579 format.format.width = 4096;
1580 format.format.height = 4096;
1581 resizer_set_format(sd, fh ? fh->state : NULL, &format);
1582
1583 return 0;
1584}
1585
1586
1587static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
1588 .s_stream = resizer_set_stream,
1589};
1590
1591
1592static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
1593 .enum_mbus_code = resizer_enum_mbus_code,
1594 .enum_frame_size = resizer_enum_frame_size,
1595 .get_fmt = resizer_get_format,
1596 .set_fmt = resizer_set_format,
1597 .get_selection = resizer_get_selection,
1598 .set_selection = resizer_set_selection,
1599 .link_validate = resizer_link_validate,
1600};
1601
1602
1603static const struct v4l2_subdev_ops resizer_v4l2_ops = {
1604 .video = &resizer_v4l2_video_ops,
1605 .pad = &resizer_v4l2_pad_ops,
1606};
1607
1608
1609static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
1610 .open = resizer_init_formats,
1611};
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625static int resizer_link_setup(struct media_entity *entity,
1626 const struct media_pad *local,
1627 const struct media_pad *remote, u32 flags)
1628{
1629 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
1630 struct isp_res_device *res = v4l2_get_subdevdata(sd);
1631 unsigned int index = local->index;
1632
1633
1634 if (is_media_entity_v4l2_subdev(remote->entity))
1635 index |= 2 << 16;
1636
1637 switch (index) {
1638 case RESZ_PAD_SINK:
1639
1640 if (flags & MEDIA_LNK_FL_ENABLED) {
1641 if (res->input == RESIZER_INPUT_VP)
1642 return -EBUSY;
1643 res->input = RESIZER_INPUT_MEMORY;
1644 } else {
1645 if (res->input == RESIZER_INPUT_MEMORY)
1646 res->input = RESIZER_INPUT_NONE;
1647 }
1648 break;
1649
1650 case RESZ_PAD_SINK | 2 << 16:
1651
1652 if (flags & MEDIA_LNK_FL_ENABLED) {
1653 if (res->input == RESIZER_INPUT_MEMORY)
1654 return -EBUSY;
1655 res->input = RESIZER_INPUT_VP;
1656 } else {
1657 if (res->input == RESIZER_INPUT_VP)
1658 res->input = RESIZER_INPUT_NONE;
1659 }
1660 break;
1661
1662 case RESZ_PAD_SOURCE:
1663
1664 break;
1665
1666 default:
1667 return -EINVAL;
1668 }
1669
1670 return 0;
1671}
1672
1673
1674static const struct media_entity_operations resizer_media_ops = {
1675 .link_setup = resizer_link_setup,
1676 .link_validate = v4l2_subdev_link_validate,
1677};
1678
1679void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
1680{
1681 v4l2_device_unregister_subdev(&res->subdev);
1682 omap3isp_video_unregister(&res->video_in);
1683 omap3isp_video_unregister(&res->video_out);
1684}
1685
1686int omap3isp_resizer_register_entities(struct isp_res_device *res,
1687 struct v4l2_device *vdev)
1688{
1689 int ret;
1690
1691
1692 res->subdev.dev = vdev->mdev->dev;
1693 ret = v4l2_device_register_subdev(vdev, &res->subdev);
1694 if (ret < 0)
1695 goto error;
1696
1697 ret = omap3isp_video_register(&res->video_in, vdev);
1698 if (ret < 0)
1699 goto error;
1700
1701 ret = omap3isp_video_register(&res->video_out, vdev);
1702 if (ret < 0)
1703 goto error;
1704
1705 return 0;
1706
1707error:
1708 omap3isp_resizer_unregister_entities(res);
1709 return ret;
1710}
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721static int resizer_init_entities(struct isp_res_device *res)
1722{
1723 struct v4l2_subdev *sd = &res->subdev;
1724 struct media_pad *pads = res->pads;
1725 struct media_entity *me = &sd->entity;
1726 int ret;
1727
1728 res->input = RESIZER_INPUT_NONE;
1729
1730 v4l2_subdev_init(sd, &resizer_v4l2_ops);
1731 sd->internal_ops = &resizer_v4l2_internal_ops;
1732 strscpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name));
1733 sd->grp_id = 1 << 16;
1734 v4l2_set_subdevdata(sd, res);
1735 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1736
1737 pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
1738 | MEDIA_PAD_FL_MUST_CONNECT;
1739 pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1740
1741 me->ops = &resizer_media_ops;
1742 ret = media_entity_pads_init(me, RESZ_PADS_NUM, pads);
1743 if (ret < 0)
1744 return ret;
1745
1746 resizer_init_formats(sd, NULL);
1747
1748 res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
1749 res->video_in.ops = &resizer_video_ops;
1750 res->video_in.isp = to_isp_device(res);
1751 res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1752 res->video_in.bpl_alignment = 32;
1753 res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1754 res->video_out.ops = &resizer_video_ops;
1755 res->video_out.isp = to_isp_device(res);
1756 res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3;
1757 res->video_out.bpl_alignment = 32;
1758
1759 ret = omap3isp_video_init(&res->video_in, "resizer");
1760 if (ret < 0)
1761 goto error_video_in;
1762
1763 ret = omap3isp_video_init(&res->video_out, "resizer");
1764 if (ret < 0)
1765 goto error_video_out;
1766
1767 res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
1768
1769 return 0;
1770
1771error_video_out:
1772 omap3isp_video_cleanup(&res->video_in);
1773error_video_in:
1774 media_entity_cleanup(&res->subdev.entity);
1775 return ret;
1776}
1777
1778
1779
1780
1781
1782
1783int omap3isp_resizer_init(struct isp_device *isp)
1784{
1785 struct isp_res_device *res = &isp->isp_res;
1786
1787 init_waitqueue_head(&res->wait);
1788 atomic_set(&res->stopping, 0);
1789 spin_lock_init(&res->lock);
1790
1791 return resizer_init_entities(res);
1792}
1793
1794void omap3isp_resizer_cleanup(struct isp_device *isp)
1795{
1796 struct isp_res_device *res = &isp->isp_res;
1797
1798 omap3isp_video_cleanup(&res->video_in);
1799 omap3isp_video_cleanup(&res->video_out);
1800 media_entity_cleanup(&res->subdev.entity);
1801}
1802