hc
2024-05-16 8d2a02b24d66aa359e83eebc1ed3c0f85367a1cb
kernel/drivers/gpu/ipu-v3/ipu-image-convert.c
....@@ -1,17 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2012-2016 Mentor Graphics Inc.
34 *
45 * Queued image conversion support, with tiling and rotation.
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms of the GNU General Public License as published by the
8
- * Free Software Foundation; either version 2 of the License, or (at your
9
- * option) any later version.
10
- *
11
- * This program is distributed in the hope that it will be useful, but
12
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
- * for more details.
156 */
167
178 #include <linux/interrupt.h>
....@@ -37,17 +28,36 @@
3728 * when double_buffering boolean is set).
3829 *
3930 * Note that the input frame must be split up into the same number
40
- * of tiles as the output frame.
31
+ * of tiles as the output frame:
4132 *
42
- * FIXME: at this point there is no attempt to deal with visible seams
43
- * at the tile boundaries when upscaling. The seams are caused by a reset
44
- * of the bilinear upscale interpolation when starting a new tile. The
45
- * seams are barely visible for small upscale factors, but become
46
- * increasingly visible as the upscale factor gets larger, since more
47
- * interpolated pixels get thrown out at the tile boundaries. A possilble
48
- * fix might be to overlap tiles of different sizes, but this must be done
49
- * while also maintaining the IDMAC dma buffer address alignment and 8x8 IRT
50
- * alignment restrictions of each tile.
33
+ * +---------+-----+
34
+ * +-----+---+ | A | B |
35
+ * | A | B | | | |
36
+ * +-----+---+ --> +---------+-----+
37
+ * | C | D | | C | D |
38
+ * +-----+---+ | | |
39
+ * +---------+-----+
40
+ *
41
+ * Clockwise 90° rotations are handled by first rescaling into a
42
+ * reusable temporary tile buffer and then rotating with the 8x8
43
+ * block rotator, writing to the correct destination:
44
+ *
45
+ * +-----+-----+
46
+ * | | |
47
+ * +-----+---+ +---------+ | C | A |
48
+ * | A | B | | A,B, | | | | |
49
+ * +-----+---+ --> | C,D | | --> | | |
50
+ * | C | D | +---------+ +-----+-----+
51
+ * +-----+---+ | D | B |
52
+ * | | |
53
+ * +-----+-----+
54
+ *
55
+ * If the 8x8 block rotator is used, horizontal or vertical flipping
56
+ * is done during the rotation step, otherwise flipping is done
57
+ * during the scaling step.
58
+ * With rotation or flipping, tile order changes between input and
59
+ * output image. Tiles are numbered row major from top left to bottom
60
+ * right for both input and output image.
5161 */
5262
5363 #define MAX_STRIPES_W 4
....@@ -84,6 +94,8 @@
8494 struct ipu_image_tile {
8595 u32 width;
8696 u32 height;
97
+ u32 left;
98
+ u32 top;
8799 /* size and strides are in bytes */
88100 u32 size;
89101 u32 stride;
....@@ -125,6 +137,17 @@
125137 struct ipu_image_convert_chan;
126138 struct ipu_image_convert_priv;
127139
140
+enum eof_irq_mask {
141
+ EOF_IRQ_IN = BIT(0),
142
+ EOF_IRQ_ROT_IN = BIT(1),
143
+ EOF_IRQ_OUT = BIT(2),
144
+ EOF_IRQ_ROT_OUT = BIT(3),
145
+};
146
+
147
+#define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
148
+#define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT | \
149
+ EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
150
+
128151 struct ipu_image_convert_ctx {
129152 struct ipu_image_convert_chan *chan;
130153
....@@ -134,7 +157,14 @@
134157 /* Source/destination image data and rotation mode */
135158 struct ipu_image_convert_image in;
136159 struct ipu_image_convert_image out;
160
+ struct ipu_ic_csc csc;
137161 enum ipu_rotate_mode rot_mode;
162
+ u32 downsize_coeff_h;
163
+ u32 downsize_coeff_v;
164
+ u32 image_resize_coeff_h;
165
+ u32 image_resize_coeff_v;
166
+ u32 resize_coeffs_h[MAX_STRIPES_W];
167
+ u32 resize_coeffs_v[MAX_STRIPES_H];
138168
139169 /* intermediate buffer for rotation */
140170 struct ipu_image_convert_dma_buf rot_intermediate[2];
....@@ -154,6 +184,9 @@
154184 /* where to place converted tile in dest image */
155185 unsigned int out_tile_map[MAX_TILES];
156186
187
+ /* mask of completed EOF irqs at every tile conversion */
188
+ enum eof_irq_mask eof_mask;
189
+
157190 struct list_head list;
158191 };
159192
....@@ -170,6 +203,8 @@
170203 struct ipuv3_channel *rotation_out_chan;
171204
172205 /* the IPU end-of-frame irqs */
206
+ int in_eof_irq;
207
+ int rot_in_eof_irq;
173208 int out_eof_irq;
174209 int rot_out_eof_irq;
175210
....@@ -231,6 +266,12 @@
231266 .bpp = 32,
232267 }, {
233268 .fourcc = V4L2_PIX_FMT_XBGR32,
269
+ .bpp = 32,
270
+ }, {
271
+ .fourcc = V4L2_PIX_FMT_BGRX32,
272
+ .bpp = 32,
273
+ }, {
274
+ .fourcc = V4L2_PIX_FMT_RGBX32,
234275 .bpp = 32,
235276 }, {
236277 .fourcc = V4L2_PIX_FMT_YUYV,
....@@ -300,12 +341,11 @@
300341 struct ipu_image_convert_priv *priv = chan->priv;
301342
302343 dev_dbg(priv->ipu->dev,
303
- "task %u: ctx %p: %s format: %dx%d (%dx%d tiles of size %dx%d), %c%c%c%c\n",
344
+ "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
304345 chan->ic_task, ctx,
305346 ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
306347 ic_image->base.pix.width, ic_image->base.pix.height,
307348 ic_image->num_cols, ic_image->num_rows,
308
- ic_image->tile[0].width, ic_image->tile[0].height,
309349 ic_image->fmt->fourcc & 0xff,
310350 (ic_image->fmt->fourcc >> 8) & 0xff,
311351 (ic_image->fmt->fourcc >> 16) & 0xff,
....@@ -353,24 +393,490 @@
353393
354394 static inline int num_stripes(int dim)
355395 {
356
- if (dim <= 1024)
357
- return 1;
358
- else if (dim <= 2048)
359
- return 2;
360
- else
361
- return 4;
396
+ return (dim - 1) / 1024 + 1;
362397 }
363398
364
-static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
365
- struct ipu_image_convert_image *image)
399
+/*
400
+ * Calculate downsizing coefficients, which are the same for all tiles,
401
+ * and initial bilinear resizing coefficients, which are used to find the
402
+ * best seam positions.
403
+ * Also determine the number of tiles necessary to guarantee that no tile
404
+ * is larger than 1024 pixels in either dimension at the output and between
405
+ * IC downsizing and main processing sections.
406
+ */
407
+static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
408
+ struct ipu_image *in,
409
+ struct ipu_image *out)
366410 {
367
- int i;
411
+ u32 downsized_width = in->rect.width;
412
+ u32 downsized_height = in->rect.height;
413
+ u32 downsize_coeff_v = 0;
414
+ u32 downsize_coeff_h = 0;
415
+ u32 resized_width = out->rect.width;
416
+ u32 resized_height = out->rect.height;
417
+ u32 resize_coeff_h;
418
+ u32 resize_coeff_v;
419
+ u32 cols;
420
+ u32 rows;
421
+
422
+ if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
423
+ resized_width = out->rect.height;
424
+ resized_height = out->rect.width;
425
+ }
426
+
427
+ /* Do not let invalid input lead to an endless loop below */
428
+ if (WARN_ON(resized_width == 0 || resized_height == 0))
429
+ return -EINVAL;
430
+
431
+ while (downsized_width >= resized_width * 2) {
432
+ downsized_width >>= 1;
433
+ downsize_coeff_h++;
434
+ }
435
+
436
+ while (downsized_height >= resized_height * 2) {
437
+ downsized_height >>= 1;
438
+ downsize_coeff_v++;
439
+ }
440
+
441
+ /*
442
+ * Calculate the bilinear resizing coefficients that could be used if
443
+ * we were converting with a single tile. The bottom right output pixel
444
+ * should sample as close as possible to the bottom right input pixel
445
+ * out of the decimator, but not overshoot it:
446
+ */
447
+ resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
448
+ resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
449
+
450
+ /*
451
+ * Both the output of the IC downsizing section before being passed to
452
+ * the IC main processing section and the final output of the IC main
453
+ * processing section must be <= 1024 pixels in both dimensions.
454
+ */
455
+ cols = num_stripes(max_t(u32, downsized_width, resized_width));
456
+ rows = num_stripes(max_t(u32, downsized_height, resized_height));
457
+
458
+ dev_dbg(ctx->chan->priv->ipu->dev,
459
+ "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
460
+ __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
461
+ resize_coeff_v, cols, rows);
462
+
463
+ if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
464
+ resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
465
+ return -EINVAL;
466
+
467
+ ctx->downsize_coeff_h = downsize_coeff_h;
468
+ ctx->downsize_coeff_v = downsize_coeff_v;
469
+ ctx->image_resize_coeff_h = resize_coeff_h;
470
+ ctx->image_resize_coeff_v = resize_coeff_v;
471
+ ctx->in.num_cols = cols;
472
+ ctx->in.num_rows = rows;
473
+
474
+ return 0;
475
+}
476
+
477
+#define round_closest(x, y) round_down((x) + (y)/2, (y))
478
+
479
+/*
480
+ * Find the best aligned seam position for the given column / row index.
481
+ * Rotation and image offsets are out of scope.
482
+ *
483
+ * @index: column / row index, used to calculate valid interval
484
+ * @in_edge: input right / bottom edge
485
+ * @out_edge: output right / bottom edge
486
+ * @in_align: input alignment, either horizontal 8-byte line start address
487
+ * alignment, or pixel alignment due to image format
488
+ * @out_align: output alignment, either horizontal 8-byte line start address
489
+ * alignment, or pixel alignment due to image format or rotator
490
+ * block size
491
+ * @in_burst: horizontal input burst size in case of horizontal flip
492
+ * @out_burst: horizontal output burst size or rotator block size
493
+ * @downsize_coeff: downsizing section coefficient
494
+ * @resize_coeff: main processing section resizing coefficient
495
+ * @_in_seam: aligned input seam position return value
496
+ * @_out_seam: aligned output seam position return value
497
+ */
498
+static void find_best_seam(struct ipu_image_convert_ctx *ctx,
499
+ unsigned int index,
500
+ unsigned int in_edge,
501
+ unsigned int out_edge,
502
+ unsigned int in_align,
503
+ unsigned int out_align,
504
+ unsigned int in_burst,
505
+ unsigned int out_burst,
506
+ unsigned int downsize_coeff,
507
+ unsigned int resize_coeff,
508
+ u32 *_in_seam,
509
+ u32 *_out_seam)
510
+{
511
+ struct device *dev = ctx->chan->priv->ipu->dev;
512
+ unsigned int out_pos;
513
+ /* Input / output seam position candidates */
514
+ unsigned int out_seam = 0;
515
+ unsigned int in_seam = 0;
516
+ unsigned int min_diff = UINT_MAX;
517
+ unsigned int out_start;
518
+ unsigned int out_end;
519
+ unsigned int in_start;
520
+ unsigned int in_end;
521
+
522
+ /* Start within 1024 pixels of the right / bottom edge */
523
+ out_start = max_t(int, index * out_align, out_edge - 1024);
524
+ /* End before having to add more columns to the left / rows above */
525
+ out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
526
+
527
+ /*
528
+ * Limit input seam position to make sure that the downsized input tile
529
+ * to the right or bottom does not exceed 1024 pixels.
530
+ */
531
+ in_start = max_t(int, index * in_align,
532
+ in_edge - (1024 << downsize_coeff));
533
+ in_end = min_t(unsigned int, in_edge,
534
+ index * (1024 << downsize_coeff) + 1);
535
+
536
+ /*
537
+ * Output tiles must start at a multiple of 8 bytes horizontally and
538
+ * possibly at an even line horizontally depending on the pixel format.
539
+ * Only consider output aligned positions for the seam.
540
+ */
541
+ out_start = round_up(out_start, out_align);
542
+ for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
543
+ unsigned int in_pos;
544
+ unsigned int in_pos_aligned;
545
+ unsigned int in_pos_rounded;
546
+ unsigned int abs_diff;
547
+
548
+ /*
549
+ * Tiles in the right row / bottom column may not be allowed to
550
+ * overshoot horizontally / vertically. out_burst may be the
551
+ * actual DMA burst size, or the rotator block size.
552
+ */
553
+ if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
554
+ continue;
555
+
556
+ /*
557
+ * Input sample position, corresponding to out_pos, 19.13 fixed
558
+ * point.
559
+ */
560
+ in_pos = (out_pos * resize_coeff) << downsize_coeff;
561
+ /*
562
+ * The closest input sample position that we could actually
563
+ * start the input tile at, 19.13 fixed point.
564
+ */
565
+ in_pos_aligned = round_closest(in_pos, 8192U * in_align);
566
+ /* Convert 19.13 fixed point to integer */
567
+ in_pos_rounded = in_pos_aligned / 8192U;
568
+
569
+ if (in_pos_rounded < in_start)
570
+ continue;
571
+ if (in_pos_rounded >= in_end)
572
+ break;
573
+
574
+ if ((in_burst > 1) &&
575
+ (in_edge - in_pos_rounded) % in_burst)
576
+ continue;
577
+
578
+ if (in_pos < in_pos_aligned)
579
+ abs_diff = in_pos_aligned - in_pos;
580
+ else
581
+ abs_diff = in_pos - in_pos_aligned;
582
+
583
+ if (abs_diff < min_diff) {
584
+ in_seam = in_pos_rounded;
585
+ out_seam = out_pos;
586
+ min_diff = abs_diff;
587
+ }
588
+ }
589
+
590
+ *_out_seam = out_seam;
591
+ *_in_seam = in_seam;
592
+
593
+ dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
594
+ __func__, out_seam, out_align, out_start, out_end,
595
+ in_seam, in_align, in_start, in_end, min_diff / 8192,
596
+ DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
597
+}
598
+
599
+/*
600
+ * Tile left edges are required to be aligned to multiples of 8 bytes
601
+ * by the IDMAC.
602
+ */
603
+static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
604
+{
605
+ if (fmt->planar)
606
+ return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
607
+ else
608
+ return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
609
+}
610
+
611
+/*
612
+ * Tile top edge alignment is only limited by chroma subsampling.
613
+ */
614
+static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
615
+{
616
+ return fmt->uv_height_dec > 1 ? 2 : 1;
617
+}
618
+
619
+static inline u32 tile_width_align(enum ipu_image_convert_type type,
620
+ const struct ipu_image_pixfmt *fmt,
621
+ enum ipu_rotate_mode rot_mode)
622
+{
623
+ if (type == IMAGE_CONVERT_IN) {
624
+ /*
625
+ * The IC burst reads 8 pixels at a time. Reading beyond the
626
+ * end of the line is usually acceptable. Those pixels are
627
+ * ignored, unless the IC has to write the scaled line in
628
+ * reverse.
629
+ */
630
+ return (!ipu_rot_mode_is_irt(rot_mode) &&
631
+ (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
632
+ }
633
+
634
+ /*
635
+ * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
636
+ * formats to guarantee 8-byte aligned line start addresses in the
637
+ * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
638
+ * for all other formats.
639
+ */
640
+ return (ipu_rot_mode_is_irt(rot_mode) &&
641
+ fmt->planar && !fmt->uv_packed) ?
642
+ 8 * fmt->uv_width_dec : 8;
643
+}
644
+
645
+static inline u32 tile_height_align(enum ipu_image_convert_type type,
646
+ const struct ipu_image_pixfmt *fmt,
647
+ enum ipu_rotate_mode rot_mode)
648
+{
649
+ if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
650
+ return 2;
651
+
652
+ /*
653
+ * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
654
+ * formats to guarantee 8-byte aligned line start addresses in the
655
+ * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
656
+ * for all other formats.
657
+ */
658
+ return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
659
+}
660
+
661
+/*
662
+ * Fill in left position and width and for all tiles in an input column, and
663
+ * for all corresponding output tiles. If the 90° rotator is used, the output
664
+ * tiles are in a row, and output tile top position and height are set.
665
+ */
666
+static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
667
+ unsigned int col,
668
+ struct ipu_image_convert_image *in,
669
+ unsigned int in_left, unsigned int in_width,
670
+ struct ipu_image_convert_image *out,
671
+ unsigned int out_left, unsigned int out_width)
672
+{
673
+ unsigned int row, tile_idx;
674
+ struct ipu_image_tile *in_tile, *out_tile;
675
+
676
+ for (row = 0; row < in->num_rows; row++) {
677
+ tile_idx = in->num_cols * row + col;
678
+ in_tile = &in->tile[tile_idx];
679
+ out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
680
+
681
+ in_tile->left = in_left;
682
+ in_tile->width = in_width;
683
+
684
+ if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
685
+ out_tile->top = out_left;
686
+ out_tile->height = out_width;
687
+ } else {
688
+ out_tile->left = out_left;
689
+ out_tile->width = out_width;
690
+ }
691
+ }
692
+}
693
+
694
+/*
695
+ * Fill in top position and height and for all tiles in an input row, and
696
+ * for all corresponding output tiles. If the 90° rotator is used, the output
697
+ * tiles are in a column, and output tile left position and width are set.
698
+ */
699
+static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
700
+ struct ipu_image_convert_image *in,
701
+ unsigned int in_top, unsigned int in_height,
702
+ struct ipu_image_convert_image *out,
703
+ unsigned int out_top, unsigned int out_height)
704
+{
705
+ unsigned int col, tile_idx;
706
+ struct ipu_image_tile *in_tile, *out_tile;
707
+
708
+ for (col = 0; col < in->num_cols; col++) {
709
+ tile_idx = in->num_cols * row + col;
710
+ in_tile = &in->tile[tile_idx];
711
+ out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
712
+
713
+ in_tile->top = in_top;
714
+ in_tile->height = in_height;
715
+
716
+ if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
717
+ out_tile->left = out_top;
718
+ out_tile->width = out_height;
719
+ } else {
720
+ out_tile->top = out_top;
721
+ out_tile->height = out_height;
722
+ }
723
+ }
724
+}
725
+
726
+/*
727
+ * Find the best horizontal and vertical seam positions to split into tiles.
728
+ * Minimize the fractional part of the input sampling position for the
729
+ * top / left pixels of each tile.
730
+ */
731
+static void find_seams(struct ipu_image_convert_ctx *ctx,
732
+ struct ipu_image_convert_image *in,
733
+ struct ipu_image_convert_image *out)
734
+{
735
+ struct device *dev = ctx->chan->priv->ipu->dev;
736
+ unsigned int resized_width = out->base.rect.width;
737
+ unsigned int resized_height = out->base.rect.height;
738
+ unsigned int col;
739
+ unsigned int row;
740
+ unsigned int in_left_align = tile_left_align(in->fmt);
741
+ unsigned int in_top_align = tile_top_align(in->fmt);
742
+ unsigned int out_left_align = tile_left_align(out->fmt);
743
+ unsigned int out_top_align = tile_top_align(out->fmt);
744
+ unsigned int out_width_align = tile_width_align(out->type, out->fmt,
745
+ ctx->rot_mode);
746
+ unsigned int out_height_align = tile_height_align(out->type, out->fmt,
747
+ ctx->rot_mode);
748
+ unsigned int in_right = in->base.rect.width;
749
+ unsigned int in_bottom = in->base.rect.height;
750
+ unsigned int out_right = out->base.rect.width;
751
+ unsigned int out_bottom = out->base.rect.height;
752
+ unsigned int flipped_out_left;
753
+ unsigned int flipped_out_top;
754
+
755
+ if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
756
+ /* Switch width/height and align top left to IRT block size */
757
+ resized_width = out->base.rect.height;
758
+ resized_height = out->base.rect.width;
759
+ out_left_align = out_height_align;
760
+ out_top_align = out_width_align;
761
+ out_width_align = out_left_align;
762
+ out_height_align = out_top_align;
763
+ out_right = out->base.rect.height;
764
+ out_bottom = out->base.rect.width;
765
+ }
766
+
767
+ for (col = in->num_cols - 1; col > 0; col--) {
768
+ bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
769
+ !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
770
+ bool allow_out_overshoot = (col < in->num_cols - 1) &&
771
+ !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
772
+ unsigned int in_left;
773
+ unsigned int out_left;
774
+
775
+ /*
776
+ * Align input width to burst length if the scaling step flips
777
+ * horizontally.
778
+ */
779
+
780
+ find_best_seam(ctx, col,
781
+ in_right, out_right,
782
+ in_left_align, out_left_align,
783
+ allow_in_overshoot ? 1 : 8 /* burst length */,
784
+ allow_out_overshoot ? 1 : out_width_align,
785
+ ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
786
+ &in_left, &out_left);
787
+
788
+ if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
789
+ flipped_out_left = resized_width - out_right;
790
+ else
791
+ flipped_out_left = out_left;
792
+
793
+ fill_tile_column(ctx, col, in, in_left, in_right - in_left,
794
+ out, flipped_out_left, out_right - out_left);
795
+
796
+ dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
797
+ in_left, in_right - in_left,
798
+ flipped_out_left, out_right - out_left);
799
+
800
+ in_right = in_left;
801
+ out_right = out_left;
802
+ }
803
+
804
+ flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
805
+ resized_width - out_right : 0;
806
+
807
+ fill_tile_column(ctx, 0, in, 0, in_right,
808
+ out, flipped_out_left, out_right);
809
+
810
+ dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
811
+ in_right, flipped_out_left, out_right);
812
+
813
+ for (row = in->num_rows - 1; row > 0; row--) {
814
+ bool allow_overshoot = row < in->num_rows - 1;
815
+ unsigned int in_top;
816
+ unsigned int out_top;
817
+
818
+ find_best_seam(ctx, row,
819
+ in_bottom, out_bottom,
820
+ in_top_align, out_top_align,
821
+ 1, allow_overshoot ? 1 : out_height_align,
822
+ ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
823
+ &in_top, &out_top);
824
+
825
+ if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
826
+ ipu_rot_mode_is_irt(ctx->rot_mode))
827
+ flipped_out_top = resized_height - out_bottom;
828
+ else
829
+ flipped_out_top = out_top;
830
+
831
+ fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
832
+ out, flipped_out_top, out_bottom - out_top);
833
+
834
+ dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
835
+ in_top, in_bottom - in_top,
836
+ flipped_out_top, out_bottom - out_top);
837
+
838
+ in_bottom = in_top;
839
+ out_bottom = out_top;
840
+ }
841
+
842
+ if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
843
+ ipu_rot_mode_is_irt(ctx->rot_mode))
844
+ flipped_out_top = resized_height - out_bottom;
845
+ else
846
+ flipped_out_top = 0;
847
+
848
+ fill_tile_row(ctx, 0, in, 0, in_bottom,
849
+ out, flipped_out_top, out_bottom);
850
+
851
+ dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
852
+ in_bottom, flipped_out_top, out_bottom);
853
+}
854
+
855
+static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
856
+ struct ipu_image_convert_image *image)
857
+{
858
+ struct ipu_image_convert_chan *chan = ctx->chan;
859
+ struct ipu_image_convert_priv *priv = chan->priv;
860
+ unsigned int max_width = 1024;
861
+ unsigned int max_height = 1024;
862
+ unsigned int i;
863
+
864
+ if (image->type == IMAGE_CONVERT_IN) {
865
+ /* Up to 4096x4096 input tile size */
866
+ max_width <<= ctx->downsize_coeff_h;
867
+ max_height <<= ctx->downsize_coeff_v;
868
+ }
368869
369870 for (i = 0; i < ctx->num_tiles; i++) {
370
- struct ipu_image_tile *tile = &image->tile[i];
871
+ struct ipu_image_tile *tile;
872
+ const unsigned int row = i / image->num_cols;
873
+ const unsigned int col = i % image->num_cols;
371874
372
- tile->height = image->base.pix.height / image->num_rows;
373
- tile->width = image->base.pix.width / image->num_cols;
875
+ if (image->type == IMAGE_CONVERT_OUT)
876
+ tile = &image->tile[ctx->out_tile_map[i]];
877
+ else
878
+ tile = &image->tile[i];
879
+
374880 tile->size = ((tile->height * image->fmt->bpp) >> 3) *
375881 tile->width;
376882
....@@ -383,7 +889,24 @@
383889 tile->rot_stride =
384890 (image->fmt->bpp * tile->height) >> 3;
385891 }
892
+
893
+ dev_dbg(priv->ipu->dev,
894
+ "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
895
+ chan->ic_task, ctx,
896
+ image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
897
+ row, col,
898
+ tile->width, tile->height, tile->left, tile->top);
899
+
900
+ if (!tile->width || tile->width > max_width ||
901
+ !tile->height || tile->height > max_height) {
902
+ dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
903
+ image->type == IMAGE_CONVERT_IN ? "input" :
904
+ "output", tile->width, tile->height);
905
+ return -EINVAL;
906
+ }
386907 }
908
+
909
+ return 0;
387910 }
388911
389912 /*
....@@ -459,14 +982,14 @@
459982 }
460983 }
461984
462
-static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
463
- struct ipu_image_convert_image *image)
985
+static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
986
+ struct ipu_image_convert_image *image)
464987 {
465988 struct ipu_image_convert_chan *chan = ctx->chan;
466989 struct ipu_image_convert_priv *priv = chan->priv;
467990 const struct ipu_image_pixfmt *fmt = image->fmt;
468991 unsigned int row, col, tile = 0;
469
- u32 H, w, h, y_stride, uv_stride;
992
+ u32 H, top, y_stride, uv_stride;
470993 u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
471994 u32 y_row_off, y_col_off, y_off;
472995 u32 y_size, uv_size;
....@@ -483,13 +1006,12 @@
4831006 uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
4841007
4851008 for (row = 0; row < image->num_rows; row++) {
486
- w = image->tile[tile].width;
487
- h = image->tile[tile].height;
488
- y_row_off = row * h * y_stride;
489
- uv_row_off = (row * h * uv_stride) / fmt->uv_height_dec;
1009
+ top = image->tile[tile].top;
1010
+ y_row_off = top * y_stride;
1011
+ uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
4901012
4911013 for (col = 0; col < image->num_cols; col++) {
492
- y_col_off = col * w;
1014
+ y_col_off = image->tile[tile].left;
4931015 uv_col_off = y_col_off / fmt->uv_width_dec;
4941016 if (fmt->uv_packed)
4951017 uv_col_off *= 2;
....@@ -509,24 +1031,30 @@
5091031 image->tile[tile].u_off = u_off;
5101032 image->tile[tile++].v_off = v_off;
5111033
512
- dev_dbg(priv->ipu->dev,
513
- "task %u: ctx %p: %s@[%d,%d]: y_off %08x, u_off %08x, v_off %08x\n",
514
- chan->ic_task, ctx,
515
- image->type == IMAGE_CONVERT_IN ?
516
- "Input" : "Output", row, col,
517
- y_off, u_off, v_off);
1034
+ if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
1035
+ dev_err(priv->ipu->dev,
1036
+ "task %u: ctx %p: %s@[%d,%d]: "
1037
+ "y_off %08x, u_off %08x, v_off %08x\n",
1038
+ chan->ic_task, ctx,
1039
+ image->type == IMAGE_CONVERT_IN ?
1040
+ "Input" : "Output", row, col,
1041
+ y_off, u_off, v_off);
1042
+ return -EINVAL;
1043
+ }
5181044 }
5191045 }
1046
+
1047
+ return 0;
5201048 }
5211049
522
-static void calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
523
- struct ipu_image_convert_image *image)
1050
+static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
1051
+ struct ipu_image_convert_image *image)
5241052 {
5251053 struct ipu_image_convert_chan *chan = ctx->chan;
5261054 struct ipu_image_convert_priv *priv = chan->priv;
5271055 const struct ipu_image_pixfmt *fmt = image->fmt;
5281056 unsigned int row, col, tile = 0;
529
- u32 w, h, bpp, stride;
1057
+ u32 bpp, stride, offset;
5301058 u32 row_off, col_off;
5311059
5321060 /* setup some convenience vars */
....@@ -534,34 +1062,189 @@
5341062 bpp = fmt->bpp;
5351063
5361064 for (row = 0; row < image->num_rows; row++) {
537
- w = image->tile[tile].width;
538
- h = image->tile[tile].height;
539
- row_off = row * h * stride;
1065
+ row_off = image->tile[tile].top * stride;
5401066
5411067 for (col = 0; col < image->num_cols; col++) {
542
- col_off = (col * w * bpp) >> 3;
1068
+ col_off = (image->tile[tile].left * bpp) >> 3;
5431069
544
- image->tile[tile].offset = row_off + col_off;
1070
+ offset = row_off + col_off;
1071
+
1072
+ image->tile[tile].offset = offset;
5451073 image->tile[tile].u_off = 0;
5461074 image->tile[tile++].v_off = 0;
5471075
548
- dev_dbg(priv->ipu->dev,
549
- "task %u: ctx %p: %s@[%d,%d]: phys %08x\n",
550
- chan->ic_task, ctx,
551
- image->type == IMAGE_CONVERT_IN ?
552
- "Input" : "Output", row, col,
553
- row_off + col_off);
1076
+ if (offset & 0x7) {
1077
+ dev_err(priv->ipu->dev,
1078
+ "task %u: ctx %p: %s@[%d,%d]: "
1079
+ "phys %08x\n",
1080
+ chan->ic_task, ctx,
1081
+ image->type == IMAGE_CONVERT_IN ?
1082
+ "Input" : "Output", row, col,
1083
+ row_off + col_off);
1084
+ return -EINVAL;
1085
+ }
5541086 }
5551087 }
1088
+
1089
+ return 0;
5561090 }
5571091
558
-static void calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
1092
+static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
5591093 struct ipu_image_convert_image *image)
5601094 {
5611095 if (image->fmt->planar)
562
- calc_tile_offsets_planar(ctx, image);
1096
+ return calc_tile_offsets_planar(ctx, image);
1097
+
1098
+ return calc_tile_offsets_packed(ctx, image);
1099
+}
1100
+
1101
+/*
1102
+ * Calculate the resizing ratio for the IC main processing section given input
1103
+ * size, fixed downsizing coefficient, and output size.
1104
+ * Either round to closest for the next tile's first pixel to minimize seams
1105
+ * and distortion (for all but right column / bottom row), or round down to
1106
+ * avoid sampling beyond the edges of the input image for this tile's last
1107
+ * pixel.
1108
+ * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
1109
+ */
1110
+static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
1111
+ u32 output_size, bool allow_overshoot)
1112
+{
1113
+ u32 downsized = input_size >> downsize_coeff;
1114
+
1115
+ if (allow_overshoot)
1116
+ return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
5631117 else
564
- calc_tile_offsets_packed(ctx, image);
1118
+ return 8192 * (downsized - 1) / (output_size - 1);
1119
+}
1120
+
1121
+/*
1122
+ * Slightly modify resize coefficients per tile to hide the bilinear
1123
+ * interpolator reset at tile borders, shifting the right / bottom edge
1124
+ * by up to a half input pixel. This removes noticeable seams between
1125
+ * tiles at higher upscaling factors.
1126
+ */
1127
+static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
1128
+{
1129
+ struct ipu_image_convert_chan *chan = ctx->chan;
1130
+ struct ipu_image_convert_priv *priv = chan->priv;
1131
+ struct ipu_image_tile *in_tile, *out_tile;
1132
+ unsigned int col, row, tile_idx;
1133
+ unsigned int last_output;
1134
+
1135
+ for (col = 0; col < ctx->in.num_cols; col++) {
1136
+ bool closest = (col < ctx->in.num_cols - 1) &&
1137
+ !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
1138
+ u32 resized_width;
1139
+ u32 resize_coeff_h;
1140
+ u32 in_width;
1141
+
1142
+ tile_idx = col;
1143
+ in_tile = &ctx->in.tile[tile_idx];
1144
+ out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1145
+
1146
+ if (ipu_rot_mode_is_irt(ctx->rot_mode))
1147
+ resized_width = out_tile->height;
1148
+ else
1149
+ resized_width = out_tile->width;
1150
+
1151
+ resize_coeff_h = calc_resize_coeff(in_tile->width,
1152
+ ctx->downsize_coeff_h,
1153
+ resized_width, closest);
1154
+
1155
+ dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
1156
+ __func__, col, resize_coeff_h);
1157
+
1158
+ /*
1159
+ * With the horizontal scaling factor known, round up resized
1160
+ * width (output width or height) to burst size.
1161
+ */
1162
+ resized_width = round_up(resized_width, 8);
1163
+
1164
+ /*
1165
+ * Calculate input width from the last accessed input pixel
1166
+ * given resized width and scaling coefficients. Round up to
1167
+ * burst size.
1168
+ */
1169
+ last_output = resized_width - 1;
1170
+ if (closest && ((last_output * resize_coeff_h) % 8192))
1171
+ last_output++;
1172
+ in_width = round_up(
1173
+ (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
1174
+ << ctx->downsize_coeff_h, 8);
1175
+
1176
+ for (row = 0; row < ctx->in.num_rows; row++) {
1177
+ tile_idx = row * ctx->in.num_cols + col;
1178
+ in_tile = &ctx->in.tile[tile_idx];
1179
+ out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1180
+
1181
+ if (ipu_rot_mode_is_irt(ctx->rot_mode))
1182
+ out_tile->height = resized_width;
1183
+ else
1184
+ out_tile->width = resized_width;
1185
+
1186
+ in_tile->width = in_width;
1187
+ }
1188
+
1189
+ ctx->resize_coeffs_h[col] = resize_coeff_h;
1190
+ }
1191
+
1192
+ for (row = 0; row < ctx->in.num_rows; row++) {
1193
+ bool closest = (row < ctx->in.num_rows - 1) &&
1194
+ !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
1195
+ u32 resized_height;
1196
+ u32 resize_coeff_v;
1197
+ u32 in_height;
1198
+
1199
+ tile_idx = row * ctx->in.num_cols;
1200
+ in_tile = &ctx->in.tile[tile_idx];
1201
+ out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1202
+
1203
+ if (ipu_rot_mode_is_irt(ctx->rot_mode))
1204
+ resized_height = out_tile->width;
1205
+ else
1206
+ resized_height = out_tile->height;
1207
+
1208
+ resize_coeff_v = calc_resize_coeff(in_tile->height,
1209
+ ctx->downsize_coeff_v,
1210
+ resized_height, closest);
1211
+
1212
+ dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
1213
+ __func__, row, resize_coeff_v);
1214
+
1215
+ /*
1216
+ * With the vertical scaling factor known, round up resized
1217
+ * height (output width or height) to IDMAC limitations.
1218
+ */
1219
+ resized_height = round_up(resized_height, 2);
1220
+
1221
+ /*
1222
+ * Calculate input width from the last accessed input pixel
1223
+ * given resized height and scaling coefficients. Align to
1224
+ * IDMAC restrictions.
1225
+ */
1226
+ last_output = resized_height - 1;
1227
+ if (closest && ((last_output * resize_coeff_v) % 8192))
1228
+ last_output++;
1229
+ in_height = round_up(
1230
+ (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
1231
+ << ctx->downsize_coeff_v, 2);
1232
+
1233
+ for (col = 0; col < ctx->in.num_cols; col++) {
1234
+ tile_idx = row * ctx->in.num_cols + col;
1235
+ in_tile = &ctx->in.tile[tile_idx];
1236
+ out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1237
+
1238
+ if (ipu_rot_mode_is_irt(ctx->rot_mode))
1239
+ out_tile->width = resized_height;
1240
+ else
1241
+ out_tile->height = resized_height;
1242
+
1243
+ in_tile->height = in_height;
1244
+ }
1245
+
1246
+ ctx->resize_coeffs_v[row] = resize_coeff_v;
1247
+ }
5651248 }
5661249
5671250 /*
....@@ -611,7 +1294,8 @@
6111294 struct ipuv3_channel *channel,
6121295 struct ipu_image_convert_image *image,
6131296 enum ipu_rotate_mode rot_mode,
614
- bool rot_swap_width_height)
1297
+ bool rot_swap_width_height,
1298
+ unsigned int tile)
6151299 {
6161300 struct ipu_image_convert_chan *chan = ctx->chan;
6171301 unsigned int burst_size;
....@@ -621,23 +1305,23 @@
6211305 unsigned int tile_idx[2];
6221306
6231307 if (image->type == IMAGE_CONVERT_OUT) {
624
- tile_idx[0] = ctx->out_tile_map[0];
1308
+ tile_idx[0] = ctx->out_tile_map[tile];
6251309 tile_idx[1] = ctx->out_tile_map[1];
6261310 } else {
627
- tile_idx[0] = 0;
1311
+ tile_idx[0] = tile;
6281312 tile_idx[1] = 1;
6291313 }
6301314
6311315 if (rot_swap_width_height) {
632
- width = image->tile[0].height;
633
- height = image->tile[0].width;
634
- stride = image->tile[0].rot_stride;
1316
+ width = image->tile[tile_idx[0]].height;
1317
+ height = image->tile[tile_idx[0]].width;
1318
+ stride = image->tile[tile_idx[0]].rot_stride;
6351319 addr0 = ctx->rot_intermediate[0].phys;
6361320 if (ctx->double_buffering)
6371321 addr1 = ctx->rot_intermediate[1].phys;
6381322 } else {
639
- width = image->tile[0].width;
640
- height = image->tile[0].height;
1323
+ width = image->tile[tile_idx[0]].width;
1324
+ height = image->tile[tile_idx[0]].height;
6411325 stride = image->stride;
6421326 addr0 = image->base.phys0 +
6431327 image->tile[tile_idx[0]].offset;
....@@ -655,15 +1339,24 @@
6551339 tile_image.pix.pixelformat = image->fmt->fourcc;
6561340 tile_image.phys0 = addr0;
6571341 tile_image.phys1 = addr1;
658
- ipu_cpmem_set_image(channel, &tile_image);
1342
+ if (image->fmt->planar && !rot_swap_width_height) {
1343
+ tile_image.u_offset = image->tile[tile_idx[0]].u_off;
1344
+ tile_image.v_offset = image->tile[tile_idx[0]].v_off;
1345
+ }
6591346
660
- if (image->fmt->planar && !rot_swap_width_height)
661
- ipu_cpmem_set_uv_offset(channel,
662
- image->tile[tile_idx[0]].u_off,
663
- image->tile[tile_idx[0]].v_off);
1347
+ ipu_cpmem_set_image(channel, &tile_image);
6641348
6651349 if (rot_mode)
6661350 ipu_cpmem_set_rotation(channel, rot_mode);
1351
+
1352
+ /*
1353
+ * Skip writing U and V components to odd rows in the output
1354
+ * channels for planar 4:2:0.
1355
+ */
1356
+ if ((channel == chan->out_chan ||
1357
+ channel == chan->rotation_out_chan) &&
1358
+ image->fmt->planar && image->fmt->uv_height_dec == 2)
1359
+ ipu_cpmem_skip_odd_chroma_rows(channel);
6671360
6681361 if (channel == chan->rotation_in_chan ||
6691362 channel == chan->rotation_out_chan) {
....@@ -687,39 +1380,53 @@
6871380 ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
6881381 }
6891382
690
-static int convert_start(struct ipu_image_convert_run *run)
1383
+static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
6911384 {
6921385 struct ipu_image_convert_ctx *ctx = run->ctx;
6931386 struct ipu_image_convert_chan *chan = ctx->chan;
6941387 struct ipu_image_convert_priv *priv = chan->priv;
6951388 struct ipu_image_convert_image *s_image = &ctx->in;
6961389 struct ipu_image_convert_image *d_image = &ctx->out;
697
- enum ipu_color_space src_cs, dest_cs;
1390
+ unsigned int dst_tile = ctx->out_tile_map[tile];
6981391 unsigned int dest_width, dest_height;
1392
+ unsigned int col, row;
1393
+ u32 rsc;
6991394 int ret;
7001395
701
- dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p\n",
702
- __func__, chan->ic_task, ctx, run);
1396
+ dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
1397
+ __func__, chan->ic_task, ctx, run, tile, dst_tile);
7031398
704
- src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc);
705
- dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc);
1399
+ /* clear EOF irq mask */
1400
+ ctx->eof_mask = 0;
7061401
7071402 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7081403 /* swap width/height for resizer */
709
- dest_width = d_image->tile[0].height;
710
- dest_height = d_image->tile[0].width;
1404
+ dest_width = d_image->tile[dst_tile].height;
1405
+ dest_height = d_image->tile[dst_tile].width;
7111406 } else {
712
- dest_width = d_image->tile[0].width;
713
- dest_height = d_image->tile[0].height;
1407
+ dest_width = d_image->tile[dst_tile].width;
1408
+ dest_height = d_image->tile[dst_tile].height;
7141409 }
7151410
1411
+ row = tile / s_image->num_cols;
1412
+ col = tile % s_image->num_cols;
1413
+
1414
+ rsc = (ctx->downsize_coeff_v << 30) |
1415
+ (ctx->resize_coeffs_v[row] << 16) |
1416
+ (ctx->downsize_coeff_h << 14) |
1417
+ (ctx->resize_coeffs_h[col]);
1418
+
1419
+ dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
1420
+ __func__, s_image->tile[tile].width,
1421
+ s_image->tile[tile].height, dest_width, dest_height, rsc);
1422
+
7161423 /* setup the IC resizer and CSC */
717
- ret = ipu_ic_task_init(chan->ic,
718
- s_image->tile[0].width,
719
- s_image->tile[0].height,
720
- dest_width,
721
- dest_height,
722
- src_cs, dest_cs);
1424
+ ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
1425
+ s_image->tile[tile].width,
1426
+ s_image->tile[tile].height,
1427
+ dest_width,
1428
+ dest_height,
1429
+ rsc);
7231430 if (ret) {
7241431 dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
7251432 return ret;
....@@ -727,27 +1434,27 @@
7271434
7281435 /* init the source MEM-->IC PP IDMAC channel */
7291436 init_idmac_channel(ctx, chan->in_chan, s_image,
730
- IPU_ROTATE_NONE, false);
1437
+ IPU_ROTATE_NONE, false, tile);
7311438
7321439 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
7331440 /* init the IC PP-->MEM IDMAC channel */
7341441 init_idmac_channel(ctx, chan->out_chan, d_image,
735
- IPU_ROTATE_NONE, true);
1442
+ IPU_ROTATE_NONE, true, tile);
7361443
7371444 /* init the MEM-->IC PP ROT IDMAC channel */
7381445 init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
739
- ctx->rot_mode, true);
1446
+ ctx->rot_mode, true, tile);
7401447
7411448 /* init the destination IC PP ROT-->MEM IDMAC channel */
7421449 init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
743
- IPU_ROTATE_NONE, false);
1450
+ IPU_ROTATE_NONE, false, tile);
7441451
7451452 /* now link IC PP-->MEM to MEM-->IC PP ROT */
7461453 ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
7471454 } else {
7481455 /* init the destination IC PP-->MEM IDMAC channel */
7491456 init_idmac_channel(ctx, chan->out_chan, d_image,
750
- ctx->rot_mode, false);
1457
+ ctx->rot_mode, false, tile);
7511458 }
7521459
7531460 /* enable the IC */
....@@ -805,7 +1512,7 @@
8051512 list_del(&run->list);
8061513 chan->current_run = run;
8071514
808
- return convert_start(run);
1515
+ return convert_start(run, 0);
8091516 }
8101517
8111518 /* hold irqlock when calling */
....@@ -896,7 +1603,7 @@
8961603 dev_dbg(priv->ipu->dev,
8971604 "%s: task %u: signaling abort for ctx %p\n",
8981605 __func__, chan->ic_task, ctx);
899
- complete(&ctx->aborted);
1606
+ complete_all(&ctx->aborted);
9001607 }
9011608 }
9021609
....@@ -908,8 +1615,26 @@
9081615 return IRQ_HANDLED;
9091616 }
9101617
1618
+static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
1619
+{
1620
+ unsigned int cur_tile = ctx->next_tile - 1;
1621
+ unsigned int next_tile = ctx->next_tile;
1622
+
1623
+ if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
1624
+ ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
1625
+ ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
1626
+ ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
1627
+ ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
1628
+ ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
1629
+ ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
1630
+ ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
1631
+ return true;
1632
+
1633
+ return false;
1634
+}
1635
+
9111636 /* hold irqlock when calling */
912
-static irqreturn_t do_irq(struct ipu_image_convert_run *run)
1637
+static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
9131638 {
9141639 struct ipu_image_convert_ctx *ctx = run->ctx;
9151640 struct ipu_image_convert_chan *chan = ctx->chan;
....@@ -951,27 +1676,32 @@
9511676 * not done, place the next tile buffers.
9521677 */
9531678 if (!ctx->double_buffering) {
1679
+ if (ic_settings_changed(ctx)) {
1680
+ convert_stop(run);
1681
+ convert_start(run, ctx->next_tile);
1682
+ } else {
1683
+ src_tile = &s_image->tile[ctx->next_tile];
1684
+ dst_idx = ctx->out_tile_map[ctx->next_tile];
1685
+ dst_tile = &d_image->tile[dst_idx];
9541686
955
- src_tile = &s_image->tile[ctx->next_tile];
956
- dst_idx = ctx->out_tile_map[ctx->next_tile];
957
- dst_tile = &d_image->tile[dst_idx];
1687
+ ipu_cpmem_set_buffer(chan->in_chan, 0,
1688
+ s_image->base.phys0 +
1689
+ src_tile->offset);
1690
+ ipu_cpmem_set_buffer(outch, 0,
1691
+ d_image->base.phys0 +
1692
+ dst_tile->offset);
1693
+ if (s_image->fmt->planar)
1694
+ ipu_cpmem_set_uv_offset(chan->in_chan,
1695
+ src_tile->u_off,
1696
+ src_tile->v_off);
1697
+ if (d_image->fmt->planar)
1698
+ ipu_cpmem_set_uv_offset(outch,
1699
+ dst_tile->u_off,
1700
+ dst_tile->v_off);
9581701
959
- ipu_cpmem_set_buffer(chan->in_chan, 0,
960
- s_image->base.phys0 + src_tile->offset);
961
- ipu_cpmem_set_buffer(outch, 0,
962
- d_image->base.phys0 + dst_tile->offset);
963
- if (s_image->fmt->planar)
964
- ipu_cpmem_set_uv_offset(chan->in_chan,
965
- src_tile->u_off,
966
- src_tile->v_off);
967
- if (d_image->fmt->planar)
968
- ipu_cpmem_set_uv_offset(outch,
969
- dst_tile->u_off,
970
- dst_tile->v_off);
971
-
972
- ipu_idmac_select_buffer(chan->in_chan, 0);
973
- ipu_idmac_select_buffer(outch, 0);
974
-
1702
+ ipu_idmac_select_buffer(chan->in_chan, 0);
1703
+ ipu_idmac_select_buffer(outch, 0);
1704
+ }
9751705 } else if (ctx->next_tile < ctx->num_tiles - 1) {
9761706
9771707 src_tile = &s_image->tile[ctx->next_tile + 1];
....@@ -989,6 +1719,7 @@
9891719 ctx->cur_buf_num ^= 1;
9901720 }
9911721
1722
+ ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
9921723 ctx->next_tile++;
9931724 return IRQ_HANDLED;
9941725 done:
....@@ -1004,8 +1735,9 @@
10041735 struct ipu_image_convert_priv *priv = chan->priv;
10051736 struct ipu_image_convert_ctx *ctx;
10061737 struct ipu_image_convert_run *run;
1738
+ irqreturn_t ret = IRQ_HANDLED;
1739
+ bool tile_complete = false;
10071740 unsigned long flags;
1008
- irqreturn_t ret;
10091741
10101742 spin_lock_irqsave(&chan->irqlock, flags);
10111743
....@@ -1018,27 +1750,33 @@
10181750
10191751 ctx = run->ctx;
10201752
1021
- if (irq == chan->out_eof_irq) {
1022
- if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1023
- /* this is a rotation op, just ignore */
1024
- ret = IRQ_HANDLED;
1025
- goto out;
1026
- }
1027
- } else if (irq == chan->rot_out_eof_irq) {
1753
+ if (irq == chan->in_eof_irq) {
1754
+ ctx->eof_mask |= EOF_IRQ_IN;
1755
+ } else if (irq == chan->out_eof_irq) {
1756
+ ctx->eof_mask |= EOF_IRQ_OUT;
1757
+ } else if (irq == chan->rot_in_eof_irq ||
1758
+ irq == chan->rot_out_eof_irq) {
10281759 if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
10291760 /* this was NOT a rotation op, shouldn't happen */
10301761 dev_err(priv->ipu->dev,
10311762 "Unexpected rotation interrupt\n");
1032
- ret = IRQ_HANDLED;
10331763 goto out;
10341764 }
1765
+ ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
1766
+ EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
10351767 } else {
10361768 dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
10371769 ret = IRQ_NONE;
10381770 goto out;
10391771 }
10401772
1041
- ret = do_irq(run);
1773
+ if (ipu_rot_mode_is_irt(ctx->rot_mode))
1774
+ tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
1775
+ else
1776
+ tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
1777
+
1778
+ if (tile_complete)
1779
+ ret = do_tile_complete(run);
10421780 out:
10431781 spin_unlock_irqrestore(&chan->irqlock, flags);
10441782 return ret;
....@@ -1072,6 +1810,10 @@
10721810
10731811 static void release_ipu_resources(struct ipu_image_convert_chan *chan)
10741812 {
1813
+ if (chan->in_eof_irq >= 0)
1814
+ free_irq(chan->in_eof_irq, chan);
1815
+ if (chan->rot_in_eof_irq >= 0)
1816
+ free_irq(chan->rot_in_eof_irq, chan);
10751817 if (chan->out_eof_irq >= 0)
10761818 free_irq(chan->out_eof_irq, chan);
10771819 if (chan->rot_out_eof_irq >= 0)
....@@ -1090,7 +1832,27 @@
10901832
10911833 chan->in_chan = chan->out_chan = chan->rotation_in_chan =
10921834 chan->rotation_out_chan = NULL;
1093
- chan->out_eof_irq = chan->rot_out_eof_irq = -1;
1835
+ chan->in_eof_irq = -1;
1836
+ chan->rot_in_eof_irq = -1;
1837
+ chan->out_eof_irq = -1;
1838
+ chan->rot_out_eof_irq = -1;
1839
+}
1840
+
1841
+static int get_eof_irq(struct ipu_image_convert_chan *chan,
1842
+ struct ipuv3_channel *channel)
1843
+{
1844
+ struct ipu_image_convert_priv *priv = chan->priv;
1845
+ int ret, irq;
1846
+
1847
+ irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF);
1848
+
1849
+ ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan);
1850
+ if (ret < 0) {
1851
+ dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq);
1852
+ return ret;
1853
+ }
1854
+
1855
+ return irq;
10941856 }
10951857
10961858 static int get_ipu_resources(struct ipu_image_convert_chan *chan)
....@@ -1126,31 +1888,33 @@
11261888 }
11271889
11281890 /* acquire the EOF interrupts */
1129
- chan->out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
1130
- chan->out_chan,
1131
- IPU_IRQ_EOF);
1132
-
1133
- ret = request_threaded_irq(chan->out_eof_irq, eof_irq, do_bh,
1134
- 0, "ipu-ic", chan);
1891
+ ret = get_eof_irq(chan, chan->in_chan);
11351892 if (ret < 0) {
1136
- dev_err(priv->ipu->dev, "could not acquire irq %d\n",
1137
- chan->out_eof_irq);
1893
+ chan->in_eof_irq = -1;
1894
+ goto err;
1895
+ }
1896
+ chan->in_eof_irq = ret;
1897
+
1898
+ ret = get_eof_irq(chan, chan->rotation_in_chan);
1899
+ if (ret < 0) {
1900
+ chan->rot_in_eof_irq = -1;
1901
+ goto err;
1902
+ }
1903
+ chan->rot_in_eof_irq = ret;
1904
+
1905
+ ret = get_eof_irq(chan, chan->out_chan);
1906
+ if (ret < 0) {
11381907 chan->out_eof_irq = -1;
11391908 goto err;
11401909 }
1910
+ chan->out_eof_irq = ret;
11411911
1142
- chan->rot_out_eof_irq = ipu_idmac_channel_irq(priv->ipu,
1143
- chan->rotation_out_chan,
1144
- IPU_IRQ_EOF);
1145
-
1146
- ret = request_threaded_irq(chan->rot_out_eof_irq, eof_irq, do_bh,
1147
- 0, "ipu-ic", chan);
1912
+ ret = get_eof_irq(chan, chan->rotation_out_chan);
11481913 if (ret < 0) {
1149
- dev_err(priv->ipu->dev, "could not acquire irq %d\n",
1150
- chan->rot_out_eof_irq);
11511914 chan->rot_out_eof_irq = -1;
11521915 goto err;
11531916 }
1917
+ chan->rot_out_eof_irq = ret;
11541918
11551919 return 0;
11561920 err:
....@@ -1180,9 +1944,6 @@
11801944 else
11811945 ic_image->stride = ic_image->base.pix.bytesperline;
11821946
1183
- calc_tile_dimensions(ctx, ic_image);
1184
- calc_tile_offsets(ctx, ic_image);
1185
-
11861947 return 0;
11871948 }
11881949
....@@ -1203,41 +1964,13 @@
12031964 return x;
12041965 }
12051966
1206
-/*
1207
- * We have to adjust the tile width such that the tile physaddrs and
1208
- * U and V plane offsets are multiples of 8 bytes as required by
1209
- * the IPU DMA Controller. For the planar formats, this corresponds
1210
- * to a pixel alignment of 16 (but use a more formal equation since
1211
- * the variables are available). For all the packed formats, 8 is
1212
- * good enough.
1213
- */
1214
-static inline u32 tile_width_align(const struct ipu_image_pixfmt *fmt)
1215
-{
1216
- return fmt->planar ? 8 * fmt->uv_width_dec : 8;
1217
-}
1218
-
1219
-/*
1220
- * For tile height alignment, we have to ensure that the output tile
1221
- * heights are multiples of 8 lines if the IRT is required by the
1222
- * given rotation mode (the IRT performs rotations on 8x8 blocks
1223
- * at a time). If the IRT is not used, or for input image tiles,
1224
- * 2 lines are good enough.
1225
- */
1226
-static inline u32 tile_height_align(enum ipu_image_convert_type type,
1227
- enum ipu_rotate_mode rot_mode)
1228
-{
1229
- return (type == IMAGE_CONVERT_OUT &&
1230
- ipu_rot_mode_is_irt(rot_mode)) ? 8 : 2;
1231
-}
1232
-
12331967 /* Adjusts input/output images to IPU restrictions */
12341968 void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
12351969 enum ipu_rotate_mode rot_mode)
12361970 {
12371971 const struct ipu_image_pixfmt *infmt, *outfmt;
1238
- unsigned int num_in_rows, num_in_cols;
1239
- unsigned int num_out_rows, num_out_cols;
1240
- u32 w_align, h_align;
1972
+ u32 w_align_out, h_align_out;
1973
+ u32 w_align_in, h_align_in;
12411974
12421975 infmt = get_format(in->pix.pixelformat);
12431976 outfmt = get_format(out->pix.pixelformat);
....@@ -1268,36 +2001,42 @@
12682001 in->pix.height / 4);
12692002 }
12702003
1271
- /* get tiling rows/cols from output format */
1272
- num_out_rows = num_stripes(out->pix.height);
1273
- num_out_cols = num_stripes(out->pix.width);
1274
- if (ipu_rot_mode_is_irt(rot_mode)) {
1275
- num_in_rows = num_out_cols;
1276
- num_in_cols = num_out_rows;
1277
- } else {
1278
- num_in_rows = num_out_rows;
1279
- num_in_cols = num_out_cols;
1280
- }
1281
-
12822004 /* align input width/height */
1283
- w_align = ilog2(tile_width_align(infmt) * num_in_cols);
1284
- h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, rot_mode) *
1285
- num_in_rows);
1286
- in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align);
1287
- in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align);
2005
+ w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
2006
+ rot_mode));
2007
+ h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
2008
+ rot_mode));
2009
+ in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
2010
+ w_align_in);
2011
+ in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
2012
+ h_align_in);
12882013
12892014 /* align output width/height */
1290
- w_align = ilog2(tile_width_align(outfmt) * num_out_cols);
1291
- h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, rot_mode) *
1292
- num_out_rows);
1293
- out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align);
1294
- out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align);
2015
+ w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
2016
+ rot_mode));
2017
+ h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
2018
+ rot_mode));
2019
+ out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
2020
+ w_align_out);
2021
+ out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
2022
+ h_align_out);
12952023
12962024 /* set input/output strides and image sizes */
1297
- in->pix.bytesperline = (in->pix.width * infmt->bpp) >> 3;
1298
- in->pix.sizeimage = in->pix.height * in->pix.bytesperline;
1299
- out->pix.bytesperline = (out->pix.width * outfmt->bpp) >> 3;
1300
- out->pix.sizeimage = out->pix.height * out->pix.bytesperline;
2025
+ in->pix.bytesperline = infmt->planar ?
2026
+ clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
2027
+ w_align_in) :
2028
+ clamp_align((in->pix.width * infmt->bpp) >> 3,
2029
+ ((2 << w_align_in) * infmt->bpp) >> 3,
2030
+ (MAX_W * infmt->bpp) >> 3,
2031
+ w_align_in);
2032
+ in->pix.sizeimage = infmt->planar ?
2033
+ (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
2034
+ in->pix.height * in->pix.bytesperline;
2035
+ out->pix.bytesperline = outfmt->planar ? out->pix.width :
2036
+ (out->pix.width * outfmt->bpp) >> 3;
2037
+ out->pix.sizeimage = outfmt->planar ?
2038
+ (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
2039
+ out->pix.height * out->pix.bytesperline;
13012040 }
13022041 EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
13032042
....@@ -1342,6 +2081,7 @@
13422081 struct ipu_image_convert_chan *chan;
13432082 struct ipu_image_convert_ctx *ctx;
13442083 unsigned long flags;
2084
+ unsigned int i;
13452085 bool get_res;
13462086 int ret;
13472087
....@@ -1370,22 +2110,26 @@
13702110 ctx->chan = chan;
13712111 init_completion(&ctx->aborted);
13722112
2113
+ ctx->rot_mode = rot_mode;
2114
+
2115
+ /* Sets ctx->in.num_rows/cols as well */
2116
+ ret = calc_image_resize_coefficients(ctx, in, out);
2117
+ if (ret)
2118
+ goto out_free;
2119
+
13732120 s_image = &ctx->in;
13742121 d_image = &ctx->out;
13752122
13762123 /* set tiling and rotation */
1377
- d_image->num_rows = num_stripes(out->pix.height);
1378
- d_image->num_cols = num_stripes(out->pix.width);
13792124 if (ipu_rot_mode_is_irt(rot_mode)) {
1380
- s_image->num_rows = d_image->num_cols;
1381
- s_image->num_cols = d_image->num_rows;
2125
+ d_image->num_rows = s_image->num_cols;
2126
+ d_image->num_cols = s_image->num_rows;
13822127 } else {
1383
- s_image->num_rows = d_image->num_rows;
1384
- s_image->num_cols = d_image->num_cols;
2128
+ d_image->num_rows = s_image->num_rows;
2129
+ d_image->num_cols = s_image->num_cols;
13852130 }
13862131
13872132 ctx->num_tiles = d_image->num_cols * d_image->num_rows;
1388
- ctx->rot_mode = rot_mode;
13892133
13902134 ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
13912135 if (ret)
....@@ -1395,6 +2139,33 @@
13952139 goto out_free;
13962140
13972141 calc_out_tile_map(ctx);
2142
+
2143
+ find_seams(ctx, s_image, d_image);
2144
+
2145
+ ret = calc_tile_dimensions(ctx, s_image);
2146
+ if (ret)
2147
+ goto out_free;
2148
+
2149
+ ret = calc_tile_offsets(ctx, s_image);
2150
+ if (ret)
2151
+ goto out_free;
2152
+
2153
+ calc_tile_dimensions(ctx, d_image);
2154
+ ret = calc_tile_offsets(ctx, d_image);
2155
+ if (ret)
2156
+ goto out_free;
2157
+
2158
+ calc_tile_resize_coefficients(ctx);
2159
+
2160
+ ret = ipu_ic_calc_csc(&ctx->csc,
2161
+ s_image->base.pix.ycbcr_enc,
2162
+ s_image->base.pix.quantization,
2163
+ ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
2164
+ d_image->base.pix.ycbcr_enc,
2165
+ d_image->base.pix.quantization,
2166
+ ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
2167
+ if (ret)
2168
+ goto out_free;
13982169
13992170 dump_format(ctx, s_image);
14002171 dump_format(ctx, d_image);
....@@ -1411,21 +2182,51 @@
14112182 * for every tile, and therefore would have to be updated for
14122183 * each buffer which is not possible. So double-buffering is
14132184 * impossible when either the source or destination images are
1414
- * a planar format (YUV420, YUV422P, etc.).
2185
+ * a planar format (YUV420, YUV422P, etc.). Further, differently
2186
+ * sized tiles or different resizing coefficients per tile
2187
+ * prevent double-buffering as well.
14152188 */
14162189 ctx->double_buffering = (ctx->num_tiles > 1 &&
14172190 !s_image->fmt->planar &&
14182191 !d_image->fmt->planar);
2192
+ for (i = 1; i < ctx->num_tiles; i++) {
2193
+ if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
2194
+ ctx->in.tile[i].height != ctx->in.tile[0].height ||
2195
+ ctx->out.tile[i].width != ctx->out.tile[0].width ||
2196
+ ctx->out.tile[i].height != ctx->out.tile[0].height) {
2197
+ ctx->double_buffering = false;
2198
+ break;
2199
+ }
2200
+ }
2201
+ for (i = 1; i < ctx->in.num_cols; i++) {
2202
+ if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
2203
+ ctx->double_buffering = false;
2204
+ break;
2205
+ }
2206
+ }
2207
+ for (i = 1; i < ctx->in.num_rows; i++) {
2208
+ if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
2209
+ ctx->double_buffering = false;
2210
+ break;
2211
+ }
2212
+ }
14192213
14202214 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
2215
+ unsigned long intermediate_size = d_image->tile[0].size;
2216
+
2217
+ for (i = 1; i < ctx->num_tiles; i++) {
2218
+ if (d_image->tile[i].size > intermediate_size)
2219
+ intermediate_size = d_image->tile[i].size;
2220
+ }
2221
+
14212222 ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
1422
- d_image->tile[0].size);
2223
+ intermediate_size);
14232224 if (ret)
14242225 goto out_free;
14252226 if (ctx->double_buffering) {
14262227 ret = alloc_dma_buf(priv,
14272228 &ctx->rot_intermediate[1],
1428
- d_image->tile[0].size);
2229
+ intermediate_size);
14292230 if (ret)
14302231 goto out_free_dmabuf0;
14312232 }
....@@ -1513,9 +2314,6 @@
15132314 struct ipu_image_convert_run *run, *active_run, *tmp;
15142315 unsigned long flags;
15152316 int run_count, ret;
1516
- bool need_abort;
1517
-
1518
- reinit_completion(&ctx->aborted);
15192317
15202318 spin_lock_irqsave(&chan->irqlock, flags);
15212319
....@@ -1531,22 +2329,28 @@
15312329 active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
15322330 chan->current_run : NULL;
15332331
1534
- need_abort = (run_count || active_run);
2332
+ if (active_run)
2333
+ reinit_completion(&ctx->aborted);
15352334
15362335 ctx->aborting = true;
15372336
15382337 spin_unlock_irqrestore(&chan->irqlock, flags);
15392338
1540
- if (!need_abort) {
2339
+ if (!run_count && !active_run) {
15412340 dev_dbg(priv->ipu->dev,
15422341 "%s: task %u: no abort needed for ctx %p\n",
15432342 __func__, chan->ic_task, ctx);
15442343 return;
15452344 }
15462345
2346
+ if (!active_run) {
2347
+ empty_done_q(chan);
2348
+ return;
2349
+ }
2350
+
15472351 dev_dbg(priv->ipu->dev,
1548
- "%s: task %u: wait for completion: %d runs, active run %p\n",
1549
- __func__, chan->ic_task, run_count, active_run);
2352
+ "%s: task %u: wait for completion: %d runs\n",
2353
+ __func__, chan->ic_task, run_count);
15502354
15512355 ret = wait_for_completion_timeout(&ctx->aborted,
15522356 msecs_to_jiffies(10000));
....@@ -1689,6 +2493,8 @@
16892493 chan->ic_task = i;
16902494 chan->priv = priv;
16912495 chan->dma_ch = &image_convert_dma_chan[i];
2496
+ chan->in_eof_irq = -1;
2497
+ chan->rot_in_eof_irq = -1;
16922498 chan->out_eof_irq = -1;
16932499 chan->rot_out_eof_irq = -1;
16942500