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