diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 22:49:23 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 22:49:23 +0300 |
commit | 2183a58803c2bbd87c2d0057eed6779ec4718d4d (patch) | |
tree | 910860a2f0c1f22efe840428f11077a5bd478933 /drivers/media/platform/coda | |
parent | e28870f9b3e92cd3570925089c6bb789c2603bc4 (diff) | |
parent | 71947828caef0c83d4245f7d1eaddc799b4ff1d1 (diff) | |
download | linux-2183a58803c2bbd87c2d0057eed6779ec4718d4d.tar.xz |
Merge tag 'media/v3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Two new dvb frontend drivers: mn88472 and mn88473
- A new driver for some PCIe DVBSky cards
- A new remote controller driver: meson-ir
- One LIRC staging driver got rewritten and promoted to mainstream:
igorplugusb
- A new tuner driver (m88rs6000t)
- The old omap2 media driver got removed from staging. This driver
uses an old DMA API and it is likely broken on recent kernels.
Nobody cared enough to fix it
- Media bus format moved to a separate header, as DRM will also use the
definitions there
- mem2mem_testdev were renamed to vim2m, in order to use the same
naming convention taken by the other virtual test driver (vivid)
- Added a new driver for coda SoC (coda-jpeg)
- The cx88 driver got converted to use videobuf2 core
- Make DMABUF export buffer to work with DMA Scatter/Gather and Vmalloc
cores
- Lots of other fixes, improvements and cleanups on the drivers.
* tag 'media/v3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (384 commits)
[media] mn88473: One function call less in mn88473_init() after error
[media] mn88473: Remove uneeded check before release_firmware()
[media] lirc_zilog: Deletion of unnecessary checks before vfree()
[media] MAINTAINERS: Add myself as img-ir maintainer
[media] img-ir: Don't set driver's module owner
[media] img-ir: Depend on METAG or MIPS or COMPILE_TEST
[media] img-ir/hw: Drop [un]register_decoder declarations
[media] img-ir/hw: Fix potential deadlock stopping timer
[media] img-ir/hw: Always read data to clear buffer
[media] redrat3: ensure dma is setup properly
[media] ddbridge: remove unneeded check before dvb_unregister_device()
[media] si2157: One function call less in si2157_init() after error
[media] tuners: remove uneeded checks before release_firmware()
[media] arm: omap2: rx51-peripherals: fix build warning
[media] stv090x: add an extra protetion against buffer overflow
[media] stv090x: Remove an unreachable code
[media] stv090x: Some whitespace cleanups
[media] em28xx: checkpatch cleanup: whitespaces/new lines cleanups
[media] si2168: add support for firmware files in new format
[media] si2168: debug printout for firmware version
...
Diffstat (limited to 'drivers/media/platform/coda')
-rw-r--r-- | drivers/media/platform/coda/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-bit.c | 322 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 607 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-jpeg.c | 238 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda.h | 24 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda_regs.h | 7 |
6 files changed, 862 insertions, 338 deletions
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 3543291e6273..25ce15561695 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,3 @@ -coda-objs := coda-common.o coda-bit.o coda-h264.o +coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9b8ea8bbeb4e..b4029ae293d3 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -217,11 +217,34 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, void coda_fill_bitstream(struct coda_ctx *ctx) { struct vb2_buffer *src_buf; - struct coda_timestamp *ts; + struct coda_buffer_meta *meta; + u32 start; while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { + /* + * Only queue a single JPEG into the bitstream buffer, except + * to increase payload over 512 bytes or if in hold state. + */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && + (coda_get_bitstream_payload(ctx) >= 512) && !ctx->hold) + break; + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + /* Drop frames that do not start/end with a SOI/EOI markers */ + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && + !coda_jpeg_check_buffer(ctx, src_buf)) { + v4l2_err(&ctx->dev->v4l2_dev, + "dropping invalid JPEG frame\n"); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + continue; + } + + /* Buffer start position */ + start = ctx->bitstream_fifo.kfifo.in & + ctx->bitstream_fifo.kfifo.mask; + if (coda_bitstream_try_queue(ctx, src_buf)) { /* * Source buffer is queued in the bitstream ringbuffer; @@ -229,12 +252,16 @@ void coda_fill_bitstream(struct coda_ctx *ctx) */ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - ts = kmalloc(sizeof(*ts), GFP_KERNEL); - if (ts) { - ts->sequence = src_buf->v4l2_buf.sequence; - ts->timecode = src_buf->v4l2_buf.timecode; - ts->timestamp = src_buf->v4l2_buf.timestamp; - list_add_tail(&ts->list, &ctx->timestamp_list); + meta = kmalloc(sizeof(*meta), GFP_KERNEL); + if (meta) { + meta->sequence = src_buf->v4l2_buf.sequence; + meta->timecode = src_buf->v4l2_buf.timecode; + meta->timestamp = src_buf->v4l2_buf.timestamp; + meta->start = start; + meta->end = ctx->bitstream_fifo.kfifo.in & + ctx->bitstream_fifo.kfifo.mask; + list_add_tail(&meta->list, + &ctx->buffer_meta_list); } v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); @@ -691,6 +718,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) struct vb2_buffer *buf; int gamma, ret, value; u32 dst_fourcc; + u32 stride; q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); @@ -710,6 +738,14 @@ static int coda_start_encoding(struct coda_ctx *ctx) return -EFAULT; } + if (dst_fourcc == V4L2_PIX_FMT_JPEG) { + if (!ctx->params.jpeg_qmat_tab[0]) + ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); + if (!ctx->params.jpeg_qmat_tab[1]) + ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); + coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); + } + mutex_lock(&dev->coda_mutex); coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); @@ -729,10 +765,10 @@ static int coda_start_encoding(struct coda_ctx *ctx) break; } - value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL); - value &= ~(1 << 2 | 0x7 << 9); - ctx->frame_mem_ctrl = value; - coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL); + ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); if (dev->devtype->product == CODA_DX6) { /* Configure the coda */ @@ -741,6 +777,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) } /* Could set rotation here if needed */ + value = 0; switch (dev->devtype->product) { case CODA_DX6: value = (q_data_src->width & CODADX6_PICWIDTH_MASK) @@ -764,6 +801,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) << CODA_PICHEIGHT_OFFSET; } coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); + if (dst_fourcc == V4L2_PIX_FMT_JPEG) + ctx->params.framerate = 0; coda_write(dev, ctx->params.framerate, CODA_CMD_ENC_SEQ_SRC_F_RATE); @@ -797,6 +836,16 @@ static int coda_start_encoding(struct coda_ctx *ctx) } coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); break; + case V4L2_PIX_FMT_JPEG: + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); + coda_write(dev, ctx->params.jpeg_restart_interval, + CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); + coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); + + coda_jpeg_write_tables(ctx); + break; default: v4l2_err(v4l2_dev, "dst format (0x%08x) invalid.\n", dst_fourcc); @@ -804,28 +853,36 @@ static int coda_start_encoding(struct coda_ctx *ctx) goto out; } - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; + /* + * slice mode and GOP size registers are used for thumb size/offset + * in JPEG mode + */ + if (dst_fourcc != V4L2_PIX_FMT_JPEG) { + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + value = 0; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + value = (ctx->params.slice_max_mb & + CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (1 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + value = (ctx->params.slice_max_bits & + CODA_SLICING_SIZE_MASK) + << CODA_SLICING_SIZE_OFFSET; + value |= (0 & CODA_SLICING_UNIT_MASK) + << CODA_SLICING_UNIT_OFFSET; + value |= 1 & CODA_SLICING_MODE_MASK; + break; + } + coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); + value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; + coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); } - coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); - value = ctx->params.gop_size & CODA_GOP_SIZE_MASK; - coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); if (ctx->params.bitrate) { /* Rate control enabled */ @@ -916,19 +973,24 @@ static int coda_start_encoding(struct coda_ctx *ctx) goto out; } - if (dev->devtype->product == CODA_960) - ctx->num_internal_frames = 4; - else - ctx->num_internal_frames = 2; - ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); - if (ret < 0) { - v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); - goto out; + if (dst_fourcc != V4L2_PIX_FMT_JPEG) { + if (dev->devtype->product == CODA_960) + ctx->num_internal_frames = 4; + else + ctx->num_internal_frames = 2; + ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); + if (ret < 0) { + v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); + goto out; + } + stride = q_data_src->bytesperline; + } else { + ctx->num_internal_frames = 0; + stride = 0; } - coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, q_data_src->bytesperline, - CODA_CMD_SET_FRAME_BUF_STRIDE); + coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); + if (dev->devtype->product == CODA_7541) { coda_write(dev, q_data_src->bytesperline, CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); @@ -1036,9 +1098,10 @@ static int coda_prepare_encode(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; int force_ipicture; int quant_param = 0; - u32 picture_y, picture_cb, picture_cr; u32 pic_stream_buffer_addr, pic_stream_buffer_size; + u32 rot_mode = 0; u32 dst_fourcc; + u32 reg; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1076,7 +1139,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx) ctx->vpu_header_size[0] + ctx->vpu_header_size[1] + ctx->vpu_header_size[2]; - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE - + pic_stream_buffer_size = q_data_dst->sizeimage - ctx->vpu_header_size[0] - ctx->vpu_header_size[1] - ctx->vpu_header_size[2]; @@ -1090,7 +1153,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx) } else { pic_stream_buffer_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - pic_stream_buffer_size = CODA_MAX_FRAME_SIZE; + pic_stream_buffer_size = q_data_dst->sizeimage; } if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) { @@ -1102,6 +1165,9 @@ static int coda_prepare_encode(struct coda_ctx *ctx) case V4L2_PIX_FMT_MPEG4: quant_param = ctx->params.mpeg4_intra_qp; break; + case V4L2_PIX_FMT_JPEG: + quant_param = 30; + break; default: v4l2_warn(&ctx->dev->v4l2_dev, "cannot set intra qp, fmt not supported\n"); @@ -1124,42 +1190,22 @@ static int coda_prepare_encode(struct coda_ctx *ctx) } /* submit */ - coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, - CODA_CMD_ENC_PIC_ROT_MODE); + if (ctx->params.rot_mode) + rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; + coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); - - picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0); - switch (q_data_src->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - picture_cr = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cb = picture_cr + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - case V4L2_PIX_FMT_YUV420: - default: - picture_cb = picture_y + q_data_src->bytesperline * - q_data_src->height; - picture_cr = picture_cb + q_data_src->bytesperline / 2 * - q_data_src->height / 2; - break; - } - if (dev->devtype->product == CODA_960) { coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE); coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); - coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR); + reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; } else { - coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR); + reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; } + coda_write_base(ctx, q_data_src, src_buf, reg); + coda_write(dev, force_ipicture << 1 & 0x2, CODA_CMD_ENC_PIC_OPTION); @@ -1293,7 +1339,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 bitstream_buf, bitstream_size; struct coda_dev *dev = ctx->dev; int width, height; - u32 src_fourcc; + u32 src_fourcc, dst_fourcc; u32 val; int ret; @@ -1303,6 +1349,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) bitstream_buf = ctx->bitstream.paddr; bitstream_size = ctx->bitstream.size; src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; /* Allocate per-instance buffers */ ret = coda_alloc_context_buffers(ctx, q_data_src); @@ -1314,6 +1361,11 @@ static int __coda_start_decoding(struct coda_ctx *ctx) /* Update coda bitstream read and write pointers from kfifo */ coda_kfifo_sync_to_device_full(ctx); + ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + if (dst_fourcc == V4L2_PIX_FMT_NV12) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); + ctx->display_idx = -1; ctx->frm_dis_flg = 0; coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); @@ -1327,6 +1379,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) if ((dev->devtype->product == CODA_7541) || (dev->devtype->product == CODA_960)) val |= CODA_REORDER_ENABLE; + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) + val |= CODA_NO_INT_ENABLE; coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); ctx->params.codec_mode = ctx->codec->mode; @@ -1442,13 +1496,23 @@ static int __coda_start_decoding(struct coda_ctx *ctx) } if (dev->devtype->product == CODA_960) { - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + int cbb_size, crb_size; + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); + + if (dst_fourcc == V4L2_PIX_FMT_NV12) { + cbb_size = 0; + crb_size = 16; + } else { + cbb_size = 8; + crb_size = 8; + } coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, + cbb_size << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | + crb_size << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, CODA9_CMD_SET_FRAME_CACHE_CONFIG); } @@ -1501,20 +1565,11 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct vb2_buffer *dst_buf; struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; - u32 stridey, height; - u32 picture_y, picture_cb, picture_cr; + u32 reg_addr, reg_stride; dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (ctx->params.rot_mode & CODA_ROT_90) { - stridey = q_data_dst->height; - height = q_data_dst->width; - } else { - stridey = q_data_dst->width; - height = q_data_dst->height; - } - /* Try to copy source buffer contents into the bitstream ringbuffer */ mutex_lock(&ctx->bitstream_mutex); coda_fill_bitstream(ctx); @@ -1545,17 +1600,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) if (dev->devtype->product == CODA_960) coda_set_gdi_regs(ctx); - /* Set rotator output */ - picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) { - /* Switch Cr and Cb for YVU420 format */ - picture_cr = picture_y + stridey * height; - picture_cb = picture_cr + stridey / 2 * height / 2; - } else { - picture_cb = picture_y + stridey * height; - picture_cr = picture_cb + stridey / 2 * height / 2; - } - if (dev->devtype->product == CODA_960) { /* * The CODA960 seems to have an internal list of buffers with @@ -1565,16 +1609,16 @@ static int coda_prepare_decode(struct coda_ctx *ctx) */ coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index, CODA9_CMD_DEC_PIC_ROT_INDEX); - coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE); + + reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; + reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; } else { - coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y); - coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB); - coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR); - coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE); + reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; + reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; } + coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); + coda_write(dev, q_data_dst->bytesperline, reg_stride); + coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); @@ -1599,6 +1643,26 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); + if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { + struct coda_buffer_meta *meta; + + /* If this is the last buffer in the bitstream, add padding */ + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + if (meta->end == (ctx->bitstream_fifo.kfifo.in & + ctx->bitstream_fifo.kfifo.mask)) { + static unsigned char buf[512]; + unsigned int pad; + + /* Pad to multiple of 256 and then add 256 more */ + pad = ((0 - meta->end) & 0xff) + 256; + + memset(buf, 0xff, sizeof(buf)); + + kfifo_in(&ctx->bitstream_fifo, buf, pad); + } + } + coda_kfifo_sync_to_device_full(ctx); coda_command_async(ctx, CODA_COMMAND_PIC_RUN); @@ -1612,7 +1676,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct coda_q_data *q_data_src; struct coda_q_data *q_data_dst; struct vb2_buffer *dst_buf; - struct coda_timestamp *ts; + struct coda_buffer_meta *meta; + unsigned long payload; int width, height; int decoded_idx; int display_idx; @@ -1739,23 +1804,23 @@ static void coda_finish_decode(struct coda_ctx *ctx) val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; mutex_lock(&ctx->bitstream_mutex); - if (!list_empty(&ctx->timestamp_list)) { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - if (val != (ts->sequence & 0xffff)) { + if (!list_empty(&ctx->buffer_meta_list)) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + list_del(&meta->list); + if (val != (meta->sequence & 0xffff)) { v4l2_err(&dev->v4l2_dev, "sequence number mismatch (%d(%d) != %d)\n", val, ctx->sequence_offset, - ts->sequence); + meta->sequence); } - ctx->frame_timestamps[decoded_idx] = *ts; - kfree(ts); + ctx->frame_metas[decoded_idx] = *meta; + kfree(meta); } else { v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); - memset(&ctx->frame_timestamps[decoded_idx], 0, - sizeof(struct coda_timestamp)); - ctx->frame_timestamps[decoded_idx].sequence = val; + memset(&ctx->frame_metas[decoded_idx], 0, + sizeof(struct coda_buffer_meta)); + ctx->frame_metas[decoded_idx].sequence = val; } mutex_unlock(&ctx->bitstream_mutex); @@ -1794,11 +1859,22 @@ static void coda_finish_decode(struct coda_ctx *ctx) V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx]; - ts = &ctx->frame_timestamps[ctx->display_idx]; - dst_buf->v4l2_buf.timecode = ts->timecode; - dst_buf->v4l2_buf.timestamp = ts->timestamp; - - vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2); + meta = &ctx->frame_metas[ctx->display_idx]; + dst_buf->v4l2_buf.timecode = meta->timecode; + dst_buf->v4l2_buf.timestamp = meta->timestamp; + + switch (q_data_dst->fourcc) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + default: + payload = width * height * 3 / 2; + break; + case V4L2_PIX_FMT_YUV422P: + payload = width * height * 2; + break; + } + vb2_set_plane_payload(dst_buf, 0, payload); v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 5f0cd5cafea2..90b7791d36e1 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -43,6 +43,7 @@ #define CODA_NAME "coda" #define CODADX6_MAX_INSTANCES 4 +#define CODA_MAX_FORMATS 4 #define CODA_PARA_BUF_SIZE (10 * 1024) #define CODA_ISRAM_SIZE (2048 * 2) @@ -82,6 +83,34 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) return data; } +void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, + struct vb2_buffer *buf, unsigned int reg_y) +{ + u32 base_y = vb2_dma_contig_plane_dma_addr(buf, 0); + u32 base_cb, base_cr; + + switch (q_data->fourcc) { + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + base_cr = base_y + q_data->bytesperline * q_data->height; + base_cb = base_cr + q_data->bytesperline * q_data->height / 4; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_NV12: + default: + base_cb = base_y + q_data->bytesperline * q_data->height; + base_cr = base_cb + q_data->bytesperline * q_data->height / 4; + break; + case V4L2_PIX_FMT_YUV422P: + base_cb = base_y + q_data->bytesperline * q_data->height; + base_cr = base_cb + q_data->bytesperline * q_data->height / 2; + } + + coda_write(ctx->dev, base_y, reg_y); + coda_write(ctx->dev, base_cb, reg_y + 4); + coda_write(ctx->dev, base_cr, reg_y + 8); +} + /* * Array of all formats supported by any version of Coda: */ @@ -95,6 +124,14 @@ static const struct coda_fmt coda_formats[] = { .fourcc = V4L2_PIX_FMT_YVU420, }, { + .name = "YUV 4:2:0 Partial interleaved Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12, + }, + { + .name = "YUV 4:2:2 Planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV422P, + }, + { .name = "H264 Encoded Stream", .fourcc = V4L2_PIX_FMT_H264, }, @@ -102,6 +139,10 @@ static const struct coda_fmt coda_formats[] = { .name = "MPEG4 Encoded Stream", .fourcc = V4L2_PIX_FMT_MPEG4, }, + { + .name = "JPEG Encoded Images", + .fourcc = V4L2_PIX_FMT_JPEG, + }, }; #define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ @@ -122,8 +163,10 @@ static const struct coda_codec codadx6_codecs[] = { static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), + CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), }; static const struct coda_codec coda9_codecs[] = { @@ -133,17 +176,115 @@ static const struct coda_codec coda9_codecs[] = { CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; +struct coda_video_device { + const char *name; + enum coda_inst_type type; + const struct coda_context_ops *ops; + u32 src_formats[CODA_MAX_FORMATS]; + u32 dst_formats[CODA_MAX_FORMATS]; +}; + +static const struct coda_video_device coda_bit_encoder = { + .name = "coda-encoder", + .type = CODA_INST_ENCODER, + .ops = &coda_bit_encode_ops, + .src_formats = { + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_NV12, + }, + .dst_formats = { + V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_MPEG4, + }, +}; + +static const struct coda_video_device coda_bit_jpeg_encoder = { + .name = "coda-jpeg-encoder", + .type = CODA_INST_ENCODER, + .ops = &coda_bit_encode_ops, + .src_formats = { + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV422P, + }, + .dst_formats = { + V4L2_PIX_FMT_JPEG, + }, +}; + +static const struct coda_video_device coda_bit_decoder = { + .name = "coda-decoder", + .type = CODA_INST_DECODER, + .ops = &coda_bit_decode_ops, + .src_formats = { + V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_MPEG4, + }, + .dst_formats = { + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_NV12, + }, +}; + +static const struct coda_video_device coda_bit_jpeg_decoder = { + .name = "coda-jpeg-decoder", + .type = CODA_INST_DECODER, + .ops = &coda_bit_decode_ops, + .src_formats = { + V4L2_PIX_FMT_JPEG, + }, + .dst_formats = { + V4L2_PIX_FMT_YUV420, + V4L2_PIX_FMT_YVU420, + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_YUV422P, + }, +}; + +static const struct coda_video_device *codadx6_video_devices[] = { + &coda_bit_encoder, +}; + +static const struct coda_video_device *coda7_video_devices[] = { + &coda_bit_jpeg_encoder, + &coda_bit_jpeg_decoder, + &coda_bit_encoder, + &coda_bit_decoder, +}; + +static const struct coda_video_device *coda9_video_devices[] = { + &coda_bit_encoder, + &coda_bit_decoder, +}; + static bool coda_format_is_yuv(u32 fourcc) { switch (fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV422P: return true; default: return false; } } +static const char *coda_format_name(u32 fourcc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coda_formats); i++) { + if (coda_formats[i].fourcc == fourcc) + return coda_formats[i].name; + } + + return NULL; +} + /* * Normalize all supported YUV 4:2:0 formats to the value used in the codec * tables. @@ -202,6 +343,17 @@ static void coda_get_max_dimensions(struct coda_dev *dev, *max_h = h; } +const struct coda_video_device *to_coda_video_device(struct video_device *vdev) +{ + struct coda_dev *dev = video_get_drvdata(vdev); + unsigned int i = vdev - dev->vfd; + + if (i >= dev->devtype->num_vdevs) + return NULL; + + return dev->devtype->vdevs[i]; +} + const char *coda_product_name(int product) { static char buf[9]; @@ -240,58 +392,28 @@ static int coda_querycap(struct file *file, void *priv, static int coda_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codecs = ctx->dev->devtype->codecs; - const struct coda_fmt *formats = coda_formats; - const struct coda_fmt *fmt; - int num_codecs = ctx->dev->devtype->num_codecs; - int num_formats = ARRAY_SIZE(coda_formats); - int i, k, num = 0; - bool yuv; - - if (ctx->inst_type == CODA_INST_ENCODER) - yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); + struct video_device *vdev = video_devdata(file); + const struct coda_video_device *cvd = to_coda_video_device(vdev); + const u32 *formats; + const char *name; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + formats = cvd->src_formats; + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + formats = cvd->dst_formats; else - yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE); - - for (i = 0; i < num_formats; i++) { - /* Skip either raw or compressed formats */ - if (yuv != coda_format_is_yuv(formats[i].fourcc)) - continue; - /* All uncompressed formats are always supported */ - if (yuv) { - if (num == f->index) - break; - ++num; - continue; - } - /* Compressed formats may be supported, check the codec list */ - for (k = 0; k < num_codecs; k++) { - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && - formats[i].fourcc == codecs[k].dst_fourcc) - break; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - formats[i].fourcc == codecs[k].src_fourcc) - break; - } - if (k < num_codecs) { - if (num == f->index) - break; - ++num; - } - } + return -EINVAL; - if (i < num_formats) { - fmt = &formats[i]; - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; - if (!yuv) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; - return 0; - } + if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) + return -EINVAL; + + name = coda_format_name(formats[f->index]); + strlcpy(f->description, name, sizeof(f->description)); + f->pixelformat = formats[f->index]; + if (!coda_format_is_yuv(formats[f->index])) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; - /* Format not found */ - return -EINVAL; + return 0; } static int coda_g_fmt(struct file *file, void *priv, @@ -311,7 +433,37 @@ static int coda_g_fmt(struct file *file, void *priv, f->fmt.pix.bytesperline = q_data->bytesperline; f->fmt.pix.sizeimage = q_data->sizeimage; - f->fmt.pix.colorspace = ctx->colorspace; + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + else + f->fmt.pix.colorspace = ctx->colorspace; + + return 0; +} + +static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) +{ + struct coda_q_data *q_data; + const u32 *formats; + int i; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + formats = ctx->cvd->src_formats; + else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + formats = ctx->cvd->dst_formats; + else + return -EINVAL; + + for (i = 0; i < CODA_MAX_FORMATS; i++) { + if (formats[i] == f->fmt.pix.pixelformat) { + f->fmt.pix.pixelformat = formats[i]; + return 0; + } + } + + /* Fall back to currently set pixelformat */ + q_data = get_q_data(ctx, f->type); + f->fmt.pix.pixelformat = q_data->fourcc; return 0; } @@ -320,7 +472,6 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, struct v4l2_format *f) { struct coda_dev *dev = ctx->dev; - struct coda_q_data *q_data; unsigned int max_w, max_h; enum v4l2_field field; @@ -342,30 +493,35 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_H264: - case V4L2_PIX_FMT_MPEG4: - case V4L2_PIX_FMT_JPEG: - break; - default: - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - f->fmt.pix.pixelformat = q_data->fourcc; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - /* Frame stride must be multiple of 8, but 16 for h.264 */ + case V4L2_PIX_FMT_NV12: + /* + * Frame stride must be at least multiple of 8, + * but multiple of 16 for h.264 or JPEG 4:2:x + */ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height * 3 / 2; break; + case V4L2_PIX_FMT_YUV422P: + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height * 2; + break; + case V4L2_PIX_FMT_JPEG: + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + /* fallthrough */ case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_MPEG4: - case V4L2_PIX_FMT_JPEG: f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE; + /* + * This is a rough estimate for sensible compressed buffer + * sizes (between 1 and 16 bits per pixel). This could be + * improved by better format specific worst case estimates. + */ + f->fmt.pix.sizeimage = round_up(clamp(f->fmt.pix.sizeimage, + f->fmt.pix.width * f->fmt.pix.height / 8, + f->fmt.pix.width * f->fmt.pix.height * 2), + PAGE_SIZE); break; default: BUG(); @@ -378,34 +534,35 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec = NULL; + const struct coda_q_data *q_data_src; + const struct coda_codec *codec; struct vb2_queue *src_vq; int ret; + ret = coda_try_pixelformat(ctx, f); + if (ret < 0) + return ret; + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + /* - * If the source format is already fixed, try to find a codec that - * converts to the given destination format + * If the source format is already fixed, only allow the same output + * resolution */ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (vb2_is_streaming(src_vq)) { - struct coda_q_data *q_data_src; - - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - f->fmt.pix.pixelformat); - if (!codec) - return -EINVAL; - f->fmt.pix.width = q_data_src->width; f->fmt.pix.height = q_data_src->height; - } else { - /* Otherwise determine codec by encoded format, if possible */ - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, - f->fmt.pix.pixelformat); } f->fmt.pix.colorspace = ctx->colorspace; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) + return -EINVAL; + ret = coda_try_fmt(ctx, codec, f); if (ret < 0) return ret; @@ -426,21 +583,24 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); - const struct coda_codec *codec = NULL; + struct coda_dev *dev = ctx->dev; + const struct coda_q_data *q_data_dst; + const struct coda_codec *codec; + int ret; - /* Determine codec by encoded format, returns NULL if raw or invalid */ - if (ctx->inst_type == CODA_INST_DECODER) { - codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, - V4L2_PIX_FMT_YUV420); - if (!codec) - codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264, - V4L2_PIX_FMT_YUV420); - if (!codec) - return -EINVAL; + ret = coda_try_pixelformat(ctx, f); + if (ret < 0) + return ret; + + if (!f->fmt.pix.colorspace) { + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + else + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; } - if (!f->fmt.pix.colorspace) - f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc); return coda_try_fmt(ctx, codec, f); } @@ -781,6 +941,7 @@ static int coda_job_ready(void *m2m_priv) if (ctx->hold || ((ctx->inst_type == CODA_INST_DECODER) && + !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && (coda_get_bitstream_payload(ctx) < 512) && !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, @@ -862,25 +1023,17 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) static void set_default_params(struct coda_ctx *ctx) { - u32 src_fourcc, dst_fourcc; - int max_w; - int max_h; + unsigned int max_w, max_h, size; - if (ctx->inst_type == CODA_INST_ENCODER) { - src_fourcc = V4L2_PIX_FMT_YUV420; - dst_fourcc = V4L2_PIX_FMT_H264; - } else { - src_fourcc = V4L2_PIX_FMT_H264; - dst_fourcc = V4L2_PIX_FMT_YUV420; - } - ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc); - max_w = ctx->codec->max_w; - max_h = ctx->codec->max_h; + ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], + ctx->cvd->dst_formats[0]); + max_w = min(ctx->codec->max_w, 1920U); + max_h = min(ctx->codec->max_h, 1088U); + size = max_w * max_h * 3 / 2; ctx->params.codec_mode = ctx->codec->mode; ctx->colorspace = V4L2_COLORSPACE_REC709; ctx->params.framerate = 30; - ctx->aborting = 0; /* Default formats for output and input queues */ ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; @@ -891,14 +1044,14 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].height = max_h; if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; - ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2; + ctx->q_data[V4L2_M2M_SRC].sizeimage = size; ctx->q_data[V4L2_M2M_DST].bytesperline = 0; - ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_SIZE); } else { ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; - ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE; + ctx->q_data[V4L2_M2M_SRC].sizeimage = round_up(size, PAGE_SIZE); ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; - ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2; + ctx->q_data[V4L2_M2M_DST].sizeimage = size; } ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; @@ -964,7 +1117,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) * In the decoder case, immediately try to copy the buffer into the * bitstream ringbuffer and mark it as ready to be dequeued. */ - if (q_data->fourcc == V4L2_PIX_FMT_H264 && + if (ctx->inst_type == CODA_INST_DECODER && vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* * For backwards compatibility, queuing an empty buffer marks @@ -1027,12 +1180,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; struct coda_q_data *q_data_src, *q_data_dst; struct vb2_buffer *buf; - u32 dst_fourcc; int ret = 0; q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264) { + if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || + (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_7541)) { /* copy the buffers that where queued before streamon */ mutex_lock(&ctx->bitstream_mutex); coda_fill_bitstream(ctx); @@ -1063,13 +1217,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (!(ctx->streamon_out & ctx->streamon_cap)) return 0; - /* Allow decoder device_run with no new buffers queued */ + /* Allow BIT decoder device_run with no new buffers queued */ if (ctx->inst_type == CODA_INST_DECODER) v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); ctx->gopcounter = ctx->params.gop_size - 1; q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_fourcc = q_data_dst->fourcc; ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, q_data_dst->fourcc); @@ -1079,6 +1232,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) goto err; } + if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) + ctx->params.gop_size = 1; + ctx->gopcounter = ctx->params.gop_size - 1; + ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { if (ret == -EAGAIN) @@ -1093,10 +1250,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) err: if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); } else { while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) - v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED); + v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); } return ret; } @@ -1131,19 +1288,20 @@ static void coda_stop_streaming(struct vb2_queue *q) } if (!ctx->streamon_out && !ctx->streamon_cap) { - struct coda_timestamp *ts; + struct coda_buffer_meta *meta; mutex_lock(&ctx->bitstream_mutex); - while (!list_empty(&ctx->timestamp_list)) { - ts = list_first_entry(&ctx->timestamp_list, - struct coda_timestamp, list); - list_del(&ts->list); - kfree(ts); + while (!list_empty(&ctx->buffer_meta_list)) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + list_del(&meta->list); + kfree(meta); } mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; + ctx->aborting = 0; } } @@ -1226,6 +1384,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: ctx->params.intra_refresh = ctrl->val; break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + coda_set_jpeg_compression_quality(ctx, ctrl->val); + break; + case V4L2_CID_JPEG_RESTART_INTERVAL: + ctx->params.jpeg_restart_interval = ctrl->val; + break; default: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", @@ -1240,14 +1404,8 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = { .s_ctrl = coda_s_ctrl, }; -static int coda_ctrls_setup(struct coda_ctx *ctx) +static void coda_encode_ctrls(struct coda_ctx *ctx) { - v4l2_ctrl_handler_init(&ctx->ctrls, 9); - - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, @@ -1291,6 +1449,30 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); +} + +static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) +{ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0); +} + +static int coda_ctrls_setup(struct coda_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrls, 2); + + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (ctx->inst_type == CODA_INST_ENCODER) { + if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) + coda_jpeg_encode_ctrls(ctx); + else + coda_encode_ctrls(ctx); + } if (ctx->ctrls.error) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1364,10 +1546,14 @@ static int coda_next_free_instance(struct coda_dev *dev) return idx; } -static int coda_open(struct file *file, enum coda_inst_type inst_type, - const struct coda_context_ops *ctx_ops) +/* + * File operations + */ + +static int coda_open(struct file *file) { - struct coda_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + struct coda_dev *dev = video_get_drvdata(vdev); struct coda_ctx *ctx = NULL; char *name; int ret; @@ -1388,8 +1574,9 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); kfree(name); - ctx->inst_type = inst_type; - ctx->ops = ctx_ops; + ctx->cvd = to_coda_video_device(vdev); + ctx->inst_type = ctx->cvd->type; + ctx->ops = ctx->cvd->ops; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); @@ -1399,8 +1586,10 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->dev = dev; ctx->idx = idx; switch (dev->devtype->product) { - case CODA_7541: case CODA_960: + ctx->frame_mem_ctrl = 1 << 12; + /* fallthrough */ + case CODA_7541: ctx->reg_idx = 0; break; default: @@ -1441,16 +1630,17 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->fh.ctrl_handler = &ctx->ctrls; - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE, - "parabuf"); + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, + CODA_PARA_BUF_SIZE, "parabuf"); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); goto err_dma_alloc; } ctx->bitstream.size = CODA_MAX_FRAME_SIZE; - ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev, - ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); + ctx->bitstream.vaddr = dma_alloc_writecombine( + &dev->plat_dev->dev, ctx->bitstream.size, + &ctx->bitstream.paddr, GFP_KERNEL); if (!ctx->bitstream.vaddr) { v4l2_err(&dev->v4l2_dev, "failed to allocate bitstream ringbuffer"); @@ -1461,7 +1651,7 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type, ctx->bitstream.vaddr, ctx->bitstream.size); mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); - INIT_LIST_HEAD(&ctx->timestamp_list); + INIT_LIST_HEAD(&ctx->buffer_meta_list); coda_lock(ctx); list_add(&ctx->list, &dev->instances); @@ -1495,16 +1685,6 @@ err_coda_max: return ret; } -static int coda_encoder_open(struct file *file) -{ - return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops); -} - -static int coda_decoder_open(struct file *file) -{ - return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops); -} - static int coda_release(struct file *file) { struct coda_dev *dev = video_drvdata(file); @@ -1515,6 +1695,9 @@ static int coda_release(struct file *file) debugfs_remove_recursive(ctx->debugfs_entry); + if (ctx->inst_type == CODA_INST_DECODER) + coda_bit_stream_end_flag(ctx); + /* If this instance is running, call .job_abort and wait for it to end */ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); @@ -1528,8 +1711,10 @@ static int coda_release(struct file *file) list_del(&ctx->list); coda_unlock(ctx); - dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, - ctx->bitstream.vaddr, ctx->bitstream.paddr); + if (ctx->bitstream.vaddr) { + dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, + ctx->bitstream.vaddr, ctx->bitstream.paddr); + } if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); @@ -1548,18 +1733,9 @@ static int coda_release(struct file *file) return 0; } -static const struct v4l2_file_operations coda_encoder_fops = { - .owner = THIS_MODULE, - .open = coda_encoder_open, - .release = coda_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct v4l2_file_operations coda_decoder_fops = { +static const struct v4l2_file_operations coda_fops = { .owner = THIS_MODULE, - .open = coda_decoder_open, + .open = coda_open, .release = coda_release, .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, @@ -1664,8 +1840,16 @@ err_clk_per: return ret; } -static int coda_register_device(struct coda_dev *dev, struct video_device *vfd) +static int coda_register_device(struct coda_dev *dev, int i) { + struct video_device *vfd = &dev->vfd[i]; + + if (i > ARRAY_SIZE(dev->vfd)) + return -EINVAL; + + snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name); + vfd->fops = &coda_fops; + vfd->ioctl_ops = &coda_ioctl_ops; vfd->release = video_device_release_empty, vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; @@ -1684,7 +1868,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) { struct coda_dev *dev = context; struct platform_device *pdev = dev->plat_dev; - int ret; + int i, ret; if (!fw) { v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); @@ -1725,33 +1909,25 @@ static void coda_fw_callback(const struct firmware *fw, void *context) goto rel_ctx; } - dev->vfd[0].fops = &coda_encoder_fops, - dev->vfd[0].ioctl_ops = &coda_ioctl_ops; - snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder"); - ret = coda_register_device(dev, &dev->vfd[0]); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to register encoder video device\n"); - goto rel_m2m; - } - - dev->vfd[1].fops = &coda_decoder_fops, - dev->vfd[1].ioctl_ops = &coda_ioctl_ops; - snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder"); - ret = coda_register_device(dev, &dev->vfd[1]); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to register decoder video device\n"); - goto rel_m2m; + for (i = 0; i < dev->devtype->num_vdevs; i++) { + ret = coda_register_device(dev, i); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to register %s video device: %d\n", + dev->devtype->vdevs[i]->name, ret); + goto rel_vfd; + } } v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", - dev->vfd[0].num, dev->vfd[1].num); + dev->vfd[0].num, dev->vfd[i - 1].num); pm_runtime_put_sync(&pdev->dev); return; -rel_m2m: +rel_vfd: + while (--i >= 0) + video_unregister_device(&dev->vfd[i]); v4l2_m2m_release(dev->m2m_dev); rel_ctx: vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); @@ -1783,6 +1959,8 @@ static const struct coda_devtype coda_devdata[] = { .product = CODA_DX6, .codecs = codadx6_codecs, .num_codecs = ARRAY_SIZE(codadx6_codecs), + .vdevs = codadx6_video_devices, + .num_vdevs = ARRAY_SIZE(codadx6_video_devices), .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, .iram_size = 0xb000, }, @@ -1791,6 +1969,8 @@ static const struct coda_devtype coda_devdata[] = { .product = CODA_7541, .codecs = coda7_codecs, .num_codecs = ARRAY_SIZE(coda7_codecs), + .vdevs = coda7_video_devices, + .num_vdevs = ARRAY_SIZE(coda7_video_devices), .workbuf_size = 128 * 1024, .tempbuf_size = 304 * 1024, .iram_size = 0x14000, @@ -1800,6 +1980,8 @@ static const struct coda_devtype coda_devdata[] = { .product = CODA_960, .codecs = coda9_codecs, .num_codecs = ARRAY_SIZE(coda9_codecs), + .vdevs = coda9_video_devices, + .num_vdevs = ARRAY_SIZE(coda9_video_devices), .workbuf_size = 80 * 1024, .tempbuf_size = 204 * 1024, .iram_size = 0x21000, @@ -1809,6 +1991,8 @@ static const struct coda_devtype coda_devdata[] = { .product = CODA_960, .codecs = coda9_codecs, .num_codecs = ARRAY_SIZE(coda9_codecs), + .vdevs = coda9_video_devices, + .num_vdevs = ARRAY_SIZE(coda9_video_devices), .workbuf_size = 80 * 1024, .tempbuf_size = 204 * 1024, .iram_size = 0x20000, @@ -1846,10 +2030,18 @@ static int coda_probe(struct platform_device *pdev) int ret, irq; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Not enough memory for %s\n", - CODA_NAME); + if (!dev) return -ENOMEM; + + pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); + + if (of_id) { + dev->devtype = of_id->data; + } else if (pdev_id) { + dev->devtype = &coda_devdata[pdev_id->driver_data]; + } else { + ret = -EINVAL; + goto err_v4l2_register; } spin_lock_init(&dev->irqlock); @@ -1919,17 +2111,6 @@ static int coda_probe(struct platform_device *pdev) mutex_init(&dev->dev_mutex); mutex_init(&dev->coda_mutex); - pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); - - if (of_id) { - dev->devtype = of_id->data; - } else if (pdev_id) { - dev->devtype = &coda_devdata[pdev_id->driver_data]; - } else { - v4l2_device_unregister(&dev->v4l2_dev); - return -EINVAL; - } - dev->debugfs_root = debugfs_create_dir("coda", NULL); if (!dev->debugfs_root) dev_warn(&pdev->dev, "failed to create debugfs root\n"); @@ -1941,8 +2122,7 @@ static int coda_probe(struct platform_device *pdev) dev->debugfs_root); if (ret < 0) { dev_err(&pdev->dev, "failed to allocate work buffer\n"); - v4l2_device_unregister(&dev->v4l2_dev); - return ret; + goto err_v4l2_register; } } @@ -1952,8 +2132,7 @@ static int coda_probe(struct platform_device *pdev) dev->debugfs_root); if (ret < 0) { dev_err(&pdev->dev, "failed to allocate temp buffer\n"); - v4l2_device_unregister(&dev->v4l2_dev); - return ret; + goto err_v4l2_register; } } @@ -1973,7 +2152,8 @@ static int coda_probe(struct platform_device *pdev) dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); if (!dev->workqueue) { dev_err(&pdev->dev, "unable to alloc workqueue\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_v4l2_register; } platform_set_drvdata(pdev, dev); @@ -1988,14 +2168,21 @@ static int coda_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); return coda_firmware_request(dev); + +err_v4l2_register: + v4l2_device_unregister(&dev->v4l2_dev); + return ret; } static int coda_remove(struct platform_device *pdev) { struct coda_dev *dev = platform_get_drvdata(pdev); + int i; - video_unregister_device(&dev->vfd[0]); - video_unregister_device(&dev->vfd[1]); + for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) { + if (video_get_drvdata(&dev->vfd[i])) + video_unregister_device(&dev->vfd[i]); + } if (dev->m2m_dev) v4l2_m2m_release(dev->m2m_dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c new file mode 100644 index 000000000000..8fa3e353f9e2 --- /dev/null +++ b/drivers/media/platform/coda/coda-jpeg.c @@ -0,0 +1,238 @@ +/* + * Coda multi-standard codec IP - JPEG support functions + * + * Copyright (C) 2014 Philipp Zabel, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/swab.h> + +#include "coda.h" + +#define SOI_MARKER 0xffd8 +#define EOI_MARKER 0xffd9 + +/* + * Typical Huffman tables for 8-bit precision luminance and + * chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3 + */ + +static const unsigned char luma_dc_bits[16] = { + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char luma_dc_value[12] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char chroma_dc_bits[16] = { + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char chroma_dc_value[12] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char luma_ac_bits[16] = { + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, +}; + +static const unsigned char luma_ac_value[162 + 2] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, /* padded to 32-bit */ +}; + +static const unsigned char chroma_ac_bits[16] = { + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, +}; + +static const unsigned char chroma_ac_value[162 + 2] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, /* padded to 32-bit */ +}; + +/* + * Quantization tables for luminance and chrominance components in + * zig-zag scan order from the Freescale i.MX VPU libaries + */ + +static unsigned char luma_q[64] = { + 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05, + 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b, + 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, 0x0a, + 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, +}; + +static unsigned char chroma_q[64] = { + 0x07, 0x07, 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10, + 0x10, 0x18, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14, + 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, +}; + +struct coda_memcpy_desc { + int offset; + const void *src; + size_t len; +}; + +static void coda_memcpy_parabuf(void *parabuf, + const struct coda_memcpy_desc *desc) +{ + u32 *dst = parabuf + desc->offset; + const u32 *src = desc->src; + int len = desc->len / 4; + int i; + + for (i = 0; i < len; i += 2) { + dst[i + 1] = swab32(src[i]); + dst[i] = swab32(src[i + 1]); + } +} + +int coda_jpeg_write_tables(struct coda_ctx *ctx) +{ + int i; + static const struct coda_memcpy_desc huff[8] = { + { 0, luma_dc_bits, sizeof(luma_dc_bits) }, + { 16, luma_dc_value, sizeof(luma_dc_value) }, + { 32, luma_ac_bits, sizeof(luma_ac_bits) }, + { 48, luma_ac_value, sizeof(luma_ac_value) }, + { 216, chroma_dc_bits, sizeof(chroma_dc_bits) }, + { 232, chroma_dc_value, sizeof(chroma_dc_value) }, + { 248, chroma_ac_bits, sizeof(chroma_ac_bits) }, + { 264, chroma_ac_value, sizeof(chroma_ac_value) }, + }; + struct coda_memcpy_desc qmat[3] = { + { 512, ctx->params.jpeg_qmat_tab[0], 64 }, + { 576, ctx->params.jpeg_qmat_tab[1], 64 }, + { 640, ctx->params.jpeg_qmat_tab[1], 64 }, + }; + + /* Write huffman tables to parameter memory */ + for (i = 0; i < ARRAY_SIZE(huff); i++) + coda_memcpy_parabuf(ctx->parabuf.vaddr, huff + i); + + /* Write Q-matrix to parameter memory */ + for (i = 0; i < ARRAY_SIZE(qmat); i++) + coda_memcpy_parabuf(ctx->parabuf.vaddr, qmat + i); + + return 0; +} + +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb) +{ + void *vaddr = vb2_plane_vaddr(vb, 0); + u16 soi = be16_to_cpup((__be16 *)vaddr); + u16 eoi = be16_to_cpup((__be16 *)(vaddr + + vb2_get_plane_payload(vb, 0) - 2)); + + return soi == SOI_MARKER && eoi == EOI_MARKER; +} + +/* + * Scale quantization table using nonlinear scaling factor + * u8 qtab[64], scale [50,190] + */ +static void coda_scale_quant_table(u8 *q_tab, int scale) +{ + unsigned int temp; + int i; + + for (i = 0; i < 64; i++) { + temp = DIV_ROUND_CLOSEST((unsigned int)q_tab[i] * scale, 100); + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + q_tab[i] = (unsigned char)temp; + } +} + +void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality) +{ + unsigned int scale; + + ctx->params.jpeg_quality = quality; + + /* Clip quality setting to [5,100] interval */ + if (quality > 100) + quality = 100; + if (quality < 5) + quality = 5; + + /* + * Non-linear scaling factor: + * [5,50] -> [1000..100], [51,100] -> [98..0] + */ + if (quality < 50) + scale = 5000 / quality; + else + scale = 200 - 2 * quality; + + if (ctx->params.jpeg_qmat_tab[0]) { + memcpy(ctx->params.jpeg_qmat_tab[0], luma_q, 64); + coda_scale_quant_table(ctx->params.jpeg_qmat_tab[0], scale); + } + if (ctx->params.jpeg_qmat_tab[1]) { + memcpy(ctx->params.jpeg_qmat_tab[1], chroma_q, 64); + coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale); + } +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index bbc18c0dacd9..5dd47e5f97c1 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -45,11 +45,15 @@ enum coda_product { CODA_960 = 0xf020, }; +struct coda_video_device; + struct coda_devtype { char *firmware; enum coda_product product; const struct coda_codec *codecs; unsigned int num_codecs; + const struct coda_video_device **vdevs; + unsigned int num_vdevs; size_t workbuf_size; size_t tempbuf_size; size_t iram_size; @@ -65,7 +69,7 @@ struct coda_aux_buf { struct coda_dev { struct v4l2_device v4l2_dev; - struct video_device vfd[2]; + struct video_device vfd[5]; struct platform_device *plat_dev; const struct coda_devtype *devtype; @@ -114,6 +118,9 @@ struct coda_params { u8 mpeg4_inter_qp; u8 gop_size; int intra_refresh; + u8 jpeg_quality; + u8 jpeg_restart_interval; + u8 *jpeg_qmat_tab[3]; int codec_mode; int codec_mode_aux; enum v4l2_mpeg_video_multi_slice_mode slice_mode; @@ -123,11 +130,13 @@ struct coda_params { u32 slice_max_mb; }; -struct coda_timestamp { +struct coda_buffer_meta { struct list_head list; u32 sequence; struct v4l2_timecode timecode; struct timeval timestamp; + u32 start; + u32 end; }; /* Per-queue, driver-specific private data */ @@ -183,6 +192,7 @@ struct coda_ctx { struct work_struct pic_run_work; struct work_struct seq_end_work; struct completion completion; + const struct coda_video_device *cvd; const struct coda_context_ops *ops; int aborting; int initialized; @@ -212,9 +222,9 @@ struct coda_ctx { struct coda_aux_buf slicebuf; struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS]; + struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS]; u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; - struct list_head timestamp_list; + struct list_head buffer_meta_list; struct coda_aux_buf workbuf; int num_internal_frames; int idx; @@ -232,6 +242,8 @@ extern int coda_debug; void coda_write(struct coda_dev *dev, u32 data, u32 reg); unsigned int coda_read(struct coda_dev *dev, u32 reg); +void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, + struct vb2_buffer *buf, unsigned int reg_y); int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, size_t size, const char *name, struct dentry *parent); @@ -281,6 +293,10 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx); int coda_h264_padding(int size, char *p); +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); +int coda_jpeg_write_tables(struct coda_ctx *ctx); +void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); + extern const struct coda_context_ops coda_bit_encode_ops; extern const struct coda_context_ops coda_bit_decode_ops; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index c791275e307b..8e015b8aa8fa 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -147,6 +147,7 @@ #define CODA_CMD_DEC_SEQ_BB_START 0x180 #define CODA_CMD_DEC_SEQ_BB_SIZE 0x184 #define CODA_CMD_DEC_SEQ_OPTION 0x188 +#define CODA_NO_INT_ENABLE (1 << 10) #define CODA_REORDER_ENABLE (1 << 1) #define CODADX6_QP_REPORT (1 << 0) #define CODA7_MP4_DEBLK_ENABLE (1 << 0) @@ -332,6 +333,12 @@ #define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8 #define CODA_RET_ENC_SEQ_SUCCESS 0x1c0 +#define CODA_CMD_ENC_SEQ_JPG_PARA 0x198 +#define CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C +#define CODA_CMD_ENC_SEQ_JPG_THUMB_EN 0x1a0 +#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4 +#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8 + /* Encoder Picture Run */ #define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 #define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 |