diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 7f239cbcb4f7..d46fc4d4912d 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ struct ti_csi2rx_buffer { struct vb2_v4l2_buffer vb; struct list_head list; struct ti_csi2rx_ctx *ctx; + struct sg_table interlaced_sgt; }; enum ti_csi2rx_dma_state { @@ -765,19 +767,70 @@ static void ti_csi2rx_dma_callback(void *param) spin_unlock_irqrestore(&dma->lock, flags); } +static int build_sgt_for_interlaced_dma(struct sg_table *dst_sgt, dma_addr_t base_addr, size_t width, int height) +{ + int ret; + int i; + int half_height = height / 2; + int line_size = width * 2; // Assume 16 bit format for now (720*2, 1440) + int stride = line_size * 2; // 1440 * 2 (2880) + struct scatterlist *sg; + + if (!dst_sgt) + return -EINVAL; + + ret = sg_alloc_table(dst_sgt, height, GFP_KERNEL); + if (ret) + return ret; + + sg = dst_sgt->sgl; + + for (i = 0; i < half_height; i++) + { + sg[i].dma_address = base_addr + (dma_addr_t) (i * stride); + sg[i].length = line_size; +#ifdef CONFIG_NEED_SG_DMA_LENGTH + sg[i].dma_length = line_size; +#endif + sg[i].offset = 0; + sg[i].page_link = 0; + + sg[i + half_height].dma_address = base_addr + (dma_addr_t) ((i * stride) + line_size); + sg[i + half_height].length = line_size; +#ifdef CONFIG_NEED_SG_DMA_LENGTH + sg[i + half_height].dma_length = line_size; +#endif + sg[i + half_height].offset = 0; + sg[i + half_height].page_link = 0; + } + + return 0; +} + static int ti_csi2rx_start_dma(struct ti_csi2rx_ctx *ctx, struct ti_csi2rx_buffer *buf) { unsigned long addr; struct dma_async_tx_descriptor *desc; - size_t len = ctx->v_fmt.fmt.pix.sizeimage; + size_t height = ctx->v_fmt.fmt.pix.height; + size_t width = ctx->v_fmt.fmt.pix.width; dma_cookie_t cookie; int ret = 0; addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); - desc = dmaengine_prep_slave_single(ctx->dma.chan, addr, len, - DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + + ret = build_sgt_for_interlaced_dma(&buf->interlaced_sgt, (dma_addr_t) addr, width, height); + + if (ret) + { + dev_info(ctx->csi->dev, "Failed build_sgt_for_interlaced_dma\n"); + return ret; + } + + desc = dmaengine_prep_slave_sg(ctx->dma.chan, buf->interlaced_sgt.sgl, buf->interlaced_sgt.nents, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) return -EIO; @@ -833,10 +886,14 @@ static void ti_csi2rx_cleanup_buffers(struct ti_csi2rx_ctx *ctx, spin_lock_irqsave(&dma->lock, flags); list_for_each_entry_safe(buf, tmp, &ctx->dma.queue, list) { + if (buf->interlaced_sgt.sgl) + sg_free_table(&buf->interlaced_sgt); list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, state); } list_for_each_entry_safe(buf, tmp, &ctx->dma.submitted, list) { + if (buf->interlaced_sgt.sgl) + sg_free_table(&buf->interlaced_sgt); list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, state); } @@ -1119,7 +1176,12 @@ static int ti_csi2rx_sd_set_fmt(struct v4l2_subdev *sd, if (!find_format_by_code(format->format.code)) format->format.code = ti_csi2rx_formats[0].code; - format->format.field = V4L2_FIELD_NONE; + /* V4L2_FIELD_SEQ_TB and V4L2_FIELD_SEQ_TB can be converted into V4L2_FIELD_NONE*/ + if (format->format.field != V4L2_FIELD_SEQ_TB && + format->format.field != V4L2_FIELD_SEQ_BT ) + { + format->format.field = V4L2_FIELD_NONE; + } fmt = v4l2_subdev_state_get_stream_format(state, format->pad, format->stream); if (!fmt) { @@ -1147,10 +1209,10 @@ static int _ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd, int ret; const struct v4l2_mbus_framefmt format = { - .width = 640, + .width = 720, .height = 480, .code = MEDIA_BUS_FMT_UYVY8_1X16, - .field = V4L2_FIELD_NONE, + .field = V4L2_FIELD_SEQ_BT, .colorspace = V4L2_COLORSPACE_SRGB, .ycbcr_enc = V4L2_YCBCR_ENC_601, .quantization = V4L2_QUANTIZATION_LIM_RANGE, @@ -1186,10 +1248,28 @@ static int ti_csi2rx_sd_init_cfg(struct v4l2_subdev *sd, .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE, .source_stream = 0, .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, { + .sink_pad = 0, + .sink_stream = 1, + .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE + 1, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, { + .sink_pad = 0, + .sink_stream = 2, + .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE + 2, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, { + .sink_pad = 0, + .sink_stream = 3, + .source_pad = TI_CSI2RX_PAD_FIRST_SOURCE + 3, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, } }; struct v4l2_subdev_krouting routing = { - .num_routes = 1, + .num_routes = 4, .routes = routes, }; @@ -1527,9 +1607,9 @@ static int ti_csi2rx_init_ctx(struct ti_csi2rx_ctx *ctx) if (!fmt) return -EINVAL; - pix_fmt->width = 640; + pix_fmt->width = 720; pix_fmt->height = 480; - pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->field = V4L2_FIELD_SEQ_BT; pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601, pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE,