Lines Matching +full:min +full:- +full:pix +full:- +full:sizes
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2012-2016 Mentor Graphics Inc.
9 #include <linux/dma-mapping.h>
12 #include <video/imx-ipu-image-convert.h>
14 #include "ipu-prv.h"
29 * the DMA channel's parameter memory!). IDMA double-buffering is used
30 * to convert each tile back-to-back when possible (see note below
36 * +---------+-----+
37 * +-----+---+ | A | B |
39 * +-----+---+ --> +---------+-----+
41 * +-----+---+ | | |
42 * +---------+-----+
48 * +-----+-----+
50 * +-----+---+ +---------+ | C | A |
52 * +-----+---+ --> | C,D | | --> | | |
53 * | C | D | +---------+ +-----+-----+
54 * +-----+---+ | D | B |
56 * +-----+-----+
181 /* can we use double-buffering for this conversion operation? */
208 /* the IPU end-of-frame irqs */
343 struct ipu_image_convert_chan *chan = ctx->chan;
344 struct ipu_image_convert_priv *priv = chan->priv;
346 dev_dbg(priv->ipu->dev,
348 chan->ic_task, ctx,
349 ic_image->type == IMAGE_CONVERT_OUT ? "Output" : "Input",
350 ic_image->base.pix.width, ic_image->base.pix.height,
351 ic_image->num_cols, ic_image->num_rows,
352 ic_image->fmt->fourcc & 0xff,
353 (ic_image->fmt->fourcc >> 8) & 0xff,
354 (ic_image->fmt->fourcc >> 16) & 0xff,
355 (ic_image->fmt->fourcc >> 24) & 0xff);
361 if (buf->virt)
362 dma_free_coherent(priv->ipu->dev,
363 buf->len, buf->virt, buf->phys);
364 buf->virt = NULL;
365 buf->phys = 0;
372 buf->len = PAGE_ALIGN(size);
373 buf->virt = dma_alloc_coherent(priv->ipu->dev, buf->len, &buf->phys,
375 if (!buf->virt) {
376 dev_err(priv->ipu->dev, "failed to alloc dma buffer\n");
377 return -ENOMEM;
385 return (dim - 1) / 1024 + 1;
400 u32 downsized_width = in->rect.width;
401 u32 downsized_height = in->rect.height;
404 u32 resized_width = out->rect.width;
405 u32 resized_height = out->rect.height;
411 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
412 resized_width = out->rect.height;
413 resized_height = out->rect.width;
418 return -EINVAL;
436 resize_coeff_h = 8192 * (downsized_width - 1) / (resized_width - 1);
437 resize_coeff_v = 8192 * (downsized_height - 1) / (resized_height - 1);
447 dev_dbg(ctx->chan->priv->ipu->dev,
454 return -EINVAL;
456 ctx->downsize_coeff_h = downsize_coeff_h;
457 ctx->downsize_coeff_v = downsize_coeff_v;
458 ctx->image_resize_coeff_h = resize_coeff_h;
459 ctx->image_resize_coeff_v = resize_coeff_v;
460 ctx->in.num_cols = cols;
461 ctx->in.num_rows = rows;
475 * @in_align: input alignment, either horizontal 8-byte line start address
477 * @out_align: output alignment, either horizontal 8-byte line start address
500 struct device *dev = ctx->chan->priv->ipu->dev;
512 out_start = max_t(int, index * out_align, out_edge - 1024);
521 in_edge - (1024 << downsize_coeff));
542 if ((out_burst > 1) && (out_edge - out_pos) % out_burst)
564 (in_edge - in_pos_rounded) % in_burst)
590 if (fmt->planar)
591 return fmt->uv_packed ? 8 : 8 * fmt->uv_width_dec;
593 return fmt->bpp == 32 ? 2 : fmt->bpp == 16 ? 4 : 8;
601 return fmt->uv_height_dec > 1 ? 2 : 1;
621 * formats to guarantee 8-byte aligned line start addresses in the
626 fmt->planar && !fmt->uv_packed) ?
627 8 * fmt->uv_width_dec : 8;
639 * formats to guarantee 8-byte aligned line start addresses in the
643 return (fmt->planar && !fmt->uv_packed) ? 8 * fmt->uv_width_dec : 8;
661 for (row = 0; row < in->num_rows; row++) {
662 tile_idx = in->num_cols * row + col;
663 in_tile = &in->tile[tile_idx];
664 out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
666 in_tile->left = in_left;
667 in_tile->width = in_width;
669 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
670 out_tile->top = out_left;
671 out_tile->height = out_width;
673 out_tile->left = out_left;
674 out_tile->width = out_width;
693 for (col = 0; col < in->num_cols; col++) {
694 tile_idx = in->num_cols * row + col;
695 in_tile = &in->tile[tile_idx];
696 out_tile = &out->tile[ctx->out_tile_map[tile_idx]];
698 in_tile->top = in_top;
699 in_tile->height = in_height;
701 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
702 out_tile->left = out_top;
703 out_tile->width = out_height;
705 out_tile->top = out_top;
706 out_tile->height = out_height;
720 struct device *dev = ctx->chan->priv->ipu->dev;
721 unsigned int resized_width = out->base.rect.width;
722 unsigned int resized_height = out->base.rect.height;
725 unsigned int in_left_align = tile_left_align(in->fmt);
726 unsigned int in_top_align = tile_top_align(in->fmt);
727 unsigned int out_left_align = tile_left_align(out->fmt);
728 unsigned int out_top_align = tile_top_align(out->fmt);
729 unsigned int out_width_align = tile_width_align(out->type, out->fmt,
730 ctx->rot_mode);
731 unsigned int out_height_align = tile_height_align(out->type, out->fmt,
732 ctx->rot_mode);
733 unsigned int in_right = in->base.rect.width;
734 unsigned int in_bottom = in->base.rect.height;
735 unsigned int out_right = out->base.rect.width;
736 unsigned int out_bottom = out->base.rect.height;
740 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
742 resized_width = out->base.rect.height;
743 resized_height = out->base.rect.width;
748 out_right = out->base.rect.height;
749 out_bottom = out->base.rect.width;
752 for (col = in->num_cols - 1; col > 0; col--) {
753 bool allow_in_overshoot = ipu_rot_mode_is_irt(ctx->rot_mode) ||
754 !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
755 bool allow_out_overshoot = (col < in->num_cols - 1) &&
756 !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
770 ctx->downsize_coeff_h, ctx->image_resize_coeff_h,
773 if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
774 flipped_out_left = resized_width - out_right;
778 fill_tile_column(ctx, col, in, in_left, in_right - in_left,
779 out, flipped_out_left, out_right - out_left);
781 dev_dbg(dev, "%s: col %u: %u, %u -> %u, %u\n", __func__, col,
782 in_left, in_right - in_left,
783 flipped_out_left, out_right - out_left);
789 flipped_out_left = (ctx->rot_mode & IPU_ROT_BIT_HFLIP) ?
790 resized_width - out_right : 0;
795 dev_dbg(dev, "%s: col 0: 0, %u -> %u, %u\n", __func__,
798 for (row = in->num_rows - 1; row > 0; row--) {
799 bool allow_overshoot = row < in->num_rows - 1;
807 ctx->downsize_coeff_v, ctx->image_resize_coeff_v,
810 if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
811 ipu_rot_mode_is_irt(ctx->rot_mode))
812 flipped_out_top = resized_height - out_bottom;
816 fill_tile_row(ctx, row, in, in_top, in_bottom - in_top,
817 out, flipped_out_top, out_bottom - out_top);
819 dev_dbg(dev, "%s: row %u: %u, %u -> %u, %u\n", __func__, row,
820 in_top, in_bottom - in_top,
821 flipped_out_top, out_bottom - out_top);
827 if ((ctx->rot_mode & IPU_ROT_BIT_VFLIP) ^
828 ipu_rot_mode_is_irt(ctx->rot_mode))
829 flipped_out_top = resized_height - out_bottom;
836 dev_dbg(dev, "%s: row 0: 0, %u -> %u, %u\n", __func__,
843 struct ipu_image_convert_chan *chan = ctx->chan;
844 struct ipu_image_convert_priv *priv = chan->priv;
849 if (image->type == IMAGE_CONVERT_IN) {
851 max_width <<= ctx->downsize_coeff_h;
852 max_height <<= ctx->downsize_coeff_v;
855 for (i = 0; i < ctx->num_tiles; i++) {
857 const unsigned int row = i / image->num_cols;
858 const unsigned int col = i % image->num_cols;
860 if (image->type == IMAGE_CONVERT_OUT)
861 tile = &image->tile[ctx->out_tile_map[i]];
863 tile = &image->tile[i];
865 tile->size = ((tile->height * image->fmt->bpp) >> 3) *
866 tile->width;
868 if (image->fmt->planar) {
869 tile->stride = tile->width;
870 tile->rot_stride = tile->height;
872 tile->stride =
873 (image->fmt->bpp * tile->width) >> 3;
874 tile->rot_stride =
875 (image->fmt->bpp * tile->height) >> 3;
878 dev_dbg(priv->ipu->dev,
880 chan->ic_task, ctx,
881 image->type == IMAGE_CONVERT_IN ? "Input" : "Output",
883 tile->width, tile->height, tile->left, tile->top);
885 if (!tile->width || tile->width > max_width ||
886 !tile->height || tile->height > max_height) {
887 dev_err(priv->ipu->dev, "invalid %s tile size: %ux%u\n",
888 image->type == IMAGE_CONVERT_IN ? "input" :
889 "output", tile->width, tile->height);
890 return -EINVAL;
906 struct ipu_image_convert_chan *chan = ctx->chan;
907 struct ipu_image_convert_priv *priv = chan->priv;
908 struct ipu_image_convert_image *s_image = &ctx->in;
909 struct ipu_image_convert_image *d_image = &ctx->out;
913 if (ctx->rot_mode == IPU_ROTATE_NONE)
914 return src_row * s_image->num_cols + src_col;
920 src_row = src_row * 2 - (s_image->num_rows - 1);
921 src_col = src_col * 2 - (s_image->num_cols - 1);
924 if (ctx->rot_mode & IPU_ROT_BIT_90) {
925 dst_col = -src_row;
933 if (ctx->rot_mode & IPU_ROT_BIT_HFLIP)
934 dst_col = -dst_col;
935 if (ctx->rot_mode & IPU_ROT_BIT_VFLIP)
936 dst_row = -dst_row;
938 dev_dbg(priv->ipu->dev, "task %u: ctx %p: [%d,%d] --> [%d,%d]\n",
939 chan->ic_task, ctx, src_col, src_row, dst_col, dst_row);
945 dst_row += d_image->num_rows - 1;
946 dst_col += d_image->num_cols - 1;
950 return dst_row * d_image->num_cols + dst_col;
958 struct ipu_image_convert_image *s_image = &ctx->in;
961 for (row = 0; row < s_image->num_rows; row++) {
962 for (col = 0; col < s_image->num_cols; col++) {
963 ctx->out_tile_map[tile] =
973 struct ipu_image_convert_chan *chan = ctx->chan;
974 struct ipu_image_convert_priv *priv = chan->priv;
975 const struct ipu_image_pixfmt *fmt = image->fmt;
983 H = image->base.pix.height;
985 y_stride = image->stride;
986 uv_stride = y_stride / fmt->uv_width_dec;
987 if (fmt->uv_packed)
991 uv_size = y_size / (fmt->uv_width_dec * fmt->uv_height_dec);
993 for (row = 0; row < image->num_rows; row++) {
994 top = image->tile[tile].top;
996 uv_row_off = (top * uv_stride) / fmt->uv_height_dec;
998 for (col = 0; col < image->num_cols; col++) {
999 y_col_off = image->tile[tile].left;
1000 uv_col_off = y_col_off / fmt->uv_width_dec;
1001 if (fmt->uv_packed)
1007 u_off = y_size - y_off + uv_off;
1008 v_off = (fmt->uv_packed) ? 0 : u_off + uv_size;
1009 if (fmt->uv_swapped)
1012 image->tile[tile].offset = y_off;
1013 image->tile[tile].u_off = u_off;
1014 image->tile[tile++].v_off = v_off;
1017 dev_err(priv->ipu->dev,
1020 chan->ic_task, ctx,
1021 image->type == IMAGE_CONVERT_IN ?
1024 return -EINVAL;
1035 struct ipu_image_convert_chan *chan = ctx->chan;
1036 struct ipu_image_convert_priv *priv = chan->priv;
1037 const struct ipu_image_pixfmt *fmt = image->fmt;
1043 stride = image->stride;
1044 bpp = fmt->bpp;
1046 for (row = 0; row < image->num_rows; row++) {
1047 row_off = image->tile[tile].top * stride;
1049 for (col = 0; col < image->num_cols; col++) {
1050 col_off = (image->tile[tile].left * bpp) >> 3;
1054 image->tile[tile].offset = offset;
1055 image->tile[tile].u_off = 0;
1056 image->tile[tile++].v_off = 0;
1059 dev_err(priv->ipu->dev,
1062 chan->ic_task, ctx,
1063 image->type == IMAGE_CONVERT_IN ?
1066 return -EINVAL;
1077 if (image->fmt->planar)
1100 return 8192 * (downsized - 1) / (output_size - 1);
1111 struct ipu_image_convert_chan *chan = ctx->chan;
1112 struct ipu_image_convert_priv *priv = chan->priv;
1117 for (col = 0; col < ctx->in.num_cols; col++) {
1118 bool closest = (col < ctx->in.num_cols - 1) &&
1119 !(ctx->rot_mode & IPU_ROT_BIT_HFLIP);
1125 in_tile = &ctx->in.tile[tile_idx];
1126 out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1128 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1129 resized_width = out_tile->height;
1131 resized_width = out_tile->width;
1133 resize_coeff_h = calc_resize_coeff(in_tile->width,
1134 ctx->downsize_coeff_h,
1137 dev_dbg(priv->ipu->dev, "%s: column %u hscale: *8192/%u\n",
1151 last_output = resized_width - 1;
1156 << ctx->downsize_coeff_h, 8);
1158 for (row = 0; row < ctx->in.num_rows; row++) {
1159 tile_idx = row * ctx->in.num_cols + col;
1160 in_tile = &ctx->in.tile[tile_idx];
1161 out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1163 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1164 out_tile->height = resized_width;
1166 out_tile->width = resized_width;
1168 in_tile->width = in_width;
1171 ctx->resize_coeffs_h[col] = resize_coeff_h;
1174 for (row = 0; row < ctx->in.num_rows; row++) {
1175 bool closest = (row < ctx->in.num_rows - 1) &&
1176 !(ctx->rot_mode & IPU_ROT_BIT_VFLIP);
1181 tile_idx = row * ctx->in.num_cols;
1182 in_tile = &ctx->in.tile[tile_idx];
1183 out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1185 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1186 resized_height = out_tile->width;
1188 resized_height = out_tile->height;
1190 resize_coeff_v = calc_resize_coeff(in_tile->height,
1191 ctx->downsize_coeff_v,
1194 dev_dbg(priv->ipu->dev, "%s: row %u vscale: *8192/%u\n",
1208 last_output = resized_height - 1;
1213 << ctx->downsize_coeff_v, 2);
1215 for (col = 0; col < ctx->in.num_cols; col++) {
1216 tile_idx = row * ctx->in.num_cols + col;
1217 in_tile = &ctx->in.tile[tile_idx];
1218 out_tile = &ctx->out.tile[ctx->out_tile_map[tile_idx]];
1220 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1221 out_tile->width = resized_height;
1223 out_tile->height = resized_height;
1225 in_tile->height = in_height;
1228 ctx->resize_coeffs_v[row] = resize_coeff_v;
1242 lockdep_assert_held(&ctx->chan->irqlock);
1245 if (run->ctx == ctx)
1254 struct ipu_image_convert_ctx *ctx = run->ctx;
1255 struct ipu_image_convert_chan *chan = ctx->chan;
1256 struct ipu_image_convert_priv *priv = chan->priv;
1258 dev_dbg(priv->ipu->dev, "%s: task %u: stopping ctx %p run %p\n",
1259 __func__, chan->ic_task, ctx, run);
1262 ipu_ic_task_disable(chan->ic);
1263 ipu_idmac_disable_channel(chan->in_chan);
1264 ipu_idmac_disable_channel(chan->out_chan);
1266 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1267 ipu_idmac_disable_channel(chan->rotation_in_chan);
1268 ipu_idmac_disable_channel(chan->rotation_out_chan);
1269 ipu_idmac_unlink(chan->out_chan, chan->rotation_in_chan);
1272 ipu_ic_disable(chan->ic);
1282 struct ipu_image_convert_chan *chan = ctx->chan;
1289 if (image->type == IMAGE_CONVERT_OUT) {
1290 tile_idx[0] = ctx->out_tile_map[tile];
1291 tile_idx[1] = ctx->out_tile_map[1];
1298 width = image->tile[tile_idx[0]].height;
1299 height = image->tile[tile_idx[0]].width;
1300 stride = image->tile[tile_idx[0]].rot_stride;
1301 addr0 = ctx->rot_intermediate[0].phys;
1302 if (ctx->double_buffering)
1303 addr1 = ctx->rot_intermediate[1].phys;
1305 width = image->tile[tile_idx[0]].width;
1306 height = image->tile[tile_idx[0]].height;
1307 stride = image->stride;
1308 addr0 = image->base.phys0 +
1309 image->tile[tile_idx[0]].offset;
1310 if (ctx->double_buffering)
1311 addr1 = image->base.phys0 +
1312 image->tile[tile_idx[1]].offset;
1318 tile_image.pix.width = tile_image.rect.width = width;
1319 tile_image.pix.height = tile_image.rect.height = height;
1320 tile_image.pix.bytesperline = stride;
1321 tile_image.pix.pixelformat = image->fmt->fourcc;
1324 if (image->fmt->planar && !rot_swap_width_height) {
1325 tile_image.u_offset = image->tile[tile_idx[0]].u_off;
1326 tile_image.v_offset = image->tile[tile_idx[0]].v_off;
1338 if ((channel == chan->out_chan ||
1339 channel == chan->rotation_out_chan) &&
1340 image->fmt->planar && image->fmt->uv_height_dec == 2)
1343 if (channel == chan->rotation_in_chan ||
1344 channel == chan->rotation_out_chan) {
1352 ipu_ic_task_idma_init(chan->ic, channel, width, height,
1356 * Setting a non-zero AXI ID collides with the PRG AXI snooping, so
1359 if (!channel->ipu->prg_priv)
1362 ipu_idmac_set_double_buffer(channel, ctx->double_buffering);
1367 struct ipu_image_convert_ctx *ctx = run->ctx;
1368 struct ipu_image_convert_chan *chan = ctx->chan;
1369 struct ipu_image_convert_priv *priv = chan->priv;
1370 struct ipu_image_convert_image *s_image = &ctx->in;
1371 struct ipu_image_convert_image *d_image = &ctx->out;
1372 unsigned int dst_tile = ctx->out_tile_map[tile];
1378 dev_dbg(priv->ipu->dev, "%s: task %u: starting ctx %p run %p tile %u -> %u\n",
1379 __func__, chan->ic_task, ctx, run, tile, dst_tile);
1382 ctx->eof_mask = 0;
1384 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1386 dest_width = d_image->tile[dst_tile].height;
1387 dest_height = d_image->tile[dst_tile].width;
1389 dest_width = d_image->tile[dst_tile].width;
1390 dest_height = d_image->tile[dst_tile].height;
1393 row = tile / s_image->num_cols;
1394 col = tile % s_image->num_cols;
1396 rsc = (ctx->downsize_coeff_v << 30) |
1397 (ctx->resize_coeffs_v[row] << 16) |
1398 (ctx->downsize_coeff_h << 14) |
1399 (ctx->resize_coeffs_h[col]);
1401 dev_dbg(priv->ipu->dev, "%s: %ux%u -> %ux%u (rsc = 0x%x)\n",
1402 __func__, s_image->tile[tile].width,
1403 s_image->tile[tile].height, dest_width, dest_height, rsc);
1406 ret = ipu_ic_task_init_rsc(chan->ic, &ctx->csc,
1407 s_image->tile[tile].width,
1408 s_image->tile[tile].height,
1413 dev_err(priv->ipu->dev, "ipu_ic_task_init failed, %d\n", ret);
1417 /* init the source MEM-->IC PP IDMAC channel */
1418 init_idmac_channel(ctx, chan->in_chan, s_image,
1421 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1422 /* init the IC PP-->MEM IDMAC channel */
1423 init_idmac_channel(ctx, chan->out_chan, d_image,
1426 /* init the MEM-->IC PP ROT IDMAC channel */
1427 init_idmac_channel(ctx, chan->rotation_in_chan, d_image,
1428 ctx->rot_mode, true, tile);
1430 /* init the destination IC PP ROT-->MEM IDMAC channel */
1431 init_idmac_channel(ctx, chan->rotation_out_chan, d_image,
1434 /* now link IC PP-->MEM to MEM-->IC PP ROT */
1435 ipu_idmac_link(chan->out_chan, chan->rotation_in_chan);
1437 /* init the destination IC PP-->MEM IDMAC channel */
1438 init_idmac_channel(ctx, chan->out_chan, d_image,
1439 ctx->rot_mode, false, tile);
1443 ipu_ic_enable(chan->ic);
1446 ipu_idmac_select_buffer(chan->in_chan, 0);
1447 ipu_idmac_select_buffer(chan->out_chan, 0);
1448 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1449 ipu_idmac_select_buffer(chan->rotation_out_chan, 0);
1450 if (ctx->double_buffering) {
1451 ipu_idmac_select_buffer(chan->in_chan, 1);
1452 ipu_idmac_select_buffer(chan->out_chan, 1);
1453 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1454 ipu_idmac_select_buffer(chan->rotation_out_chan, 1);
1458 ipu_idmac_enable_channel(chan->in_chan);
1459 ipu_idmac_enable_channel(chan->out_chan);
1460 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1461 ipu_idmac_enable_channel(chan->rotation_in_chan);
1462 ipu_idmac_enable_channel(chan->rotation_out_chan);
1465 ipu_ic_task_enable(chan->ic);
1467 ipu_cpmem_dump(chan->in_chan);
1468 ipu_cpmem_dump(chan->out_chan);
1469 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
1470 ipu_cpmem_dump(chan->rotation_in_chan);
1471 ipu_cpmem_dump(chan->rotation_out_chan);
1474 ipu_dump(priv->ipu);
1482 struct ipu_image_convert_ctx *ctx = run->ctx;
1483 struct ipu_image_convert_chan *chan = ctx->chan;
1485 lockdep_assert_held(&chan->irqlock);
1487 ctx->in.base.phys0 = run->in_phys;
1488 ctx->out.base.phys0 = run->out_phys;
1490 ctx->cur_buf_num = 0;
1491 ctx->next_tile = 1;
1494 list_del(&run->list);
1495 chan->current_run = run;
1503 struct ipu_image_convert_priv *priv = chan->priv;
1507 lockdep_assert_held(&chan->irqlock);
1509 list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
1511 if (run->ctx->aborting) {
1512 dev_dbg(priv->ipu->dev,
1514 __func__, chan->ic_task, run->ctx, run);
1527 run->status = ret;
1528 list_add_tail(&run->list, &chan->done_q);
1529 chan->current_run = NULL;
1535 struct ipu_image_convert_priv *priv = chan->priv;
1539 spin_lock_irqsave(&chan->irqlock, flags);
1541 while (!list_empty(&chan->done_q)) {
1542 run = list_entry(chan->done_q.next,
1546 list_del(&run->list);
1548 dev_dbg(priv->ipu->dev,
1550 __func__, chan->ic_task, run->ctx, run, run->status);
1553 spin_unlock_irqrestore(&chan->irqlock, flags);
1554 run->ctx->complete(run, run->ctx->complete_context);
1555 spin_lock_irqsave(&chan->irqlock, flags);
1558 spin_unlock_irqrestore(&chan->irqlock, flags);
1568 struct ipu_image_convert_priv *priv = chan->priv;
1572 dev_dbg(priv->ipu->dev, "%s: task %u: enter\n", __func__,
1573 chan->ic_task);
1577 spin_lock_irqsave(&chan->irqlock, flags);
1583 list_for_each_entry(ctx, &chan->ctx_list, list) {
1584 if (ctx->aborting) {
1585 dev_dbg(priv->ipu->dev,
1587 __func__, chan->ic_task, ctx);
1588 complete_all(&ctx->aborted);
1592 spin_unlock_irqrestore(&chan->irqlock, flags);
1594 dev_dbg(priv->ipu->dev, "%s: task %u: exit\n", __func__,
1595 chan->ic_task);
1602 unsigned int cur_tile = ctx->next_tile - 1;
1603 unsigned int next_tile = ctx->next_tile;
1605 if (ctx->resize_coeffs_h[cur_tile % ctx->in.num_cols] !=
1606 ctx->resize_coeffs_h[next_tile % ctx->in.num_cols] ||
1607 ctx->resize_coeffs_v[cur_tile / ctx->in.num_cols] !=
1608 ctx->resize_coeffs_v[next_tile / ctx->in.num_cols] ||
1609 ctx->in.tile[cur_tile].width != ctx->in.tile[next_tile].width ||
1610 ctx->in.tile[cur_tile].height != ctx->in.tile[next_tile].height ||
1611 ctx->out.tile[cur_tile].width != ctx->out.tile[next_tile].width ||
1612 ctx->out.tile[cur_tile].height != ctx->out.tile[next_tile].height)
1621 struct ipu_image_convert_ctx *ctx = run->ctx;
1622 struct ipu_image_convert_chan *chan = ctx->chan;
1624 struct ipu_image_convert_image *s_image = &ctx->in;
1625 struct ipu_image_convert_image *d_image = &ctx->out;
1629 lockdep_assert_held(&chan->irqlock);
1631 outch = ipu_rot_mode_is_irt(ctx->rot_mode) ?
1632 chan->rotation_out_chan : chan->out_chan;
1636 * enter the paused state. Without double-buffering the channels
1638 * is safe to stop the channels now. For double-buffering we
1642 if (ctx->aborting && !ctx->double_buffering) {
1644 run->status = -EIO;
1648 if (ctx->next_tile == ctx->num_tiles) {
1653 run->status = 0;
1660 if (!ctx->double_buffering) {
1663 convert_start(run, ctx->next_tile);
1665 src_tile = &s_image->tile[ctx->next_tile];
1666 dst_idx = ctx->out_tile_map[ctx->next_tile];
1667 dst_tile = &d_image->tile[dst_idx];
1669 ipu_cpmem_set_buffer(chan->in_chan, 0,
1670 s_image->base.phys0 +
1671 src_tile->offset);
1673 d_image->base.phys0 +
1674 dst_tile->offset);
1675 if (s_image->fmt->planar)
1676 ipu_cpmem_set_uv_offset(chan->in_chan,
1677 src_tile->u_off,
1678 src_tile->v_off);
1679 if (d_image->fmt->planar)
1681 dst_tile->u_off,
1682 dst_tile->v_off);
1684 ipu_idmac_select_buffer(chan->in_chan, 0);
1687 } else if (ctx->next_tile < ctx->num_tiles - 1) {
1689 src_tile = &s_image->tile[ctx->next_tile + 1];
1690 dst_idx = ctx->out_tile_map[ctx->next_tile + 1];
1691 dst_tile = &d_image->tile[dst_idx];
1693 ipu_cpmem_set_buffer(chan->in_chan, ctx->cur_buf_num,
1694 s_image->base.phys0 + src_tile->offset);
1695 ipu_cpmem_set_buffer(outch, ctx->cur_buf_num,
1696 d_image->base.phys0 + dst_tile->offset);
1698 ipu_idmac_select_buffer(chan->in_chan, ctx->cur_buf_num);
1699 ipu_idmac_select_buffer(outch, ctx->cur_buf_num);
1701 ctx->cur_buf_num ^= 1;
1704 ctx->eof_mask = 0; /* clear EOF irq mask for next tile */
1705 ctx->next_tile++;
1708 list_add_tail(&run->list, &chan->done_q);
1709 chan->current_run = NULL;
1717 struct ipu_image_convert_priv *priv = chan->priv;
1724 spin_lock_irqsave(&chan->irqlock, flags);
1727 run = chan->current_run;
1733 ctx = run->ctx;
1735 if (irq == chan->in_eof_irq) {
1736 ctx->eof_mask |= EOF_IRQ_IN;
1737 } else if (irq == chan->out_eof_irq) {
1738 ctx->eof_mask |= EOF_IRQ_OUT;
1739 } else if (irq == chan->rot_in_eof_irq ||
1740 irq == chan->rot_out_eof_irq) {
1741 if (!ipu_rot_mode_is_irt(ctx->rot_mode)) {
1743 dev_err(priv->ipu->dev,
1747 ctx->eof_mask |= (irq == chan->rot_in_eof_irq) ?
1750 dev_err(priv->ipu->dev, "Received unknown irq %d\n", irq);
1755 if (ipu_rot_mode_is_irt(ctx->rot_mode))
1756 tile_complete = (ctx->eof_mask == EOF_IRQ_ROT_COMPLETE);
1758 tile_complete = (ctx->eof_mask == EOF_IRQ_COMPLETE);
1763 spin_unlock_irqrestore(&chan->irqlock, flags);
1773 struct ipu_image_convert_chan *chan = ctx->chan;
1777 spin_lock_irqsave(&chan->irqlock, flags);
1779 run = chan->current_run;
1780 if (run && run->ctx == ctx) {
1782 run->status = -EIO;
1783 list_add_tail(&run->list, &chan->done_q);
1784 chan->current_run = NULL;
1788 spin_unlock_irqrestore(&chan->irqlock, flags);
1795 if (chan->in_eof_irq >= 0)
1796 free_irq(chan->in_eof_irq, chan);
1797 if (chan->rot_in_eof_irq >= 0)
1798 free_irq(chan->rot_in_eof_irq, chan);
1799 if (chan->out_eof_irq >= 0)
1800 free_irq(chan->out_eof_irq, chan);
1801 if (chan->rot_out_eof_irq >= 0)
1802 free_irq(chan->rot_out_eof_irq, chan);
1804 if (!IS_ERR_OR_NULL(chan->in_chan))
1805 ipu_idmac_put(chan->in_chan);
1806 if (!IS_ERR_OR_NULL(chan->out_chan))
1807 ipu_idmac_put(chan->out_chan);
1808 if (!IS_ERR_OR_NULL(chan->rotation_in_chan))
1809 ipu_idmac_put(chan->rotation_in_chan);
1810 if (!IS_ERR_OR_NULL(chan->rotation_out_chan))
1811 ipu_idmac_put(chan->rotation_out_chan);
1812 if (!IS_ERR_OR_NULL(chan->ic))
1813 ipu_ic_put(chan->ic);
1815 chan->in_chan = chan->out_chan = chan->rotation_in_chan =
1816 chan->rotation_out_chan = NULL;
1817 chan->in_eof_irq = -1;
1818 chan->rot_in_eof_irq = -1;
1819 chan->out_eof_irq = -1;
1820 chan->rot_out_eof_irq = -1;
1826 struct ipu_image_convert_priv *priv = chan->priv;
1829 irq = ipu_idmac_channel_irq(priv->ipu, channel, IPU_IRQ_EOF);
1831 ret = request_threaded_irq(irq, eof_irq, do_bh, 0, "ipu-ic", chan);
1833 dev_err(priv->ipu->dev, "could not acquire irq %d\n", irq);
1842 const struct ipu_image_convert_dma_chan *dma = chan->dma_ch;
1843 struct ipu_image_convert_priv *priv = chan->priv;
1847 chan->ic = ipu_ic_get(priv->ipu, chan->ic_task);
1848 if (IS_ERR(chan->ic)) {
1849 dev_err(priv->ipu->dev, "could not acquire IC\n");
1850 ret = PTR_ERR(chan->ic);
1855 chan->in_chan = ipu_idmac_get(priv->ipu, dma->in);
1856 chan->out_chan = ipu_idmac_get(priv->ipu, dma->out);
1857 if (IS_ERR(chan->in_chan) || IS_ERR(chan->out_chan)) {
1858 dev_err(priv->ipu->dev, "could not acquire idmac channels\n");
1859 ret = -EBUSY;
1863 chan->rotation_in_chan = ipu_idmac_get(priv->ipu, dma->rot_in);
1864 chan->rotation_out_chan = ipu_idmac_get(priv->ipu, dma->rot_out);
1865 if (IS_ERR(chan->rotation_in_chan) || IS_ERR(chan->rotation_out_chan)) {
1866 dev_err(priv->ipu->dev,
1868 ret = -EBUSY;
1873 ret = get_eof_irq(chan, chan->in_chan);
1875 chan->in_eof_irq = -1;
1878 chan->in_eof_irq = ret;
1880 ret = get_eof_irq(chan, chan->rotation_in_chan);
1882 chan->rot_in_eof_irq = -1;
1885 chan->rot_in_eof_irq = ret;
1887 ret = get_eof_irq(chan, chan->out_chan);
1889 chan->out_eof_irq = -1;
1892 chan->out_eof_irq = ret;
1894 ret = get_eof_irq(chan, chan->rotation_out_chan);
1896 chan->rot_out_eof_irq = -1;
1899 chan->rot_out_eof_irq = ret;
1912 struct ipu_image_convert_priv *priv = ctx->chan->priv;
1914 ic_image->base = *image;
1915 ic_image->type = type;
1917 ic_image->fmt = get_format(image->pix.pixelformat);
1918 if (!ic_image->fmt) {
1919 dev_err(priv->ipu->dev, "pixelformat not supported for %s\n",
1921 return -EINVAL;
1924 if (ic_image->fmt->planar)
1925 ic_image->stride = ic_image->base.pix.width;
1927 ic_image->stride = ic_image->base.pix.bytesperline;
1932 /* borrowed from drivers/media/v4l2-core/v4l2-common.c */
1933 static unsigned int clamp_align(unsigned int x, unsigned int min,
1937 unsigned int mask = ~((1 << align) - 1);
1939 /* Clamp to aligned min and max */
1940 x = clamp(x, (min + ~mask) & mask, max & mask);
1944 x = (x + (1 << (align - 1))) & mask;
1957 infmt = get_format(in->pix.pixelformat);
1958 outfmt = get_format(out->pix.pixelformat);
1962 in->pix.pixelformat = V4L2_PIX_FMT_RGB24;
1966 out->pix.pixelformat = V4L2_PIX_FMT_RGB24;
1971 in->pix.field = out->pix.field = V4L2_FIELD_NONE;
1975 out->pix.height = max_t(__u32, out->pix.height,
1976 in->pix.width / 4);
1977 out->pix.width = max_t(__u32, out->pix.width,
1978 in->pix.height / 4);
1980 out->pix.width = max_t(__u32, out->pix.width,
1981 in->pix.width / 4);
1982 out->pix.height = max_t(__u32, out->pix.height,
1983 in->pix.height / 4);
1991 in->pix.width = clamp_align(in->pix.width, MIN_W, MAX_W,
1993 in->pix.height = clamp_align(in->pix.height, MIN_H, MAX_H,
2001 out->pix.width = clamp_align(out->pix.width, MIN_W, MAX_W,
2003 out->pix.height = clamp_align(out->pix.height, MIN_H, MAX_H,
2006 /* set input/output strides and image sizes */
2007 in->pix.bytesperline = infmt->planar ?
2008 clamp_align(in->pix.width, 2 << w_align_in, MAX_W,
2010 clamp_align((in->pix.width * infmt->bpp) >> 3,
2011 ((2 << w_align_in) * infmt->bpp) >> 3,
2012 (MAX_W * infmt->bpp) >> 3,
2014 in->pix.sizeimage = infmt->planar ?
2015 (in->pix.height * in->pix.bytesperline * infmt->bpp) >> 3 :
2016 in->pix.height * in->pix.bytesperline;
2017 out->pix.bytesperline = outfmt->planar ? out->pix.width :
2018 (out->pix.width * outfmt->bpp) >> 3;
2019 out->pix.sizeimage = outfmt->planar ?
2020 (out->pix.height * out->pix.bytesperline * outfmt->bpp) >> 3 :
2021 out->pix.height * out->pix.bytesperline;
2040 if (testin.pix.width != in->pix.width ||
2041 testin.pix.height != in->pix.height ||
2042 testout.pix.width != out->pix.width ||
2043 testout.pix.height != out->pix.height)
2044 return -EINVAL;
2061 struct ipu_image_convert_priv *priv = ipu->image_convert_priv;
2073 return ERR_PTR(-EINVAL);
2078 dev_err(priv->ipu->dev, "%s: in/out formats invalid\n",
2083 chan = &priv->chan[ic_task];
2087 return ERR_PTR(-ENOMEM);
2089 dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p\n", __func__,
2090 chan->ic_task, ctx);
2092 ctx->chan = chan;
2093 init_completion(&ctx->aborted);
2095 ctx->rot_mode = rot_mode;
2097 /* Sets ctx->in.num_rows/cols as well */
2102 s_image = &ctx->in;
2103 d_image = &ctx->out;
2107 d_image->num_rows = s_image->num_cols;
2108 d_image->num_cols = s_image->num_rows;
2110 d_image->num_rows = s_image->num_rows;
2111 d_image->num_cols = s_image->num_cols;
2114 ctx->num_tiles = d_image->num_cols * d_image->num_rows;
2142 ret = ipu_ic_calc_csc(&ctx->csc,
2143 s_image->base.pix.ycbcr_enc,
2144 s_image->base.pix.quantization,
2145 ipu_pixelformat_to_colorspace(s_image->fmt->fourcc),
2146 d_image->base.pix.ycbcr_enc,
2147 d_image->base.pix.quantization,
2148 ipu_pixelformat_to_colorspace(d_image->fmt->fourcc));
2155 ctx->complete = complete;
2156 ctx->complete_context = complete_context;
2159 * Can we use double-buffering for this operation? If there is
2161 * operation) there's no point in using double-buffering. Also,
2165 * each buffer which is not possible. So double-buffering is
2169 * prevent double-buffering as well.
2171 ctx->double_buffering = (ctx->num_tiles > 1 &&
2172 !s_image->fmt->planar &&
2173 !d_image->fmt->planar);
2174 for (i = 1; i < ctx->num_tiles; i++) {
2175 if (ctx->in.tile[i].width != ctx->in.tile[0].width ||
2176 ctx->in.tile[i].height != ctx->in.tile[0].height ||
2177 ctx->out.tile[i].width != ctx->out.tile[0].width ||
2178 ctx->out.tile[i].height != ctx->out.tile[0].height) {
2179 ctx->double_buffering = false;
2183 for (i = 1; i < ctx->in.num_cols; i++) {
2184 if (ctx->resize_coeffs_h[i] != ctx->resize_coeffs_h[0]) {
2185 ctx->double_buffering = false;
2189 for (i = 1; i < ctx->in.num_rows; i++) {
2190 if (ctx->resize_coeffs_v[i] != ctx->resize_coeffs_v[0]) {
2191 ctx->double_buffering = false;
2196 if (ipu_rot_mode_is_irt(ctx->rot_mode)) {
2197 unsigned long intermediate_size = d_image->tile[0].size;
2199 for (i = 1; i < ctx->num_tiles; i++) {
2200 if (d_image->tile[i].size > intermediate_size)
2201 intermediate_size = d_image->tile[i].size;
2204 ret = alloc_dma_buf(priv, &ctx->rot_intermediate[0],
2208 if (ctx->double_buffering) {
2210 &ctx->rot_intermediate[1],
2217 spin_lock_irqsave(&chan->irqlock, flags);
2219 get_res = list_empty(&chan->ctx_list);
2221 list_add_tail(&ctx->list, &chan->ctx_list);
2223 spin_unlock_irqrestore(&chan->irqlock, flags);
2234 free_dma_buf(priv, &ctx->rot_intermediate[1]);
2235 spin_lock_irqsave(&chan->irqlock, flags);
2236 list_del(&ctx->list);
2237 spin_unlock_irqrestore(&chan->irqlock, flags);
2239 free_dma_buf(priv, &ctx->rot_intermediate[0]);
2259 if (!run || !run->ctx || !run->in_phys || !run->out_phys)
2260 return -EINVAL;
2262 ctx = run->ctx;
2263 chan = ctx->chan;
2264 priv = chan->priv;
2266 dev_dbg(priv->ipu->dev, "%s: task %u: ctx %p run %p\n", __func__,
2267 chan->ic_task, ctx, run);
2269 INIT_LIST_HEAD(&run->list);
2271 spin_lock_irqsave(&chan->irqlock, flags);
2273 if (ctx->aborting) {
2274 ret = -EIO;
2278 list_add_tail(&run->list, &chan->pending_q);
2280 if (!chan->current_run) {
2283 chan->current_run = NULL;
2286 spin_unlock_irqrestore(&chan->irqlock, flags);
2294 struct ipu_image_convert_chan *chan = ctx->chan;
2295 struct ipu_image_convert_priv *priv = chan->priv;
2300 spin_lock_irqsave(&chan->irqlock, flags);
2303 list_for_each_entry_safe(run, tmp, &chan->pending_q, list) {
2304 if (run->ctx != ctx)
2306 run->status = -EIO;
2307 list_move_tail(&run->list, &chan->done_q);
2310 run_count = get_run_count(ctx, &chan->done_q);
2311 active_run = (chan->current_run && chan->current_run->ctx == ctx) ?
2312 chan->current_run : NULL;
2315 reinit_completion(&ctx->aborted);
2317 ctx->aborting = true;
2319 spin_unlock_irqrestore(&chan->irqlock, flags);
2322 dev_dbg(priv->ipu->dev,
2324 __func__, chan->ic_task, ctx);
2333 dev_dbg(priv->ipu->dev,
2335 __func__, chan->ic_task, run_count);
2337 ret = wait_for_completion_timeout(&ctx->aborted,
2340 dev_warn(priv->ipu->dev, "%s: timeout\n", __func__);
2348 ctx->aborting = false;
2355 struct ipu_image_convert_chan *chan = ctx->chan;
2356 struct ipu_image_convert_priv *priv = chan->priv;
2363 dev_dbg(priv->ipu->dev, "%s: task %u: removing ctx %p\n", __func__,
2364 chan->ic_task, ctx);
2366 spin_lock_irqsave(&chan->irqlock, flags);
2368 list_del(&ctx->list);
2370 put_res = list_empty(&chan->ctx_list);
2372 spin_unlock_irqrestore(&chan->irqlock, flags);
2377 free_dma_buf(priv, &ctx->rot_intermediate[1]);
2378 free_dma_buf(priv, &ctx->rot_intermediate[0]);
2408 return ERR_PTR(-ENOMEM);
2411 run->ctx = ctx;
2412 run->in_phys = in->phys0;
2413 run->out_phys = out->phys0;
2433 return -ENOMEM;
2435 ipu->image_convert_priv = priv;
2436 priv->ipu = ipu;
2439 struct ipu_image_convert_chan *chan = &priv->chan[i];
2441 chan->ic_task = i;
2442 chan->priv = priv;
2443 chan->dma_ch = &image_convert_dma_chan[i];
2444 chan->in_eof_irq = -1;
2445 chan->rot_in_eof_irq = -1;
2446 chan->out_eof_irq = -1;
2447 chan->rot_out_eof_irq = -1;
2449 spin_lock_init(&chan->irqlock);
2450 INIT_LIST_HEAD(&chan->ctx_list);
2451 INIT_LIST_HEAD(&chan->pending_q);
2452 INIT_LIST_HEAD(&chan->done_q);