.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2012-2016 Mentor Graphics Inc. |
---|
3 | 4 | * |
---|
4 | 5 | * 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. |
---|
15 | 6 | */ |
---|
16 | 7 | |
---|
17 | 8 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
37 | 28 | * when double_buffering boolean is set). |
---|
38 | 29 | * |
---|
39 | 30 | * 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: |
---|
41 | 32 | * |
---|
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. |
---|
51 | 61 | */ |
---|
52 | 62 | |
---|
53 | 63 | #define MAX_STRIPES_W 4 |
---|
.. | .. |
---|
84 | 94 | struct ipu_image_tile { |
---|
85 | 95 | u32 width; |
---|
86 | 96 | u32 height; |
---|
| 97 | + u32 left; |
---|
| 98 | + u32 top; |
---|
87 | 99 | /* size and strides are in bytes */ |
---|
88 | 100 | u32 size; |
---|
89 | 101 | u32 stride; |
---|
.. | .. |
---|
125 | 137 | struct ipu_image_convert_chan; |
---|
126 | 138 | struct ipu_image_convert_priv; |
---|
127 | 139 | |
---|
| 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 | + |
---|
128 | 151 | struct ipu_image_convert_ctx { |
---|
129 | 152 | struct ipu_image_convert_chan *chan; |
---|
130 | 153 | |
---|
.. | .. |
---|
134 | 157 | /* Source/destination image data and rotation mode */ |
---|
135 | 158 | struct ipu_image_convert_image in; |
---|
136 | 159 | struct ipu_image_convert_image out; |
---|
| 160 | + struct ipu_ic_csc csc; |
---|
137 | 161 | 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]; |
---|
138 | 168 | |
---|
139 | 169 | /* intermediate buffer for rotation */ |
---|
140 | 170 | struct ipu_image_convert_dma_buf rot_intermediate[2]; |
---|
.. | .. |
---|
154 | 184 | /* where to place converted tile in dest image */ |
---|
155 | 185 | unsigned int out_tile_map[MAX_TILES]; |
---|
156 | 186 | |
---|
| 187 | + /* mask of completed EOF irqs at every tile conversion */ |
---|
| 188 | + enum eof_irq_mask eof_mask; |
---|
| 189 | + |
---|
157 | 190 | struct list_head list; |
---|
158 | 191 | }; |
---|
159 | 192 | |
---|
.. | .. |
---|
170 | 203 | struct ipuv3_channel *rotation_out_chan; |
---|
171 | 204 | |
---|
172 | 205 | /* the IPU end-of-frame irqs */ |
---|
| 206 | + int in_eof_irq; |
---|
| 207 | + int rot_in_eof_irq; |
---|
173 | 208 | int out_eof_irq; |
---|
174 | 209 | int rot_out_eof_irq; |
---|
175 | 210 | |
---|
.. | .. |
---|
231 | 266 | .bpp = 32, |
---|
232 | 267 | }, { |
---|
233 | 268 | .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, |
---|
234 | 275 | .bpp = 32, |
---|
235 | 276 | }, { |
---|
236 | 277 | .fourcc = V4L2_PIX_FMT_YUYV, |
---|
.. | .. |
---|
300 | 341 | struct ipu_image_convert_priv *priv = chan->priv; |
---|
301 | 342 | |
---|
302 | 343 | 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", |
---|
304 | 345 | chan->ic_task, ctx, |
---|
305 | 346 | ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input", |
---|
306 | 347 | ic_image->base.pix.width, ic_image->base.pix.height, |
---|
307 | 348 | ic_image->num_cols, ic_image->num_rows, |
---|
308 | | - ic_image->tile[0].width, ic_image->tile[0].height, |
---|
309 | 349 | ic_image->fmt->fourcc & 0xff, |
---|
310 | 350 | (ic_image->fmt->fourcc >> 8) & 0xff, |
---|
311 | 351 | (ic_image->fmt->fourcc >> 16) & 0xff, |
---|
.. | .. |
---|
353 | 393 | |
---|
354 | 394 | static inline int num_stripes(int dim) |
---|
355 | 395 | { |
---|
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; |
---|
362 | 397 | } |
---|
363 | 398 | |
---|
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) |
---|
366 | 410 | { |
---|
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 | + } |
---|
368 | 869 | |
---|
369 | 870 | 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; |
---|
371 | 874 | |
---|
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 | + |
---|
374 | 880 | tile->size = ((tile->height * image->fmt->bpp) >> 3) * |
---|
375 | 881 | tile->width; |
---|
376 | 882 | |
---|
.. | .. |
---|
383 | 889 | tile->rot_stride = |
---|
384 | 890 | (image->fmt->bpp * tile->height) >> 3; |
---|
385 | 891 | } |
---|
| 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 | + } |
---|
386 | 907 | } |
---|
| 908 | + |
---|
| 909 | + return 0; |
---|
387 | 910 | } |
---|
388 | 911 | |
---|
389 | 912 | /* |
---|
.. | .. |
---|
459 | 982 | } |
---|
460 | 983 | } |
---|
461 | 984 | |
---|
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) |
---|
464 | 987 | { |
---|
465 | 988 | struct ipu_image_convert_chan *chan = ctx->chan; |
---|
466 | 989 | struct ipu_image_convert_priv *priv = chan->priv; |
---|
467 | 990 | const struct ipu_image_pixfmt *fmt = image->fmt; |
---|
468 | 991 | unsigned int row, col, tile = 0; |
---|
469 | | - u32 H, w, h, y_stride, uv_stride; |
---|
| 992 | + u32 H, top, y_stride, uv_stride; |
---|
470 | 993 | u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp; |
---|
471 | 994 | u32 y_row_off, y_col_off, y_off; |
---|
472 | 995 | u32 y_size, uv_size; |
---|
.. | .. |
---|
483 | 1006 | uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec); |
---|
484 | 1007 | |
---|
485 | 1008 | 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; |
---|
490 | 1012 | |
---|
491 | 1013 | for (col = 0; col < image->num_cols; col++) { |
---|
492 | | - y_col_off = col * w; |
---|
| 1014 | + y_col_off = image->tile[tile].left; |
---|
493 | 1015 | uv_col_off = y_col_off / fmt->uv_width_dec; |
---|
494 | 1016 | if (fmt->uv_packed) |
---|
495 | 1017 | uv_col_off *= 2; |
---|
.. | .. |
---|
509 | 1031 | image->tile[tile].u_off = u_off; |
---|
510 | 1032 | image->tile[tile++].v_off = v_off; |
---|
511 | 1033 | |
---|
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 | + } |
---|
518 | 1044 | } |
---|
519 | 1045 | } |
---|
| 1046 | + |
---|
| 1047 | + return 0; |
---|
520 | 1048 | } |
---|
521 | 1049 | |
---|
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) |
---|
524 | 1052 | { |
---|
525 | 1053 | struct ipu_image_convert_chan *chan = ctx->chan; |
---|
526 | 1054 | struct ipu_image_convert_priv *priv = chan->priv; |
---|
527 | 1055 | const struct ipu_image_pixfmt *fmt = image->fmt; |
---|
528 | 1056 | unsigned int row, col, tile = 0; |
---|
529 | | - u32 w, h, bpp, stride; |
---|
| 1057 | + u32 bpp, stride, offset; |
---|
530 | 1058 | u32 row_off, col_off; |
---|
531 | 1059 | |
---|
532 | 1060 | /* setup some convenience vars */ |
---|
.. | .. |
---|
534 | 1062 | bpp = fmt->bpp; |
---|
535 | 1063 | |
---|
536 | 1064 | 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; |
---|
540 | 1066 | |
---|
541 | 1067 | for (col = 0; col < image->num_cols; col++) { |
---|
542 | | - col_off = (col * w * bpp) >> 3; |
---|
| 1068 | + col_off = (image->tile[tile].left * bpp) >> 3; |
---|
543 | 1069 | |
---|
544 | | - image->tile[tile].offset = row_off + col_off; |
---|
| 1070 | + offset = row_off + col_off; |
---|
| 1071 | + |
---|
| 1072 | + image->tile[tile].offset = offset; |
---|
545 | 1073 | image->tile[tile].u_off = 0; |
---|
546 | 1074 | image->tile[tile++].v_off = 0; |
---|
547 | 1075 | |
---|
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 | + } |
---|
554 | 1086 | } |
---|
555 | 1087 | } |
---|
| 1088 | + |
---|
| 1089 | + return 0; |
---|
556 | 1090 | } |
---|
557 | 1091 | |
---|
558 | | -static void calc_tile_offsets(struct ipu_image_convert_ctx *ctx, |
---|
| 1092 | +static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx, |
---|
559 | 1093 | struct ipu_image_convert_image *image) |
---|
560 | 1094 | { |
---|
561 | 1095 | 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); |
---|
563 | 1117 | 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 | + } |
---|
565 | 1248 | } |
---|
566 | 1249 | |
---|
567 | 1250 | /* |
---|
.. | .. |
---|
611 | 1294 | struct ipuv3_channel *channel, |
---|
612 | 1295 | struct ipu_image_convert_image *image, |
---|
613 | 1296 | enum ipu_rotate_mode rot_mode, |
---|
614 | | - bool rot_swap_width_height) |
---|
| 1297 | + bool rot_swap_width_height, |
---|
| 1298 | + unsigned int tile) |
---|
615 | 1299 | { |
---|
616 | 1300 | struct ipu_image_convert_chan *chan = ctx->chan; |
---|
617 | 1301 | unsigned int burst_size; |
---|
.. | .. |
---|
621 | 1305 | unsigned int tile_idx[2]; |
---|
622 | 1306 | |
---|
623 | 1307 | if (image->type == IMAGE_CONVERT_OUT) { |
---|
624 | | - tile_idx[0] = ctx->out_tile_map[0]; |
---|
| 1308 | + tile_idx[0] = ctx->out_tile_map[tile]; |
---|
625 | 1309 | tile_idx[1] = ctx->out_tile_map[1]; |
---|
626 | 1310 | } else { |
---|
627 | | - tile_idx[0] = 0; |
---|
| 1311 | + tile_idx[0] = tile; |
---|
628 | 1312 | tile_idx[1] = 1; |
---|
629 | 1313 | } |
---|
630 | 1314 | |
---|
631 | 1315 | 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; |
---|
635 | 1319 | addr0 = ctx->rot_intermediate[0].phys; |
---|
636 | 1320 | if (ctx->double_buffering) |
---|
637 | 1321 | addr1 = ctx->rot_intermediate[1].phys; |
---|
638 | 1322 | } 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; |
---|
641 | 1325 | stride = image->stride; |
---|
642 | 1326 | addr0 = image->base.phys0 + |
---|
643 | 1327 | image->tile[tile_idx[0]].offset; |
---|
.. | .. |
---|
655 | 1339 | tile_image.pix.pixelformat = image->fmt->fourcc; |
---|
656 | 1340 | tile_image.phys0 = addr0; |
---|
657 | 1341 | 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 | + } |
---|
659 | 1346 | |
---|
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); |
---|
664 | 1348 | |
---|
665 | 1349 | if (rot_mode) |
---|
666 | 1350 | 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); |
---|
667 | 1360 | |
---|
668 | 1361 | if (channel == chan->rotation_in_chan || |
---|
669 | 1362 | channel == chan->rotation_out_chan) { |
---|
.. | .. |
---|
687 | 1380 | ipu_idmac_set_double_buffer(channel, ctx->double_buffering); |
---|
688 | 1381 | } |
---|
689 | 1382 | |
---|
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) |
---|
691 | 1384 | { |
---|
692 | 1385 | struct ipu_image_convert_ctx *ctx = run->ctx; |
---|
693 | 1386 | struct ipu_image_convert_chan *chan = ctx->chan; |
---|
694 | 1387 | struct ipu_image_convert_priv *priv = chan->priv; |
---|
695 | 1388 | struct ipu_image_convert_image *s_image = &ctx->in; |
---|
696 | 1389 | 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]; |
---|
698 | 1391 | unsigned int dest_width, dest_height; |
---|
| 1392 | + unsigned int col, row; |
---|
| 1393 | + u32 rsc; |
---|
699 | 1394 | int ret; |
---|
700 | 1395 | |
---|
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); |
---|
703 | 1398 | |
---|
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; |
---|
706 | 1401 | |
---|
707 | 1402 | if (ipu_rot_mode_is_irt(ctx->rot_mode)) { |
---|
708 | 1403 | /* 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; |
---|
711 | 1406 | } 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; |
---|
714 | 1409 | } |
---|
715 | 1410 | |
---|
| 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 | + |
---|
716 | 1423 | /* 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); |
---|
723 | 1430 | if (ret) { |
---|
724 | 1431 | dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret); |
---|
725 | 1432 | return ret; |
---|
.. | .. |
---|
727 | 1434 | |
---|
728 | 1435 | /* init the source MEM-->IC PP IDMAC channel */ |
---|
729 | 1436 | init_idmac_channel(ctx, chan->in_chan, s_image, |
---|
730 | | - IPU_ROTATE_NONE, false); |
---|
| 1437 | + IPU_ROTATE_NONE, false, tile); |
---|
731 | 1438 | |
---|
732 | 1439 | if (ipu_rot_mode_is_irt(ctx->rot_mode)) { |
---|
733 | 1440 | /* init the IC PP-->MEM IDMAC channel */ |
---|
734 | 1441 | init_idmac_channel(ctx, chan->out_chan, d_image, |
---|
735 | | - IPU_ROTATE_NONE, true); |
---|
| 1442 | + IPU_ROTATE_NONE, true, tile); |
---|
736 | 1443 | |
---|
737 | 1444 | /* init the MEM-->IC PP ROT IDMAC channel */ |
---|
738 | 1445 | init_idmac_channel(ctx, chan->rotation_in_chan, d_image, |
---|
739 | | - ctx->rot_mode, true); |
---|
| 1446 | + ctx->rot_mode, true, tile); |
---|
740 | 1447 | |
---|
741 | 1448 | /* init the destination IC PP ROT-->MEM IDMAC channel */ |
---|
742 | 1449 | init_idmac_channel(ctx, chan->rotation_out_chan, d_image, |
---|
743 | | - IPU_ROTATE_NONE, false); |
---|
| 1450 | + IPU_ROTATE_NONE, false, tile); |
---|
744 | 1451 | |
---|
745 | 1452 | /* now link IC PP-->MEM to MEM-->IC PP ROT */ |
---|
746 | 1453 | ipu_idmac_link(chan->out_chan, chan->rotation_in_chan); |
---|
747 | 1454 | } else { |
---|
748 | 1455 | /* init the destination IC PP-->MEM IDMAC channel */ |
---|
749 | 1456 | init_idmac_channel(ctx, chan->out_chan, d_image, |
---|
750 | | - ctx->rot_mode, false); |
---|
| 1457 | + ctx->rot_mode, false, tile); |
---|
751 | 1458 | } |
---|
752 | 1459 | |
---|
753 | 1460 | /* enable the IC */ |
---|
.. | .. |
---|
805 | 1512 | list_del(&run->list); |
---|
806 | 1513 | chan->current_run = run; |
---|
807 | 1514 | |
---|
808 | | - return convert_start(run); |
---|
| 1515 | + return convert_start(run, 0); |
---|
809 | 1516 | } |
---|
810 | 1517 | |
---|
811 | 1518 | /* hold irqlock when calling */ |
---|
.. | .. |
---|
896 | 1603 | dev_dbg(priv->ipu->dev, |
---|
897 | 1604 | "%s: task %u: signaling abort for ctx %p\n", |
---|
898 | 1605 | __func__, chan->ic_task, ctx); |
---|
899 | | - complete(&ctx->aborted); |
---|
| 1606 | + complete_all(&ctx->aborted); |
---|
900 | 1607 | } |
---|
901 | 1608 | } |
---|
902 | 1609 | |
---|
.. | .. |
---|
908 | 1615 | return IRQ_HANDLED; |
---|
909 | 1616 | } |
---|
910 | 1617 | |
---|
| 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 | + |
---|
911 | 1636 | /* 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) |
---|
913 | 1638 | { |
---|
914 | 1639 | struct ipu_image_convert_ctx *ctx = run->ctx; |
---|
915 | 1640 | struct ipu_image_convert_chan *chan = ctx->chan; |
---|
.. | .. |
---|
951 | 1676 | * not done, place the next tile buffers. |
---|
952 | 1677 | */ |
---|
953 | 1678 | 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]; |
---|
954 | 1686 | |
---|
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); |
---|
958 | 1701 | |
---|
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 | + } |
---|
975 | 1705 | } else if (ctx->next_tile < ctx->num_tiles - 1) { |
---|
976 | 1706 | |
---|
977 | 1707 | src_tile = &s_image->tile[ctx->next_tile + 1]; |
---|
.. | .. |
---|
989 | 1719 | ctx->cur_buf_num ^= 1; |
---|
990 | 1720 | } |
---|
991 | 1721 | |
---|
| 1722 | + ctx->eof_mask = 0; /* clear EOF irq mask for next tile */ |
---|
992 | 1723 | ctx->next_tile++; |
---|
993 | 1724 | return IRQ_HANDLED; |
---|
994 | 1725 | done: |
---|
.. | .. |
---|
1004 | 1735 | struct ipu_image_convert_priv *priv = chan->priv; |
---|
1005 | 1736 | struct ipu_image_convert_ctx *ctx; |
---|
1006 | 1737 | struct ipu_image_convert_run *run; |
---|
| 1738 | + irqreturn_t ret = IRQ_HANDLED; |
---|
| 1739 | + bool tile_complete = false; |
---|
1007 | 1740 | unsigned long flags; |
---|
1008 | | - irqreturn_t ret; |
---|
1009 | 1741 | |
---|
1010 | 1742 | spin_lock_irqsave(&chan->irqlock, flags); |
---|
1011 | 1743 | |
---|
.. | .. |
---|
1018 | 1750 | |
---|
1019 | 1751 | ctx = run->ctx; |
---|
1020 | 1752 | |
---|
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) { |
---|
1028 | 1759 | if (!ipu_rot_mode_is_irt(ctx->rot_mode)) { |
---|
1029 | 1760 | /* this was NOT a rotation op, shouldn't happen */ |
---|
1030 | 1761 | dev_err(priv->ipu->dev, |
---|
1031 | 1762 | "Unexpected rotation interrupt\n"); |
---|
1032 | | - ret = IRQ_HANDLED; |
---|
1033 | 1763 | goto out; |
---|
1034 | 1764 | } |
---|
| 1765 | + ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ? |
---|
| 1766 | + EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT; |
---|
1035 | 1767 | } else { |
---|
1036 | 1768 | dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq); |
---|
1037 | 1769 | ret = IRQ_NONE; |
---|
1038 | 1770 | goto out; |
---|
1039 | 1771 | } |
---|
1040 | 1772 | |
---|
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); |
---|
1042 | 1780 | out: |
---|
1043 | 1781 | spin_unlock_irqrestore(&chan->irqlock, flags); |
---|
1044 | 1782 | return ret; |
---|
.. | .. |
---|
1072 | 1810 | |
---|
1073 | 1811 | static void release_ipu_resources(struct ipu_image_convert_chan *chan) |
---|
1074 | 1812 | { |
---|
| 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); |
---|
1075 | 1817 | if (chan->out_eof_irq >= 0) |
---|
1076 | 1818 | free_irq(chan->out_eof_irq, chan); |
---|
1077 | 1819 | if (chan->rot_out_eof_irq >= 0) |
---|
.. | .. |
---|
1090 | 1832 | |
---|
1091 | 1833 | chan->in_chan = chan->out_chan = chan->rotation_in_chan = |
---|
1092 | 1834 | 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; |
---|
1094 | 1856 | } |
---|
1095 | 1857 | |
---|
1096 | 1858 | static int get_ipu_resources(struct ipu_image_convert_chan *chan) |
---|
.. | .. |
---|
1126 | 1888 | } |
---|
1127 | 1889 | |
---|
1128 | 1890 | /* 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); |
---|
1135 | 1892 | 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) { |
---|
1138 | 1907 | chan->out_eof_irq = -1; |
---|
1139 | 1908 | goto err; |
---|
1140 | 1909 | } |
---|
| 1910 | + chan->out_eof_irq = ret; |
---|
1141 | 1911 | |
---|
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); |
---|
1148 | 1913 | if (ret < 0) { |
---|
1149 | | - dev_err(priv->ipu->dev, "could not acquire irq %d\n", |
---|
1150 | | - chan->rot_out_eof_irq); |
---|
1151 | 1914 | chan->rot_out_eof_irq = -1; |
---|
1152 | 1915 | goto err; |
---|
1153 | 1916 | } |
---|
| 1917 | + chan->rot_out_eof_irq = ret; |
---|
1154 | 1918 | |
---|
1155 | 1919 | return 0; |
---|
1156 | 1920 | err: |
---|
.. | .. |
---|
1180 | 1944 | else |
---|
1181 | 1945 | ic_image->stride = ic_image->base.pix.bytesperline; |
---|
1182 | 1946 | |
---|
1183 | | - calc_tile_dimensions(ctx, ic_image); |
---|
1184 | | - calc_tile_offsets(ctx, ic_image); |
---|
1185 | | - |
---|
1186 | 1947 | return 0; |
---|
1187 | 1948 | } |
---|
1188 | 1949 | |
---|
.. | .. |
---|
1203 | 1964 | return x; |
---|
1204 | 1965 | } |
---|
1205 | 1966 | |
---|
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 | | - |
---|
1233 | 1967 | /* Adjusts input/output images to IPU restrictions */ |
---|
1234 | 1968 | void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out, |
---|
1235 | 1969 | enum ipu_rotate_mode rot_mode) |
---|
1236 | 1970 | { |
---|
1237 | 1971 | 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; |
---|
1241 | 1974 | |
---|
1242 | 1975 | infmt = get_format(in->pix.pixelformat); |
---|
1243 | 1976 | outfmt = get_format(out->pix.pixelformat); |
---|
.. | .. |
---|
1268 | 2001 | in->pix.height / 4); |
---|
1269 | 2002 | } |
---|
1270 | 2003 | |
---|
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 | | - |
---|
1282 | 2004 | /* 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); |
---|
1288 | 2013 | |
---|
1289 | 2014 | /* 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); |
---|
1295 | 2023 | |
---|
1296 | 2024 | /* 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; |
---|
1301 | 2040 | } |
---|
1302 | 2041 | EXPORT_SYMBOL_GPL(ipu_image_convert_adjust); |
---|
1303 | 2042 | |
---|
.. | .. |
---|
1342 | 2081 | struct ipu_image_convert_chan *chan; |
---|
1343 | 2082 | struct ipu_image_convert_ctx *ctx; |
---|
1344 | 2083 | unsigned long flags; |
---|
| 2084 | + unsigned int i; |
---|
1345 | 2085 | bool get_res; |
---|
1346 | 2086 | int ret; |
---|
1347 | 2087 | |
---|
.. | .. |
---|
1370 | 2110 | ctx->chan = chan; |
---|
1371 | 2111 | init_completion(&ctx->aborted); |
---|
1372 | 2112 | |
---|
| 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 | + |
---|
1373 | 2120 | s_image = &ctx->in; |
---|
1374 | 2121 | d_image = &ctx->out; |
---|
1375 | 2122 | |
---|
1376 | 2123 | /* set tiling and rotation */ |
---|
1377 | | - d_image->num_rows = num_stripes(out->pix.height); |
---|
1378 | | - d_image->num_cols = num_stripes(out->pix.width); |
---|
1379 | 2124 | 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; |
---|
1382 | 2127 | } 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; |
---|
1385 | 2130 | } |
---|
1386 | 2131 | |
---|
1387 | 2132 | ctx->num_tiles = d_image->num_cols * d_image->num_rows; |
---|
1388 | | - ctx->rot_mode = rot_mode; |
---|
1389 | 2133 | |
---|
1390 | 2134 | ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN); |
---|
1391 | 2135 | if (ret) |
---|
.. | .. |
---|
1395 | 2139 | goto out_free; |
---|
1396 | 2140 | |
---|
1397 | 2141 | 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; |
---|
1398 | 2169 | |
---|
1399 | 2170 | dump_format(ctx, s_image); |
---|
1400 | 2171 | dump_format(ctx, d_image); |
---|
.. | .. |
---|
1411 | 2182 | * for every tile, and therefore would have to be updated for |
---|
1412 | 2183 | * each buffer which is not possible. So double-buffering is |
---|
1413 | 2184 | * 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. |
---|
1415 | 2188 | */ |
---|
1416 | 2189 | ctx->double_buffering = (ctx->num_tiles > 1 && |
---|
1417 | 2190 | !s_image->fmt->planar && |
---|
1418 | 2191 | !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 | + } |
---|
1419 | 2213 | |
---|
1420 | 2214 | 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 | + |
---|
1421 | 2222 | ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0], |
---|
1422 | | - d_image->tile[0].size); |
---|
| 2223 | + intermediate_size); |
---|
1423 | 2224 | if (ret) |
---|
1424 | 2225 | goto out_free; |
---|
1425 | 2226 | if (ctx->double_buffering) { |
---|
1426 | 2227 | ret = alloc_dma_buf(priv, |
---|
1427 | 2228 | &ctx->rot_intermediate[1], |
---|
1428 | | - d_image->tile[0].size); |
---|
| 2229 | + intermediate_size); |
---|
1429 | 2230 | if (ret) |
---|
1430 | 2231 | goto out_free_dmabuf0; |
---|
1431 | 2232 | } |
---|
.. | .. |
---|
1513 | 2314 | struct ipu_image_convert_run *run, *active_run, *tmp; |
---|
1514 | 2315 | unsigned long flags; |
---|
1515 | 2316 | int run_count, ret; |
---|
1516 | | - bool need_abort; |
---|
1517 | | - |
---|
1518 | | - reinit_completion(&ctx->aborted); |
---|
1519 | 2317 | |
---|
1520 | 2318 | spin_lock_irqsave(&chan->irqlock, flags); |
---|
1521 | 2319 | |
---|
.. | .. |
---|
1531 | 2329 | active_run = (chan->current_run && chan->current_run->ctx == ctx) ? |
---|
1532 | 2330 | chan->current_run : NULL; |
---|
1533 | 2331 | |
---|
1534 | | - need_abort = (run_count || active_run); |
---|
| 2332 | + if (active_run) |
---|
| 2333 | + reinit_completion(&ctx->aborted); |
---|
1535 | 2334 | |
---|
1536 | 2335 | ctx->aborting = true; |
---|
1537 | 2336 | |
---|
1538 | 2337 | spin_unlock_irqrestore(&chan->irqlock, flags); |
---|
1539 | 2338 | |
---|
1540 | | - if (!need_abort) { |
---|
| 2339 | + if (!run_count && !active_run) { |
---|
1541 | 2340 | dev_dbg(priv->ipu->dev, |
---|
1542 | 2341 | "%s: task %u: no abort needed for ctx %p\n", |
---|
1543 | 2342 | __func__, chan->ic_task, ctx); |
---|
1544 | 2343 | return; |
---|
1545 | 2344 | } |
---|
1546 | 2345 | |
---|
| 2346 | + if (!active_run) { |
---|
| 2347 | + empty_done_q(chan); |
---|
| 2348 | + return; |
---|
| 2349 | + } |
---|
| 2350 | + |
---|
1547 | 2351 | 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); |
---|
1550 | 2354 | |
---|
1551 | 2355 | ret = wait_for_completion_timeout(&ctx->aborted, |
---|
1552 | 2356 | msecs_to_jiffies(10000)); |
---|
.. | .. |
---|
1689 | 2493 | chan->ic_task = i; |
---|
1690 | 2494 | chan->priv = priv; |
---|
1691 | 2495 | chan->dma_ch = &image_convert_dma_chan[i]; |
---|
| 2496 | + chan->in_eof_irq = -1; |
---|
| 2497 | + chan->rot_in_eof_irq = -1; |
---|
1692 | 2498 | chan->out_eof_irq = -1; |
---|
1693 | 2499 | chan->rot_out_eof_irq = -1; |
---|
1694 | 2500 | |
---|