linux/drivers/gpu/ipu-v3/ipu-image-convert.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2012-2016 Mentor Graphics Inc.
 *
 * Queued image conversion support, with tiling and rotation.
 */

#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/math.h>

#include <video/imx-ipu-image-convert.h>

#include "ipu-prv.h"

/*
 * The IC Resizer has a restriction that the output frame from the
 * resizer must be 1024 or less in both width (pixels) and height
 * (lines).
 *
 * The image converter attempts to split up a conversion when
 * the desired output (converted) frame resolution exceeds the
 * IC resizer limit of 1024 in either dimension.
 *
 * If either dimension of the output frame exceeds the limit, the
 * dimension is split into 1, 2, or 4 equal stripes, for a maximum
 * of 4*4 or 16 tiles. A conversion is then carried out for each
 * tile (but taking care to pass the full frame stride length to
 * the DMA channel's parameter memory!). IDMA double-buffering is used
 * to convert each tile back-to-back when possible (see note below
 * when double_buffering boolean is set).
 *
 * Note that the input frame must be split up into the same number
 * of tiles as the output frame:
 *
 *                       +---------+-----+
 *   +-----+---+         |  A      | B   |
 *   | A   | B |         |         |     |
 *   +-----+---+   -->   +---------+-----+
 *   | C   | D |         |  C      | D   |
 *   +-----+---+         |         |     |
 *                       +---------+-----+
 *
 * Clockwise 90° rotations are handled by first rescaling into a
 * reusable temporary tile buffer and then rotating with the 8x8
 * block rotator, writing to the correct destination:
 *
 *                                         +-----+-----+
 *                                         |     |     |
 *   +-----+---+         +---------+       | C   | A   |
 *   | A   | B |         | A,B, |  |       |     |     |
 *   +-----+---+   -->   | C,D  |  |  -->  |     |     |
 *   | C   | D |         +---------+       +-----+-----+
 *   +-----+---+                           | D   | B   |
 *                                         |     |     |
 *                                         +-----+-----+
 *
 * If the 8x8 block rotator is used, horizontal or vertical flipping
 * is done during the rotation step, otherwise flipping is done
 * during the scaling step.
 * With rotation or flipping, tile order changes between input and
 * output image. Tiles are numbered row major from top left to bottom
 * right for both input and output image.
 */

#define MAX_STRIPES_W
#define MAX_STRIPES_H
#define MAX_TILES

#define MIN_W
#define MIN_H
#define MAX_W
#define MAX_H

enum ipu_image_convert_type {};

struct ipu_image_convert_dma_buf {};

struct ipu_image_convert_dma_chan {};

/* dimensions of one tile */
struct ipu_image_tile {};

struct ipu_image_convert_image {};

struct ipu_image_pixfmt {};

struct ipu_image_convert_ctx;
struct ipu_image_convert_chan;
struct ipu_image_convert_priv;

enum eof_irq_mask {};

#define EOF_IRQ_COMPLETE
#define EOF_IRQ_ROT_COMPLETE

struct ipu_image_convert_ctx {};

struct ipu_image_convert_chan {};

struct ipu_image_convert_priv {};

static const struct ipu_image_convert_dma_chan
image_convert_dma_chan[IC_NUM_TASKS] =;

static const struct ipu_image_pixfmt image_convert_formats[] =;

static const struct ipu_image_pixfmt *get_format(u32 fourcc)
{}

static void dump_format(struct ipu_image_convert_ctx *ctx,
			struct ipu_image_convert_image *ic_image)
{}

int ipu_image_convert_enum_format(int index, u32 *fourcc)
{}
EXPORT_SYMBOL_GPL();

static void free_dma_buf(struct ipu_image_convert_priv *priv,
			 struct ipu_image_convert_dma_buf *buf)
{}

static int alloc_dma_buf(struct ipu_image_convert_priv *priv,
			 struct ipu_image_convert_dma_buf *buf,
			 int size)
{}

static inline int num_stripes(int dim)
{}

/*
 * Calculate downsizing coefficients, which are the same for all tiles,
 * and initial bilinear resizing coefficients, which are used to find the
 * best seam positions.
 * Also determine the number of tiles necessary to guarantee that no tile
 * is larger than 1024 pixels in either dimension at the output and between
 * IC downsizing and main processing sections.
 */
static int calc_image_resize_coefficients(struct ipu_image_convert_ctx *ctx,
					  struct ipu_image *in,
					  struct ipu_image *out)
{}

#define round_closest(x, y)

/*
 * Find the best aligned seam position for the given column / row index.
 * Rotation and image offsets are out of scope.
 *
 * @index: column / row index, used to calculate valid interval
 * @in_edge: input right / bottom edge
 * @out_edge: output right / bottom edge
 * @in_align: input alignment, either horizontal 8-byte line start address
 *            alignment, or pixel alignment due to image format
 * @out_align: output alignment, either horizontal 8-byte line start address
 *             alignment, or pixel alignment due to image format or rotator
 *             block size
 * @in_burst: horizontal input burst size in case of horizontal flip
 * @out_burst: horizontal output burst size or rotator block size
 * @downsize_coeff: downsizing section coefficient
 * @resize_coeff: main processing section resizing coefficient
 * @_in_seam: aligned input seam position return value
 * @_out_seam: aligned output seam position return value
 */
static void find_best_seam(struct ipu_image_convert_ctx *ctx,
			   unsigned int index,
			   unsigned int in_edge,
			   unsigned int out_edge,
			   unsigned int in_align,
			   unsigned int out_align,
			   unsigned int in_burst,
			   unsigned int out_burst,
			   unsigned int downsize_coeff,
			   unsigned int resize_coeff,
			   u32 *_in_seam,
			   u32 *_out_seam)
{}

/*
 * Tile left edges are required to be aligned to multiples of 8 bytes
 * by the IDMAC.
 */
static inline u32 tile_left_align(const struct ipu_image_pixfmt *fmt)
{}

/*
 * Tile top edge alignment is only limited by chroma subsampling.
 */
static inline u32 tile_top_align(const struct ipu_image_pixfmt *fmt)
{}

static inline u32 tile_width_align(enum ipu_image_convert_type type,
				   const struct ipu_image_pixfmt *fmt,
				   enum ipu_rotate_mode rot_mode)
{}

static inline u32 tile_height_align(enum ipu_image_convert_type type,
				    const struct ipu_image_pixfmt *fmt,
				    enum ipu_rotate_mode rot_mode)
{}

/*
 * Fill in left position and width and for all tiles in an input column, and
 * for all corresponding output tiles. If the 90° rotator is used, the output
 * tiles are in a row, and output tile top position and height are set.
 */
static void fill_tile_column(struct ipu_image_convert_ctx *ctx,
			     unsigned int col,
			     struct ipu_image_convert_image *in,
			     unsigned int in_left, unsigned int in_width,
			     struct ipu_image_convert_image *out,
			     unsigned int out_left, unsigned int out_width)
{}

/*
 * Fill in top position and height and for all tiles in an input row, and
 * for all corresponding output tiles. If the 90° rotator is used, the output
 * tiles are in a column, and output tile left position and width are set.
 */
static void fill_tile_row(struct ipu_image_convert_ctx *ctx, unsigned int row,
			  struct ipu_image_convert_image *in,
			  unsigned int in_top, unsigned int in_height,
			  struct ipu_image_convert_image *out,
			  unsigned int out_top, unsigned int out_height)
{}

/*
 * Find the best horizontal and vertical seam positions to split into tiles.
 * Minimize the fractional part of the input sampling position for the
 * top / left pixels of each tile.
 */
static void find_seams(struct ipu_image_convert_ctx *ctx,
		       struct ipu_image_convert_image *in,
		       struct ipu_image_convert_image *out)
{}

static int calc_tile_dimensions(struct ipu_image_convert_ctx *ctx,
				struct ipu_image_convert_image *image)
{}

/*
 * Use the rotation transformation to find the tile coordinates
 * (row, col) of a tile in the destination frame that corresponds
 * to the given tile coordinates of a source frame. The destination
 * coordinate is then converted to a tile index.
 */
static int transform_tile_index(struct ipu_image_convert_ctx *ctx,
				int src_row, int src_col)
{}

/*
 * Fill the out_tile_map[] with transformed destination tile indeces.
 */
static void calc_out_tile_map(struct ipu_image_convert_ctx *ctx)
{}

static int calc_tile_offsets_planar(struct ipu_image_convert_ctx *ctx,
				    struct ipu_image_convert_image *image)
{}

static int calc_tile_offsets_packed(struct ipu_image_convert_ctx *ctx,
				    struct ipu_image_convert_image *image)
{}

static int calc_tile_offsets(struct ipu_image_convert_ctx *ctx,
			      struct ipu_image_convert_image *image)
{}

/*
 * Calculate the resizing ratio for the IC main processing section given input
 * size, fixed downsizing coefficient, and output size.
 * Either round to closest for the next tile's first pixel to minimize seams
 * and distortion (for all but right column / bottom row), or round down to
 * avoid sampling beyond the edges of the input image for this tile's last
 * pixel.
 * Returns the resizing coefficient, resizing ratio is 8192.0 / resize_coeff.
 */
static u32 calc_resize_coeff(u32 input_size, u32 downsize_coeff,
			     u32 output_size, bool allow_overshoot)
{}

/*
 * Slightly modify resize coefficients per tile to hide the bilinear
 * interpolator reset at tile borders, shifting the right / bottom edge
 * by up to a half input pixel. This removes noticeable seams between
 * tiles at higher upscaling factors.
 */
static void calc_tile_resize_coefficients(struct ipu_image_convert_ctx *ctx)
{}

/*
 * return the number of runs in given queue (pending_q or done_q)
 * for this context. hold irqlock when calling.
 */
static int get_run_count(struct ipu_image_convert_ctx *ctx,
			 struct list_head *q)
{}

static void convert_stop(struct ipu_image_convert_run *run)
{}

static void init_idmac_channel(struct ipu_image_convert_ctx *ctx,
			       struct ipuv3_channel *channel,
			       struct ipu_image_convert_image *image,
			       enum ipu_rotate_mode rot_mode,
			       bool rot_swap_width_height,
			       unsigned int tile)
{}

static int convert_start(struct ipu_image_convert_run *run, unsigned int tile)
{}

/* hold irqlock when calling */
static int do_run(struct ipu_image_convert_run *run)
{}

/* hold irqlock when calling */
static void run_next(struct ipu_image_convert_chan *chan)
{}

static void empty_done_q(struct ipu_image_convert_chan *chan)
{}

/*
 * the bottom half thread clears out the done_q, calling the
 * completion handler for each.
 */
static irqreturn_t do_bh(int irq, void *dev_id)
{}

static bool ic_settings_changed(struct ipu_image_convert_ctx *ctx)
{}

/* hold irqlock when calling */
static irqreturn_t do_tile_complete(struct ipu_image_convert_run *run)
{}

static irqreturn_t eof_irq(int irq, void *data)
{}

/*
 * try to force the completion of runs for this ctx. Called when
 * abort wait times out in ipu_image_convert_abort().
 */
static void force_abort(struct ipu_image_convert_ctx *ctx)
{}

static void release_ipu_resources(struct ipu_image_convert_chan *chan)
{}

static int get_eof_irq(struct ipu_image_convert_chan *chan,
		       struct ipuv3_channel *channel)
{}

static int get_ipu_resources(struct ipu_image_convert_chan *chan)
{}

static int fill_image(struct ipu_image_convert_ctx *ctx,
		      struct ipu_image_convert_image *ic_image,
		      struct ipu_image *image,
		      enum ipu_image_convert_type type)
{}

/* borrowed from drivers/media/v4l2-core/v4l2-common.c */
static unsigned int clamp_align(unsigned int x, unsigned int min,
				unsigned int max, unsigned int align)
{}

/* Adjusts input/output images to IPU restrictions */
void ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
			      enum ipu_rotate_mode rot_mode)
{}
EXPORT_SYMBOL_GPL();

/*
 * this is used by ipu_image_convert_prepare() to verify set input and
 * output images are valid before starting the conversion. Clients can
 * also call it before calling ipu_image_convert_prepare().
 */
int ipu_image_convert_verify(struct ipu_image *in, struct ipu_image *out,
			     enum ipu_rotate_mode rot_mode)
{}
EXPORT_SYMBOL_GPL();

/*
 * Call ipu_image_convert_prepare() to prepare for the conversion of
 * given images and rotation mode. Returns a new conversion context.
 */
struct ipu_image_convert_ctx *
ipu_image_convert_prepare(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
			  struct ipu_image *in, struct ipu_image *out,
			  enum ipu_rotate_mode rot_mode,
			  ipu_image_convert_cb_t complete,
			  void *complete_context)
{}
EXPORT_SYMBOL_GPL();

/*
 * Carry out a single image conversion run. Only the physaddr's of the input
 * and output image buffers are needed. The conversion context must have
 * been created previously with ipu_image_convert_prepare().
 */
int ipu_image_convert_queue(struct ipu_image_convert_run *run)
{}
EXPORT_SYMBOL_GPL();

/* Abort any active or pending conversions for this context */
static void __ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
{}

void ipu_image_convert_abort(struct ipu_image_convert_ctx *ctx)
{}
EXPORT_SYMBOL_GPL();

/* Unprepare image conversion context */
void ipu_image_convert_unprepare(struct ipu_image_convert_ctx *ctx)
{}
EXPORT_SYMBOL_GPL();

/*
 * "Canned" asynchronous single image conversion. Allocates and returns
 * a new conversion run.  On successful return the caller must free the
 * run and call ipu_image_convert_unprepare() after conversion completes.
 */
struct ipu_image_convert_run *
ipu_image_convert(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
		  struct ipu_image *in, struct ipu_image *out,
		  enum ipu_rotate_mode rot_mode,
		  ipu_image_convert_cb_t complete,
		  void *complete_context)
{}
EXPORT_SYMBOL_GPL();

/* "Canned" synchronous single image conversion */
static void image_convert_sync_complete(struct ipu_image_convert_run *run,
					void *data)
{}

int ipu_image_convert_sync(struct ipu_soc *ipu, enum ipu_ic_task ic_task,
			   struct ipu_image *in, struct ipu_image *out,
			   enum ipu_rotate_mode rot_mode)
{}
EXPORT_SYMBOL_GPL();

int ipu_image_convert_init(struct ipu_soc *ipu, struct device *dev)
{}

void ipu_image_convert_exit(struct ipu_soc *ipu)
{}