^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2012-2016 Mentor Graphics Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Queued image conversion support, with tiling and rotation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <video/imx-ipu-image-convert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "ipu-prv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * The IC Resizer has a restriction that the output frame from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * resizer must be 1024 or less in both width (pixels) and height
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * (lines).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * The image converter attempts to split up a conversion when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * the desired output (converted) frame resolution exceeds the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * IC resizer limit of 1024 in either dimension.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * If either dimension of the output frame exceeds the limit, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * dimension is split into 1, 2, or 4 equal stripes, for a maximum
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * of 4*4 or 16 tiles. A conversion is then carried out for each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * tile (but taking care to pass the full frame stride length to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * the DMA channel's parameter memory!). IDMA double-buffering is used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * to convert each tile back-to-back when possible (see note below
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * when double_buffering boolean is set).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * Note that the input frame must be split up into the same number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * of tiles as the output frame:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * +---------+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * +-----+---+ | A | B |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * | A | B | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * +-----+---+ --> +---------+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * | C | D | | C | D |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * +-----+---+ | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * +---------+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Clockwise 90° rotations are handled by first rescaling into a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * reusable temporary tile buffer and then rotating with the 8x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * block rotator, writing to the correct destination:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * +-----+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * +-----+---+ +---------+ | C | A |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * | A | B | | A,B, | | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * +-----+---+ --> | C,D | | --> | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * | C | D | +---------+ +-----+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * +-----+---+ | D | B |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * +-----+-----+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * If the 8x8 block rotator is used, horizontal or vertical flipping
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * is done during the rotation step, otherwise flipping is done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * during the scaling step.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * With rotation or flipping, tile order changes between input and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * output image. Tiles are numbered row major from top left to bottom
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * right for both input and output image.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define MAX_STRIPES_W 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define MAX_STRIPES_H 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define MAX_TILES (MAX_STRIPES_W * MAX_STRIPES_H)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define MIN_W 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define MIN_H 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define MAX_W 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define MAX_H 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) enum ipu_image_convert_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) IMAGE_CONVERT_IN = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) IMAGE_CONVERT_OUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct ipu_image_convert_dma_buf {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) void *virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) dma_addr_t phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned long len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct ipu_image_convert_dma_chan {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) int out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int rot_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int rot_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) int vdi_in_p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int vdi_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) int vdi_in_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* dimensions of one tile */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct ipu_image_tile {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) u32 width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u32 height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u32 left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u32 top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* size and strides are in bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u32 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u32 stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u32 rot_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* start Y or packed offset of this tile */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u32 offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* offset from start to tile in U plane, for planar formats */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u32 u_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* offset from start to tile in V plane, for planar formats */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u32 v_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct ipu_image_convert_image {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct ipu_image base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) enum ipu_image_convert_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) const struct ipu_image_pixfmt *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned int stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* # of rows (horizontal stripes) if dest height is > 1024 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned int num_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /* # of columns (vertical stripes) if dest width is > 1024 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct ipu_image_tile tile[MAX_TILES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct ipu_image_pixfmt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) u32 fourcc; /* V4L2 fourcc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) int bpp; /* total bpp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int uv_width_dec; /* decimation in width for U/V planes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) int uv_height_dec; /* decimation in height for U/V planes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) bool planar; /* planar format */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) bool uv_swapped; /* U and V planes are swapped */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) bool uv_packed; /* partial planar (U and V in same plane) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct ipu_image_convert_ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct ipu_image_convert_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct ipu_image_convert_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) enum eof_irq_mask {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) EOF_IRQ_IN = BIT(0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) EOF_IRQ_ROT_IN = BIT(1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) EOF_IRQ_OUT = BIT(2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) EOF_IRQ_ROT_OUT = BIT(3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define EOF_IRQ_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define EOF_IRQ_ROT_COMPLETE (EOF_IRQ_IN | EOF_IRQ_OUT | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) EOF_IRQ_ROT_IN | EOF_IRQ_ROT_OUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct ipu_image_convert_ctx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct ipu_image_convert_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) ipu_image_convert_cb_t complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) void *complete_context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Source/destination image data and rotation mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct ipu_image_convert_image in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct ipu_image_convert_image out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct ipu_ic_csc csc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) enum ipu_rotate_mode rot_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) u32 downsize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) u32 downsize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) u32 image_resize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u32 image_resize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) u32 resize_coeffs_h[MAX_STRIPES_W];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) u32 resize_coeffs_v[MAX_STRIPES_H];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /* intermediate buffer for rotation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct ipu_image_convert_dma_buf rot_intermediate[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* current buffer number for double buffering */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int cur_buf_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) bool aborting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct completion aborted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* can we use double-buffering for this conversion operation? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) bool double_buffering;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /* num_rows * num_cols */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) unsigned int num_tiles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /* next tile to process */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned int next_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* where to place converted tile in dest image */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) unsigned int out_tile_map[MAX_TILES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* mask of completed EOF irqs at every tile conversion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) enum eof_irq_mask eof_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct ipu_image_convert_chan {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct ipu_image_convert_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) enum ipu_ic_task ic_task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) const struct ipu_image_convert_dma_chan *dma_ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct ipu_ic *ic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct ipuv3_channel *in_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct ipuv3_channel *out_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct ipuv3_channel *rotation_in_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct ipuv3_channel *rotation_out_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) /* the IPU end-of-frame irqs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int in_eof_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int rot_in_eof_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) int out_eof_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) int rot_out_eof_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) spinlock_t irqlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* list of convert contexts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct list_head ctx_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* queue of conversion runs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct list_head pending_q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* queue of completed runs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct list_head done_q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* the current conversion run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) struct ipu_image_convert_run *current_run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) struct ipu_image_convert_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) struct ipu_image_convert_chan chan[IC_NUM_TASKS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) struct ipu_soc *ipu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static const struct ipu_image_convert_dma_chan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) image_convert_dma_chan[IC_NUM_TASKS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) [IC_TASK_VIEWFINDER] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .in = IPUV3_CHANNEL_MEM_IC_PRP_VF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .out = IPUV3_CHANNEL_IC_PRP_VF_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .rot_in = IPUV3_CHANNEL_MEM_ROT_VF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .rot_out = IPUV3_CHANNEL_ROT_VF_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .vdi_in_p = IPUV3_CHANNEL_MEM_VDI_PREV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .vdi_in = IPUV3_CHANNEL_MEM_VDI_CUR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .vdi_in_n = IPUV3_CHANNEL_MEM_VDI_NEXT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) [IC_TASK_POST_PROCESSOR] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .in = IPUV3_CHANNEL_MEM_IC_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .out = IPUV3_CHANNEL_IC_PP_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .rot_in = IPUV3_CHANNEL_MEM_ROT_PP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .rot_out = IPUV3_CHANNEL_ROT_PP_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static const struct ipu_image_pixfmt image_convert_formats[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .fourcc = V4L2_PIX_FMT_RGB565,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .bpp = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .fourcc = V4L2_PIX_FMT_RGB24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .bpp = 24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) .fourcc = V4L2_PIX_FMT_BGR24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) .bpp = 24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) .fourcc = V4L2_PIX_FMT_RGB32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) .fourcc = V4L2_PIX_FMT_BGR32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) .fourcc = V4L2_PIX_FMT_XRGB32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .fourcc = V4L2_PIX_FMT_XBGR32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .fourcc = V4L2_PIX_FMT_BGRX32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .fourcc = V4L2_PIX_FMT_RGBX32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .bpp = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) .fourcc = V4L2_PIX_FMT_YUYV,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) .bpp = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .uv_height_dec = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .fourcc = V4L2_PIX_FMT_UYVY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .bpp = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .uv_height_dec = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) .fourcc = V4L2_PIX_FMT_YUV420,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .bpp = 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .planar = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) .uv_height_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .fourcc = V4L2_PIX_FMT_YVU420,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .bpp = 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .planar = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .uv_height_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .uv_swapped = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .fourcc = V4L2_PIX_FMT_NV12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .bpp = 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .planar = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) .uv_height_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .uv_packed = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) .fourcc = V4L2_PIX_FMT_YUV422P,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) .bpp = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .planar = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .uv_height_dec = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .fourcc = V4L2_PIX_FMT_NV16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .bpp = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .planar = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .uv_width_dec = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .uv_height_dec = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .uv_packed = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static const struct ipu_image_pixfmt *get_format(u32 fourcc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) const struct ipu_image_pixfmt *ret = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) for (i = 0; i < ARRAY_SIZE(image_convert_formats); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (image_convert_formats[i].fourcc == fourcc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) ret = &image_convert_formats[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static void dump_format(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct ipu_image_convert_image *ic_image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) "task %u: ctx %p: %s format: %dx%d (%dx%d tiles), %c%c%c%c\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) chan->ic_task, ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ic_image->base.pix.width, ic_image->base.pix.height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ic_image->num_cols, ic_image->num_rows,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) ic_image->fmt->fourcc & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) (ic_image->fmt->fourcc >> 8) & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) (ic_image->fmt->fourcc >> 16) & 0xff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) (ic_image->fmt->fourcc >> 24) & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) int ipu_image_convert_enum_format(int index, u32 *fourcc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) const struct ipu_image_pixfmt *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (index >= (int)ARRAY_SIZE(image_convert_formats))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* Format found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) fmt = &image_convert_formats[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) *fourcc = fmt->fourcc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) EXPORT_SYMBOL_GPL(ipu_image_convert_enum_format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static void free_dma_buf(struct ipu_image_convert_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct ipu_image_convert_dma_buf *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (buf->virt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) dma_free_coherent(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) buf->len, buf->virt, buf->phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) buf->virt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) buf->phys = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct ipu_image_convert_dma_buf *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) buf->len = PAGE_ALIGN(size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) GFP_DMA | GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (!buf->virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static inline int num_stripes(int dim)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return (dim - 1) / 1024 + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * Calculate downsizing coefficients, which are the same for all tiles,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * and initial bilinear resizing coefficients, which are used to find the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) * best seam positions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * Also determine the number of tiles necessary to guarantee that no tile
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * is larger than 1024 pixels in either dimension at the output and between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) * IC downsizing and main processing sections.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct ipu_image *in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) struct ipu_image *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) u32 downsized_width = in->rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) u32 downsized_height = in->rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) u32 downsize_coeff_v = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) u32 downsize_coeff_h = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) u32 resized_width = out->rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) u32 resized_height = out->rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) u32 resize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) u32 resize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) u32 cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) u32 rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) resized_width = out->rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) resized_height = out->rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* Do not let invalid input lead to an endless loop below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (WARN_ON(resized_width == 0 || resized_height == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) while (downsized_width >= resized_width * 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) downsized_width >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) downsize_coeff_h++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) while (downsized_height >= resized_height * 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) downsized_height >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) downsize_coeff_v++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * Calculate the bilinear resizing coefficients that could be used if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * we were converting with a single tile. The bottom right output pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * should sample as close as possible to the bottom right input pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * out of the decimator, but not overshoot it:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * Both the output of the IC downsizing section before being passed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * the IC main processing section and the final output of the IC main
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * processing section must be <= 1024 pixels in both dimensions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) cols = num_stripes(max_t(u32, downsized_width, resized_width));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) rows = num_stripes(max_t(u32, downsized_height, resized_height));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) dev_dbg(ctx->chan->priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) "%s: hscale: >>%u, *8192/%u vscale: >>%u, *8192/%u, %ux%u tiles\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) __func__, downsize_coeff_h, resize_coeff_h, downsize_coeff_v,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) resize_coeff_v, cols, rows);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (downsize_coeff_h > 2 || downsize_coeff_v > 2 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) resize_coeff_h > 0x3fff || resize_coeff_v > 0x3fff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) ctx->downsize_coeff_h = downsize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) ctx->downsize_coeff_v = downsize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) ctx->image_resize_coeff_h = resize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) ctx->image_resize_coeff_v = resize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) ctx->in.num_cols = cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) ctx->in.num_rows = rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) #define round_closest(x, y) round_down((x) + (y)/2, (y))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) * Find the best aligned seam position for the given column / row index.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * Rotation and image offsets are out of scope.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) * @index: column / row index, used to calculate valid interval
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) * @in_edge: input right / bottom edge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * @out_edge: output right / bottom edge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * @in_align: input alignment, either horizontal 8-byte line start address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * alignment, or pixel alignment due to image format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * @out_align: output alignment, either horizontal 8-byte line start address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * alignment, or pixel alignment due to image format or rotator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * block size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) * @in_burst: horizontal input burst size in case of horizontal flip
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * @out_burst: horizontal output burst size or rotator block size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * @downsize_coeff: downsizing section coefficient
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * @resize_coeff: main processing section resizing coefficient
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * @_in_seam: aligned input seam position return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * @_out_seam: aligned output seam position return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static void find_best_seam(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) unsigned int index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) unsigned int in_edge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) unsigned int out_edge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) unsigned int in_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) unsigned int out_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) unsigned int in_burst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) unsigned int out_burst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) unsigned int downsize_coeff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) unsigned int resize_coeff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) u32 *_in_seam,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) u32 *_out_seam)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct device *dev = ctx->chan->priv->ipu->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) unsigned int out_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* Input / output seam position candidates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) unsigned int out_seam = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) unsigned int in_seam = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) unsigned int min_diff = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) unsigned int out_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) unsigned int out_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) unsigned int in_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) unsigned int in_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* Start within 1024 pixels of the right / bottom edge */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) out_start = max_t(int, index * out_align, out_edge - 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) /* End before having to add more columns to the left / rows above */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) out_end = min_t(unsigned int, out_edge, index * 1024 + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) * Limit input seam position to make sure that the downsized input tile
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * to the right or bottom does not exceed 1024 pixels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) in_start = max_t(int, index * in_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) in_edge - (1024 << downsize_coeff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) in_end = min_t(unsigned int, in_edge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) index * (1024 << downsize_coeff) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * Output tiles must start at a multiple of 8 bytes horizontally and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * possibly at an even line horizontally depending on the pixel format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) * Only consider output aligned positions for the seam.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) out_start = round_up(out_start, out_align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) for (out_pos = out_start; out_pos < out_end; out_pos += out_align) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) unsigned int in_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) unsigned int in_pos_aligned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) unsigned int in_pos_rounded;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) unsigned int abs_diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * Tiles in the right row / bottom column may not be allowed to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * overshoot horizontally / vertically. out_burst may be the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * actual DMA burst size, or the rotator block size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * Input sample position, corresponding to out_pos, 19.13 fixed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) in_pos = (out_pos * resize_coeff) << downsize_coeff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * The closest input sample position that we could actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * start the input tile at, 19.13 fixed point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) in_pos_aligned = round_closest(in_pos, 8192U * in_align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) /* Convert 19.13 fixed point to integer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) in_pos_rounded = in_pos_aligned / 8192U;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (in_pos_rounded < in_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (in_pos_rounded >= in_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if ((in_burst > 1) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) (in_edge - in_pos_rounded) % in_burst)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) if (in_pos < in_pos_aligned)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) abs_diff = in_pos_aligned - in_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) abs_diff = in_pos - in_pos_aligned;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (abs_diff < min_diff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) in_seam = in_pos_rounded;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) out_seam = out_pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) min_diff = abs_diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) *_out_seam = out_seam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) *_in_seam = in_seam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) dev_dbg(dev, "%s: out_seam %u(%u) in [%u, %u], in_seam %u(%u) in [%u, %u] diff %u.%03u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) __func__, out_seam, out_align, out_start, out_end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) in_seam, in_align, in_start, in_end, min_diff / 8192,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) DIV_ROUND_CLOSEST(min_diff % 8192 * 1000, 8192));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) * Tile left edges are required to be aligned to multiples of 8 bytes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) * by the IDMAC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (fmt->planar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) * Tile top edge alignment is only limited by chroma subsampling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return fmt->uv_height_dec > 1 ? 2 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) static inline u32 tile_width_align(enum ipu_image_convert_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) const struct ipu_image_pixfmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) enum ipu_rotate_mode rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) if (type == IMAGE_CONVERT_IN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * The IC burst reads 8 pixels at a time. Reading beyond the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * end of the line is usually acceptable. Those pixels are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * ignored, unless the IC has to write the scaled line in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * reverse.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return (!ipu_rot_mode_is_irt(rot_mode) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) (rot_mode & IPU_ROT_BIT_HFLIP)) ? 8 : 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * formats to guarantee 8-byte aligned line start addresses in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * for all other formats.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return (ipu_rot_mode_is_irt(rot_mode) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) fmt->planar && !fmt->uv_packed) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 8 * fmt->uv_width_dec : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) static inline u32 tile_height_align(enum ipu_image_convert_type type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) const struct ipu_image_pixfmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) enum ipu_rotate_mode rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (type == IMAGE_CONVERT_IN || !ipu_rot_mode_is_irt(rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) * Align to 16x16 pixel blocks for planar 4:2:0 chroma subsampled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) * formats to guarantee 8-byte aligned line start addresses in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) * chroma planes when IRT is used. Align to 8x8 pixel IRT block size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) * for all other formats.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * Fill in left position and width and for all tiles in an input column, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * for all corresponding output tiles. If the 90° rotator is used, the output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * tiles are in a row, and output tile top position and height are set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) unsigned int col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) struct ipu_image_convert_image *in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) unsigned int in_left, unsigned int in_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) struct ipu_image_convert_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) unsigned int out_left, unsigned int out_width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) unsigned int row, tile_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) struct ipu_image_tile *in_tile, *out_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) for (row = 0; row < in->num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) tile_idx = in->num_cols * row + col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) in_tile = &in->tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) in_tile->left = in_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) in_tile->width = in_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) out_tile->top = out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) out_tile->height = out_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) out_tile->left = out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) out_tile->width = out_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * Fill in top position and height and for all tiles in an input row, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) * for all corresponding output tiles. If the 90° rotator is used, the output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) * tiles are in a column, and output tile left position and width are set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) struct ipu_image_convert_image *in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) unsigned int in_top, unsigned int in_height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct ipu_image_convert_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) unsigned int out_top, unsigned int out_height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) unsigned int col, tile_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) struct ipu_image_tile *in_tile, *out_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) for (col = 0; col < in->num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) tile_idx = in->num_cols * row + col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) in_tile = &in->tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) in_tile->top = in_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) in_tile->height = in_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) out_tile->left = out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) out_tile->width = out_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) out_tile->top = out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) out_tile->height = out_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * Find the best horizontal and vertical seam positions to split into tiles.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) * Minimize the fractional part of the input sampling position for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) * top / left pixels of each tile.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) static void find_seams(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) struct ipu_image_convert_image *in,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) struct ipu_image_convert_image *out)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) struct device *dev = ctx->chan->priv->ipu->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) unsigned int resized_width = out->base.rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) unsigned int resized_height = out->base.rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) unsigned int col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) unsigned int row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) unsigned int in_left_align = tile_left_align(in->fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) unsigned int in_top_align = tile_top_align(in->fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) unsigned int out_left_align = tile_left_align(out->fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) unsigned int out_top_align = tile_top_align(out->fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) unsigned int out_width_align = tile_width_align(out->type, out->fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) ctx->rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) unsigned int out_height_align = tile_height_align(out->type, out->fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) ctx->rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) unsigned int in_right = in->base.rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) unsigned int in_bottom = in->base.rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) unsigned int out_right = out->base.rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) unsigned int out_bottom = out->base.rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) unsigned int flipped_out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) unsigned int flipped_out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* Switch width/height and align top left to IRT block size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) resized_width = out->base.rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) resized_height = out->base.rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) out_left_align = out_height_align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) out_top_align = out_width_align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) out_width_align = out_left_align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) out_height_align = out_top_align;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) out_right = out->base.rect.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) out_bottom = out->base.rect.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) for (col = in->num_cols - 1; col > 0; col--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) bool allow_out_overshoot = (col < in->num_cols - 1) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) unsigned int in_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) unsigned int out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) * Align input width to burst length if the scaling step flips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) * horizontally.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) find_best_seam(ctx, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) in_right, out_right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) in_left_align, out_left_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) allow_in_overshoot ? 1 : 8 /* burst length */,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) allow_out_overshoot ? 1 : out_width_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) &in_left, &out_left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) flipped_out_left = resized_width - out_right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) flipped_out_left = out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) fill_tile_column(ctx, col, in, in_left, in_right - in_left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) out, flipped_out_left, out_right - out_left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) in_left, in_right - in_left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) flipped_out_left, out_right - out_left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) in_right = in_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) out_right = out_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) resized_width - out_right : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) fill_tile_column(ctx, 0, in, 0, in_right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) out, flipped_out_left, out_right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) in_right, flipped_out_left, out_right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) for (row = in->num_rows - 1; row > 0; row--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) bool allow_overshoot = row < in->num_rows - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) unsigned int in_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) unsigned int out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) find_best_seam(ctx, row,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) in_bottom, out_bottom,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) in_top_align, out_top_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) 1, allow_overshoot ? 1 : out_height_align,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) &in_top, &out_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) flipped_out_top = resized_height - out_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) flipped_out_top = out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) out, flipped_out_top, out_bottom - out_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) in_top, in_bottom - in_top,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) flipped_out_top, out_bottom - out_top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) in_bottom = in_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) out_bottom = out_top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) flipped_out_top = resized_height - out_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) flipped_out_top = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) fill_tile_row(ctx, 0, in, 0, in_bottom,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) out, flipped_out_top, out_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) in_bottom, flipped_out_top, out_bottom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) struct ipu_image_convert_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) unsigned int max_width = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) unsigned int max_height = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (image->type == IMAGE_CONVERT_IN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /* Up to 4096x4096 input tile size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) max_width <<= ctx->downsize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) max_height <<= ctx->downsize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) for (i = 0; i < ctx->num_tiles; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) struct ipu_image_tile *tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) const unsigned int row = i / image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) const unsigned int col = i % image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) if (image->type == IMAGE_CONVERT_OUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) tile = &image->tile[ctx->out_tile_map[i]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) tile = &image->tile[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) tile->size = ((tile->height * image->fmt->bpp) >> 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) tile->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (image->fmt->planar) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) tile->stride = tile->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) tile->rot_stride = tile->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) tile->stride =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) (image->fmt->bpp * tile->width) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) tile->rot_stride =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) (image->fmt->bpp * tile->height) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) "task %u: ctx %p: %s@[%u,%u]: %ux%u@%u,%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) chan->ic_task, ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) row, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) tile->width, tile->height, tile->left, tile->top);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (!tile->width || tile->width > max_width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) !tile->height || tile->height > max_height) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) image->type == IMAGE_CONVERT_IN ? "input" :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) "output", tile->width, tile->height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * Use the rotation transformation to find the tile coordinates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) * (row, col) of a tile in the destination frame that corresponds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) * to the given tile coordinates of a source frame. The destination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) * coordinate is then converted to a tile index.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) int src_row, int src_col)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) struct ipu_image_convert_image *s_image = &ctx->in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) struct ipu_image_convert_image *d_image = &ctx->out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) int dst_row, dst_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) /* with no rotation it's a 1:1 mapping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) if (ctx->rot_mode == IPU_ROTATE_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return src_row * s_image->num_cols + src_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) * before doing the transform, first we have to translate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) * source row,col for an origin in the center of s_image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) src_row = src_row * 2 - (s_image->num_rows - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) src_col = src_col * 2 - (s_image->num_cols - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) /* do the rotation transform */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) if (ctx->rot_mode & IPU_ROT_BIT_90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) dst_col = -src_row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) dst_row = src_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) dst_col = src_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) dst_row = src_row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) /* apply flip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) dst_col = -dst_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) dst_row = -dst_row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * finally translate dest row,col using an origin in upper
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * left of d_image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) dst_row += d_image->num_rows - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) dst_col += d_image->num_cols - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) dst_row /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) dst_col /= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) return dst_row * d_image->num_cols + dst_col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) * Fill the out_tile_map[] with transformed destination tile indeces.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) struct ipu_image_convert_image *s_image = &ctx->in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) unsigned int row, col, tile = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) for (row = 0; row < s_image->num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) for (col = 0; col < s_image->num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) ctx->out_tile_map[tile] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) transform_tile_index(ctx, row, col);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) tile++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) struct ipu_image_convert_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) const struct ipu_image_pixfmt *fmt = image->fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) unsigned int row, col, tile = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) u32 H, top, y_stride, uv_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) u32 uv_row_off, uv_col_off, uv_off, u_off, v_off, tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) u32 y_row_off, y_col_off, y_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) u32 y_size, uv_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) /* setup some convenience vars */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) H = image->base.pix.height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) y_stride = image->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) uv_stride = y_stride / fmt->uv_width_dec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (fmt->uv_packed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) uv_stride *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) y_size = H * y_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) for (row = 0; row < image->num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) top = image->tile[tile].top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) y_row_off = top * y_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) for (col = 0; col < image->num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) y_col_off = image->tile[tile].left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) uv_col_off = y_col_off / fmt->uv_width_dec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (fmt->uv_packed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) uv_col_off *= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) y_off = y_row_off + y_col_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) uv_off = uv_row_off + uv_col_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) u_off = y_size - y_off + uv_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (fmt->uv_swapped) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) tmp = u_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) u_off = v_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) v_off = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) image->tile[tile].offset = y_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) image->tile[tile].u_off = u_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) image->tile[tile++].v_off = v_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) if ((y_off & 0x7) || (u_off & 0x7) || (v_off & 0x7)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) dev_err(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) "task %u: ctx %p: %s@[%d,%d]: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) "y_off %08x, u_off %08x, v_off %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) chan->ic_task, ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) image->type == IMAGE_CONVERT_IN ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) "Input" : "Output", row, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) y_off, u_off, v_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) struct ipu_image_convert_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) const struct ipu_image_pixfmt *fmt = image->fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) unsigned int row, col, tile = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) u32 bpp, stride, offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) u32 row_off, col_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) /* setup some convenience vars */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) stride = image->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) bpp = fmt->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) for (row = 0; row < image->num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) row_off = image->tile[tile].top * stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) for (col = 0; col < image->num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) col_off = (image->tile[tile].left * bpp) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) offset = row_off + col_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) image->tile[tile].offset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) image->tile[tile].u_off = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) image->tile[tile++].v_off = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (offset & 0x7) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) dev_err(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) "task %u: ctx %p: %s@[%d,%d]: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) "phys %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) chan->ic_task, ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) image->type == IMAGE_CONVERT_IN ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) "Input" : "Output", row, col,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) row_off + col_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) struct ipu_image_convert_image *image)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) if (image->fmt->planar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) return calc_tile_offsets_planar(ctx, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) return calc_tile_offsets_packed(ctx, image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) * Calculate the resizing ratio for the IC main processing section given input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) * size, fixed downsizing coefficient, and output size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * Either round to closest for the next tile's first pixel to minimize seams
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * and distortion (for all but right column / bottom row), or round down to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * avoid sampling beyond the edges of the input image for this tile's last
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) * pixel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) u32 output_size, bool allow_overshoot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) u32 downsized = input_size >> downsize_coeff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) if (allow_overshoot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) return DIV_ROUND_CLOSEST(8192 * downsized, output_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) return 8192 * (downsized - 1) / (output_size - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * Slightly modify resize coefficients per tile to hide the bilinear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) * interpolator reset at tile borders, shifting the right / bottom edge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * by up to a half input pixel. This removes noticeable seams between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * tiles at higher upscaling factors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) struct ipu_image_tile *in_tile, *out_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) unsigned int col, row, tile_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) unsigned int last_output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) for (col = 0; col < ctx->in.num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) bool closest = (col < ctx->in.num_cols - 1) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) u32 resized_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) u32 resize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) u32 in_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) tile_idx = col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) in_tile = &ctx->in.tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) resized_width = out_tile->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) resized_width = out_tile->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) resize_coeff_h = calc_resize_coeff(in_tile->width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) ctx->downsize_coeff_h,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) resized_width, closest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) __func__, col, resize_coeff_h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) * With the horizontal scaling factor known, round up resized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) * width (output width or height) to burst size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) resized_width = round_up(resized_width, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) * Calculate input width from the last accessed input pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) * given resized width and scaling coefficients. Round up to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) * burst size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) last_output = resized_width - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) if (closest && ((last_output * resize_coeff_h) % 8192))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) last_output++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) in_width = round_up(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) (DIV_ROUND_UP(last_output * resize_coeff_h, 8192) + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) << ctx->downsize_coeff_h, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) for (row = 0; row < ctx->in.num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) tile_idx = row * ctx->in.num_cols + col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) in_tile = &ctx->in.tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) out_tile->height = resized_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) out_tile->width = resized_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) in_tile->width = in_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) ctx->resize_coeffs_h[col] = resize_coeff_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) for (row = 0; row < ctx->in.num_rows; row++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) bool closest = (row < ctx->in.num_rows - 1) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) u32 resized_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) u32 resize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) u32 in_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) tile_idx = row * ctx->in.num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) in_tile = &ctx->in.tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) resized_height = out_tile->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) resized_height = out_tile->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) resize_coeff_v = calc_resize_coeff(in_tile->height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) ctx->downsize_coeff_v,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) resized_height, closest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) __func__, row, resize_coeff_v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * With the vertical scaling factor known, round up resized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) * height (output width or height) to IDMAC limitations.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) resized_height = round_up(resized_height, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) * Calculate input width from the last accessed input pixel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) * given resized height and scaling coefficients. Align to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) * IDMAC restrictions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) last_output = resized_height - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) if (closest && ((last_output * resize_coeff_v) % 8192))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) last_output++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) in_height = round_up(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) (DIV_ROUND_UP(last_output * resize_coeff_v, 8192) + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) << ctx->downsize_coeff_v, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) for (col = 0; col < ctx->in.num_cols; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) tile_idx = row * ctx->in.num_cols + col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) in_tile = &ctx->in.tile[tile_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) out_tile->width = resized_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) out_tile->height = resized_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) in_tile->height = in_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) ctx->resize_coeffs_v[row] = resize_coeff_v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) * return the number of runs in given queue (pending_q or done_q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) * for this context. hold irqlock when calling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) static int get_run_count(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) struct list_head *q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) lockdep_assert_held(&ctx->chan->irqlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) list_for_each_entry(run, q, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) if (run->ctx == ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) static void convert_stop(struct ipu_image_convert_run *run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) struct ipu_image_convert_ctx *ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) __func__, chan->ic_task, ctx, run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) /* disable IC tasks and the channels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) ipu_ic_task_disable(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) ipu_idmac_disable_channel(chan->in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) ipu_idmac_disable_channel(chan->out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) ipu_idmac_disable_channel(chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) ipu_idmac_disable_channel(chan->rotation_out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) ipu_ic_disable(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) struct ipuv3_channel *channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) struct ipu_image_convert_image *image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) enum ipu_rotate_mode rot_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) bool rot_swap_width_height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) unsigned int tile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) unsigned int burst_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) u32 width, height, stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) dma_addr_t addr0, addr1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) struct ipu_image tile_image;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) unsigned int tile_idx[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) if (image->type == IMAGE_CONVERT_OUT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) tile_idx[0] = ctx->out_tile_map[tile];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) tile_idx[1] = ctx->out_tile_map[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) tile_idx[0] = tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) tile_idx[1] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) if (rot_swap_width_height) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) width = image->tile[tile_idx[0]].height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) height = image->tile[tile_idx[0]].width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) stride = image->tile[tile_idx[0]].rot_stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) addr0 = ctx->rot_intermediate[0].phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) if (ctx->double_buffering)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) addr1 = ctx->rot_intermediate[1].phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) width = image->tile[tile_idx[0]].width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) height = image->tile[tile_idx[0]].height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) stride = image->stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) addr0 = image->base.phys0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) image->tile[tile_idx[0]].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) if (ctx->double_buffering)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) addr1 = image->base.phys0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) image->tile[tile_idx[1]].offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) ipu_cpmem_zero(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) memset(&tile_image, 0, sizeof(tile_image));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) tile_image.pix.width = tile_image.rect.width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) tile_image.pix.height = tile_image.rect.height = height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) tile_image.pix.bytesperline = stride;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) tile_image.pix.pixelformat = image->fmt->fourcc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) tile_image.phys0 = addr0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) tile_image.phys1 = addr1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) if (image->fmt->planar && !rot_swap_width_height) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) tile_image.u_offset = image->tile[tile_idx[0]].u_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) tile_image.v_offset = image->tile[tile_idx[0]].v_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) ipu_cpmem_set_image(channel, &tile_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) if (rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) ipu_cpmem_set_rotation(channel, rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) * Skip writing U and V components to odd rows in the output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) * channels for planar 4:2:0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) if ((channel == chan->out_chan ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) channel == chan->rotation_out_chan) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) image->fmt->planar && image->fmt->uv_height_dec == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) ipu_cpmem_skip_odd_chroma_rows(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) if (channel == chan->rotation_in_chan ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) channel == chan->rotation_out_chan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) burst_size = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) ipu_cpmem_set_block_mode(channel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) burst_size = (width % 16) ? 8 : 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) ipu_cpmem_set_burstsize(channel, burst_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) ipu_ic_task_idma_init(chan->ic, channel, width, height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) burst_size, rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) * only do this when there is no PRG present.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) if (!channel->ipu->prg_priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) ipu_cpmem_set_axi_id(channel, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) struct ipu_image_convert_ctx *ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) struct ipu_image_convert_image *s_image = &ctx->in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) struct ipu_image_convert_image *d_image = &ctx->out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) unsigned int dst_tile = ctx->out_tile_map[tile];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) unsigned int dest_width, dest_height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) unsigned int col, row;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) u32 rsc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) __func__, chan->ic_task, ctx, run, tile, dst_tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) /* clear EOF irq mask */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) ctx->eof_mask = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) /* swap width/height for resizer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) dest_width = d_image->tile[dst_tile].height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) dest_height = d_image->tile[dst_tile].width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) dest_width = d_image->tile[dst_tile].width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) dest_height = d_image->tile[dst_tile].height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) row = tile / s_image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) col = tile % s_image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) rsc = (ctx->downsize_coeff_v << 30) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) (ctx->resize_coeffs_v[row] << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) (ctx->downsize_coeff_h << 14) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) (ctx->resize_coeffs_h[col]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) __func__, s_image->tile[tile].width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) s_image->tile[tile].height, dest_width, dest_height, rsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) /* setup the IC resizer and CSC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) s_image->tile[tile].width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) s_image->tile[tile].height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) dest_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) dest_height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) rsc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) /* init the source MEM-->IC PP IDMAC channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) init_idmac_channel(ctx, chan->in_chan, s_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) IPU_ROTATE_NONE, false, tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) /* init the IC PP-->MEM IDMAC channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) init_idmac_channel(ctx, chan->out_chan, d_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) IPU_ROTATE_NONE, true, tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) /* init the MEM-->IC PP ROT IDMAC channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) ctx->rot_mode, true, tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) /* init the destination IC PP ROT-->MEM IDMAC channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) IPU_ROTATE_NONE, false, tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) /* now link IC PP-->MEM to MEM-->IC PP ROT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) /* init the destination IC PP-->MEM IDMAC channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) init_idmac_channel(ctx, chan->out_chan, d_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) ctx->rot_mode, false, tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) /* enable the IC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) ipu_ic_enable(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) /* set buffers ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) ipu_idmac_select_buffer(chan->in_chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) ipu_idmac_select_buffer(chan->out_chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) if (ctx->double_buffering) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) ipu_idmac_select_buffer(chan->in_chan, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) ipu_idmac_select_buffer(chan->out_chan, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) /* enable the channels! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) ipu_idmac_enable_channel(chan->in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) ipu_idmac_enable_channel(chan->out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) ipu_idmac_enable_channel(chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) ipu_idmac_enable_channel(chan->rotation_out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) ipu_ic_task_enable(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) ipu_cpmem_dump(chan->in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) ipu_cpmem_dump(chan->out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) ipu_cpmem_dump(chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) ipu_cpmem_dump(chan->rotation_out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) ipu_dump(priv->ipu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) /* hold irqlock when calling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) static int do_run(struct ipu_image_convert_run *run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) struct ipu_image_convert_ctx *ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) lockdep_assert_held(&chan->irqlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) ctx->in.base.phys0 = run->in_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) ctx->out.base.phys0 = run->out_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) ctx->cur_buf_num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) ctx->next_tile = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) /* remove run from pending_q and set as current */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) list_del(&run->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) chan->current_run = run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) return convert_start(run, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) /* hold irqlock when calling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) static void run_next(struct ipu_image_convert_chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) struct ipu_image_convert_run *run, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) lockdep_assert_held(&chan->irqlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) /* skip contexts that are aborting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) if (run->ctx->aborting) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) "%s: task %u: skipping aborting ctx %p run %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) __func__, chan->ic_task, run->ctx, run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) ret = do_run(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) * something went wrong with start, add the run
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) * to done q and continue to the next run in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) * pending q.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) run->status = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) list_add_tail(&run->list, &chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) chan->current_run = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) static void empty_done_q(struct ipu_image_convert_chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) while (!list_empty(&chan->done_q)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) run = list_entry(chan->done_q.next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) struct ipu_image_convert_run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) list_del(&run->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) "%s: task %u: completing ctx %p run %p with %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) __func__, chan->ic_task, run->ctx, run, run->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) /* call the completion callback and free the run */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) run->ctx->complete(run, run->ctx->complete_context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) * the bottom half thread clears out the done_q, calling the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) * completion handler for each.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) static irqreturn_t do_bh(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) struct ipu_image_convert_chan *chan = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) struct ipu_image_convert_ctx *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) chan->ic_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) empty_done_q(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) * the done_q is cleared out, signal any contexts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) * that are aborting that abort can complete.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) list_for_each_entry(ctx, &chan->ctx_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) if (ctx->aborting) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) "%s: task %u: signaling abort for ctx %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) __func__, chan->ic_task, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) complete_all(&ctx->aborted);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) chan->ic_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) unsigned int cur_tile = ctx->next_tile - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) unsigned int next_tile = ctx->next_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) /* hold irqlock when calling */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) struct ipu_image_convert_ctx *ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) struct ipu_image_tile *src_tile, *dst_tile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) struct ipu_image_convert_image *s_image = &ctx->in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) struct ipu_image_convert_image *d_image = &ctx->out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) struct ipuv3_channel *outch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) unsigned int dst_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) lockdep_assert_held(&chan->irqlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) chan->rotation_out_chan : chan->out_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) * It is difficult to stop the channel DMA before the channels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) * enter the paused state. Without double-buffering the channels
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) * are always in a paused state when the EOF irq occurs, so it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) * is safe to stop the channels now. For double-buffering we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) * just ignore the abort until the operation completes, when it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) * is safe to shut down.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) if (ctx->aborting && !ctx->double_buffering) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) convert_stop(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) run->status = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) if (ctx->next_tile == ctx->num_tiles) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) * the conversion is complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) convert_stop(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) run->status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) * not done, place the next tile buffers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) if (!ctx->double_buffering) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) if (ic_settings_changed(ctx)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) convert_stop(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) convert_start(run, ctx->next_tile);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) src_tile = &s_image->tile[ctx->next_tile];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) dst_idx = ctx->out_tile_map[ctx->next_tile];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) dst_tile = &d_image->tile[dst_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) ipu_cpmem_set_buffer(chan->in_chan, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) s_image->base.phys0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) src_tile->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) ipu_cpmem_set_buffer(outch, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) d_image->base.phys0 +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) dst_tile->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) if (s_image->fmt->planar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) ipu_cpmem_set_uv_offset(chan->in_chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) src_tile->u_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) src_tile->v_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) if (d_image->fmt->planar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) ipu_cpmem_set_uv_offset(outch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) dst_tile->u_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) dst_tile->v_off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) ipu_idmac_select_buffer(chan->in_chan, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) ipu_idmac_select_buffer(outch, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) } else if (ctx->next_tile < ctx->num_tiles - 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) src_tile = &s_image->tile[ctx->next_tile + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) dst_tile = &d_image->tile[dst_idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) s_image->base.phys0 + src_tile->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) d_image->base.phys0 + dst_tile->offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) ctx->cur_buf_num ^= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) ctx->next_tile++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) list_add_tail(&run->list, &chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) chan->current_run = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) run_next(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) return IRQ_WAKE_THREAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) static irqreturn_t eof_irq(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) struct ipu_image_convert_chan *chan = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) struct ipu_image_convert_ctx *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) irqreturn_t ret = IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) bool tile_complete = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) /* get current run and its context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) run = chan->current_run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) if (!run) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) ret = IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) if (irq == chan->in_eof_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) ctx->eof_mask |= EOF_IRQ_IN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) } else if (irq == chan->out_eof_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) ctx->eof_mask |= EOF_IRQ_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) } else if (irq == chan->rot_in_eof_irq ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) irq == chan->rot_out_eof_irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) /* this was NOT a rotation op, shouldn't happen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) dev_err(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) "Unexpected rotation interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) EOF_IRQ_ROT_IN : EOF_IRQ_ROT_OUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) ret = IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) if (ipu_rot_mode_is_irt(ctx->rot_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) if (tile_complete)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) ret = do_tile_complete(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) * try to force the completion of runs for this ctx. Called when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) * abort wait times out in ipu_image_convert_abort().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) static void force_abort(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) run = chan->current_run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) if (run && run->ctx == ctx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) convert_stop(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) run->status = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) list_add_tail(&run->list, &chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) chan->current_run = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) run_next(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) empty_done_q(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) static void release_ipu_resources(struct ipu_image_convert_chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) if (chan->in_eof_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) free_irq(chan->in_eof_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) if (chan->rot_in_eof_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) free_irq(chan->rot_in_eof_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) if (chan->out_eof_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) free_irq(chan->out_eof_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) if (chan->rot_out_eof_irq >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) free_irq(chan->rot_out_eof_irq, chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) if (!IS_ERR_OR_NULL(chan->in_chan))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) ipu_idmac_put(chan->in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) if (!IS_ERR_OR_NULL(chan->out_chan))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) ipu_idmac_put(chan->out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) ipu_idmac_put(chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) ipu_idmac_put(chan->rotation_out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) if (!IS_ERR_OR_NULL(chan->ic))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) ipu_ic_put(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) chan->in_chan = chan->out_chan = chan->rotation_in_chan =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) chan->rotation_out_chan = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) chan->in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) chan->rot_in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) chan->out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) chan->rot_out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) static int get_eof_irq(struct ipu_image_convert_chan *chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) struct ipuv3_channel *channel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) int ret, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) static int get_ipu_resources(struct ipu_image_convert_chan *chan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) /* get IC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) if (IS_ERR(chan->ic)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) dev_err(priv->ipu->dev, "could not acquire IC\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) ret = PTR_ERR(chan->ic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) /* get IDMAC channels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) dev_err(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) "could not acquire idmac rotation channels\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) /* acquire the EOF interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) ret = get_eof_irq(chan, chan->in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) chan->in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) chan->in_eof_irq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) ret = get_eof_irq(chan, chan->rotation_in_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) chan->rot_in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) chan->rot_in_eof_irq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) ret = get_eof_irq(chan, chan->out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) chan->out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) chan->out_eof_irq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) ret = get_eof_irq(chan, chan->rotation_out_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) chan->rot_out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) goto err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) chan->rot_out_eof_irq = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) release_ipu_resources(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) static int fill_image(struct ipu_image_convert_ctx *ctx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) struct ipu_image_convert_image *ic_image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) struct ipu_image *image,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) enum ipu_image_convert_type type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) struct ipu_image_convert_priv *priv = ctx->chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) ic_image->base = *image;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) ic_image->type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) ic_image->fmt = get_format(image->pix.pixelformat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) if (!ic_image->fmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) type == IMAGE_CONVERT_OUT ? "Output" : "Input");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) if (ic_image->fmt->planar)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) ic_image->stride = ic_image->base.pix.width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) ic_image->stride = ic_image->base.pix.bytesperline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) /* borrowed from drivers/media/v4l2-core/v4l2-common.c */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) static unsigned int clamp_align(unsigned int x, unsigned int min,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) unsigned int max, unsigned int align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) /* Bits that must be zero to be aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) unsigned int mask = ~((1 << align) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) /* Clamp to aligned min and max */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) x = clamp(x, (min + ~mask) & mask, max & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) /* Round to nearest aligned value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) if (align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) x = (x + (1 << (align - 1))) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) return x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) /* Adjusts input/output images to IPU restrictions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) enum ipu_rotate_mode rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) const struct ipu_image_pixfmt *infmt, *outfmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) u32 w_align_out, h_align_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973) u32 w_align_in, h_align_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) infmt = get_format(in->pix.pixelformat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976) outfmt = get_format(out->pix.pixelformat);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) /* set some default pixel formats if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979) if (!infmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) infmt = get_format(V4L2_PIX_FMT_RGB24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) if (!outfmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) outfmt = get_format(V4L2_PIX_FMT_RGB24);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) /* image converter does not handle fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) in->pix.field = out->pix.field = V4L2_FIELD_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) /* resizer cannot downsize more than 4:1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) if (ipu_rot_mode_is_irt(rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) out->pix.height = max_t(__u32, out->pix.height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) in->pix.width / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) out->pix.width = max_t(__u32, out->pix.width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) in->pix.height / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) out->pix.width = max_t(__u32, out->pix.width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) in->pix.width / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000) out->pix.height = max_t(__u32, out->pix.height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) in->pix.height / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) /* align input width/height */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) w_align_in = ilog2(tile_width_align(IMAGE_CONVERT_IN, infmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006) rot_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) h_align_in = ilog2(tile_height_align(IMAGE_CONVERT_IN, infmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008) rot_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010) w_align_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) h_align_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2014) /* align output width/height */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2015) w_align_out = ilog2(tile_width_align(IMAGE_CONVERT_OUT, outfmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2016) rot_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2017) h_align_out = ilog2(tile_height_align(IMAGE_CONVERT_OUT, outfmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2018) rot_mode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2019) out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2020) w_align_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2021) out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2022) h_align_out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2024) /* set input/output strides and image sizes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2025) in->pix.bytesperline = infmt->planar ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2026) clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2027) w_align_in) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2028) clamp_align((in->pix.width * infmt->bpp) >> 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2029) ((2 << w_align_in) * infmt->bpp) >> 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2030) (MAX_W * infmt->bpp) >> 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2031) w_align_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2032) in->pix.sizeimage = infmt->planar ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2033) (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2034) in->pix.height * in->pix.bytesperline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2035) out->pix.bytesperline = outfmt->planar ? out->pix.width :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2036) (out->pix.width * outfmt->bpp) >> 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2037) out->pix.sizeimage = outfmt->planar ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2038) (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2039) out->pix.height * out->pix.bytesperline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2040) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2041) EXPORT_SYMBOL_GPL(ipu_image_convert_adjust);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2043) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2044) * this is used by ipu_image_convert_prepare() to verify set input and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2045) * output images are valid before starting the conversion. Clients can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2046) * also call it before calling ipu_image_convert_prepare().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2047) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2048) int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2049) enum ipu_rotate_mode rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2050) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2051) struct ipu_image testin, testout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2053) testin = *in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2054) testout = *out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2056) ipu_image_convert_adjust(&testin, &testout, rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2058) if (testin.pix.width != in->pix.width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2059) testin.pix.height != in->pix.height ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2060) testout.pix.width != out->pix.width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2061) testout.pix.height != out->pix.height)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2062) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2064) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2065) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2066) EXPORT_SYMBOL_GPL(ipu_image_convert_verify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2068) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2069) * Call ipu_image_convert_prepare() to prepare for the conversion of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2070) * given images and rotation mode. Returns a new conversion context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2071) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2072) struct ipu_image_convert_ctx *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2073) ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2074) struct ipu_image *in, struct ipu_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2075) enum ipu_rotate_mode rot_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2076) ipu_image_convert_cb_t complete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2077) void *complete_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2078) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2079) struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2080) struct ipu_image_convert_image *s_image, *d_image;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2081) struct ipu_image_convert_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2082) struct ipu_image_convert_ctx *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2083) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2084) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2085) bool get_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2086) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2088) if (!in || !out || !complete ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2089) (ic_task != IC_TASK_VIEWFINDER &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2090) ic_task != IC_TASK_POST_PROCESSOR))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2091) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2093) /* verify the in/out images before continuing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2094) ret = ipu_image_convert_verify(in, out, rot_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2095) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2096) dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2097) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2098) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2101) chan = &priv->chan[ic_task];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2103) ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2104) if (!ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2105) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2107) dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2108) chan->ic_task, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2110) ctx->chan = chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2111) init_completion(&ctx->aborted);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2113) ctx->rot_mode = rot_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2115) /* Sets ctx->in.num_rows/cols as well */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2116) ret = calc_image_resize_coefficients(ctx, in, out);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2117) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2118) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2120) s_image = &ctx->in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2121) d_image = &ctx->out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2123) /* set tiling and rotation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2124) if (ipu_rot_mode_is_irt(rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2125) d_image->num_rows = s_image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2126) d_image->num_cols = s_image->num_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2127) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2128) d_image->num_rows = s_image->num_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2129) d_image->num_cols = s_image->num_cols;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2132) ctx->num_tiles = d_image->num_cols * d_image->num_rows;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2134) ret = fill_image(ctx, s_image, in, IMAGE_CONVERT_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2135) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2136) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2137) ret = fill_image(ctx, d_image, out, IMAGE_CONVERT_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2138) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2139) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2141) calc_out_tile_map(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2143) find_seams(ctx, s_image, d_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2145) ret = calc_tile_dimensions(ctx, s_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2146) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2147) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2149) ret = calc_tile_offsets(ctx, s_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2150) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2151) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2153) calc_tile_dimensions(ctx, d_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2154) ret = calc_tile_offsets(ctx, d_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2155) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2156) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2158) calc_tile_resize_coefficients(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2160) ret = ipu_ic_calc_csc(&ctx->csc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2161) s_image->base.pix.ycbcr_enc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2162) s_image->base.pix.quantization,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2163) ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2164) d_image->base.pix.ycbcr_enc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2165) d_image->base.pix.quantization,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2166) ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2167) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2168) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2170) dump_format(ctx, s_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2171) dump_format(ctx, d_image);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2173) ctx->complete = complete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2174) ctx->complete_context = complete_context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2176) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2177) * Can we use double-buffering for this operation? If there is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2178) * only one tile (the whole image can be converted in a single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2179) * operation) there's no point in using double-buffering. Also,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2180) * the IPU's IDMAC channels allow only a single U and V plane
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2181) * offset shared between both buffers, but these offsets change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2182) * for every tile, and therefore would have to be updated for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2183) * each buffer which is not possible. So double-buffering is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2184) * impossible when either the source or destination images are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2185) * a planar format (YUV420, YUV422P, etc.). Further, differently
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2186) * sized tiles or different resizing coefficients per tile
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2187) * prevent double-buffering as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2189) ctx->double_buffering = (ctx->num_tiles > 1 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2190) !s_image->fmt->planar &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2191) !d_image->fmt->planar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2192) for (i = 1; i < ctx->num_tiles; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2193) if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2194) ctx->in.tile[i].height != ctx->in.tile[0].height ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2195) ctx->out.tile[i].width != ctx->out.tile[0].width ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2196) ctx->out.tile[i].height != ctx->out.tile[0].height) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2197) ctx->double_buffering = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2201) for (i = 1; i < ctx->in.num_cols; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2202) if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2203) ctx->double_buffering = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2207) for (i = 1; i < ctx->in.num_rows; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2208) if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2209) ctx->double_buffering = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2210) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2214) if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2215) unsigned long intermediate_size = d_image->tile[0].size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2217) for (i = 1; i < ctx->num_tiles; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2218) if (d_image->tile[i].size > intermediate_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2219) intermediate_size = d_image->tile[i].size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2222) ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2223) intermediate_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2224) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2225) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2226) if (ctx->double_buffering) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2227) ret = alloc_dma_buf(priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2228) &ctx->rot_intermediate[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2229) intermediate_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2230) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2231) goto out_free_dmabuf0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2235) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2237) get_res = list_empty(&chan->ctx_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2239) list_add_tail(&ctx->list, &chan->ctx_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2241) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2243) if (get_res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2244) ret = get_ipu_resources(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2245) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2246) goto out_free_dmabuf1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2249) return ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2251) out_free_dmabuf1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2252) free_dma_buf(priv, &ctx->rot_intermediate[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2253) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2254) list_del(&ctx->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2255) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2256) out_free_dmabuf0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2257) free_dma_buf(priv, &ctx->rot_intermediate[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2258) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2259) kfree(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2260) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2262) EXPORT_SYMBOL_GPL(ipu_image_convert_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2264) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2265) * Carry out a single image conversion run. Only the physaddr's of the input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2266) * and output image buffers are needed. The conversion context must have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2267) * been created previously with ipu_image_convert_prepare().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2269) int ipu_image_convert_queue(struct ipu_image_convert_run *run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2271) struct ipu_image_convert_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2272) struct ipu_image_convert_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2273) struct ipu_image_convert_ctx *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2274) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2275) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2277) if (!run || !run->ctx || !run->in_phys || !run->out_phys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2278) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2280) ctx = run->ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2281) chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2282) priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2284) dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2285) chan->ic_task, ctx, run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2287) INIT_LIST_HEAD(&run->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2289) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2291) if (ctx->aborting) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2292) ret = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2293) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2296) list_add_tail(&run->list, &chan->pending_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2298) if (!chan->current_run) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2299) ret = do_run(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2300) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2301) chan->current_run = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2303) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2304) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2305) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2307) EXPORT_SYMBOL_GPL(ipu_image_convert_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2309) /* Abort any active or pending conversions for this context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2310) static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2312) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2313) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2314) struct ipu_image_convert_run *run, *active_run, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2315) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2316) int run_count, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2318) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2320) /* move all remaining pending runs in this context to done_q */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2321) list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2322) if (run->ctx != ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2323) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2324) run->status = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2325) list_move_tail(&run->list, &chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2328) run_count = get_run_count(ctx, &chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2329) active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2330) chan->current_run : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2332) if (active_run)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2333) reinit_completion(&ctx->aborted);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2335) ctx->aborting = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2337) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2339) if (!run_count && !active_run) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2340) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2341) "%s: task %u: no abort needed for ctx %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2342) __func__, chan->ic_task, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2343) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2346) if (!active_run) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2347) empty_done_q(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2348) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2351) dev_dbg(priv->ipu->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2352) "%s: task %u: wait for completion: %d runs\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2353) __func__, chan->ic_task, run_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2355) ret = wait_for_completion_timeout(&ctx->aborted,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2356) msecs_to_jiffies(10000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2357) if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2358) dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2359) force_abort(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2363) void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2365) __ipu_image_convert_abort(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2366) ctx->aborting = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2368) EXPORT_SYMBOL_GPL(ipu_image_convert_abort);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2370) /* Unprepare image conversion context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2371) void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2373) struct ipu_image_convert_chan *chan = ctx->chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2374) struct ipu_image_convert_priv *priv = chan->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2375) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2376) bool put_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2378) /* make sure no runs are hanging around */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2379) __ipu_image_convert_abort(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2381) dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2382) chan->ic_task, ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2384) spin_lock_irqsave(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2386) list_del(&ctx->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2388) put_res = list_empty(&chan->ctx_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2390) spin_unlock_irqrestore(&chan->irqlock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2392) if (put_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2393) release_ipu_resources(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2395) free_dma_buf(priv, &ctx->rot_intermediate[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2396) free_dma_buf(priv, &ctx->rot_intermediate[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2398) kfree(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2400) EXPORT_SYMBOL_GPL(ipu_image_convert_unprepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2402) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2403) * "Canned" asynchronous single image conversion. Allocates and returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2404) * a new conversion run. On successful return the caller must free the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2405) * run and call ipu_image_convert_unprepare() after conversion completes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2406) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2407) struct ipu_image_convert_run *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2408) ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2409) struct ipu_image *in, struct ipu_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2410) enum ipu_rotate_mode rot_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2411) ipu_image_convert_cb_t complete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2412) void *complete_context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2413) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2414) struct ipu_image_convert_ctx *ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2415) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2416) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2418) ctx = ipu_image_convert_prepare(ipu, ic_task, in, out, rot_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2419) complete, complete_context);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2420) if (IS_ERR(ctx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2421) return ERR_CAST(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2423) run = kzalloc(sizeof(*run), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2424) if (!run) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2425) ipu_image_convert_unprepare(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2426) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2429) run->ctx = ctx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2430) run->in_phys = in->phys0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2431) run->out_phys = out->phys0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2433) ret = ipu_image_convert_queue(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2434) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2435) ipu_image_convert_unprepare(ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2436) kfree(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2437) return ERR_PTR(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2438) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2440) return run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2442) EXPORT_SYMBOL_GPL(ipu_image_convert);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2444) /* "Canned" synchronous single image conversion */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2445) static void image_convert_sync_complete(struct ipu_image_convert_run *run,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2446) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2448) struct completion *comp = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2450) complete(comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2453) int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2454) struct ipu_image *in, struct ipu_image *out,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2455) enum ipu_rotate_mode rot_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2457) struct ipu_image_convert_run *run;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2458) struct completion comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2459) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2461) init_completion(&comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2463) run = ipu_image_convert(ipu, ic_task, in, out, rot_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2464) image_convert_sync_complete, &comp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2465) if (IS_ERR(run))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2466) return PTR_ERR(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2468) ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(10000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2469) ret = (ret == 0) ? -ETIMEDOUT : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2471) ipu_image_convert_unprepare(run->ctx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2472) kfree(run);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2474) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2475) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2476) EXPORT_SYMBOL_GPL(ipu_image_convert_sync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2478) int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2480) struct ipu_image_convert_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2481) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2483) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2484) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2485) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2487) ipu->image_convert_priv = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2488) priv->ipu = ipu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2490) for (i = 0; i < IC_NUM_TASKS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2491) struct ipu_image_convert_chan *chan = &priv->chan[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2493) chan->ic_task = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2494) chan->priv = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2495) chan->dma_ch = &image_convert_dma_chan[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2496) chan->in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2497) chan->rot_in_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2498) chan->out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2499) chan->rot_out_eof_irq = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2501) spin_lock_init(&chan->irqlock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2502) INIT_LIST_HEAD(&chan->ctx_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2503) INIT_LIST_HEAD(&chan->pending_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2504) INIT_LIST_HEAD(&chan->done_q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2507) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2510) void ipu_image_convert_exit(struct ipu_soc *ipu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2511) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2512) }