Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'imx-drm-next-2018-12-03' of git://git.pengutronix.de/git/pza/linux into drm-next

drm/imx: update image-convert with fixes for multi-tiled scaling

Update the ipu-v3 mem2mem image-convert code, with some fixes for race
conditions, alignment issues, and visual artifacts due to tile alignment
and scaling factor issues when scaling images larger than hardware
limitations in multiple tiles. This will allow the V4L2 mem2mem scaler
driver to write output images larger than 1024x1024 pixels.

Also switch drm/imx source files to SPDX license identifiers, constify
struct clk_ops in imx-tve, and add a timeout warning to the busy wait in
ipu_plane_disable().

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/1543835266.5647.1.camel@pengutronix.de

+939 -267
+1 -4
drivers/gpu/drm/imx/dw_hdmi-imx.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 1 2 /* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. 2 3 * 3 4 * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now) 4 - * 5 - * This program is free software; you can redistribute it and/or modify 6 - * it under the terms of the GNU General Public License version 2 as 7 - * published by the Free Software Foundation. 8 5 */ 9 6 #include <linux/module.h> 10 7 #include <linux/platform_device.h>
+1 -10
drivers/gpu/drm/imx/imx-drm-core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * Freescale i.MX drm driver 3 4 * 4 5 * Copyright (C) 2011 Sascha Hauer, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 - * 15 6 */ 16 7 #include <linux/component.h> 17 8 #include <linux/device.h>
+1 -9
drivers/gpu/drm/imx/imx-ldb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * i.MX drm driver - LVDS display bridge 3 4 * 4 5 * Copyright (C) 2012 Sascha Hauer, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 6 */ 15 7 16 8 #include <linux/module.h>
+2 -10
drivers/gpu/drm/imx/imx-tve.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * i.MX drm driver - Television Encoder (TVEv2) 3 4 * 4 5 * Copyright (C) 2013 Philipp Zabel, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 6 */ 15 7 16 8 #include <linux/clk.h> ··· 434 442 return 0; 435 443 } 436 444 437 - static struct clk_ops clk_tve_di_ops = { 445 + static const struct clk_ops clk_tve_di_ops = { 438 446 .round_rate = clk_tve_di_round_rate, 439 447 .set_rate = clk_tve_di_set_rate, 440 448 .recalc_rate = clk_tve_di_recalc_rate,
+1 -9
drivers/gpu/drm/imx/ipuv3-crtc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * i.MX IPUv3 Graphics driver 3 4 * 4 5 * Copyright (C) 2011 Sascha Hauer, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 6 */ 15 7 #include <linux/component.h> 16 8 #include <linux/module.h>
+8 -10
drivers/gpu/drm/imx/ipuv3-plane.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * i.MX IPUv3 DP Overlay Planes 3 4 * 4 5 * Copyright (C) 2013 Philipp Zabel, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 6 */ 15 7 16 8 #include <drm/drmP.h> ··· 228 236 229 237 void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel) 230 238 { 239 + int ret; 240 + 231 241 DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); 232 242 233 - ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); 243 + ret = ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50); 244 + if (ret == -ETIMEDOUT) { 245 + DRM_ERROR("[PLANE:%d] IDMAC timeout\n", 246 + ipu_plane->base.base.id); 247 + } 234 248 235 249 if (ipu_plane->dp && disable_dp_channel) 236 250 ipu_dp_disable_channel(ipu_plane->dp, false);
+1 -9
drivers/gpu/drm/imx/parallel-display.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 1 2 /* 2 3 * i.MX drm driver - parallel display implementation 3 4 * 4 5 * Copyright (C) 2012 Sascha Hauer, Pengutronix 5 - * 6 - * This program is free software; you can redistribute it and/or 7 - * modify it under the terms of the GNU General Public License 8 - * as published by the Free Software Foundation; either version 2 9 - * of the License, or (at your option) any later version. 10 - * This program is distributed in the hope that it will be useful, 11 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 - * GNU General Public License for more details. 14 6 */ 15 7 16 8 #include <linux/component.h>
+33 -19
drivers/gpu/ipu-v3/ipu-cpmem.c
··· 259 259 260 260 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) 261 261 { 262 + WARN_ON_ONCE(buf & 0x7); 263 + 262 264 if (bufnum) 263 265 ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); 264 266 else ··· 270 268 271 269 void ipu_cpmem_set_uv_offset(struct ipuv3_channel *ch, u32 u_off, u32 v_off) 272 270 { 271 + WARN_ON_ONCE((u_off & 0x7) || (v_off & 0x7)); 272 + 273 273 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_off / 8); 274 274 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_off / 8); 275 275 } ··· 439 435 unsigned int uv_stride, 440 436 unsigned int u_offset, unsigned int v_offset) 441 437 { 438 + WARN_ON_ONCE((u_offset & 0x7) || (v_offset & 0x7)); 439 + 442 440 ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, uv_stride - 1); 443 441 ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); 444 442 ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); ··· 745 739 switch (pix->pixelformat) { 746 740 case V4L2_PIX_FMT_YUV420: 747 741 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 748 - u_offset = U_OFFSET(pix, image->rect.left, 749 - image->rect.top) - offset; 750 - v_offset = V_OFFSET(pix, image->rect.left, 751 - image->rect.top) - offset; 742 + u_offset = image->u_offset ? 743 + image->u_offset : U_OFFSET(pix, image->rect.left, 744 + image->rect.top) - offset; 745 + v_offset = image->v_offset ? 746 + image->v_offset : V_OFFSET(pix, image->rect.left, 747 + image->rect.top) - offset; 752 748 753 749 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 754 750 u_offset, v_offset); 755 751 break; 756 752 case V4L2_PIX_FMT_YVU420: 757 753 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 758 - u_offset = U_OFFSET(pix, image->rect.left, 759 - image->rect.top) - offset; 760 - v_offset = V_OFFSET(pix, image->rect.left, 761 - image->rect.top) - offset; 754 + u_offset = image->u_offset ? 755 + image->u_offset : V_OFFSET(pix, image->rect.left, 756 + image->rect.top) - offset; 757 + v_offset = image->v_offset ? 758 + image->v_offset : U_OFFSET(pix, image->rect.left, 759 + image->rect.top) - offset; 762 760 763 761 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 764 - v_offset, u_offset); 762 + u_offset, v_offset); 765 763 break; 766 764 case V4L2_PIX_FMT_YUV422P: 767 765 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 768 - u_offset = U2_OFFSET(pix, image->rect.left, 769 - image->rect.top) - offset; 770 - v_offset = V2_OFFSET(pix, image->rect.left, 771 - image->rect.top) - offset; 766 + u_offset = image->u_offset ? 767 + image->u_offset : U2_OFFSET(pix, image->rect.left, 768 + image->rect.top) - offset; 769 + v_offset = image->v_offset ? 770 + image->v_offset : V2_OFFSET(pix, image->rect.left, 771 + image->rect.top) - offset; 772 772 773 773 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline / 2, 774 774 u_offset, v_offset); 775 775 break; 776 776 case V4L2_PIX_FMT_NV12: 777 777 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 778 - u_offset = UV_OFFSET(pix, image->rect.left, 779 - image->rect.top) - offset; 780 - v_offset = 0; 778 + u_offset = image->u_offset ? 779 + image->u_offset : UV_OFFSET(pix, image->rect.left, 780 + image->rect.top) - offset; 781 + v_offset = image->v_offset ? image->v_offset : 0; 781 782 782 783 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, 783 784 u_offset, v_offset); 784 785 break; 785 786 case V4L2_PIX_FMT_NV16: 786 787 offset = Y_OFFSET(pix, image->rect.left, image->rect.top); 787 - u_offset = UV2_OFFSET(pix, image->rect.left, 788 - image->rect.top) - offset; 789 - v_offset = 0; 788 + u_offset = image->u_offset ? 789 + image->u_offset : UV2_OFFSET(pix, image->rect.left, 790 + image->rect.top) - offset; 791 + v_offset = image->v_offset ? image->v_offset : 0; 790 792 791 793 ipu_cpmem_set_yuv_planar_full(ch, pix->bytesperline, 792 794 u_offset, v_offset);
+33 -19
drivers/gpu/ipu-v3/ipu-ic.c
··· 442 442 } 443 443 EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init); 444 444 445 - int ipu_ic_task_init(struct ipu_ic *ic, 446 - int in_width, int in_height, 447 - int out_width, int out_height, 448 - enum ipu_color_space in_cs, 449 - enum ipu_color_space out_cs) 445 + int ipu_ic_task_init_rsc(struct ipu_ic *ic, 446 + int in_width, int in_height, 447 + int out_width, int out_height, 448 + enum ipu_color_space in_cs, 449 + enum ipu_color_space out_cs, 450 + u32 rsc) 450 451 { 451 452 struct ipu_ic_priv *priv = ic->priv; 452 - u32 reg, downsize_coeff, resize_coeff; 453 + u32 downsize_coeff, resize_coeff; 453 454 unsigned long flags; 454 455 int ret = 0; 455 456 456 - /* Setup vertical resizing */ 457 - ret = calc_resize_coeffs(ic, in_height, out_height, 458 - &resize_coeff, &downsize_coeff); 459 - if (ret) 460 - return ret; 457 + if (!rsc) { 458 + /* Setup vertical resizing */ 461 459 462 - reg = (downsize_coeff << 30) | (resize_coeff << 16); 460 + ret = calc_resize_coeffs(ic, in_height, out_height, 461 + &resize_coeff, &downsize_coeff); 462 + if (ret) 463 + return ret; 463 464 464 - /* Setup horizontal resizing */ 465 - ret = calc_resize_coeffs(ic, in_width, out_width, 466 - &resize_coeff, &downsize_coeff); 467 - if (ret) 468 - return ret; 465 + rsc = (downsize_coeff << 30) | (resize_coeff << 16); 469 466 470 - reg |= (downsize_coeff << 14) | resize_coeff; 467 + /* Setup horizontal resizing */ 468 + ret = calc_resize_coeffs(ic, in_width, out_width, 469 + &resize_coeff, &downsize_coeff); 470 + if (ret) 471 + return ret; 472 + 473 + rsc |= (downsize_coeff << 14) | resize_coeff; 474 + } 471 475 472 476 spin_lock_irqsave(&priv->lock, flags); 473 477 474 - ipu_ic_write(ic, reg, ic->reg->rsc); 478 + ipu_ic_write(ic, rsc, ic->reg->rsc); 475 479 476 480 /* Setup color space conversion */ 477 481 ic->in_cs = in_cs; ··· 490 486 unlock: 491 487 spin_unlock_irqrestore(&priv->lock, flags); 492 488 return ret; 489 + } 490 + 491 + int ipu_ic_task_init(struct ipu_ic *ic, 492 + int in_width, int in_height, 493 + int out_width, int out_height, 494 + enum ipu_color_space in_cs, 495 + enum ipu_color_space out_cs) 496 + { 497 + return ipu_ic_task_init_rsc(ic, in_width, in_height, out_width, 498 + out_height, in_cs, out_cs, 0); 493 499 } 494 500 EXPORT_SYMBOL_GPL(ipu_ic_task_init); 495 501
+849 -168
drivers/gpu/ipu-v3/ipu-image-convert.c
··· 37 37 * when double_buffering boolean is set). 38 38 * 39 39 * Note that the input frame must be split up into the same number 40 - * of tiles as the output frame. 40 + * of tiles as the output frame: 41 41 * 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. 42 + * +---------+-----+ 43 + * +-----+---+ | A | B | 44 + * | A | B | | | | 45 + * +-----+---+ --> +---------+-----+ 46 + * | C | D | | C | D | 47 + * +-----+---+ | | | 48 + * +---------+-----+ 49 + * 50 + * Clockwise 90° rotations are handled by first rescaling into a 51 + * reusable temporary tile buffer and then rotating with the 8x8 52 + * block rotator, writing to the correct destination: 53 + * 54 + * +-----+-----+ 55 + * | | | 56 + * +-----+---+ +---------+ | C | A | 57 + * | A | B | | A,B, | | | | | 58 + * +-----+---+ --> | C,D | | --> | | | 59 + * | C | D | +---------+ +-----+-----+ 60 + * +-----+---+ | D | B | 61 + * | | | 62 + * +-----+-----+ 63 + * 64 + * If the 8x8 block rotator is used, horizontal or vertical flipping 65 + * is done during the rotation step, otherwise flipping is done 66 + * during the scaling step. 67 + * With rotation or flipping, tile order changes between input and 68 + * output image. Tiles are numbered row major from top left to bottom 69 + * right for both input and output image. 51 70 */ 52 71 53 72 #define MAX_STRIPES_W 4 ··· 103 84 struct ipu_image_tile { 104 85 u32 width; 105 86 u32 height; 87 + u32 left; 88 + u32 top; 106 89 /* size and strides are in bytes */ 107 90 u32 size; 108 91 u32 stride; ··· 156 135 struct ipu_image_convert_image in; 157 136 struct ipu_image_convert_image out; 158 137 enum ipu_rotate_mode rot_mode; 138 + u32 downsize_coeff_h; 139 + u32 downsize_coeff_v; 140 + u32 image_resize_coeff_h; 141 + u32 image_resize_coeff_v; 142 + u32 resize_coeffs_h[MAX_STRIPES_W]; 143 + u32 resize_coeffs_v[MAX_STRIPES_H]; 159 144 160 145 /* intermediate buffer for rotation */ 161 146 struct ipu_image_convert_dma_buf rot_intermediate[2]; ··· 327 300 struct ipu_image_convert_priv *priv = chan->priv; 328 301 329 302 dev_dbg(priv->ipu->dev, 330 - "task %u: ctx %p: %s format: %dx%d (%dx%d tiles of size %dx%d), %c%c%c%c\n", 303 + "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n", 331 304 chan->ic_task, ctx, 332 305 ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input", 333 306 ic_image->base.pix.width, ic_image->base.pix.height, 334 307 ic_image->num_cols, ic_image->num_rows, 335 - ic_image->tile[0].width, ic_image->tile[0].height, 336 308 ic_image->fmt->fourcc & 0xff, 337 309 (ic_image->fmt->fourcc >> 8) & 0xff, 338 310 (ic_image->fmt->fourcc >> 16) & 0xff, ··· 379 353 380 354 static inline int num_stripes(int dim) 381 355 { 382 - if (dim <= 1024) 383 - return 1; 384 - else if (dim <= 2048) 385 - return 2; 356 + return (dim - 1) / 1024 + 1; 357 + } 358 + 359 + /* 360 + * Calculate downsizing coefficients, which are the same for all tiles, 361 + * and bilinear resizing coefficients, which are used to find the best 362 + * seam positions. 363 + */ 364 + static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx, 365 + struct ipu_image *in, 366 + struct ipu_image *out) 367 + { 368 + u32 downsized_width = in->rect.width; 369 + u32 downsized_height = in->rect.height; 370 + u32 downsize_coeff_v = 0; 371 + u32 downsize_coeff_h = 0; 372 + u32 resized_width = out->rect.width; 373 + u32 resized_height = out->rect.height; 374 + u32 resize_coeff_h; 375 + u32 resize_coeff_v; 376 + 377 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 378 + resized_width = out->rect.height; 379 + resized_height = out->rect.width; 380 + } 381 + 382 + /* Do not let invalid input lead to an endless loop below */ 383 + if (WARN_ON(resized_width == 0 || resized_height == 0)) 384 + return -EINVAL; 385 + 386 + while (downsized_width >= resized_width * 2) { 387 + downsized_width >>= 1; 388 + downsize_coeff_h++; 389 + } 390 + 391 + while (downsized_height >= resized_height * 2) { 392 + downsized_height >>= 1; 393 + downsize_coeff_v++; 394 + } 395 + 396 + /* 397 + * Calculate the bilinear resizing coefficients that could be used if 398 + * we were converting with a single tile. The bottom right output pixel 399 + * should sample as close as possible to the bottom right input pixel 400 + * out of the decimator, but not overshoot it: 401 + */ 402 + resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1); 403 + resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1); 404 + 405 + dev_dbg(ctx->chan->priv->ipu->dev, 406 + "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n", 407 + __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v, 408 + resize_coeff_v, ctx->in.num_cols, ctx->in.num_rows); 409 + 410 + if (downsize_coeff_h > 2 || downsize_coeff_v > 2 || 411 + resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff) 412 + return -EINVAL; 413 + 414 + ctx->downsize_coeff_h = downsize_coeff_h; 415 + ctx->downsize_coeff_v = downsize_coeff_v; 416 + ctx->image_resize_coeff_h = resize_coeff_h; 417 + ctx->image_resize_coeff_v = resize_coeff_v; 418 + 419 + return 0; 420 + } 421 + 422 + #define round_closest(x, y) round_down((x) + (y)/2, (y)) 423 + 424 + /* 425 + * Find the best aligned seam position in the inverval [out_start, out_end]. 426 + * Rotation and image offsets are out of scope. 427 + * 428 + * @out_start: start of inverval, must be within 1024 pixels / lines 429 + * of out_end 430 + * @out_end: end of interval, smaller than or equal to out_edge 431 + * @in_edge: input right / bottom edge 432 + * @out_edge: output right / bottom edge 433 + * @in_align: input alignment, either horizontal 8-byte line start address 434 + * alignment, or pixel alignment due to image format 435 + * @out_align: output alignment, either horizontal 8-byte line start address 436 + * alignment, or pixel alignment due to image format or rotator 437 + * block size 438 + * @in_burst: horizontal input burst size in case of horizontal flip 439 + * @out_burst: horizontal output burst size or rotator block size 440 + * @downsize_coeff: downsizing section coefficient 441 + * @resize_coeff: main processing section resizing coefficient 442 + * @_in_seam: aligned input seam position return value 443 + * @_out_seam: aligned output seam position return value 444 + */ 445 + static void find_best_seam(struct ipu_image_convert_ctx *ctx, 446 + unsigned int out_start, 447 + unsigned int out_end, 448 + unsigned int in_edge, 449 + unsigned int out_edge, 450 + unsigned int in_align, 451 + unsigned int out_align, 452 + unsigned int in_burst, 453 + unsigned int out_burst, 454 + unsigned int downsize_coeff, 455 + unsigned int resize_coeff, 456 + u32 *_in_seam, 457 + u32 *_out_seam) 458 + { 459 + struct device *dev = ctx->chan->priv->ipu->dev; 460 + unsigned int out_pos; 461 + /* Input / output seam position candidates */ 462 + unsigned int out_seam = 0; 463 + unsigned int in_seam = 0; 464 + unsigned int min_diff = UINT_MAX; 465 + 466 + /* 467 + * Output tiles must start at a multiple of 8 bytes horizontally and 468 + * possibly at an even line horizontally depending on the pixel format. 469 + * Only consider output aligned positions for the seam. 470 + */ 471 + out_start = round_up(out_start, out_align); 472 + for (out_pos = out_start; out_pos < out_end; out_pos += out_align) { 473 + unsigned int in_pos; 474 + unsigned int in_pos_aligned; 475 + unsigned int abs_diff; 476 + 477 + /* 478 + * Tiles in the right row / bottom column may not be allowed to 479 + * overshoot horizontally / vertically. out_burst may be the 480 + * actual DMA burst size, or the rotator block size. 481 + */ 482 + if ((out_burst > 1) && (out_edge - out_pos) % out_burst) 483 + continue; 484 + 485 + /* 486 + * Input sample position, corresponding to out_pos, 19.13 fixed 487 + * point. 488 + */ 489 + in_pos = (out_pos * resize_coeff) << downsize_coeff; 490 + /* 491 + * The closest input sample position that we could actually 492 + * start the input tile at, 19.13 fixed point. 493 + */ 494 + in_pos_aligned = round_closest(in_pos, 8192U * in_align); 495 + 496 + if ((in_burst > 1) && 497 + (in_edge - in_pos_aligned / 8192U) % in_burst) 498 + continue; 499 + 500 + if (in_pos < in_pos_aligned) 501 + abs_diff = in_pos_aligned - in_pos; 502 + else 503 + abs_diff = in_pos - in_pos_aligned; 504 + 505 + if (abs_diff < min_diff) { 506 + in_seam = in_pos_aligned; 507 + out_seam = out_pos; 508 + min_diff = abs_diff; 509 + } 510 + } 511 + 512 + *_out_seam = out_seam; 513 + /* Convert 19.13 fixed point to integer seam position */ 514 + *_in_seam = DIV_ROUND_CLOSEST(in_seam, 8192U); 515 + 516 + dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) diff %u.%03u\n", 517 + __func__, out_seam, out_align, out_start, out_end, 518 + *_in_seam, in_align, min_diff / 8192, 519 + DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192)); 520 + } 521 + 522 + /* 523 + * Tile left edges are required to be aligned to multiples of 8 bytes 524 + * by the IDMAC. 525 + */ 526 + static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt) 527 + { 528 + if (fmt->planar) 529 + return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec; 386 530 else 387 - return 4; 531 + return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8; 532 + } 533 + 534 + /* 535 + * Tile top edge alignment is only limited by chroma subsampling. 536 + */ 537 + static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt) 538 + { 539 + return fmt->uv_height_dec > 1 ? 2 : 1; 540 + } 541 + 542 + static inline u32 tile_width_align(enum ipu_image_convert_type type, 543 + const struct ipu_image_pixfmt *fmt, 544 + enum ipu_rotate_mode rot_mode) 545 + { 546 + if (type == IMAGE_CONVERT_IN) { 547 + /* 548 + * The IC burst reads 8 pixels at a time. Reading beyond the 549 + * end of the line is usually acceptable. Those pixels are 550 + * ignored, unless the IC has to write the scaled line in 551 + * reverse. 552 + */ 553 + return (!ipu_rot_mode_is_irt(rot_mode) && 554 + (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2; 555 + } 556 + 557 + /* 558 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled 559 + * formats to guarantee 8-byte aligned line start addresses in the 560 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size 561 + * for all other formats. 562 + */ 563 + return (ipu_rot_mode_is_irt(rot_mode) && 564 + fmt->planar && !fmt->uv_packed) ? 565 + 8 * fmt->uv_width_dec : 8; 566 + } 567 + 568 + static inline u32 tile_height_align(enum ipu_image_convert_type type, 569 + const struct ipu_image_pixfmt *fmt, 570 + enum ipu_rotate_mode rot_mode) 571 + { 572 + if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode)) 573 + return 2; 574 + 575 + /* 576 + * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled 577 + * formats to guarantee 8-byte aligned line start addresses in the 578 + * chroma planes when IRT is used. Align to 8x8 pixel IRT block size 579 + * for all other formats. 580 + */ 581 + return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8; 582 + } 583 + 584 + /* 585 + * Fill in left position and width and for all tiles in an input column, and 586 + * for all corresponding output tiles. If the 90° rotator is used, the output 587 + * tiles are in a row, and output tile top position and height are set. 588 + */ 589 + static void fill_tile_column(struct ipu_image_convert_ctx *ctx, 590 + unsigned int col, 591 + struct ipu_image_convert_image *in, 592 + unsigned int in_left, unsigned int in_width, 593 + struct ipu_image_convert_image *out, 594 + unsigned int out_left, unsigned int out_width) 595 + { 596 + unsigned int row, tile_idx; 597 + struct ipu_image_tile *in_tile, *out_tile; 598 + 599 + for (row = 0; row < in->num_rows; row++) { 600 + tile_idx = in->num_cols * row + col; 601 + in_tile = &in->tile[tile_idx]; 602 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]]; 603 + 604 + in_tile->left = in_left; 605 + in_tile->width = in_width; 606 + 607 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 608 + out_tile->top = out_left; 609 + out_tile->height = out_width; 610 + } else { 611 + out_tile->left = out_left; 612 + out_tile->width = out_width; 613 + } 614 + } 615 + } 616 + 617 + /* 618 + * Fill in top position and height and for all tiles in an input row, and 619 + * for all corresponding output tiles. If the 90° rotator is used, the output 620 + * tiles are in a column, and output tile left position and width are set. 621 + */ 622 + static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row, 623 + struct ipu_image_convert_image *in, 624 + unsigned int in_top, unsigned int in_height, 625 + struct ipu_image_convert_image *out, 626 + unsigned int out_top, unsigned int out_height) 627 + { 628 + unsigned int col, tile_idx; 629 + struct ipu_image_tile *in_tile, *out_tile; 630 + 631 + for (col = 0; col < in->num_cols; col++) { 632 + tile_idx = in->num_cols * row + col; 633 + in_tile = &in->tile[tile_idx]; 634 + out_tile = &out->tile[ctx->out_tile_map[tile_idx]]; 635 + 636 + in_tile->top = in_top; 637 + in_tile->height = in_height; 638 + 639 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 640 + out_tile->left = out_top; 641 + out_tile->width = out_height; 642 + } else { 643 + out_tile->top = out_top; 644 + out_tile->height = out_height; 645 + } 646 + } 647 + } 648 + 649 + /* 650 + * Find the best horizontal and vertical seam positions to split into tiles. 651 + * Minimize the fractional part of the input sampling position for the 652 + * top / left pixels of each tile. 653 + */ 654 + static void find_seams(struct ipu_image_convert_ctx *ctx, 655 + struct ipu_image_convert_image *in, 656 + struct ipu_image_convert_image *out) 657 + { 658 + struct device *dev = ctx->chan->priv->ipu->dev; 659 + unsigned int resized_width = out->base.rect.width; 660 + unsigned int resized_height = out->base.rect.height; 661 + unsigned int col; 662 + unsigned int row; 663 + unsigned int in_left_align = tile_left_align(in->fmt); 664 + unsigned int in_top_align = tile_top_align(in->fmt); 665 + unsigned int out_left_align = tile_left_align(out->fmt); 666 + unsigned int out_top_align = tile_top_align(out->fmt); 667 + unsigned int out_width_align = tile_width_align(out->type, out->fmt, 668 + ctx->rot_mode); 669 + unsigned int out_height_align = tile_height_align(out->type, out->fmt, 670 + ctx->rot_mode); 671 + unsigned int in_right = in->base.rect.width; 672 + unsigned int in_bottom = in->base.rect.height; 673 + unsigned int out_right = out->base.rect.width; 674 + unsigned int out_bottom = out->base.rect.height; 675 + unsigned int flipped_out_left; 676 + unsigned int flipped_out_top; 677 + 678 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 679 + /* Switch width/height and align top left to IRT block size */ 680 + resized_width = out->base.rect.height; 681 + resized_height = out->base.rect.width; 682 + out_left_align = out_height_align; 683 + out_top_align = out_width_align; 684 + out_width_align = out_left_align; 685 + out_height_align = out_top_align; 686 + out_right = out->base.rect.height; 687 + out_bottom = out->base.rect.width; 688 + } 689 + 690 + for (col = in->num_cols - 1; col > 0; col--) { 691 + bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) || 692 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP); 693 + bool allow_out_overshoot = (col < in->num_cols - 1) && 694 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP); 695 + unsigned int out_start; 696 + unsigned int out_end; 697 + unsigned int in_left; 698 + unsigned int out_left; 699 + 700 + /* 701 + * Align input width to burst length if the scaling step flips 702 + * horizontally. 703 + */ 704 + 705 + /* Start within 1024 pixels of the right edge */ 706 + out_start = max_t(int, 0, out_right - 1024); 707 + /* End before having to add more columns to the left */ 708 + out_end = min_t(unsigned int, out_right, col * 1024); 709 + 710 + find_best_seam(ctx, out_start, out_end, 711 + in_right, out_right, 712 + in_left_align, out_left_align, 713 + allow_in_overshoot ? 1 : 8 /* burst length */, 714 + allow_out_overshoot ? 1 : out_width_align, 715 + ctx->downsize_coeff_h, ctx->image_resize_coeff_h, 716 + &in_left, &out_left); 717 + 718 + if (ctx->rot_mode & IPU_ROT_BIT_HFLIP) 719 + flipped_out_left = resized_width - out_right; 720 + else 721 + flipped_out_left = out_left; 722 + 723 + fill_tile_column(ctx, col, in, in_left, in_right - in_left, 724 + out, flipped_out_left, out_right - out_left); 725 + 726 + dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col, 727 + in_left, in_right - in_left, 728 + flipped_out_left, out_right - out_left); 729 + 730 + in_right = in_left; 731 + out_right = out_left; 732 + } 733 + 734 + flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ? 735 + resized_width - out_right : 0; 736 + 737 + fill_tile_column(ctx, 0, in, 0, in_right, 738 + out, flipped_out_left, out_right); 739 + 740 + dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__, 741 + in_right, flipped_out_left, out_right); 742 + 743 + for (row = in->num_rows - 1; row > 0; row--) { 744 + bool allow_overshoot = row < in->num_rows - 1; 745 + unsigned int out_start; 746 + unsigned int out_end; 747 + unsigned int in_top; 748 + unsigned int out_top; 749 + 750 + /* Start within 1024 lines of the bottom edge */ 751 + out_start = max_t(int, 0, out_bottom - 1024); 752 + /* End before having to add more rows above */ 753 + out_end = min_t(unsigned int, out_bottom, row * 1024); 754 + 755 + find_best_seam(ctx, out_start, out_end, 756 + in_bottom, out_bottom, 757 + in_top_align, out_top_align, 758 + 1, allow_overshoot ? 1 : out_height_align, 759 + ctx->downsize_coeff_v, ctx->image_resize_coeff_v, 760 + &in_top, &out_top); 761 + 762 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^ 763 + ipu_rot_mode_is_irt(ctx->rot_mode)) 764 + flipped_out_top = resized_height - out_bottom; 765 + else 766 + flipped_out_top = out_top; 767 + 768 + fill_tile_row(ctx, row, in, in_top, in_bottom - in_top, 769 + out, flipped_out_top, out_bottom - out_top); 770 + 771 + dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row, 772 + in_top, in_bottom - in_top, 773 + flipped_out_top, out_bottom - out_top); 774 + 775 + in_bottom = in_top; 776 + out_bottom = out_top; 777 + } 778 + 779 + if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^ 780 + ipu_rot_mode_is_irt(ctx->rot_mode)) 781 + flipped_out_top = resized_height - out_bottom; 782 + else 783 + flipped_out_top = 0; 784 + 785 + fill_tile_row(ctx, 0, in, 0, in_bottom, 786 + out, flipped_out_top, out_bottom); 787 + 788 + dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__, 789 + in_bottom, flipped_out_top, out_bottom); 388 790 } 389 791 390 792 static void calc_tile_dimensions(struct ipu_image_convert_ctx *ctx, 391 793 struct ipu_image_convert_image *image) 392 794 { 393 - int i; 795 + struct ipu_image_convert_chan *chan = ctx->chan; 796 + struct ipu_image_convert_priv *priv = chan->priv; 797 + unsigned int i; 394 798 395 799 for (i = 0; i < ctx->num_tiles; i++) { 396 - struct ipu_image_tile *tile = &image->tile[i]; 800 + struct ipu_image_tile *tile; 801 + const unsigned int row = i / image->num_cols; 802 + const unsigned int col = i % image->num_cols; 397 803 398 - tile->height = image->base.pix.height / image->num_rows; 399 - tile->width = image->base.pix.width / image->num_cols; 804 + if (image->type == IMAGE_CONVERT_OUT) 805 + tile = &image->tile[ctx->out_tile_map[i]]; 806 + else 807 + tile = &image->tile[i]; 808 + 400 809 tile->size = ((tile->height * image->fmt->bpp) >> 3) * 401 810 tile->width; 402 811 ··· 844 383 tile->rot_stride = 845 384 (image->fmt->bpp * tile->height) >> 3; 846 385 } 386 + 387 + dev_dbg(priv->ipu->dev, 388 + "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n", 389 + chan->ic_task, ctx, 390 + image->type == IMAGE_CONVERT_IN ? "Input" : "Output", 391 + row, col, 392 + tile->width, tile->height, tile->left, tile->top); 847 393 } 848 394 } 849 395 ··· 927 459 } 928 460 } 929 461 930 - static void calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx, 931 - struct ipu_image_convert_image *image) 462 + static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx, 463 + struct ipu_image_convert_image *image) 932 464 { 933 465 struct ipu_image_convert_chan *chan = ctx->chan; 934 466 struct ipu_image_convert_priv *priv = chan->priv; 935 467 const struct ipu_image_pixfmt *fmt = image->fmt; 936 468 unsigned int row, col, tile = 0; 937 - u32 H, w, h, y_stride, uv_stride; 469 + u32 H, top, y_stride, uv_stride; 938 470 u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp; 939 471 u32 y_row_off, y_col_off, y_off; 940 472 u32 y_size, uv_size; ··· 951 483 uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec); 952 484 953 485 for (row = 0; row < image->num_rows; row++) { 954 - w = image->tile[tile].width; 955 - h = image->tile[tile].height; 956 - y_row_off = row * h * y_stride; 957 - uv_row_off = (row * h * uv_stride) / fmt->uv_height_dec; 486 + top = image->tile[tile].top; 487 + y_row_off = top * y_stride; 488 + uv_row_off = (top * uv_stride) / fmt->uv_height_dec; 958 489 959 490 for (col = 0; col < image->num_cols; col++) { 960 - y_col_off = col * w; 491 + y_col_off = image->tile[tile].left; 961 492 uv_col_off = y_col_off / fmt->uv_width_dec; 962 493 if (fmt->uv_packed) 963 494 uv_col_off *= 2; ··· 976 509 image->tile[tile].u_off = u_off; 977 510 image->tile[tile++].v_off = v_off; 978 511 979 - dev_dbg(priv->ipu->dev, 980 - "task %u: ctx %p: %s@[%d,%d]: y_off %08x, u_off %08x, v_off %08x\n", 981 - chan->ic_task, ctx, 982 - image->type == IMAGE_CONVERT_IN ? 983 - "Input" : "Output", row, col, 984 - y_off, u_off, v_off); 512 + if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) { 513 + dev_err(priv->ipu->dev, 514 + "task %u: ctx %p: %s@[%d,%d]: " 515 + "y_off %08x, u_off %08x, v_off %08x\n", 516 + chan->ic_task, ctx, 517 + image->type == IMAGE_CONVERT_IN ? 518 + "Input" : "Output", row, col, 519 + y_off, u_off, v_off); 520 + return -EINVAL; 521 + } 985 522 } 986 523 } 524 + 525 + return 0; 987 526 } 988 527 989 - static void calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx, 990 - struct ipu_image_convert_image *image) 528 + static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx, 529 + struct ipu_image_convert_image *image) 991 530 { 992 531 struct ipu_image_convert_chan *chan = ctx->chan; 993 532 struct ipu_image_convert_priv *priv = chan->priv; 994 533 const struct ipu_image_pixfmt *fmt = image->fmt; 995 534 unsigned int row, col, tile = 0; 996 - u32 w, h, bpp, stride; 535 + u32 bpp, stride, offset; 997 536 u32 row_off, col_off; 998 537 999 538 /* setup some convenience vars */ ··· 1007 534 bpp = fmt->bpp; 1008 535 1009 536 for (row = 0; row < image->num_rows; row++) { 1010 - w = image->tile[tile].width; 1011 - h = image->tile[tile].height; 1012 - row_off = row * h * stride; 537 + row_off = image->tile[tile].top * stride; 1013 538 1014 539 for (col = 0; col < image->num_cols; col++) { 1015 - col_off = (col * w * bpp) >> 3; 540 + col_off = (image->tile[tile].left * bpp) >> 3; 1016 541 1017 - image->tile[tile].offset = row_off + col_off; 542 + offset = row_off + col_off; 543 + 544 + image->tile[tile].offset = offset; 1018 545 image->tile[tile].u_off = 0; 1019 546 image->tile[tile++].v_off = 0; 1020 547 1021 - dev_dbg(priv->ipu->dev, 1022 - "task %u: ctx %p: %s@[%d,%d]: phys %08x\n", 1023 - chan->ic_task, ctx, 1024 - image->type == IMAGE_CONVERT_IN ? 1025 - "Input" : "Output", row, col, 1026 - row_off + col_off); 548 + if (offset & 0x7) { 549 + dev_err(priv->ipu->dev, 550 + "task %u: ctx %p: %s@[%d,%d]: " 551 + "phys %08x\n", 552 + chan->ic_task, ctx, 553 + image->type == IMAGE_CONVERT_IN ? 554 + "Input" : "Output", row, col, 555 + row_off + col_off); 556 + return -EINVAL; 557 + } 1027 558 } 1028 559 } 560 + 561 + return 0; 1029 562 } 1030 563 1031 - static void calc_tile_offsets(struct ipu_image_convert_ctx *ctx, 564 + static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx, 1032 565 struct ipu_image_convert_image *image) 1033 566 { 1034 567 if (image->fmt->planar) 1035 - calc_tile_offsets_planar(ctx, image); 568 + return calc_tile_offsets_planar(ctx, image); 569 + 570 + return calc_tile_offsets_packed(ctx, image); 571 + } 572 + 573 + /* 574 + * Calculate the resizing ratio for the IC main processing section given input 575 + * size, fixed downsizing coefficient, and output size. 576 + * Either round to closest for the next tile's first pixel to minimize seams 577 + * and distortion (for all but right column / bottom row), or round down to 578 + * avoid sampling beyond the edges of the input image for this tile's last 579 + * pixel. 580 + * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff. 581 + */ 582 + static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff, 583 + u32 output_size, bool allow_overshoot) 584 + { 585 + u32 downsized = input_size >> downsize_coeff; 586 + 587 + if (allow_overshoot) 588 + return DIV_ROUND_CLOSEST(8192 * downsized, output_size); 1036 589 else 1037 - calc_tile_offsets_packed(ctx, image); 590 + return 8192 * (downsized - 1) / (output_size - 1); 591 + } 592 + 593 + /* 594 + * Slightly modify resize coefficients per tile to hide the bilinear 595 + * interpolator reset at tile borders, shifting the right / bottom edge 596 + * by up to a half input pixel. This removes noticeable seams between 597 + * tiles at higher upscaling factors. 598 + */ 599 + static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx) 600 + { 601 + struct ipu_image_convert_chan *chan = ctx->chan; 602 + struct ipu_image_convert_priv *priv = chan->priv; 603 + struct ipu_image_tile *in_tile, *out_tile; 604 + unsigned int col, row, tile_idx; 605 + unsigned int last_output; 606 + 607 + for (col = 0; col < ctx->in.num_cols; col++) { 608 + bool closest = (col < ctx->in.num_cols - 1) && 609 + !(ctx->rot_mode & IPU_ROT_BIT_HFLIP); 610 + u32 resized_width; 611 + u32 resize_coeff_h; 612 + 613 + tile_idx = col; 614 + in_tile = &ctx->in.tile[tile_idx]; 615 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]]; 616 + 617 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) 618 + resized_width = out_tile->height; 619 + else 620 + resized_width = out_tile->width; 621 + 622 + resize_coeff_h = calc_resize_coeff(in_tile->width, 623 + ctx->downsize_coeff_h, 624 + resized_width, closest); 625 + 626 + dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n", 627 + __func__, col, resize_coeff_h); 628 + 629 + 630 + for (row = 0; row < ctx->in.num_rows; row++) { 631 + tile_idx = row * ctx->in.num_cols + col; 632 + in_tile = &ctx->in.tile[tile_idx]; 633 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]]; 634 + 635 + /* 636 + * With the horizontal scaling factor known, round up 637 + * resized width (output width or height) to burst size. 638 + */ 639 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) 640 + out_tile->height = round_up(resized_width, 8); 641 + else 642 + out_tile->width = round_up(resized_width, 8); 643 + 644 + /* 645 + * Calculate input width from the last accessed input 646 + * pixel given resized width and scaling coefficients. 647 + * Round up to burst size. 648 + */ 649 + last_output = round_up(resized_width, 8) - 1; 650 + if (closest) 651 + last_output++; 652 + in_tile->width = round_up( 653 + (DIV_ROUND_UP(last_output * resize_coeff_h, 654 + 8192) + 1) 655 + << ctx->downsize_coeff_h, 8); 656 + } 657 + 658 + ctx->resize_coeffs_h[col] = resize_coeff_h; 659 + } 660 + 661 + for (row = 0; row < ctx->in.num_rows; row++) { 662 + bool closest = (row < ctx->in.num_rows - 1) && 663 + !(ctx->rot_mode & IPU_ROT_BIT_VFLIP); 664 + u32 resized_height; 665 + u32 resize_coeff_v; 666 + 667 + tile_idx = row * ctx->in.num_cols; 668 + in_tile = &ctx->in.tile[tile_idx]; 669 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]]; 670 + 671 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) 672 + resized_height = out_tile->width; 673 + else 674 + resized_height = out_tile->height; 675 + 676 + resize_coeff_v = calc_resize_coeff(in_tile->height, 677 + ctx->downsize_coeff_v, 678 + resized_height, closest); 679 + 680 + dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n", 681 + __func__, row, resize_coeff_v); 682 + 683 + for (col = 0; col < ctx->in.num_cols; col++) { 684 + tile_idx = row * ctx->in.num_cols + col; 685 + in_tile = &ctx->in.tile[tile_idx]; 686 + out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]]; 687 + 688 + /* 689 + * With the vertical scaling factor known, round up 690 + * resized height (output width or height) to IDMAC 691 + * limitations. 692 + */ 693 + if (ipu_rot_mode_is_irt(ctx->rot_mode)) 694 + out_tile->width = round_up(resized_height, 2); 695 + else 696 + out_tile->height = round_up(resized_height, 2); 697 + 698 + /* 699 + * Calculate input width from the last accessed input 700 + * pixel given resized height and scaling coefficients. 701 + * Align to IDMAC restrictions. 702 + */ 703 + last_output = round_up(resized_height, 2) - 1; 704 + if (closest) 705 + last_output++; 706 + in_tile->height = round_up( 707 + (DIV_ROUND_UP(last_output * resize_coeff_v, 708 + 8192) + 1) 709 + << ctx->downsize_coeff_v, 2); 710 + } 711 + 712 + ctx->resize_coeffs_v[row] = resize_coeff_v; 713 + } 1038 714 } 1039 715 1040 716 /* ··· 1233 611 struct ipuv3_channel *channel, 1234 612 struct ipu_image_convert_image *image, 1235 613 enum ipu_rotate_mode rot_mode, 1236 - bool rot_swap_width_height) 614 + bool rot_swap_width_height, 615 + unsigned int tile) 1237 616 { 1238 617 struct ipu_image_convert_chan *chan = ctx->chan; 1239 618 unsigned int burst_size; ··· 1244 621 unsigned int tile_idx[2]; 1245 622 1246 623 if (image->type == IMAGE_CONVERT_OUT) { 1247 - tile_idx[0] = ctx->out_tile_map[0]; 624 + tile_idx[0] = ctx->out_tile_map[tile]; 1248 625 tile_idx[1] = ctx->out_tile_map[1]; 1249 626 } else { 1250 - tile_idx[0] = 0; 627 + tile_idx[0] = tile; 1251 628 tile_idx[1] = 1; 1252 629 } 1253 630 1254 631 if (rot_swap_width_height) { 1255 - width = image->tile[0].height; 1256 - height = image->tile[0].width; 1257 - stride = image->tile[0].rot_stride; 632 + width = image->tile[tile_idx[0]].height; 633 + height = image->tile[tile_idx[0]].width; 634 + stride = image->tile[tile_idx[0]].rot_stride; 1258 635 addr0 = ctx->rot_intermediate[0].phys; 1259 636 if (ctx->double_buffering) 1260 637 addr1 = ctx->rot_intermediate[1].phys; 1261 638 } else { 1262 - width = image->tile[0].width; 1263 - height = image->tile[0].height; 639 + width = image->tile[tile_idx[0]].width; 640 + height = image->tile[tile_idx[0]].height; 1264 641 stride = image->stride; 1265 642 addr0 = image->base.phys0 + 1266 643 image->tile[tile_idx[0]].offset; ··· 1278 655 tile_image.pix.pixelformat = image->fmt->fourcc; 1279 656 tile_image.phys0 = addr0; 1280 657 tile_image.phys1 = addr1; 1281 - ipu_cpmem_set_image(channel, &tile_image); 658 + if (image->fmt->planar && !rot_swap_width_height) { 659 + tile_image.u_offset = image->tile[tile_idx[0]].u_off; 660 + tile_image.v_offset = image->tile[tile_idx[0]].v_off; 661 + } 1282 662 1283 - if (image->fmt->planar && !rot_swap_width_height) 1284 - ipu_cpmem_set_uv_offset(channel, 1285 - image->tile[tile_idx[0]].u_off, 1286 - image->tile[tile_idx[0]].v_off); 663 + ipu_cpmem_set_image(channel, &tile_image); 1287 664 1288 665 if (rot_mode) 1289 666 ipu_cpmem_set_rotation(channel, rot_mode); ··· 1310 687 ipu_idmac_set_double_buffer(channel, ctx->double_buffering); 1311 688 } 1312 689 1313 - static int convert_start(struct ipu_image_convert_run *run) 690 + static int convert_start(struct ipu_image_convert_run *run, unsigned int tile) 1314 691 { 1315 692 struct ipu_image_convert_ctx *ctx = run->ctx; 1316 693 struct ipu_image_convert_chan *chan = ctx->chan; ··· 1318 695 struct ipu_image_convert_image *s_image = &ctx->in; 1319 696 struct ipu_image_convert_image *d_image = &ctx->out; 1320 697 enum ipu_color_space src_cs, dest_cs; 698 + unsigned int dst_tile = ctx->out_tile_map[tile]; 1321 699 unsigned int dest_width, dest_height; 700 + unsigned int col, row; 701 + u32 rsc; 1322 702 int ret; 1323 703 1324 - dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p\n", 1325 - __func__, chan->ic_task, ctx, run); 704 + dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n", 705 + __func__, chan->ic_task, ctx, run, tile, dst_tile); 1326 706 1327 707 src_cs = ipu_pixelformat_to_colorspace(s_image->fmt->fourcc); 1328 708 dest_cs = ipu_pixelformat_to_colorspace(d_image->fmt->fourcc); 1329 709 1330 710 if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 1331 711 /* swap width/height for resizer */ 1332 - dest_width = d_image->tile[0].height; 1333 - dest_height = d_image->tile[0].width; 712 + dest_width = d_image->tile[dst_tile].height; 713 + dest_height = d_image->tile[dst_tile].width; 1334 714 } else { 1335 - dest_width = d_image->tile[0].width; 1336 - dest_height = d_image->tile[0].height; 715 + dest_width = d_image->tile[dst_tile].width; 716 + dest_height = d_image->tile[dst_tile].height; 1337 717 } 1338 718 719 + row = tile / s_image->num_cols; 720 + col = tile % s_image->num_cols; 721 + 722 + rsc = (ctx->downsize_coeff_v << 30) | 723 + (ctx->resize_coeffs_v[row] << 16) | 724 + (ctx->downsize_coeff_h << 14) | 725 + (ctx->resize_coeffs_h[col]); 726 + 727 + dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n", 728 + __func__, s_image->tile[tile].width, 729 + s_image->tile[tile].height, dest_width, dest_height, rsc); 730 + 1339 731 /* setup the IC resizer and CSC */ 1340 - ret = ipu_ic_task_init(chan->ic, 1341 - s_image->tile[0].width, 1342 - s_image->tile[0].height, 732 + ret = ipu_ic_task_init_rsc(chan->ic, 733 + s_image->tile[tile].width, 734 + s_image->tile[tile].height, 1343 735 dest_width, 1344 736 dest_height, 1345 - src_cs, dest_cs); 737 + src_cs, dest_cs, 738 + rsc); 1346 739 if (ret) { 1347 740 dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret); 1348 741 return ret; ··· 1366 727 1367 728 /* init the source MEM-->IC PP IDMAC channel */ 1368 729 init_idmac_channel(ctx, chan->in_chan, s_image, 1369 - IPU_ROTATE_NONE, false); 730 + IPU_ROTATE_NONE, false, tile); 1370 731 1371 732 if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 1372 733 /* init the IC PP-->MEM IDMAC channel */ 1373 734 init_idmac_channel(ctx, chan->out_chan, d_image, 1374 - IPU_ROTATE_NONE, true); 735 + IPU_ROTATE_NONE, true, tile); 1375 736 1376 737 /* init the MEM-->IC PP ROT IDMAC channel */ 1377 738 init_idmac_channel(ctx, chan->rotation_in_chan, d_image, 1378 - ctx->rot_mode, true); 739 + ctx->rot_mode, true, tile); 1379 740 1380 741 /* init the destination IC PP ROT-->MEM IDMAC channel */ 1381 742 init_idmac_channel(ctx, chan->rotation_out_chan, d_image, 1382 - IPU_ROTATE_NONE, false); 743 + IPU_ROTATE_NONE, false, tile); 1383 744 1384 745 /* now link IC PP-->MEM to MEM-->IC PP ROT */ 1385 746 ipu_idmac_link(chan->out_chan, chan->rotation_in_chan); 1386 747 } else { 1387 748 /* init the destination IC PP-->MEM IDMAC channel */ 1388 749 init_idmac_channel(ctx, chan->out_chan, d_image, 1389 - ctx->rot_mode, false); 750 + ctx->rot_mode, false, tile); 1390 751 } 1391 752 1392 753 /* enable the IC */ ··· 1444 805 list_del(&run->list); 1445 806 chan->current_run = run; 1446 807 1447 - return convert_start(run); 808 + return convert_start(run, 0); 1448 809 } 1449 810 1450 811 /* hold irqlock when calling */ ··· 1535 896 dev_dbg(priv->ipu->dev, 1536 897 "%s: task %u: signaling abort for ctx %p\n", 1537 898 __func__, chan->ic_task, ctx); 1538 - complete(&ctx->aborted); 899 + complete_all(&ctx->aborted); 1539 900 } 1540 901 } 1541 902 ··· 1545 906 chan->ic_task); 1546 907 1547 908 return IRQ_HANDLED; 909 + } 910 + 911 + static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx) 912 + { 913 + unsigned int cur_tile = ctx->next_tile - 1; 914 + unsigned int next_tile = ctx->next_tile; 915 + 916 + if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] != 917 + ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] || 918 + ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] != 919 + ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] || 920 + ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width || 921 + ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height || 922 + ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width || 923 + ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height) 924 + return true; 925 + 926 + return false; 1548 927 } 1549 928 1550 929 /* hold irqlock when calling */ ··· 1608 951 * not done, place the next tile buffers. 1609 952 */ 1610 953 if (!ctx->double_buffering) { 954 + if (ic_settings_changed(ctx)) { 955 + convert_stop(run); 956 + convert_start(run, ctx->next_tile); 957 + } else { 958 + src_tile = &s_image->tile[ctx->next_tile]; 959 + dst_idx = ctx->out_tile_map[ctx->next_tile]; 960 + dst_tile = &d_image->tile[dst_idx]; 1611 961 1612 - src_tile = &s_image->tile[ctx->next_tile]; 1613 - dst_idx = ctx->out_tile_map[ctx->next_tile]; 1614 - dst_tile = &d_image->tile[dst_idx]; 962 + ipu_cpmem_set_buffer(chan->in_chan, 0, 963 + s_image->base.phys0 + 964 + src_tile->offset); 965 + ipu_cpmem_set_buffer(outch, 0, 966 + d_image->base.phys0 + 967 + dst_tile->offset); 968 + if (s_image->fmt->planar) 969 + ipu_cpmem_set_uv_offset(chan->in_chan, 970 + src_tile->u_off, 971 + src_tile->v_off); 972 + if (d_image->fmt->planar) 973 + ipu_cpmem_set_uv_offset(outch, 974 + dst_tile->u_off, 975 + dst_tile->v_off); 1615 976 1616 - ipu_cpmem_set_buffer(chan->in_chan, 0, 1617 - s_image->base.phys0 + src_tile->offset); 1618 - ipu_cpmem_set_buffer(outch, 0, 1619 - d_image->base.phys0 + dst_tile->offset); 1620 - if (s_image->fmt->planar) 1621 - ipu_cpmem_set_uv_offset(chan->in_chan, 1622 - src_tile->u_off, 1623 - src_tile->v_off); 1624 - if (d_image->fmt->planar) 1625 - ipu_cpmem_set_uv_offset(outch, 1626 - dst_tile->u_off, 1627 - dst_tile->v_off); 1628 - 1629 - ipu_idmac_select_buffer(chan->in_chan, 0); 1630 - ipu_idmac_select_buffer(outch, 0); 1631 - 977 + ipu_idmac_select_buffer(chan->in_chan, 0); 978 + ipu_idmac_select_buffer(outch, 0); 979 + } 1632 980 } else if (ctx->next_tile < ctx->num_tiles - 1) { 1633 981 1634 982 src_tile = &s_image->tile[ctx->next_tile + 1]; ··· 1860 1198 else 1861 1199 ic_image->stride = ic_image->base.pix.bytesperline; 1862 1200 1863 - calc_tile_dimensions(ctx, ic_image); 1864 - calc_tile_offsets(ctx, ic_image); 1865 - 1866 1201 return 0; 1867 1202 } 1868 1203 ··· 1880 1221 return x; 1881 1222 } 1882 1223 1883 - /* 1884 - * We have to adjust the tile width such that the tile physaddrs and 1885 - * U and V plane offsets are multiples of 8 bytes as required by 1886 - * the IPU DMA Controller. For the planar formats, this corresponds 1887 - * to a pixel alignment of 16 (but use a more formal equation since 1888 - * the variables are available). For all the packed formats, 8 is 1889 - * good enough. 1890 - */ 1891 - static inline u32 tile_width_align(const struct ipu_image_pixfmt *fmt) 1892 - { 1893 - return fmt->planar ? 8 * fmt->uv_width_dec : 8; 1894 - } 1895 - 1896 - /* 1897 - * For tile height alignment, we have to ensure that the output tile 1898 - * heights are multiples of 8 lines if the IRT is required by the 1899 - * given rotation mode (the IRT performs rotations on 8x8 blocks 1900 - * at a time). If the IRT is not used, or for input image tiles, 1901 - * 2 lines are good enough. 1902 - */ 1903 - static inline u32 tile_height_align(enum ipu_image_convert_type type, 1904 - enum ipu_rotate_mode rot_mode) 1905 - { 1906 - return (type == IMAGE_CONVERT_OUT && 1907 - ipu_rot_mode_is_irt(rot_mode)) ? 8 : 2; 1908 - } 1909 - 1910 1224 /* Adjusts input/output images to IPU restrictions */ 1911 1225 void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out, 1912 1226 enum ipu_rotate_mode rot_mode) 1913 1227 { 1914 1228 const struct ipu_image_pixfmt *infmt, *outfmt; 1915 - unsigned int num_in_rows, num_in_cols; 1916 - unsigned int num_out_rows, num_out_cols; 1917 1229 u32 w_align, h_align; 1918 1230 1919 1231 infmt = get_format(in->pix.pixelformat); ··· 1916 1286 in->pix.height / 4); 1917 1287 } 1918 1288 1919 - /* get tiling rows/cols from output format */ 1920 - num_out_rows = num_stripes(out->pix.height); 1921 - num_out_cols = num_stripes(out->pix.width); 1922 - if (ipu_rot_mode_is_irt(rot_mode)) { 1923 - num_in_rows = num_out_cols; 1924 - num_in_cols = num_out_rows; 1925 - } else { 1926 - num_in_rows = num_out_rows; 1927 - num_in_cols = num_out_cols; 1928 - } 1929 - 1930 1289 /* align input width/height */ 1931 - w_align = ilog2(tile_width_align(infmt) * num_in_cols); 1932 - h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, rot_mode) * 1933 - num_in_rows); 1290 + w_align = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt, rot_mode)); 1291 + h_align = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt, rot_mode)); 1934 1292 in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W, w_align); 1935 1293 in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H, h_align); 1936 1294 1937 1295 /* align output width/height */ 1938 - w_align = ilog2(tile_width_align(outfmt) * num_out_cols); 1939 - h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, rot_mode) * 1940 - num_out_rows); 1296 + w_align = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt, rot_mode)); 1297 + h_align = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt, rot_mode)); 1941 1298 out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W, w_align); 1942 1299 out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H, h_align); 1943 1300 1944 1301 /* set input/output strides and image sizes */ 1945 - in->pix.bytesperline = (in->pix.width * infmt->bpp) >> 3; 1946 - in->pix.sizeimage = in->pix.height * in->pix.bytesperline; 1947 - out->pix.bytesperline = (out->pix.width * outfmt->bpp) >> 3; 1948 - out->pix.sizeimage = out->pix.height * out->pix.bytesperline; 1302 + in->pix.bytesperline = infmt->planar ? 1303 + clamp_align(in->pix.width, 2 << w_align, MAX_W, w_align) : 1304 + clamp_align((in->pix.width * infmt->bpp) >> 3, 1305 + 2 << w_align, MAX_W, w_align); 1306 + in->pix.sizeimage = infmt->planar ? 1307 + (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 : 1308 + in->pix.height * in->pix.bytesperline; 1309 + out->pix.bytesperline = outfmt->planar ? out->pix.width : 1310 + (out->pix.width * outfmt->bpp) >> 3; 1311 + out->pix.sizeimage = outfmt->planar ? 1312 + (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 : 1313 + out->pix.height * out->pix.bytesperline; 1949 1314 } 1950 1315 EXPORT_SYMBOL_GPL(ipu_image_convert_adjust); 1951 1316 ··· 1985 1360 struct ipu_image_convert_chan *chan; 1986 1361 struct ipu_image_convert_ctx *ctx; 1987 1362 unsigned long flags; 1363 + unsigned int i; 1988 1364 bool get_res; 1989 1365 int ret; 1990 1366 ··· 2038 1412 if (ret) 2039 1413 goto out_free; 2040 1414 1415 + ret = calc_image_resize_coefficients(ctx, in, out); 1416 + if (ret) 1417 + goto out_free; 1418 + 2041 1419 calc_out_tile_map(ctx); 1420 + 1421 + find_seams(ctx, s_image, d_image); 1422 + 1423 + calc_tile_dimensions(ctx, s_image); 1424 + ret = calc_tile_offsets(ctx, s_image); 1425 + if (ret) 1426 + goto out_free; 1427 + 1428 + calc_tile_dimensions(ctx, d_image); 1429 + ret = calc_tile_offsets(ctx, d_image); 1430 + if (ret) 1431 + goto out_free; 1432 + 1433 + calc_tile_resize_coefficients(ctx); 2042 1434 2043 1435 dump_format(ctx, s_image); 2044 1436 dump_format(ctx, d_image); ··· 2073 1429 * for every tile, and therefore would have to be updated for 2074 1430 * each buffer which is not possible. So double-buffering is 2075 1431 * impossible when either the source or destination images are 2076 - * a planar format (YUV420, YUV422P, etc.). 1432 + * a planar format (YUV420, YUV422P, etc.). Further, differently 1433 + * sized tiles or different resizing coefficients per tile 1434 + * prevent double-buffering as well. 2077 1435 */ 2078 1436 ctx->double_buffering = (ctx->num_tiles > 1 && 2079 1437 !s_image->fmt->planar && 2080 1438 !d_image->fmt->planar); 1439 + for (i = 1; i < ctx->num_tiles; i++) { 1440 + if (ctx->in.tile[i].width != ctx->in.tile[0].width || 1441 + ctx->in.tile[i].height != ctx->in.tile[0].height || 1442 + ctx->out.tile[i].width != ctx->out.tile[0].width || 1443 + ctx->out.tile[i].height != ctx->out.tile[0].height) { 1444 + ctx->double_buffering = false; 1445 + break; 1446 + } 1447 + } 1448 + for (i = 1; i < ctx->in.num_cols; i++) { 1449 + if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) { 1450 + ctx->double_buffering = false; 1451 + break; 1452 + } 1453 + } 1454 + for (i = 1; i < ctx->in.num_rows; i++) { 1455 + if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) { 1456 + ctx->double_buffering = false; 1457 + break; 1458 + } 1459 + } 2081 1460 2082 1461 if (ipu_rot_mode_is_irt(ctx->rot_mode)) { 1462 + unsigned long intermediate_size = d_image->tile[0].size; 1463 + 1464 + for (i = 1; i < ctx->num_tiles; i++) { 1465 + if (d_image->tile[i].size > intermediate_size) 1466 + intermediate_size = d_image->tile[i].size; 1467 + } 1468 + 2083 1469 ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0], 2084 - d_image->tile[0].size); 1470 + intermediate_size); 2085 1471 if (ret) 2086 1472 goto out_free; 2087 1473 if (ctx->double_buffering) { 2088 1474 ret = alloc_dma_buf(priv, 2089 1475 &ctx->rot_intermediate[1], 2090 - d_image->tile[0].size); 1476 + intermediate_size); 2091 1477 if (ret) 2092 1478 goto out_free_dmabuf0; 2093 1479 } ··· 2198 1524 EXPORT_SYMBOL_GPL(ipu_image_convert_queue); 2199 1525 2200 1526 /* Abort any active or pending conversions for this context */ 2201 - void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx) 1527 + static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx) 2202 1528 { 2203 1529 struct ipu_image_convert_chan *chan = ctx->chan; 2204 1530 struct ipu_image_convert_priv *priv = chan->priv; 2205 1531 struct ipu_image_convert_run *run, *active_run, *tmp; 2206 1532 unsigned long flags; 2207 1533 int run_count, ret; 2208 - bool need_abort; 2209 - 2210 - reinit_completion(&ctx->aborted); 2211 1534 2212 1535 spin_lock_irqsave(&chan->irqlock, flags); 2213 1536 ··· 2220 1549 active_run = (chan->current_run && chan->current_run->ctx == ctx) ? 2221 1550 chan->current_run : NULL; 2222 1551 2223 - need_abort = (run_count || active_run); 1552 + if (active_run) 1553 + reinit_completion(&ctx->aborted); 2224 1554 2225 - ctx->aborting = need_abort; 1555 + ctx->aborting = true; 2226 1556 2227 1557 spin_unlock_irqrestore(&chan->irqlock, flags); 2228 1558 2229 - if (!need_abort) { 1559 + if (!run_count && !active_run) { 2230 1560 dev_dbg(priv->ipu->dev, 2231 1561 "%s: task %u: no abort needed for ctx %p\n", 2232 1562 __func__, chan->ic_task, ctx); 2233 1563 return; 2234 1564 } 2235 1565 1566 + if (!active_run) { 1567 + empty_done_q(chan); 1568 + return; 1569 + } 1570 + 2236 1571 dev_dbg(priv->ipu->dev, 2237 - "%s: task %u: wait for completion: %d runs, active run %p\n", 2238 - __func__, chan->ic_task, run_count, active_run); 1572 + "%s: task %u: wait for completion: %d runs\n", 1573 + __func__, chan->ic_task, run_count); 2239 1574 2240 1575 ret = wait_for_completion_timeout(&ctx->aborted, 2241 1576 msecs_to_jiffies(10000)); ··· 2249 1572 dev_warn(priv->ipu->dev, "%s: timeout\n", __func__); 2250 1573 force_abort(ctx); 2251 1574 } 1575 + } 2252 1576 1577 + void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx) 1578 + { 1579 + __ipu_image_convert_abort(ctx); 2253 1580 ctx->aborting = false; 2254 1581 } 2255 1582 EXPORT_SYMBOL_GPL(ipu_image_convert_abort); ··· 2267 1586 bool put_res; 2268 1587 2269 1588 /* make sure no runs are hanging around */ 2270 - ipu_image_convert_abort(ctx); 1589 + __ipu_image_convert_abort(ctx); 2271 1590 2272 1591 dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__, 2273 1592 chan->ic_task, ctx);
+9
include/video/imx-ipu-v3.h
··· 246 246 struct v4l2_rect rect; 247 247 dma_addr_t phys0; 248 248 dma_addr_t phys1; 249 + /* chroma plane offset overrides */ 250 + u32 u_offset; 251 + u32 v_offset; 249 252 }; 250 253 251 254 void ipu_cpmem_zero(struct ipuv3_channel *ch); ··· 390 387 int out_width, int out_height, 391 388 enum ipu_color_space in_cs, 392 389 enum ipu_color_space out_cs); 390 + int ipu_ic_task_init_rsc(struct ipu_ic *ic, 391 + int in_width, int in_height, 392 + int out_width, int out_height, 393 + enum ipu_color_space in_cs, 394 + enum ipu_color_space out_cs, 395 + u32 rsc); 393 396 int ipu_ic_task_graphics_init(struct ipu_ic *ic, 394 397 enum ipu_color_space in_g_cs, 395 398 bool galpha_en, u32 galpha,