Hi Steve,
Am Mittwoch, den 17.08.2016, 17:50 -0700 schrieb Steve Longerbeam:
This patch implements complete image conversion support to ipu-ic,... and possibly allocates intermediate buffers for rotation support.
with tiling to support scaling to and from images up to 4096x4096.
Image rotation is also supported.
The internal API is subsystem agnostic (no V4L2 dependency except
for the use of V4L2 fourcc pixel formats).
Callers prepare for image conversion by calling
ipu_image_convert_prepare(), which initializes the parameters of
the conversion.
This should be documented somewhere, with a node that v4l2 users should
be doing this during REQBUFS.
The caller passes in the ipu_ic task to use forAs I commented on the other patch, I think the image_convert functions
the conversion, the input and output image formats, a rotation mode,
and a completion callback and completion context pointer:
struct image_converter_ctx *
ipu_image_convert_prepare(struct ipu_ic *ic,
struct ipu_image *in, struct ipu_image *out,
enum ipu_rotate_mode rot_mode,
image_converter_cb_t complete,
void *complete_context);
should use a separate handle for the image conversion queues that sit on
top of the ipu_ic task handles.
+Where does this minimum come from?
+#define MIN_W 128
+#define MIN_H 128
+struct ic_task_channels {The vdi channels are unused.
+ int in;
+ int out;
+ int rot_in;
+ int rot_out;
+ int vdi_in_p;
+ int vdi_in;
+ int vdi_in_n;
+struct image_converter_ctx {No need to change it now, but I assume these could be per IC task
+ struct image_converter *cvt;
+
+ image_converter_cb_t complete;
+ void *complete_context;
+
+ /* Source/destination image data and rotation mode */
+ struct ipu_ic_image in;
+ struct ipu_ic_image out;
+ enum ipu_rotate_mode rot_mode;
+
+ /* intermediate buffer for rotation */
+ struct ipu_ic_dma_buf rot_intermediate[2];
instead of per context.
+static const struct ipu_ic_pixfmt ipu_ic_formats[] = {Please drop the names, keeping a list of user readable format names is
+ {
+ .name = "RGB565",
the v4l2 core's business, not ours.
+ .fourcc = V4L2_PIX_FMT_RGB565,bpp is only ever used in bytes, not bits (always divided by 8).
+ .bpp = 16,
Why not make this bytes_per_pixel or pixel_stride = 2.
+ }, {y_depth is only ever used in bytes, not bits (always divided by 8).
+ .name = "4:2:0 planar, YUV",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .bpp = 12,
+ .y_depth = 8,
Why not make this bool planar instead.
Is it necessary to support reallocation? This is currently only used by
+static int ipu_ic_alloc_dma_buf(struct ipu_ic_priv *priv,
+ struct ipu_ic_dma_buf *buf,
+ int size)
+{
+ unsigned long newlen = PAGE_ALIGN(size);
+
+ if (buf->virt) {
+ if (buf->len == newlen)
+ return 0;
+ ipu_ic_free_dma_buf(priv, buf);
+ }
the prepare function, which creates a new context.
+static void ipu_ic_calc_tile_dimensions(struct image_converter_ctx *ctx,We already have talked about this, this simplified tiling will cause
+ struct ipu_ic_image *image)
+{
+ int i;
+
+ for (i = 0; i < ctx->num_tiles; i++) {
+ struct ipu_ic_tile *tile = &image->tile[i];
+
+ tile->height = image->base.pix.height / image->num_rows;
+ tile->width = image->base.pix.width / image->num_cols;
image artifacts (horizontal and vertical seams at the tile borders) when
the bilinear upscaler source pixel step is significantly smaller than a
whole pixel.
This can be fixed in the future by using overlapping tiles of different
sizes and possibly by slightly changing the scaling factors of
individual tiles.
This looks nice, but I'd just move the rot_mode conditional below
assignment of src_row/col and do away with the sin/cos temporary
variables:
/*
* before doing the transform, first we have to translate
* source row,col for an origin in the center of s_image
*/
src_row = src_row * 2 - (s_image->num_rows - 1);
src_col = src_col * 2 - (s_image->num_cols - 1);
/* do the rotation transform */
if (ctx->rot_mode & IPU_ROT_BIT_90) {
dst_col = -src_row;
dst_row = src_col;
} else {
dst_col = src_col;
dst_row = src_row;
}
+ for (col = 0; col < image->num_cols; col++) {We know that for planar formats, y_depth can only ever be 8. No need to
+ y_col_off = (col * w * y_depth) >> 3;
calculate this here.
Most of the following code seems to be running under one big spinlock.
Is this really necessary?
+static int ipu_ic_get_run_count(struct image_converter_ctx *ctx,Add
+ struct list_head *q)
+{
+ struct image_converter_run *run;
+ int count = 0;
lockdep_assert_held(&ctx->irqlock);
for the functions that expect their caller to be holding the lock.
+ list_for_each_entry(run, q, list) {Maybe add some indication which IC task this context belongs to?
+ if (run->ctx == ctx)
+ count++;
+ }
+
+ return count;
+}
+
+/* hold irqlock when calling */
+static void ipu_ic_convert_stop(struct image_converter_run *run)
+{
+ struct image_converter_ctx *ctx = run->ctx;
+ struct image_converter *cvt = ctx->cvt;
+ struct ipu_ic_priv *priv = cvt->ic->priv;
+
+ dev_dbg(priv->ipu->dev, "%s: stopping ctx %p run %p\n",
+ __func__, ctx, run);
+This is for later, but it might turn out to be better to accept a little
+ if (channel == cvt->rotation_in_chan ||
+ channel == cvt->rotation_out_chan) {
+ burst_size = 8;
+ ipu_cpmem_set_block_mode(channel);
+ } else
+ burst_size = (width % 16) ? 8 : 16;
overdraw if stride allows for it and use the larger burst size,
especially for wide images.
Why enable the out_chan EOF irq at all when using the IRT mode?
+
+static irqreturn_t ipu_ic_norotate_irq(int irq, void *data)
+{
+ struct image_converter *cvt = data;
+ struct image_converter_ctx *ctx;
+ struct image_converter_run *run;
+ unsigned long flags;
+ irqreturn_t ret;
+
+ spin_lock_irqsave(&cvt->irqlock, flags);
+
+ /* get current run and its context */
+ run = cvt->current_run;
+ if (!run) {
+ ret = IRQ_NONE;
+ goto out;
+ }
+
+ ctx = run->ctx;
+
+ if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
+ /* this is a rotation operation, just ignore */
+ spin_unlock_irqrestore(&cvt->irqlock, flags);
+ return IRQ_HANDLED;
+ }
Is this our task at all?
+/* Adjusts input/output images to IPU restrictions */
+int ipu_image_convert_adjust(struct ipu_image *in, struct ipu_image *out,
+ enum ipu_rotate_mode rot_mode)
+{
+ const struct ipu_ic_pixfmt *infmt, *outfmt;
+ unsigned int num_in_rows, num_in_cols;
+ unsigned int num_out_rows, num_out_cols;
+ u32 w_align, h_align;
+
+ infmt = ipu_ic_get_format(in->pix.pixelformat);
+ outfmt = ipu_ic_get_format(out->pix.pixelformat);
+
+ /* set some defaults if needed */
+ if (!infmt) {Why not? The scaler can scale alternate top/bottom fields no problem.
+ in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ infmt = ipu_ic_get_format(V4L2_PIX_FMT_RGB24);
+ }
+ if (!outfmt) {
+ out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ outfmt = ipu_ic_get_format(V4L2_PIX_FMT_RGB24);
+ }
+
+ if (!in->pix.width || !in->pix.height) {
+ in->pix.width = 640;
+ in->pix.height = 480;
+ }
+ if (!out->pix.width || !out->pix.height) {
+ out->pix.width = 640;
+ out->pix.height = 480;
+ }
+
+ /* image converter does not handle fields */
+ in->pix.field = out->pix.field = V4L2_FIELD_NONE;
For SEQ_TB/BT and the interleaved interlacing we'd have to adjust
scaling factors per field and use two vertical tiles for the fields
before this can be supported.
+/*What is the reasoning behind making the image_converter_run opaque to
+ * Carry out a single image conversion. 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(). Returns the
+ * new run object.
+ */
+struct image_converter_run *
+ipu_image_convert_run(struct image_converter_ctx *ctx,
+ dma_addr_t in_phys, dma_addr_t out_phys)
+{
+ struct image_converter *cvt = ctx->cvt;
+ struct ipu_ic_priv *priv = cvt->ic->priv;
+ struct image_converter_run *run;
+ unsigned long flags;
+ int ret = 0;
+
+ run = kzalloc(sizeof(*run), GFP_KERNEL);
+ if (!run)
+ return ERR_PTR(-ENOMEM);
the user? If you let the user provide it to ipu_image_convert_run, it
wouldn't have to be allocated/freed with each frame.
Most of this calculation of tile geometry and conversion queue handling
code is not really low level IC hardware access. I'd like the code that
doesn't have to access ipu_ic internals directly to be moved into a
separate source file. I'd suggest ipu-ic-queue.c, or
ipu-image-convert.c.
+Add an ipu_ prefix to those.
+struct image_converter_ctx;
+struct image_converter_run;
+