diff options
Diffstat (limited to 'drivers/media/platform/coda/coda-common.c')
-rw-r--r-- | drivers/media/platform/coda/coda-common.c | 246 |
1 files changed, 133 insertions, 113 deletions
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; } |