diff options
Diffstat (limited to 'drivers/media/platform/coda')
-rw-r--r-- | drivers/media/platform/coda/coda-bit.c | 132 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 246 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda.h | 34 | ||||
-rw-r--r-- | drivers/media/platform/coda/coda_regs.h | 2 | ||||
-rw-r--r-- | drivers/media/platform/coda/trace.h | 10 |
5 files changed, 238 insertions, 186 deletions
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index d26c2d85a009..8e0194993a52 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -253,7 +253,6 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) { struct vb2_v4l2_buffer *src_buf; struct coda_buffer_meta *meta; - unsigned long flags; u32 start; if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) @@ -269,6 +268,23 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) ctx->num_metas > 1) break; + if (ctx->num_internal_frames && + ctx->num_metas >= ctx->num_internal_frames) { + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + + /* + * If we managed to fill in at least a full reorder + * window of buffers (num_internal_frames is a + * conservative estimate for this) and the bitstream + * prefetcher has at least 2 256 bytes periods beyond + * the first buffer to fetch, we can safely stop queuing + * in order to limit the decoder drain latency. + */ + if (coda_bitstream_can_fetch_past(ctx, meta->end)) + break; + } + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); /* Drop frames that do not start/end with a SOI/EOI markers */ @@ -299,8 +315,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) } /* Buffer start position */ - start = ctx->bitstream_fifo.kfifo.in & - ctx->bitstream_fifo.kfifo.mask; + start = ctx->bitstream_fifo.kfifo.in; if (coda_bitstream_try_queue(ctx, src_buf)) { /* @@ -315,15 +330,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) meta->timecode = src_buf->timecode; meta->timestamp = src_buf->vb2_buf.timestamp; meta->start = start; - meta->end = ctx->bitstream_fifo.kfifo.in & - ctx->bitstream_fifo.kfifo.mask; - spin_lock_irqsave(&ctx->buffer_meta_lock, - flags); + meta->end = ctx->bitstream_fifo.kfifo.in; + spin_lock(&ctx->buffer_meta_lock); list_add_tail(&meta->list, &ctx->buffer_meta_list); ctx->num_metas++; - spin_unlock_irqrestore(&ctx->buffer_meta_lock, - flags); + spin_unlock(&ctx->buffer_meta_lock); trace_coda_bit_queue(ctx, src_buf, meta); } @@ -713,8 +725,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) out: if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "IRAM smaller than needed\n"); + coda_dbg(1, ctx, "IRAM smaller than needed\n"); if (dev->devtype->product == CODA_HX4 || dev->devtype->product == CODA_7541) { @@ -991,16 +1002,15 @@ static int coda_start_encoding(struct coda_ctx *ctx) else coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD); - if (ctx->params.h264_deblk_enabled) { - value = ((ctx->params.h264_deblk_alpha & - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | - ((ctx->params.h264_deblk_beta & - CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); - } else { - value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET; - } + value = ((ctx->params.h264_disable_deblocking_filter_idc & + CODA_264PARAM_DISABLEDEBLK_MASK) << + CODA_264PARAM_DISABLEDEBLK_OFFSET) | + ((ctx->params.h264_slice_alpha_c0_offset_div2 & + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | + ((ctx->params.h264_slice_beta_offset_div2 & + CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); break; case V4L2_PIX_FMT_JPEG: @@ -1201,6 +1211,12 @@ static int coda_start_encoding(struct coda_ctx *ctx) goto out; } + coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", + q_data_src->rect.width, q_data_src->rect.height, + (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, + ctx->params.framerate & 0xffff, + (ctx->params.framerate >> 16) + 1); + /* Save stream headers */ buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); switch (dst_fourcc) { @@ -1462,8 +1478,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); } - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n", - wr_ptr - start_ptr); + coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); coda_read(dev, CODA_RET_ENC_PIC_FLAG); @@ -1492,11 +1507,9 @@ static void coda_finish_encode(struct coda_ctx *ctx) if (ctx->gopcounter < 0) ctx->gopcounter = ctx->params.gop_size - 1; - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: encoding frame (%d) (%s)\n", - dst_buf->sequence, - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); + coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n", + (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P', + dst_buf->sequence); } static void coda_seq_end_work(struct work_struct *work) @@ -1510,9 +1523,7 @@ static void coda_seq_end_work(struct work_struct *work) if (ctx->initialized == 0) goto out; - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, - __func__); + coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_END failed\n"); @@ -1655,8 +1666,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 val; int ret; - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "Video Data Order Adapter: %s\n", + coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", ctx->use_vdoa ? "Enabled" : "Disabled"); /* Start decoding */ @@ -1736,7 +1746,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { v4l2_err(&dev->v4l2_dev, - "CODA_COMMAND_SEQ_INIT failed, error code = %d\n", + "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); return -EAGAIN; } @@ -1760,8 +1770,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) width = round_up(width, 16); height = round_up(height, 16); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n", - __func__, ctx->idx, width, height); + coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); /* @@ -1879,7 +1888,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; struct coda_buffer_meta *meta; - unsigned long flags; u32 rot_mode = 0; u32 reg_addr, reg_stride; @@ -1893,8 +1901,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) if (coda_get_bitstream_payload(ctx) < 512 && (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "bitstream payload: %d, skipping\n", + coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", coda_get_bitstream_payload(ctx)); v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return -EAGAIN; @@ -1973,15 +1980,14 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); - spin_lock_irqsave(&ctx->buffer_meta_lock, flags); + spin_lock(&ctx->buffer_meta_lock); meta = list_first_entry_or_null(&ctx->buffer_meta_list, struct coda_buffer_meta, list); if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { /* If this is the last buffer in the bitstream, add padding */ - if (meta->end == (ctx->bitstream_fifo.kfifo.in & - ctx->bitstream_fifo.kfifo.mask)) { + if (meta->end == ctx->bitstream_fifo.kfifo.in) { static unsigned char buf[512]; unsigned int pad; @@ -1993,7 +1999,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) kfifo_in(&ctx->bitstream_fifo, buf, pad); } } - spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); + spin_unlock(&ctx->buffer_meta_lock); coda_kfifo_sync_to_device_full(ctx); @@ -2015,7 +2021,6 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct vb2_v4l2_buffer *dst_buf; struct coda_buffer_meta *meta; unsigned long payload; - unsigned long flags; int width, height; int decoded_idx; int display_idx; @@ -2100,8 +2105,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); if (val == 0) { /* not enough bitstream data */ - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "prescan failed: %d\n", val); + coda_dbg(1, ctx, "prescan failed: %d\n", val); ctx->hold = true; return; } @@ -2147,13 +2151,13 @@ static void coda_finish_decode(struct coda_ctx *ctx) } else { val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; - spin_lock_irqsave(&ctx->buffer_meta_lock, flags); + spin_lock(&ctx->buffer_meta_lock); if (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); ctx->num_metas--; - spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); + spin_unlock(&ctx->buffer_meta_lock); /* * Clamp counters to 16 bits for comparison, as the HW * counter rolls over at this point for h.264. This @@ -2170,7 +2174,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) ctx->frame_metas[decoded_idx] = *meta; kfree(meta); } else { - spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); + spin_unlock(&ctx->buffer_meta_lock); v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); memset(&ctx->frame_metas[decoded_idx], 0, sizeof(struct coda_buffer_meta)); @@ -2243,18 +2247,28 @@ static void coda_finish_decode(struct coda_ctx *ctx) else coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: decoding frame (%d) (%s)\n", - dst_buf->sequence, - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? - "KEYFRAME" : "PFRAME"); + coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n", + (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : + ((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'), + dst_buf->sequence, ctx->qsequence); } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "job finished: no frame decoded\n"); + coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n", + ctx->osequence, ctx->qsequence); } /* The rotator will copy the current display frame next time */ ctx->display_idx = display_idx; + + /* + * The current decode run might have brought the bitstream fill level + * below the size where we can start the next decode run. As userspace + * might have filled the output queue completely and might thus be + * blocked, we can't rely on the next qbuf to trigger the bitstream + * refill. Check if we have data to refill the bitstream now. + */ + mutex_lock(&ctx->bitstream_mutex); + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); } static void coda_decode_timeout(struct coda_ctx *ctx) @@ -2308,13 +2322,11 @@ irqreturn_t coda_irq_handler(int irq, void *data) trace_coda_bit_done(ctx); if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "task has been aborted\n"); + coda_dbg(1, ctx, "task has been aborted\n"); } if (coda_isbusy(ctx->dev)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "coda is still busy!!!!\n"); + coda_dbg(1, ctx, "coda is still busy!!!!\n"); return IRQ_NONE; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 2848ea5f464d..7518f01c48f7 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -17,6 +17,7 @@ #include <linux/firmware.h> #include <linux/gcd.h> #include <linux/genalloc.h> +#include <linux/idr.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> @@ -50,8 +51,8 @@ #define CODA_ISRAM_SIZE (2048 * 2) -#define MIN_W 176 -#define MIN_H 144 +#define MIN_W 48 +#define MIN_H 16 #define S_ALIGN 1 /* multiple of 2 */ #define W_ALIGN 1 /* multiple of 2 */ @@ -703,7 +704,8 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, return -EINVAL; if (vb2_is_busy(vq)) { - v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n", + __func__, v4l2_type_names[f->type], vq->num_buffers); return -EBUSY; } @@ -749,11 +751,10 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, else ctx->use_vdoa = false; - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Setting format for type %d, wxh: %dx%d, fmt: %4.4s %c\n", - f->type, q_data->width, q_data->height, - (char *)&q_data->fourcc, - (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T'); + coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n", + v4l2_type_names[f->type], q_data->width, q_data->height, + (char *)&q_data->fourcc, + (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T'); return 0; } @@ -938,32 +939,42 @@ static int coda_s_selection(struct file *file, void *fh, struct coda_ctx *ctx = fh_to_ctx(fh); struct coda_q_data *q_data; - if (ctx->inst_type == CODA_INST_ENCODER && - s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - s->target == V4L2_SEL_TGT_CROP) { - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (ctx->inst_type == CODA_INST_ENCODER && + s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; - s->r.left = 0; - s->r.top = 0; - s->r.width = clamp(s->r.width, 2U, q_data->width); - s->r.height = clamp(s->r.height, 2U, q_data->height); + s->r.left = 0; + s->r.top = 0; + s->r.width = clamp(s->r.width, 2U, q_data->width); + s->r.height = clamp(s->r.height, 2U, q_data->height); + + if (s->flags & V4L2_SEL_FLAG_LE) { + s->r.width = round_up(s->r.width, 2); + s->r.height = round_up(s->r.height, 2); + } else { + s->r.width = round_down(s->r.width, 2); + s->r.height = round_down(s->r.height, 2); + } - if (s->flags & V4L2_SEL_FLAG_LE) { - s->r.width = round_up(s->r.width, 2); - s->r.height = round_up(s->r.height, 2); - } else { - s->r.width = round_down(s->r.width, 2); - s->r.height = round_down(s->r.height, 2); - } + q_data->rect = s->r; - q_data->rect = s->r; + coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n", + s->r.width, s->r.height); - return 0; + return 0; + } + /* else fall through */ + case V4L2_SEL_TGT_NATIVE_SIZE: + case V4L2_SEL_TGT_COMPOSE: + return coda_g_selection(file, fh, s); + default: + /* v4l2-compliance expects this to fail for read-only targets */ + return -EINVAL; } - - return coda_g_selection(file, fh, s); } static int coda_try_encoder_cmd(struct file *file, void *fh, @@ -1044,6 +1055,38 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *f) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + int i; + + if (f->index) + return -EINVAL; + + /* Disallow YUYV if the vdoa is not available */ + if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) + return -EINVAL; + + for (i = 0; i < CODA_MAX_FORMATS; i++) { + if (f->pixel_format == ctx->cvd->src_formats[i] || + f->pixel_format == ctx->cvd->dst_formats[i]) + break; + } + if (i == CODA_MAX_FORMATS) + return -EINVAL; + + f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; + f->stepwise.min.numerator = 1; + f->stepwise.min.denominator = 65535; + f->stepwise.max.numerator = 65536; + f->stepwise.max.denominator = 1; + f->stepwise.step.numerator = 1; + f->stepwise.step.denominator = 1; + + return 0; +} + static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct coda_ctx *ctx = fh_to_ctx(fh); @@ -1080,10 +1123,10 @@ static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) return; } - /* Upper bound is 65536/1, map everything above to infinity */ + /* Upper bound is 65536/1 */ if (s.denominator == 0 || s.numerator / s.denominator > 65536) { - timeperframe->numerator = 1; - timeperframe->denominator = 0; + timeperframe->numerator = 65536; + timeperframe->denominator = 1; return; } @@ -1135,6 +1178,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; tpf = &a->parm.output.timeperframe; coda_approximate_timeperframe(tpf); ctx->params.framerate = coda_timeperframe_to_frate(tpf); @@ -1189,6 +1233,8 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_g_parm = coda_g_parm, .vidioc_s_parm = coda_s_parm, + .vidioc_enum_frameintervals = coda_enum_frameintervals, + .vidioc_subscribe_event = coda_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -1257,14 +1303,12 @@ static int coda_job_ready(void *m2m_priv) * the compressed frame can be in the bitstream. */ if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: not enough video buffers.\n"); + coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n"); return 0; } if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: not enough video capture buffers.\n"); + coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n"); return 0; } @@ -1272,49 +1316,48 @@ static int coda_job_ready(void *m2m_priv) bool stream_end = ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG; int num_metas = ctx->num_metas; + struct coda_buffer_meta *meta; unsigned int count; count = hweight32(ctx->frm_dis_flg); if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: all internal buffers in use: %d/%d (0x%x)", - ctx->idx, count, ctx->num_internal_frames, + coda_dbg(1, ctx, + "not ready: all internal buffers in use: %d/%d (0x%x)", + count, ctx->num_internal_frames, ctx->frm_dis_flg); return 0; } if (ctx->hold && !src_bufs) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: on hold for more buffers.\n", - ctx->idx); + coda_dbg(1, ctx, + "not ready: on hold for more buffers.\n"); return 0; } if (!stream_end && (num_metas + src_bufs) < 2) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: need 2 buffers available (%d, %d)\n", - ctx->idx, num_metas, src_bufs); + coda_dbg(1, ctx, + "not ready: need 2 buffers available (queue:%d + bitstream:%d)\n", + num_metas, src_bufs); return 0; } - - if (!src_bufs && !stream_end && - (coda_get_bitstream_payload(ctx) < 512)) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "%d: not ready: not enough bitstream data (%d).\n", - ctx->idx, coda_get_bitstream_payload(ctx)); + meta = list_first_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, list); + if (!coda_bitstream_can_fetch_past(ctx, meta->end) && + !stream_end) { + coda_dbg(1, ctx, + "not ready: not enough bitstream data to read past %u (%u)\n", + meta->end, ctx->bitstream_fifo.kfifo.in); return 0; } } if (ctx->aborting) { - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "not ready: aborting\n"); + coda_dbg(1, ctx, "not ready: aborting\n"); return 0; } - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "job ready\n"); + coda_dbg(1, ctx, "job ready\n"); return 1; } @@ -1325,8 +1368,7 @@ static void coda_job_abort(void *priv) ctx->aborting = 1; - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Aborting task\n"); + coda_dbg(1, ctx, "job abort\n"); } static const struct v4l2_m2m_ops coda_m2m_ops = { @@ -1403,8 +1445,8 @@ static int coda_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "get %d buffer(s) of size %d each.\n", *nbuffers, size); + coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers, + size); return 0; } @@ -1469,8 +1511,7 @@ static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx) profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE); - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Profile: %s\n", - profile_names[profile]); + coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]); } static void coda_update_h264_level_ctrl(struct coda_ctx *ctx) @@ -1489,8 +1530,7 @@ static void coda_update_h264_level_ctrl(struct coda_ctx *ctx) level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL); - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Level: %s\n", - level_names[level]); + coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]); } static void coda_buf_queue(struct vb2_buffer *vb) @@ -1595,6 +1635,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (count < 1) return -EINVAL; + coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]); + INIT_LIST_HEAD(&list); q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); @@ -1687,14 +1729,13 @@ static void coda_stop_streaming(struct vb2_queue *q) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; struct vb2_v4l2_buffer *buf; - unsigned long flags; bool stop; stop = ctx->streamon_out && ctx->streamon_cap; + coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]); + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: output\n", __func__); ctx->streamon_out = 0; coda_bit_stream_end_flag(ctx); @@ -1704,8 +1745,6 @@ static void coda_stop_streaming(struct vb2_queue *q) while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } else { - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, - "%s: capture\n", __func__); ctx->streamon_cap = 0; ctx->osequence = 0; @@ -1722,7 +1761,7 @@ static void coda_stop_streaming(struct vb2_queue *q) queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } - spin_lock_irqsave(&ctx->buffer_meta_lock, flags); + spin_lock(&ctx->buffer_meta_lock); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); @@ -1730,7 +1769,7 @@ static void coda_stop_streaming(struct vb2_queue *q) kfree(meta); } ctx->num_metas = 0; - spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); + spin_unlock(&ctx->buffer_meta_lock); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; @@ -1757,8 +1796,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) struct coda_ctx *ctx = container_of(ctrl->handler, struct coda_ctx, ctrls); - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); + coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", + ctrl->id, ctrl->name, ctrl->val); switch (ctrl->id) { case V4L2_CID_HFLIP: @@ -1792,14 +1831,13 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) ctx->params.h264_max_qp = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: - ctx->params.h264_deblk_alpha = ctrl->val; + ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: - ctx->params.h264_deblk_beta = ctrl->val; + ctx->params.h264_slice_beta_offset_div2 = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - ctx->params.h264_deblk_enabled = (ctrl->val == - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: /* TODO: switch between baseline and constrained baseline */ @@ -1849,9 +1887,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); break; default: - v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, - "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); + coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); return -EINVAL; } @@ -1881,13 +1918,13 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0); + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0); + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0, - V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, @@ -2099,17 +2136,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, return coda_queue_init(priv, dst_vq); } -static int coda_next_free_instance(struct coda_dev *dev) -{ - int idx = ffz(dev->instance_mask); - - if ((idx < 0) || - (dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES)) - return -EBUSY; - - return idx; -} - /* * File operations */ @@ -2118,7 +2144,8 @@ static int coda_open(struct file *file) { struct video_device *vdev = video_devdata(file); struct coda_dev *dev = video_get_drvdata(vdev); - struct coda_ctx *ctx = NULL; + struct coda_ctx *ctx; + unsigned int max = ~0; char *name; int ret; int idx; @@ -2127,12 +2154,13 @@ static int coda_open(struct file *file) if (!ctx) return -ENOMEM; - idx = coda_next_free_instance(dev); + if (dev->devtype->product == CODA_DX6) + max = CODADX6_MAX_INSTANCES - 1; + idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL); if (idx < 0) { ret = idx; goto err_coda_max; } - set_bit(idx, &dev->instance_mask); name = kasprintf(GFP_KERNEL, "context%d", idx); if (!name) { @@ -2156,6 +2184,9 @@ static int coda_open(struct file *file) v4l2_fh_add(&ctx->fh); ctx->dev = dev; ctx->idx = idx; + + coda_dbg(1, ctx, "open instance (%p)\n", ctx); + switch (dev->devtype->product) { case CODA_960: /* @@ -2221,13 +2252,6 @@ static int coda_open(struct file *file) INIT_LIST_HEAD(&ctx->buffer_meta_list); spin_lock_init(&ctx->buffer_meta_lock); - mutex_lock(&dev->dev_mutex); - list_add(&ctx->list, &dev->instances); - mutex_unlock(&dev->dev_mutex); - - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n", - ctx->idx, ctx); - return 0; err_ctrls_setup: @@ -2241,8 +2265,8 @@ err_clk_per: err_pm_get: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); - clear_bit(ctx->idx, &dev->instance_mask); err_coda_name_init: + ida_free(&dev->ida, ctx->idx); err_coda_max: kfree(ctx); return ret; @@ -2253,8 +2277,7 @@ static int coda_release(struct file *file) struct coda_dev *dev = video_drvdata(file); struct coda_ctx *ctx = fh_to_ctx(file->private_data); - v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n", - ctx); + coda_dbg(1, ctx, "release instance (%p)\n", ctx); if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) coda_bit_stream_end_flag(ctx); @@ -2271,10 +2294,6 @@ static int coda_release(struct file *file) flush_work(&ctx->seq_end_work); } - mutex_lock(&dev->dev_mutex); - list_del(&ctx->list); - mutex_unlock(&dev->dev_mutex); - if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); @@ -2284,7 +2303,7 @@ static int coda_release(struct file *file) pm_runtime_put_sync(&dev->plat_dev->dev); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); - clear_bit(ctx->idx, &dev->instance_mask); + ida_free(&dev->ida, ctx->idx); if (ctx->ops->release) ctx->ops->release(ctx); debugfs_remove_recursive(ctx->debugfs_entry); @@ -2679,7 +2698,6 @@ static int coda_probe(struct platform_device *pdev) return -EINVAL; spin_lock_init(&dev->irqlock); - INIT_LIST_HEAD(&dev->instances); dev->plat_dev = pdev; dev->clk_per = devm_clk_get(&pdev->dev, "per"); @@ -2745,6 +2763,7 @@ static int coda_probe(struct platform_device *pdev) mutex_init(&dev->dev_mutex); mutex_init(&dev->coda_mutex); + ida_init(&dev->ida); dev->debugfs_root = debugfs_create_dir("coda", NULL); if (!dev->debugfs_root) @@ -2832,6 +2851,7 @@ static int coda_remove(struct platform_device *pdev) coda_free_aux_buf(dev, &dev->tempbuf); coda_free_aux_buf(dev, &dev->workbuf); debugfs_remove_recursive(dev->debugfs_root); + ida_destroy(&dev->ida); return 0; } diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 19ac0b9dc6eb..31cea72f5b2a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -16,6 +16,7 @@ #define __CODA_H__ #include <linux/debugfs.h> +#include <linux/idr.h> #include <linux/irqreturn.h> #include <linux/mutex.h> #include <linux/kfifo.h> @@ -94,8 +95,7 @@ struct coda_dev { struct mutex coda_mutex; struct workqueue_struct *workqueue; struct v4l2_m2m_dev *m2m_dev; - struct list_head instances; - unsigned long instance_mask; + struct ida ida; struct dentry *debugfs_root; }; @@ -115,9 +115,9 @@ struct coda_params { u8 h264_inter_qp; u8 h264_min_qp; u8 h264_max_qp; - u8 h264_deblk_enabled; - u8 h264_deblk_alpha; - u8 h264_deblk_beta; + u8 h264_disable_deblocking_filter_idc; + s8 h264_slice_alpha_c0_offset_div2; + s8 h264_slice_beta_offset_div2; u8 h264_profile_idc; u8 h264_level_idc; u8 mpeg4_intra_qp; @@ -144,8 +144,8 @@ struct coda_buffer_meta { u32 sequence; struct v4l2_timecode timecode; u64 timestamp; - u32 start; - u32 end; + unsigned int start; + unsigned int end; }; /* Per-queue, driver-specific private data */ @@ -192,7 +192,6 @@ struct coda_context_ops { struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; - struct list_head list; struct work_struct pic_run_work; struct work_struct seq_end_work; struct completion completion; @@ -253,6 +252,13 @@ struct coda_ctx { extern int coda_debug; +#define coda_dbg(level, ctx, fmt, arg...) \ + do { \ + if (coda_debug >= (level)) \ + v4l2_dbg((level), coda_debug, &(ctx)->dev->v4l2_dev, \ + "%u: " fmt, (ctx)->idx, ##arg); \ + } while (0) + 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, @@ -295,6 +301,18 @@ static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) return kfifo_len(&ctx->bitstream_fifo); } +/* + * The bitstream prefetcher needs to read at least 2 256 byte periods past + * the desired bitstream position for all data to reach the decoder. + */ +static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, + unsigned int pos) +{ + return (int)(ctx->bitstream_fifo.kfifo.in - ALIGN(pos, 256)) > 512; +} + +bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos); + void coda_bit_stream_end_flag(struct coda_ctx *ctx); void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 5e7b00a97671..e675e38f3475 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -292,7 +292,7 @@ #define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8 #define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f #define CODA_264PARAM_DISABLEDEBLK_OFFSET 6 -#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01 +#define CODA_264PARAM_DISABLEDEBLK_MASK 0x03 #define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5 #define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01 #define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0 diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index ca671e315ad0..a672bfc4c6ba 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -97,8 +97,8 @@ DECLARE_EVENT_CLASS(coda_buf_meta_class, TP_fast_assign( __entry->minor = ctx->fh.vdev->minor; __entry->index = buf->vb2_buf.index; - __entry->start = meta->start; - __entry->end = meta->end; + __entry->start = meta->start & ctx->bitstream_fifo.kfifo.mask; + __entry->end = meta->end & ctx->bitstream_fifo.kfifo.mask; __entry->ctx = ctx->idx; ), @@ -127,8 +127,10 @@ DECLARE_EVENT_CLASS(coda_meta_class, TP_fast_assign( __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta ? meta->start : 0; - __entry->end = meta ? meta->end : 0; + __entry->start = meta ? (meta->start & + ctx->bitstream_fifo.kfifo.mask) : 0; + __entry->end = meta ? (meta->end & + ctx->bitstream_fifo.kfifo.mask) : 0; __entry->ctx = ctx->idx; ), |