diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-13 01:29:48 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-13 01:29:48 +0300 |
commit | 61da593f4458f25c59f65cfd9ba1bda570db5db7 (patch) | |
tree | 42196179375dfda07901577e080f979b2897d308 /drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | |
parent | a3cc31e75185f9b1ad8dc45eac77f8de788dc410 (diff) | |
parent | 60a031b64984ad4a219a13b0fe912746b586bb9b (diff) | |
download | linux-61da593f4458f25c59f65cfd9ba1bda570db5db7.tar.xz |
Merge tag 'media/v6.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- v4l core: subdev frame interval now supports which field
- v4l kapi: moves and renames the init_cfg pad op to init_state as an
internal op.
- new sensor drivers: gc0308, gc2145, Avnet Alvium, ov64a40, tw9900
- new camera driver: STM32 DCMIPP
- s5p-mfc has gained MFC v12 support
- new ISP driver added to staging: Starfive
- new stateful encoder/decoded: Wave5 codec It is found on the J721S2
SoC, JH7100 SoC, ssd202d SoC. Etc.
- fwnode gained support for MIPI "DisCo for Imaging"
(https://www.mipi.org/specifications/mipi-disco-imaging)
- as usual, lots of cleanups, fixups and driver improvements.
* tag 'media/v6.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (309 commits)
media: i2c: thp7312: select CONFIG_FW_LOADER
media: i2c: mt9m114: use fsleep() in place of udelay()
media: videobuf2: core: Rename min_buffers_needed field in vb2_queue
media: i2c: thp7312: Store frame interval in subdev state
media: docs: uAPI: Fix documentation of 'which' field for routing ioctls
media: docs: uAPI: Expand error documentation for invalid 'which' value
media: docs: uAPI: Clarify error documentation for invalid 'which' value
media: v4l2-subdev: Store frame interval in subdev state
media: v4l2-subdev: Add which field to struct v4l2_subdev_frame_interval
media: v4l2-subdev: Turn .[gs]_frame_interval into pad operations
media: v4l: subdev: Move out subdev state lock macros outside CONFIG_MEDIA_CONTROLLER
media: s5p-mfc: DPB Count Independent of VIDIOC_REQBUF
media: s5p-mfc: Load firmware for each run in MFCv12.
media: s5p-mfc: Set context for valid case before calling try_run
media: s5p-mfc: Add support for DMABUF for encoder
media: s5p-mfc: Add support for UHD encoding.
media: s5p-mfc: Add support for rate controls in MFCv12
media: s5p-mfc: Add YV12 and I420 multiplanar format support
media: s5p-mfc: Add initial support for MFCv12
media: s5p-mfc: Rename IS_MFCV10 macro
...
Diffstat (limited to 'drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c')
-rw-r--r-- | drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | 150 |
1 files changed, 103 insertions, 47 deletions
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index 4b4c129c09e7..ef8bb40b9712 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -60,6 +60,20 @@ static struct s5p_mfc_fmt formats[] = { .versions = MFC_V6PLUS_BITS, }, { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 3, + .versions = MFC_V12_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 3, + .versions = MFC_V12_BIT, + }, + { .fourcc = V4L2_PIX_FMT_H264, .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, @@ -92,7 +106,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V10_BIT, + .versions = MFC_V10PLUS_BITS, }, }; @@ -1150,7 +1164,6 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_enc_params *p = &ctx->enc_params; struct s5p_mfc_buf *dst_mb; - unsigned int enc_pb_count; if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { if (!list_empty(&ctx->dst_queue)) { @@ -1172,14 +1185,12 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) set_work_bit_irqsave(ctx); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { - enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, - get_enc_dpb_count, dev); - if (ctx->pb_count < enc_pb_count) - ctx->pb_count = enc_pb_count; + ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_enc_dpb_count, dev); if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, get_e_min_scratch_buf_size, dev); - ctx->bank1.size += ctx->scratch_buf_size; + if (!IS_MFCV12(dev)) + ctx->bank1.size += ctx->scratch_buf_size; } ctx->state = MFCINST_HEAD_PRODUCED; } @@ -1192,14 +1203,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_mb; struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr; unsigned int dst_size; src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M) + src_c_1_addr = + vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 2); + else + src_c_1_addr = 0; s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, - src_y_addr, src_c_addr); + src_y_addr, src_c_addr, src_c_1_addr); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); @@ -1214,8 +1231,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *mb_entry; - unsigned long enc_y_addr = 0, enc_c_addr = 0; - unsigned long mb_y_addr, mb_c_addr; + unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0; + unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr; int slice_type; unsigned int strm_size; bool src_ready; @@ -1228,18 +1245,26 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); if (slice_type >= 0) { s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, - &enc_y_addr, &enc_c_addr); + &enc_y_addr, &enc_c_addr, &enc_c_1_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr( &mb_entry->b->vb2_buf, 0); mb_c_addr = vb2_dma_contig_plane_dma_addr( &mb_entry->b->vb2_buf, 1); - if ((enc_y_addr == mb_y_addr) && - (enc_c_addr == mb_c_addr)) { + if (ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YUV420M || + ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M) + mb_c_1_addr = vb2_dma_contig_plane_dma_addr + (&mb_entry->b->vb2_buf, 2); + else + mb_c_1_addr = 0; + if (enc_y_addr == mb_y_addr && enc_c_addr == mb_c_addr && enc_c_1_addr + == mb_c_1_addr) { list_del(&mb_entry->list); ctx->src_queue_cnt--; vb2_buffer_done(&mb_entry->b->vb2_buf, - VB2_BUF_STATE_DONE); + VB2_BUF_STATE_DONE); break; } } @@ -1248,20 +1273,27 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) &mb_entry->b->vb2_buf, 0); mb_c_addr = vb2_dma_contig_plane_dma_addr( &mb_entry->b->vb2_buf, 1); - if ((enc_y_addr == mb_y_addr) && - (enc_c_addr == mb_c_addr)) { + if (ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YUV420M || + ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) + mb_c_1_addr = vb2_dma_contig_plane_dma_addr(& + mb_entry->b->vb2_buf, 2); + else + mb_c_1_addr = 0; + if (enc_y_addr == mb_y_addr && enc_c_addr == mb_c_addr && enc_c_1_addr + == mb_c_1_addr) { list_del(&mb_entry->list); ctx->ref_queue_cnt--; vb2_buffer_done(&mb_entry->b->vb2_buf, - VB2_BUF_STATE_DONE); + VB2_BUF_STATE_DONE); break; } } } if (ctx->src_queue_cnt > 0 && (ctx->state == MFCINST_RUNNING || - ctx->state == MFCINST_FINISHING)) { + ctx->state == MFCINST_FINISHING)) { mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); + list); if (mb_entry->flags & MFC_BUF_FLAG_USED) { list_del(&mb_entry->list); ctx->src_queue_cnt--; @@ -1380,10 +1412,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc; pix_fmt_mp->num_planes = ctx->src_fmt->num_planes; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0]; pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1]; pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M) { + pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2]; + pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1; + } } else { mfc_err("invalid buf type\n"); return -EINVAL; @@ -1420,9 +1457,12 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_err("Unsupported format by this MFC version.\n"); return -EINVAL; } - - v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1, - &pix_fmt_mp->height, 4, 1080, 1, 0); + if (IS_MFCV12(dev)) + v4l_bound_align_image(&pix_fmt_mp->width, 8, 3840, 1, &pix_fmt_mp + ->height, 4, 2160, 1, 0); + else + v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1, &pix_fmt_mp + ->height, 4, 1080, 1, 0); } else { mfc_err("invalid buf type\n"); return -EINVAL; @@ -1467,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0]; pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1]; + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M) { + pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2]; + pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1; + } ctx->src_bufs_cnt = 0; ctx->output_state = QUEUE_FREE; @@ -1489,9 +1534,10 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; - /* if memory is not mmp or userptr return error */ + /* if memory is not mmp or userptr or dmabuf return error */ if ((reqbufs->memory != V4L2_MEMORY_MMAP) && - (reqbufs->memory != V4L2_MEMORY_USERPTR)) + (reqbufs->memory != V4L2_MEMORY_USERPTR) && + (reqbufs->memory != V4L2_MEMORY_DMABUF)) return -EINVAL; if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (reqbufs->count == 0) { @@ -1514,14 +1560,6 @@ static int vidioc_reqbufs(struct file *file, void *priv, } ctx->capture_state = QUEUE_BUFS_REQUESTED; - ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, - alloc_codec_buffers, ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; - } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); @@ -1537,15 +1575,13 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -EINVAL; } - if (IS_MFCV6_PLUS(dev)) { + if (IS_MFCV6_PLUS(dev) && (!IS_MFCV12(dev))) { /* Check for min encoder buffers */ if (ctx->pb_count && (reqbufs->count < ctx->pb_count)) { reqbufs->count = ctx->pb_count; mfc_debug(2, "Minimum %d output buffers needed\n", ctx->pb_count); - } else { - ctx->pb_count = reqbufs->count; } } @@ -1568,9 +1604,10 @@ static int vidioc_querybuf(struct file *file, void *priv, struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; - /* if memory is not mmp or userptr return error */ + /* if memory is not mmp or userptr or dmabuf return error */ if ((buf->memory != V4L2_MEMORY_MMAP) && - (buf->memory != V4L2_MEMORY_USERPTR)) + (buf->memory != V4L2_MEMORY_USERPTR) && + (buf->memory != V4L2_MEMORY_DMABUF)) return -EINVAL; if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (ctx->state != MFCINST_GOT_INST) { @@ -2413,10 +2450,18 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; + if (ctx->src_fmt && (ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M)) + psize[2] = ctx->chroma_size_1; if (IS_MFCV6_PLUS(dev)) { alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; + if (ctx->src_fmt && (ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M)) + alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX]; } else { alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX]; @@ -2455,6 +2500,11 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) vb2_dma_contig_plane_dma_addr(vb, 0); ctx->src_bufs[i].cookie.raw.chroma = vb2_dma_contig_plane_dma_addr(vb, 1); + if (ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc == + V4L2_PIX_FMT_YVU420M) + ctx->src_bufs[i].cookie.raw.chroma_1 = + vb2_dma_contig_plane_dma_addr(vb, 2); ctx->src_bufs_cnt++; } else { mfc_err("invalid queue type: %d\n", vq->type); @@ -2492,6 +2542,12 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) mfc_err("plane size is too small for output\n"); return -EINVAL; } + if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || + ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) && + (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) { + mfc_err("plane size is too small for output\n"); + return -EINVAL; + } } else { mfc_err("invalid queue type: %d\n", vq->type); return -EINVAL; @@ -2513,11 +2569,11 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } - - if (ctx->src_bufs_cnt < ctx->pb_count) { - mfc_err("Need minimum %d OUTPUT buffers\n", - ctx->pb_count); - return -ENOBUFS; + if (q->memory != V4L2_MEMORY_DMABUF) { + if (ctx->src_bufs_cnt < ctx->pb_count) { + mfc_err("Need minimum %d OUTPUT buffers\n", ctx->pb_count); + return -ENOBUFS; + } } } |