|
@@ -29,6 +29,7 @@
|
|
|
|
|
|
#include <media/v4l2-ctrls.h>
|
|
#include <media/v4l2-ctrls.h>
|
|
#include <media/v4l2-device.h>
|
|
#include <media/v4l2-device.h>
|
|
|
|
+#include <media/v4l2-event.h>
|
|
#include <media/v4l2-ioctl.h>
|
|
#include <media/v4l2-ioctl.h>
|
|
#include <media/v4l2-mem2mem.h>
|
|
#include <media/v4l2-mem2mem.h>
|
|
#include <media/videobuf2-core.h>
|
|
#include <media/videobuf2-core.h>
|
|
@@ -47,9 +48,11 @@
|
|
#define CODA_PARA_BUF_SIZE (10 * 1024)
|
|
#define CODA_PARA_BUF_SIZE (10 * 1024)
|
|
#define CODA_ISRAM_SIZE (2048 * 2)
|
|
#define CODA_ISRAM_SIZE (2048 * 2)
|
|
#define CODADX6_IRAM_SIZE 0xb000
|
|
#define CODADX6_IRAM_SIZE 0xb000
|
|
-#define CODA7_IRAM_SIZE 0x14000 /* 81920 bytes */
|
|
|
|
|
|
+#define CODA7_IRAM_SIZE 0x14000
|
|
|
|
|
|
-#define CODA_MAX_FRAMEBUFFERS 2
|
|
|
|
|
|
+#define CODA7_PS_BUF_SIZE 0x28000
|
|
|
|
+
|
|
|
|
+#define CODA_MAX_FRAMEBUFFERS 8
|
|
|
|
|
|
#define MAX_W 8192
|
|
#define MAX_W 8192
|
|
#define MAX_H 8192
|
|
#define MAX_H 8192
|
|
@@ -178,12 +181,16 @@ struct coda_iram_info {
|
|
|
|
|
|
struct coda_ctx {
|
|
struct coda_ctx {
|
|
struct coda_dev *dev;
|
|
struct coda_dev *dev;
|
|
|
|
+ struct mutex buffer_mutex;
|
|
struct list_head list;
|
|
struct list_head list;
|
|
|
|
+ struct work_struct skip_run;
|
|
int aborting;
|
|
int aborting;
|
|
|
|
+ int initialized;
|
|
int streamon_out;
|
|
int streamon_out;
|
|
int streamon_cap;
|
|
int streamon_cap;
|
|
u32 isequence;
|
|
u32 isequence;
|
|
u32 qsequence;
|
|
u32 qsequence;
|
|
|
|
+ u32 osequence;
|
|
struct coda_q_data q_data[2];
|
|
struct coda_q_data q_data[2];
|
|
enum coda_inst_type inst_type;
|
|
enum coda_inst_type inst_type;
|
|
struct coda_codec *codec;
|
|
struct coda_codec *codec;
|
|
@@ -193,12 +200,16 @@ struct coda_ctx {
|
|
struct v4l2_ctrl_handler ctrls;
|
|
struct v4l2_ctrl_handler ctrls;
|
|
struct v4l2_fh fh;
|
|
struct v4l2_fh fh;
|
|
int gopcounter;
|
|
int gopcounter;
|
|
|
|
+ int runcounter;
|
|
char vpu_header[3][64];
|
|
char vpu_header[3][64];
|
|
int vpu_header_size[3];
|
|
int vpu_header_size[3];
|
|
struct kfifo bitstream_fifo;
|
|
struct kfifo bitstream_fifo;
|
|
struct mutex bitstream_mutex;
|
|
struct mutex bitstream_mutex;
|
|
struct coda_aux_buf bitstream;
|
|
struct coda_aux_buf bitstream;
|
|
|
|
+ bool prescan_failed;
|
|
struct coda_aux_buf parabuf;
|
|
struct coda_aux_buf parabuf;
|
|
|
|
+ struct coda_aux_buf psbuf;
|
|
|
|
+ struct coda_aux_buf slicebuf;
|
|
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
|
|
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
|
|
struct coda_aux_buf workbuf;
|
|
struct coda_aux_buf workbuf;
|
|
int num_internal_frames;
|
|
int num_internal_frames;
|
|
@@ -206,6 +217,8 @@ struct coda_ctx {
|
|
int reg_idx;
|
|
int reg_idx;
|
|
struct coda_iram_info iram_info;
|
|
struct coda_iram_info iram_info;
|
|
u32 bit_stream_param;
|
|
u32 bit_stream_param;
|
|
|
|
+ u32 frm_dis_flg;
|
|
|
|
+ int display_idx;
|
|
};
|
|
};
|
|
|
|
|
|
static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
|
|
static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
|
|
@@ -257,6 +270,8 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd)
|
|
/* Restore context related registers to CODA */
|
|
/* Restore context related registers to CODA */
|
|
coda_write(dev, ctx->bit_stream_param,
|
|
coda_write(dev, ctx->bit_stream_param,
|
|
CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
|
|
+ coda_write(dev, ctx->frm_dis_flg,
|
|
|
|
+ CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
|
|
coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
|
|
coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -331,6 +346,8 @@ static struct coda_codec codadx6_codecs[] = {
|
|
static struct coda_codec coda7_codecs[] = {
|
|
static 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_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_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
|
|
|
|
+ CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080),
|
|
|
|
+ CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080),
|
|
};
|
|
};
|
|
|
|
|
|
static bool coda_format_is_yuv(u32 fourcc)
|
|
static bool coda_format_is_yuv(u32 fourcc)
|
|
@@ -399,7 +416,7 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|
}
|
|
}
|
|
|
|
|
|
static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
|
|
static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
|
|
- enum v4l2_buf_type type)
|
|
|
|
|
|
+ enum v4l2_buf_type type, int src_fourcc)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
struct coda_codec *codecs = ctx->dev->devtype->codecs;
|
|
struct coda_codec *codecs = ctx->dev->devtype->codecs;
|
|
@@ -411,7 +428,8 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
|
|
|
|
|
|
for (i = 0; i < num_formats; i++) {
|
|
for (i = 0; i < num_formats; i++) {
|
|
/* Both uncompressed formats are always supported */
|
|
/* Both uncompressed formats are always supported */
|
|
- if (coda_format_is_yuv(formats[i].fourcc)) {
|
|
|
|
|
|
+ if (coda_format_is_yuv(formats[i].fourcc) &&
|
|
|
|
+ !coda_format_is_yuv(src_fourcc)) {
|
|
if (num == f->index)
|
|
if (num == f->index)
|
|
break;
|
|
break;
|
|
++num;
|
|
++num;
|
|
@@ -419,8 +437,10 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
|
|
}
|
|
}
|
|
/* Compressed formats may be supported, check the codec list */
|
|
/* Compressed formats may be supported, check the codec list */
|
|
for (k = 0; k < num_codecs; k++) {
|
|
for (k = 0; k < num_codecs; k++) {
|
|
|
|
+ /* if src_fourcc is set, only consider matching codecs */
|
|
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
|
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
|
- formats[i].fourcc == codecs[k].dst_fourcc)
|
|
|
|
|
|
+ formats[i].fourcc == codecs[k].dst_fourcc &&
|
|
|
|
+ (!src_fourcc || src_fourcc == codecs[k].src_fourcc))
|
|
break;
|
|
break;
|
|
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
|
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
|
formats[i].fourcc == codecs[k].src_fourcc)
|
|
formats[i].fourcc == codecs[k].src_fourcc)
|
|
@@ -447,13 +467,26 @@ static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
|
|
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
|
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
|
struct v4l2_fmtdesc *f)
|
|
struct v4l2_fmtdesc *f)
|
|
{
|
|
{
|
|
- return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
|
|
|
|
+ struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
|
|
+ struct vb2_queue *src_vq;
|
|
|
|
+ struct coda_q_data *q_data_src;
|
|
|
|
+
|
|
|
|
+ /* If the source format is already fixed, only list matching formats */
|
|
|
|
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+ if (vb2_is_streaming(src_vq)) {
|
|
|
|
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+
|
|
|
|
+ return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
|
|
|
+ q_data_src->fourcc);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
|
|
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
|
|
struct v4l2_fmtdesc *f)
|
|
struct v4l2_fmtdesc *f)
|
|
{
|
|
{
|
|
- return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
|
|
+ return enum_fmt(priv, f, V4L2_BUF_TYPE_VIDEO_OUTPUT, 0);
|
|
}
|
|
}
|
|
|
|
|
|
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
|
|
@@ -526,15 +559,45 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
|
struct v4l2_format *f)
|
|
struct v4l2_format *f)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
- struct coda_codec *codec = NULL;
|
|
|
|
|
|
+ struct coda_codec *codec;
|
|
|
|
+ struct vb2_queue *src_vq;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the source format is already fixed, try to find a codec that
|
|
|
|
+ * converts to the given destination format
|
|
|
|
+ */
|
|
|
|
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+ if (vb2_is_streaming(src_vq)) {
|
|
|
|
+ struct coda_q_data *q_data_src;
|
|
|
|
|
|
- /* Determine codec by the encoded format */
|
|
|
|
- codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
|
|
|
|
- f->fmt.pix.pixelformat);
|
|
|
|
|
|
+ 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;
|
|
|
|
+ } 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;
|
|
f->fmt.pix.colorspace = ctx->colorspace;
|
|
|
|
|
|
- return vidioc_try_fmt(codec, f);
|
|
|
|
|
|
+ ret = vidioc_try_fmt(codec, f);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ /* The h.264 decoder only returns complete 16x16 macroblocks */
|
|
|
|
+ if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
|
|
|
|
+ f->fmt.pix.width = round_up(f->fmt.pix.width, 16);
|
|
|
|
+ f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
|
|
|
|
+ f->fmt.pix.bytesperline = f->fmt.pix.width;
|
|
|
|
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
|
|
|
|
+ f->fmt.pix.height * 3 / 2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
|
|
static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
|
|
@@ -644,11 +707,35 @@ static int vidioc_expbuf(struct file *file, void *priv,
|
|
return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
|
|
return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
|
|
|
|
+ struct v4l2_buffer *buf)
|
|
|
|
+{
|
|
|
|
+ struct vb2_queue *src_vq;
|
|
|
|
+
|
|
|
|
+ src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+
|
|
|
|
+ return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
|
|
|
|
+ (buf->sequence == (ctx->qsequence - 1)));
|
|
|
|
+}
|
|
|
|
+
|
|
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
|
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
|
|
|
|
|
|
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
|
|
|
|
|
|
+ /* If this is the last capture buffer, emit an end-of-stream event */
|
|
|
|
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
|
|
|
+ coda_buf_is_end_of_stream(ctx, buf)) {
|
|
|
|
+ const struct v4l2_event eos_event = {
|
|
|
|
+ .type = V4L2_EVENT_EOS
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ v4l2_event_queue_fh(&ctx->fh, &eos_event);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
static int vidioc_create_bufs(struct file *file, void *priv,
|
|
static int vidioc_create_bufs(struct file *file, void *priv,
|
|
@@ -671,8 +758,53 @@ static int vidioc_streamoff(struct file *file, void *priv,
|
|
enum v4l2_buf_type type)
|
|
enum v4l2_buf_type type)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
struct coda_ctx *ctx = fh_to_ctx(priv);
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * This indirectly calls __vb2_queue_cancel, which dequeues all buffers.
|
|
|
|
+ * We therefore have to lock it against running hardware in this context,
|
|
|
|
+ * which still needs the buffers.
|
|
|
|
+ */
|
|
|
|
+ mutex_lock(&ctx->buffer_mutex);
|
|
|
|
+ ret = v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
|
|
|
|
+ mutex_unlock(&ctx->buffer_mutex);
|
|
|
|
|
|
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
|
|
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vidioc_decoder_cmd(struct file *file, void *fh,
|
|
|
|
+ struct v4l2_decoder_cmd *dc)
|
|
|
|
+{
|
|
|
|
+ struct coda_ctx *ctx = fh_to_ctx(fh);
|
|
|
|
+
|
|
|
|
+ if (dc->cmd != V4L2_DEC_CMD_STOP)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if ((dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) ||
|
|
|
|
+ (dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (dc->stop.pts != 0)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (ctx->inst_type != CODA_INST_DECODER)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* Set the strem-end flag on this context */
|
|
|
|
+ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
|
|
|
|
+ const struct v4l2_event_subscription *sub)
|
|
|
|
+{
|
|
|
|
+ switch (sub->type) {
|
|
|
|
+ case V4L2_EVENT_EOS:
|
|
|
|
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
|
|
|
|
+ default:
|
|
|
|
+ return v4l2_ctrl_subscribe_event(fh, sub);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static const struct v4l2_ioctl_ops coda_ioctl_ops = {
|
|
static const struct v4l2_ioctl_ops coda_ioctl_ops = {
|
|
@@ -698,8 +830,22 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
|
|
|
|
|
|
.vidioc_streamon = vidioc_streamon,
|
|
.vidioc_streamon = vidioc_streamon,
|
|
.vidioc_streamoff = vidioc_streamoff,
|
|
.vidioc_streamoff = vidioc_streamoff,
|
|
|
|
+
|
|
|
|
+ .vidioc_decoder_cmd = vidioc_decoder_cmd,
|
|
|
|
+
|
|
|
|
+ .vidioc_subscribe_event = vidioc_subscribe_event,
|
|
|
|
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static int coda_start_decoding(struct coda_ctx *ctx);
|
|
|
|
+
|
|
|
|
+static void coda_skip_run(struct work_struct *work)
|
|
|
|
+{
|
|
|
|
+ struct coda_ctx *ctx = container_of(work, struct coda_ctx, skip_run);
|
|
|
|
+
|
|
|
|
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
|
|
static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
|
|
{
|
|
{
|
|
return kfifo_len(&ctx->bitstream_fifo);
|
|
return kfifo_len(&ctx->bitstream_fifo);
|
|
@@ -780,6 +926,8 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
|
|
if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
|
|
if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
|
|
coda_kfifo_sync_to_device_write(ctx);
|
|
coda_kfifo_sync_to_device_write(ctx);
|
|
|
|
|
|
|
|
+ ctx->prescan_failed = false;
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -802,6 +950,84 @@ static void coda_fill_bitstream(struct coda_ctx *ctx)
|
|
/*
|
|
/*
|
|
* Mem-to-mem operations.
|
|
* Mem-to-mem operations.
|
|
*/
|
|
*/
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->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);
|
|
|
|
+ mutex_unlock(&ctx->bitstream_mutex);
|
|
|
|
+
|
|
|
|
+ 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_get_bitstream_payload(ctx));
|
|
|
|
+ schedule_work(&ctx->skip_run);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Run coda_start_decoding (again) if not yet initialized */
|
|
|
|
+ if (!ctx->initialized) {
|
|
|
|
+ int ret = coda_start_decoding(ctx);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
|
|
|
|
+ schedule_work(&ctx->skip_run);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ } else {
|
|
|
|
+ ctx->initialized = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 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;
|
|
|
|
+ }
|
|
|
|
+ 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);
|
|
|
|
+ coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
|
|
|
|
+ CODA_CMD_DEC_PIC_ROT_MODE);
|
|
|
|
+
|
|
|
|
+ switch (dev->devtype->product) {
|
|
|
|
+ case CODA_DX6:
|
|
|
|
+ /* TBD */
|
|
|
|
+ case CODA_7541:
|
|
|
|
+ coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
|
|
|
|
+
|
|
|
|
+ coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START);
|
|
|
|
+ coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void coda_prepare_encode(struct coda_ctx *ctx)
|
|
static void coda_prepare_encode(struct coda_ctx *ctx)
|
|
{
|
|
{
|
|
struct coda_q_data *q_data_src, *q_data_dst;
|
|
struct coda_q_data *q_data_src, *q_data_dst;
|
|
@@ -819,9 +1045,9 @@ static void coda_prepare_encode(struct coda_ctx *ctx)
|
|
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
dst_fourcc = q_data_dst->fourcc;
|
|
dst_fourcc = q_data_dst->fourcc;
|
|
|
|
|
|
- src_buf->v4l2_buf.sequence = ctx->isequence;
|
|
|
|
- dst_buf->v4l2_buf.sequence = ctx->isequence;
|
|
|
|
- ctx->isequence++;
|
|
|
|
|
|
+ src_buf->v4l2_buf.sequence = ctx->osequence;
|
|
|
|
+ dst_buf->v4l2_buf.sequence = ctx->osequence;
|
|
|
|
+ ctx->osequence++;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Workaround coda firmware BUG that only marks the first
|
|
* Workaround coda firmware BUG that only marks the first
|
|
@@ -929,15 +1155,36 @@ static void coda_device_run(void *m2m_priv)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = m2m_priv;
|
|
struct coda_ctx *ctx = m2m_priv;
|
|
struct coda_dev *dev = ctx->dev;
|
|
struct coda_dev *dev = ctx->dev;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- mutex_lock(&dev->coda_mutex);
|
|
|
|
|
|
+ mutex_lock(&ctx->buffer_mutex);
|
|
|
|
|
|
- coda_prepare_encode(ctx);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If streamoff dequeued all buffers before we could get the lock,
|
|
|
|
+ * just bail out immediately.
|
|
|
|
+ */
|
|
|
|
+ if ((!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
|
|
|
|
+ ctx->inst_type != CODA_INST_DECODER) ||
|
|
|
|
+ !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
+ "%d: device_run without buffers\n", ctx->idx);
|
|
|
|
+ mutex_unlock(&ctx->buffer_mutex);
|
|
|
|
+ schedule_work(&ctx->skip_run);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (dev->devtype->product == CODA_7541) {
|
|
|
|
- coda_write(dev, CODA7_USE_BIT_ENABLE | CODA7_USE_HOST_BIT_ENABLE |
|
|
|
|
- CODA7_USE_ME_ENABLE | CODA7_USE_HOST_ME_ENABLE,
|
|
|
|
- CODA7_REG_BIT_AXI_SRAM_USE);
|
|
|
|
|
|
+ mutex_lock(&dev->coda_mutex);
|
|
|
|
+
|
|
|
|
+ if (ctx->inst_type == CODA_INST_DECODER) {
|
|
|
|
+ ret = coda_prepare_decode(ctx);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ mutex_unlock(&dev->coda_mutex);
|
|
|
|
+ mutex_unlock(&ctx->buffer_mutex);
|
|
|
|
+ /* job_finish scheduled by prepare_decode */
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ coda_prepare_encode(ctx);
|
|
}
|
|
}
|
|
|
|
|
|
if (dev->devtype->product != CODA_DX6)
|
|
if (dev->devtype->product != CODA_DX6)
|
|
@@ -947,6 +1194,8 @@ static void coda_device_run(void *m2m_priv)
|
|
/* 1 second timeout in case CODA locks up */
|
|
/* 1 second timeout in case CODA locks up */
|
|
schedule_delayed_work(&dev->timeout, HZ);
|
|
schedule_delayed_work(&dev->timeout, HZ);
|
|
|
|
|
|
|
|
+ if (ctx->inst_type == CODA_INST_DECODER)
|
|
|
|
+ coda_kfifo_sync_to_device_full(ctx);
|
|
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
|
|
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -972,6 +1221,16 @@ static int coda_job_ready(void *m2m_priv)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (ctx->prescan_failed ||
|
|
|
|
+ ((ctx->inst_type == CODA_INST_DECODER) &&
|
|
|
|
+ (coda_get_bitstream_payload(ctx) < 512) &&
|
|
|
|
+ !(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
|
|
|
|
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
|
+ "%d: not ready: not enough bitstream data.\n",
|
|
|
|
+ ctx->idx);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (ctx->aborting) {
|
|
if (ctx->aborting) {
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
"not ready: aborting\n");
|
|
"not ready: aborting\n");
|
|
@@ -1087,7 +1346,29 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
|
|
static void coda_buf_queue(struct vb2_buffer *vb)
|
|
static void coda_buf_queue(struct vb2_buffer *vb)
|
|
{
|
|
{
|
|
struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
|
|
struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
|
|
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
|
|
|
|
|
|
+ struct coda_q_data *q_data;
|
|
|
|
+
|
|
|
|
+ q_data = get_q_data(ctx, vb->vb2_queue->type);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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 &&
|
|
|
|
+ vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
|
|
|
+ /*
|
|
|
|
+ * For backwards compatiblity, queuing an empty buffer marks
|
|
|
|
+ * the stream end
|
|
|
|
+ */
|
|
|
|
+ if (vb2_get_plane_payload(vb, 0) == 0)
|
|
|
|
+ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
|
|
|
|
+ mutex_lock(&ctx->bitstream_mutex);
|
|
|
|
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
|
|
|
|
+ coda_fill_bitstream(ctx);
|
|
|
|
+ mutex_unlock(&ctx->bitstream_mutex);
|
|
|
|
+ } else {
|
|
|
|
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static void coda_wait_prepare(struct vb2_queue *q)
|
|
static void coda_wait_prepare(struct vb2_queue *q)
|
|
@@ -1375,6 +1656,8 @@ static void coda_free_context_buffers(struct coda_ctx *ctx)
|
|
{
|
|
{
|
|
struct coda_dev *dev = ctx->dev;
|
|
struct coda_dev *dev = ctx->dev;
|
|
|
|
|
|
|
|
+ coda_free_aux_buf(dev, &ctx->slicebuf);
|
|
|
|
+ coda_free_aux_buf(dev, &ctx->psbuf);
|
|
if (dev->devtype->product != CODA_DX6)
|
|
if (dev->devtype->product != CODA_DX6)
|
|
coda_free_aux_buf(dev, &ctx->workbuf);
|
|
coda_free_aux_buf(dev, &ctx->workbuf);
|
|
}
|
|
}
|
|
@@ -1394,12 +1677,40 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (ctx->psbuf.vaddr) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
|
|
+ if (ctx->slicebuf.vaddr) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n");
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
if (ctx->workbuf.vaddr) {
|
|
if (ctx->workbuf.vaddr) {
|
|
v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
|
|
v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
|
|
ret = -EBUSY;
|
|
ret = -EBUSY;
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (q_data->fourcc == V4L2_PIX_FMT_H264) {
|
|
|
|
+ /* worst case slice size */
|
|
|
|
+ size = (DIV_ROUND_UP(q_data->width, 16) *
|
|
|
|
+ DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
|
|
|
|
+ ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
|
|
|
|
+ ctx->slicebuf.size);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (dev->devtype->product == CODA_7541) {
|
|
|
|
+ ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
|
|
|
|
+ goto err;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
|
|
ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
|
|
v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
|
|
@@ -1414,6 +1725,148 @@ err:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int coda_start_decoding(struct coda_ctx *ctx)
|
|
|
|
+{
|
|
|
|
+ struct coda_q_data *q_data_src, *q_data_dst;
|
|
|
|
+ u32 bitstream_buf, bitstream_size;
|
|
|
|
+ struct coda_dev *dev = ctx->dev;
|
|
|
|
+ int width, height;
|
|
|
|
+ u32 src_fourcc;
|
|
|
|
+ u32 val;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ /* Start decoding */
|
|
|
|
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
|
|
+ bitstream_buf = ctx->bitstream.paddr;
|
|
|
|
+ bitstream_size = ctx->bitstream.size;
|
|
|
|
+ src_fourcc = q_data_src->fourcc;
|
|
|
|
+
|
|
|
|
+ coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
|
|
|
|
+
|
|
|
|
+ /* Update coda bitstream read and write pointers from kfifo */
|
|
|
|
+ coda_kfifo_sync_to_device_full(ctx);
|
|
|
|
+
|
|
|
|
+ ctx->display_idx = -1;
|
|
|
|
+ ctx->frm_dis_flg = 0;
|
|
|
|
+ coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
|
|
|
|
+
|
|
|
|
+ coda_write(dev, CODA_BIT_DEC_SEQ_INIT_ESCAPE,
|
|
|
|
+ CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
|
|
+
|
|
|
|
+ coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
|
|
|
|
+ coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
|
|
|
|
+ val = 0;
|
|
|
|
+ if (dev->devtype->product == CODA_7541)
|
|
|
|
+ val |= CODA_REORDER_ENABLE;
|
|
|
|
+ coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
|
|
|
|
+
|
|
|
|
+ ctx->params.codec_mode = ctx->codec->mode;
|
|
|
|
+ ctx->params.codec_mode_aux = 0;
|
|
|
|
+ if (src_fourcc == V4L2_PIX_FMT_H264) {
|
|
|
|
+ if (dev->devtype->product == CODA_7541) {
|
|
|
|
+ coda_write(dev, ctx->psbuf.paddr,
|
|
|
|
+ CODA_CMD_DEC_SEQ_PS_BB_START);
|
|
|
|
+ coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
|
|
|
|
+ CODA_CMD_DEC_SEQ_PS_BB_SIZE);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
|
|
|
|
+ coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
|
|
+ return -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Update kfifo out pointer from coda bitstream read pointer */
|
|
|
|
+ coda_kfifo_sync_from_device(ctx);
|
|
|
|
+
|
|
|
|
+ coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
|
|
+
|
|
|
|
+ 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_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE);
|
|
|
|
+ if (dev->devtype->product == CODA_DX6) {
|
|
|
|
+ width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK;
|
|
|
|
+ height = val & CODADX6_PICHEIGHT_MASK;
|
|
|
|
+ } else {
|
|
|
|
+ width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK;
|
|
|
|
+ height = val & CODA7_PICHEIGHT_MASK;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (width > q_data_dst->width || height > q_data_dst->height) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
|
|
|
|
+ width, height, q_data_dst->width, q_data_dst->height);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED) + 1;
|
|
|
|
+ if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "not enough framebuffers to decode (%d < %d)\n",
|
|
|
|
+ CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ /* Tell the decoder how many frame buffers we allocated. */
|
|
|
|
+ coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
|
|
|
|
+ coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE);
|
|
|
|
+
|
|
|
|
+ if (dev->devtype->product != CODA_DX6) {
|
|
|
|
+ /* Set secondary AXI IRAM */
|
|
|
|
+ coda_setup_iram(ctx);
|
|
|
|
+
|
|
|
|
+ coda_write(dev, ctx->iram_info.buf_bit_use,
|
|
|
|
+ CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
|
|
|
|
+ coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use,
|
|
|
|
+ CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR);
|
|
|
|
+ coda_write(dev, ctx->iram_info.buf_dbk_y_use,
|
|
|
|
+ CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR);
|
|
|
|
+ coda_write(dev, ctx->iram_info.buf_dbk_c_use,
|
|
|
|
+ CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
|
|
|
|
+ coda_write(dev, ctx->iram_info.buf_ovl_use,
|
|
|
|
+ CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (src_fourcc == V4L2_PIX_FMT_H264) {
|
|
|
|
+ coda_write(dev, ctx->slicebuf.paddr,
|
|
|
|
+ CODA_CMD_SET_FRAME_SLICE_BB_START);
|
|
|
|
+ coda_write(dev, ctx->slicebuf.size / 1024,
|
|
|
|
+ CODA_CMD_SET_FRAME_SLICE_BB_SIZE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (dev->devtype->product == CODA_7541) {
|
|
|
|
+ int max_mb_x = 1920 / 16;
|
|
|
|
+ int max_mb_y = 1088 / 16;
|
|
|
|
+ int max_mb_num = max_mb_x * max_mb_y;
|
|
|
|
+ coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
|
|
|
|
+ CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
|
|
|
|
+ v4l2_err(&ctx->dev->v4l2_dev,
|
|
|
|
+ "CODA_COMMAND_SET_FRAME_BUF timeout\n");
|
|
|
|
+ return -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
|
|
static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
|
|
int header_code, u8 *header, int *size)
|
|
int header_code, u8 *header, int *size)
|
|
{
|
|
{
|
|
@@ -1448,26 +1901,36 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|
u32 value;
|
|
u32 value;
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
- if (count < 1)
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ 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 (coda_get_bitstream_payload(ctx) < 512)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ } else {
|
|
|
|
+ if (count < 1)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
|
|
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
|
|
|
ctx->streamon_out = 1;
|
|
ctx->streamon_out = 1;
|
|
- else
|
|
|
|
- ctx->streamon_cap = 1;
|
|
|
|
|
|
|
|
- q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
- if (ctx->streamon_out) {
|
|
|
|
if (coda_format_is_yuv(q_data_src->fourcc))
|
|
if (coda_format_is_yuv(q_data_src->fourcc))
|
|
ctx->inst_type = CODA_INST_ENCODER;
|
|
ctx->inst_type = CODA_INST_ENCODER;
|
|
else
|
|
else
|
|
ctx->inst_type = CODA_INST_DECODER;
|
|
ctx->inst_type = CODA_INST_DECODER;
|
|
|
|
+ } else {
|
|
|
|
+ if (count < 1)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ ctx->streamon_cap = 1;
|
|
}
|
|
}
|
|
|
|
|
|
/* Don't start the coda unless both queues are on */
|
|
/* Don't start the coda unless both queues are on */
|
|
if (!(ctx->streamon_out & ctx->streamon_cap))
|
|
if (!(ctx->streamon_out & ctx->streamon_cap))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ /* Allow device_run with no buffers queued and after streamoff */
|
|
|
|
+ v4l2_m2m_set_src_buffered(ctx->m2m_ctx, true);
|
|
|
|
+
|
|
ctx->gopcounter = ctx->params.gop_size - 1;
|
|
ctx->gopcounter = ctx->params.gop_size - 1;
|
|
buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
|
|
buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
|
|
bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
|
|
bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
|
|
@@ -1487,6 +1950,20 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
|
|
|
|
|
|
+ if (ctx->inst_type == CODA_INST_DECODER) {
|
|
|
|
+ mutex_lock(&dev->coda_mutex);
|
|
|
|
+ ret = coda_start_decoding(ctx);
|
|
|
|
+ mutex_unlock(&dev->coda_mutex);
|
|
|
|
+ if (ret == -EAGAIN) {
|
|
|
|
+ return 0;
|
|
|
|
+ } else if (ret < 0) {
|
|
|
|
+ return ret;
|
|
|
|
+ } else {
|
|
|
|
+ ctx->initialized = 1;
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!coda_is_initialized(dev)) {
|
|
if (!coda_is_initialized(dev)) {
|
|
v4l2_err(v4l2_dev, "coda is not initialized.\n");
|
|
v4l2_err(v4l2_dev, "coda is not initialized.\n");
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
@@ -1628,6 +2105,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|
|
|
|
|
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
|
|
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
|
|
coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
|
|
coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
|
|
|
|
+ if (dev->devtype->product == CODA_7541)
|
|
|
|
+ coda_write(dev, round_up(q_data_src->width, 8),
|
|
|
|
+ CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
|
|
if (dev->devtype->product != CODA_DX6) {
|
|
if (dev->devtype->product != CODA_DX6) {
|
|
coda_write(dev, ctx->iram_info.buf_bit_use,
|
|
coda_write(dev, ctx->iram_info.buf_bit_use,
|
|
CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
|
|
CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
|
|
@@ -1719,32 +2199,26 @@ static int coda_stop_streaming(struct vb2_queue *q)
|
|
struct coda_dev *dev = ctx->dev;
|
|
struct coda_dev *dev = ctx->dev;
|
|
|
|
|
|
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
|
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
|
- v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
"%s: output\n", __func__);
|
|
"%s: output\n", __func__);
|
|
ctx->streamon_out = 0;
|
|
ctx->streamon_out = 0;
|
|
|
|
+
|
|
|
|
+ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
|
|
|
|
+
|
|
|
|
+ ctx->isequence = 0;
|
|
} else {
|
|
} else {
|
|
- v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
"%s: capture\n", __func__);
|
|
"%s: capture\n", __func__);
|
|
ctx->streamon_cap = 0;
|
|
ctx->streamon_cap = 0;
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Don't stop the coda unless both queues are off */
|
|
|
|
- if (ctx->streamon_out || ctx->streamon_cap)
|
|
|
|
- return 0;
|
|
|
|
|
|
|
|
- cancel_delayed_work(&dev->timeout);
|
|
|
|
-
|
|
|
|
- mutex_lock(&dev->coda_mutex);
|
|
|
|
- v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
- "%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");
|
|
|
|
- return -ETIMEDOUT;
|
|
|
|
|
|
+ ctx->osequence = 0;
|
|
}
|
|
}
|
|
- mutex_unlock(&dev->coda_mutex);
|
|
|
|
|
|
|
|
- coda_free_framebuffers(ctx);
|
|
|
|
|
|
+ if (!ctx->streamon_out && !ctx->streamon_cap) {
|
|
|
|
+ kfifo_init(&ctx->bitstream_fifo,
|
|
|
|
+ ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
|
|
+ ctx->runcounter = 0;
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -1904,7 +2378,7 @@ static int coda_open(struct file *file)
|
|
{
|
|
{
|
|
struct coda_dev *dev = video_drvdata(file);
|
|
struct coda_dev *dev = video_drvdata(file);
|
|
struct coda_ctx *ctx = NULL;
|
|
struct coda_ctx *ctx = NULL;
|
|
- int ret = 0;
|
|
|
|
|
|
+ int ret;
|
|
int idx;
|
|
int idx;
|
|
|
|
|
|
idx = coda_next_free_instance(dev);
|
|
idx = coda_next_free_instance(dev);
|
|
@@ -1916,6 +2390,7 @@ static int coda_open(struct file *file)
|
|
if (!ctx)
|
|
if (!ctx)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
+ INIT_WORK(&ctx->skip_run, coda_skip_run);
|
|
v4l2_fh_init(&ctx->fh, video_devdata(file));
|
|
v4l2_fh_init(&ctx->fh, video_devdata(file));
|
|
file->private_data = &ctx->fh;
|
|
file->private_data = &ctx->fh;
|
|
v4l2_fh_add(&ctx->fh);
|
|
v4l2_fh_add(&ctx->fh);
|
|
@@ -1963,6 +2438,7 @@ static int coda_open(struct file *file)
|
|
kfifo_init(&ctx->bitstream_fifo,
|
|
kfifo_init(&ctx->bitstream_fifo,
|
|
ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
mutex_init(&ctx->bitstream_mutex);
|
|
mutex_init(&ctx->bitstream_mutex);
|
|
|
|
+ mutex_init(&ctx->buffer_mutex);
|
|
|
|
|
|
coda_lock(ctx);
|
|
coda_lock(ctx);
|
|
list_add(&ctx->list, &dev->instances);
|
|
list_add(&ctx->list, &dev->instances);
|
|
@@ -1991,6 +2467,23 @@ static int coda_release(struct file *file)
|
|
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
|
|
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
|
|
ctx);
|
|
ctx);
|
|
|
|
|
|
|
|
+ /* If this instance is running, call .job_abort and wait for it to end */
|
|
|
|
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
|
|
|
+
|
|
|
|
+ /* In case the instance was not running, we still need to call SEQ_END */
|
|
|
|
+ mutex_lock(&dev->coda_mutex);
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
+ "%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");
|
|
|
|
+ mutex_unlock(&dev->coda_mutex);
|
|
|
|
+ return -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+ mutex_unlock(&dev->coda_mutex);
|
|
|
|
+
|
|
|
|
+ coda_free_framebuffers(ctx);
|
|
|
|
+
|
|
coda_lock(ctx);
|
|
coda_lock(ctx);
|
|
list_del(&ctx->list);
|
|
list_del(&ctx->list);
|
|
coda_unlock(ctx);
|
|
coda_unlock(ctx);
|
|
@@ -2041,7 +2534,159 @@ static const struct v4l2_file_operations coda_fops = {
|
|
.mmap = coda_mmap,
|
|
.mmap = coda_mmap,
|
|
};
|
|
};
|
|
|
|
|
|
-static void coda_encode_finish(struct coda_ctx *ctx)
|
|
|
|
|
|
+static void coda_finish_decode(struct coda_ctx *ctx)
|
|
|
|
+{
|
|
|
|
+ struct coda_dev *dev = ctx->dev;
|
|
|
|
+ struct coda_q_data *q_data_src;
|
|
|
|
+ struct coda_q_data *q_data_dst;
|
|
|
|
+ struct vb2_buffer *dst_buf;
|
|
|
|
+ int width, height;
|
|
|
|
+ int decoded_idx;
|
|
|
|
+ int display_idx;
|
|
|
|
+ u32 src_fourcc;
|
|
|
|
+ int success;
|
|
|
|
+ u32 val;
|
|
|
|
+
|
|
|
|
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
|
|
|
|
+
|
|
|
|
+ /* Update kfifo out pointer from coda bitstream read pointer */
|
|
|
|
+ coda_kfifo_sync_from_device(ctx);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * in stream-end mode, the read pointer can overshoot the write pointer
|
|
|
|
+ * by up to 512 bytes
|
|
|
|
+ */
|
|
|
|
+ if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) {
|
|
|
|
+ if (coda_get_bitstream_payload(ctx) >= 0x100000 - 512)
|
|
|
|
+ kfifo_init(&ctx->bitstream_fifo,
|
|
|
|
+ ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
|
|
+ src_fourcc = q_data_src->fourcc;
|
|
|
|
+
|
|
|
|
+ val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS);
|
|
|
|
+ if (val != 1)
|
|
|
|
+ pr_err("DEC_PIC_SUCCESS = %d\n", val);
|
|
|
|
+
|
|
|
|
+ success = val & 0x1;
|
|
|
|
+ if (!success)
|
|
|
|
+ v4l2_err(&dev->v4l2_dev, "decode failed\n");
|
|
|
|
+
|
|
|
|
+ if (src_fourcc == V4L2_PIX_FMT_H264) {
|
|
|
|
+ if (val & (1 << 3))
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "insufficient PS buffer space (%d bytes)\n",
|
|
|
|
+ ctx->psbuf.size);
|
|
|
|
+ if (val & (1 << 2))
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "insufficient slice buffer space (%d bytes)\n",
|
|
|
|
+ ctx->slicebuf.size);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ val = coda_read(dev, CODA_RET_DEC_PIC_SIZE);
|
|
|
|
+ width = (val >> 16) & 0xffff;
|
|
|
|
+ height = val & 0xffff;
|
|
|
|
+
|
|
|
|
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
|
|
+
|
|
|
|
+ val = coda_read(dev, CODA_RET_DEC_PIC_TYPE);
|
|
|
|
+ if ((val & 0x7) == 0) {
|
|
|
|
+ dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
|
|
|
|
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
|
|
|
|
+ } else {
|
|
|
|
+ dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
|
|
|
|
+ dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ val = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
|
|
|
|
+ if (val > 0)
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "errors in %d macroblocks\n", val);
|
|
|
|
+
|
|
|
|
+ if (dev->devtype->product == CODA_7541) {
|
|
|
|
+ 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);
|
|
|
|
+ ctx->prescan_failed = true;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ctx->frm_dis_flg = coda_read(dev, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The previous display frame was copied out by the rotator,
|
|
|
|
+ * now it can be overwritten again
|
|
|
|
+ */
|
|
|
|
+ if (ctx->display_idx >= 0 &&
|
|
|
|
+ ctx->display_idx < ctx->num_internal_frames) {
|
|
|
|
+ ctx->frm_dis_flg &= ~(1 << ctx->display_idx);
|
|
|
|
+ coda_write(dev, ctx->frm_dis_flg,
|
|
|
|
+ CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * The index of the last decoded frame, not necessarily in
|
|
|
|
+ * display order, and the index of the next display frame.
|
|
|
|
+ * The latter could have been decoded in a previous run.
|
|
|
|
+ */
|
|
|
|
+ decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX);
|
|
|
|
+ display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX);
|
|
|
|
+
|
|
|
|
+ if (decoded_idx == -1) {
|
|
|
|
+ /* no frame was decoded, but we might have a display frame */
|
|
|
|
+ if (display_idx < 0 && ctx->display_idx < 0)
|
|
|
|
+ ctx->prescan_failed = true;
|
|
|
|
+ } else if (decoded_idx == -2) {
|
|
|
|
+ /* no frame was decoded, we still return the remaining buffers */
|
|
|
|
+ } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "decoded frame index out of range: %d\n", decoded_idx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (display_idx == -1) {
|
|
|
|
+ /*
|
|
|
|
+ * no more frames to be decoded, but there could still
|
|
|
|
+ * be rotator output to dequeue
|
|
|
|
+ */
|
|
|
|
+ ctx->prescan_failed = true;
|
|
|
|
+ } else if (display_idx == -3) {
|
|
|
|
+ /* possibly prescan failure */
|
|
|
|
+ } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
|
|
|
|
+ v4l2_err(&dev->v4l2_dev,
|
|
|
|
+ "presentation frame index out of range: %d\n",
|
|
|
|
+ display_idx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* If a frame was copied out, return it */
|
|
|
|
+ if (ctx->display_idx >= 0 &&
|
|
|
|
+ ctx->display_idx < ctx->num_internal_frames) {
|
|
|
|
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
|
|
|
|
+ dst_buf->v4l2_buf.sequence = ctx->osequence++;
|
|
|
|
+
|
|
|
|
+ vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
|
|
|
|
+
|
|
|
|
+ v4l2_m2m_buf_done(dst_buf, success ? VB2_BUF_STATE_DONE :
|
|
|
|
+ VB2_BUF_STATE_ERROR);
|
|
|
|
+
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
+ "job finished: decoding frame (%d) (%s)\n",
|
|
|
|
+ dst_buf->v4l2_buf.sequence,
|
|
|
|
+ (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
|
|
|
|
+ "KEYFRAME" : "PFRAME");
|
|
|
|
+ } else {
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
+ "job finished: no frame decoded\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* The rotator will copy the current display frame next time */
|
|
|
|
+ ctx->display_idx = display_idx;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void coda_finish_encode(struct coda_ctx *ctx)
|
|
{
|
|
{
|
|
struct vb2_buffer *src_buf, *dst_buf;
|
|
struct vb2_buffer *src_buf, *dst_buf;
|
|
struct coda_dev *dev = ctx->dev;
|
|
struct coda_dev *dev = ctx->dev;
|
|
@@ -2118,8 +2763,7 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
|
|
if (ctx->aborting) {
|
|
if (ctx->aborting) {
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
|
"task has been aborted\n");
|
|
"task has been aborted\n");
|
|
- mutex_unlock(&dev->coda_mutex);
|
|
|
|
- return IRQ_HANDLED;
|
|
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (coda_isbusy(ctx->dev)) {
|
|
if (coda_isbusy(ctx->dev)) {
|
|
@@ -2128,9 +2772,29 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
- coda_encode_finish(ctx);
|
|
|
|
|
|
+ if (ctx->inst_type == CODA_INST_DECODER)
|
|
|
|
+ coda_finish_decode(ctx);
|
|
|
|
+ else
|
|
|
|
+ coda_finish_encode(ctx);
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) {
|
|
|
|
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
|
|
|
+ "%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");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kfifo_init(&ctx->bitstream_fifo,
|
|
|
|
+ ctx->bitstream.vaddr, ctx->bitstream.size);
|
|
|
|
+
|
|
|
|
+ coda_free_framebuffers(ctx);
|
|
|
|
+ coda_free_context_buffers(ctx);
|
|
|
|
+ }
|
|
|
|
|
|
mutex_unlock(&dev->coda_mutex);
|
|
mutex_unlock(&dev->coda_mutex);
|
|
|
|
+ mutex_unlock(&ctx->buffer_mutex);
|
|
|
|
|
|
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
|
|
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
|
|
|
|
|
|
@@ -2147,6 +2811,8 @@ static void coda_timeout(struct work_struct *work)
|
|
|
|
|
|
mutex_lock(&dev->dev_mutex);
|
|
mutex_lock(&dev->dev_mutex);
|
|
list_for_each_entry(ctx, &dev->instances, list) {
|
|
list_for_each_entry(ctx, &dev->instances, list) {
|
|
|
|
+ if (mutex_is_locked(&ctx->buffer_mutex))
|
|
|
|
+ mutex_unlock(&ctx->buffer_mutex);
|
|
v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
|
v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
}
|
|
}
|
|
@@ -2227,6 +2893,7 @@ static int coda_hw_init(struct coda_dev *dev)
|
|
if (dev->devtype->product == CODA_7541) {
|
|
if (dev->devtype->product == CODA_7541) {
|
|
coda_write(dev, dev->tempbuf.paddr,
|
|
coda_write(dev, dev->tempbuf.paddr,
|
|
CODA_REG_BIT_TEMP_BUF_ADDR);
|
|
CODA_REG_BIT_TEMP_BUF_ADDR);
|
|
|
|
+ coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
|
|
} else {
|
|
} else {
|
|
coda_write(dev, dev->workbuf.paddr,
|
|
coda_write(dev, dev->workbuf.paddr,
|
|
CODA_REG_BIT_WORK_BUF_ADDR);
|
|
CODA_REG_BIT_WORK_BUF_ADDR);
|
|
@@ -2471,8 +3138,8 @@ static int coda_probe(struct platform_device *pdev)
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
- if (devm_request_irq(&pdev->dev, irq, coda_irq_handler,
|
|
|
|
- 0, CODA_NAME, dev) < 0) {
|
|
|
|
|
|
+ if (devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
|
|
|
|
+ IRQF_ONESHOT, CODA_NAME, dev) < 0) {
|
|
dev_err(&pdev->dev, "failed to request irq\n");
|
|
dev_err(&pdev->dev, "failed to request irq\n");
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
}
|
|
}
|
|
@@ -2530,10 +3197,14 @@ static int coda_probe(struct platform_device *pdev)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (dev->devtype->product == CODA_DX6)
|
|
|
|
|
|
+ switch (dev->devtype->product) {
|
|
|
|
+ case CODA_DX6:
|
|
dev->iram_size = CODADX6_IRAM_SIZE;
|
|
dev->iram_size = CODADX6_IRAM_SIZE;
|
|
- else
|
|
|
|
|
|
+ break;
|
|
|
|
+ case CODA_7541:
|
|
dev->iram_size = CODA7_IRAM_SIZE;
|
|
dev->iram_size = CODA7_IRAM_SIZE;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
dev->iram_vaddr = gen_pool_alloc(dev->iram_pool, dev->iram_size);
|
|
dev->iram_vaddr = gen_pool_alloc(dev->iram_pool, dev->iram_size);
|
|
if (!dev->iram_vaddr) {
|
|
if (!dev->iram_vaddr) {
|
|
dev_err(&pdev->dev, "unable to alloc iram\n");
|
|
dev_err(&pdev->dev, "unable to alloc iram\n");
|