164441979SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-or-later 264441979SMauro Carvalho Chehab /* 364441979SMauro Carvalho Chehab * Coda multi-standard codec IP - BIT processor functions 464441979SMauro Carvalho Chehab * 564441979SMauro Carvalho Chehab * Copyright (C) 2012 Vista Silicon S.L. 664441979SMauro Carvalho Chehab * Javier Martin, <javier.martin@vista-silicon.com> 764441979SMauro Carvalho Chehab * Xavier Duret 864441979SMauro Carvalho Chehab * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix 964441979SMauro Carvalho Chehab */ 1064441979SMauro Carvalho Chehab 1164441979SMauro Carvalho Chehab #include <linux/clk.h> 1264441979SMauro Carvalho Chehab #include <linux/irqreturn.h> 1364441979SMauro Carvalho Chehab #include <linux/kernel.h> 1464441979SMauro Carvalho Chehab #include <linux/log2.h> 1564441979SMauro Carvalho Chehab #include <linux/platform_device.h> 1664441979SMauro Carvalho Chehab #include <linux/ratelimit.h> 1764441979SMauro Carvalho Chehab #include <linux/reset.h> 1864441979SMauro Carvalho Chehab #include <linux/slab.h> 1964441979SMauro Carvalho Chehab #include <linux/videodev2.h> 2064441979SMauro Carvalho Chehab 2164441979SMauro Carvalho Chehab #include <media/v4l2-common.h> 2264441979SMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 2364441979SMauro Carvalho Chehab #include <media/v4l2-fh.h> 2464441979SMauro Carvalho Chehab #include <media/v4l2-mem2mem.h> 2564441979SMauro Carvalho Chehab #include <media/videobuf2-v4l2.h> 2664441979SMauro Carvalho Chehab #include <media/videobuf2-dma-contig.h> 2764441979SMauro Carvalho Chehab #include <media/videobuf2-vmalloc.h> 2864441979SMauro Carvalho Chehab 2964441979SMauro Carvalho Chehab #include "coda.h" 3064441979SMauro Carvalho Chehab #include "imx-vdoa.h" 3164441979SMauro Carvalho Chehab #define CREATE_TRACE_POINTS 3264441979SMauro Carvalho Chehab #include "trace.h" 3364441979SMauro Carvalho Chehab 3464441979SMauro Carvalho Chehab #define CODA_PARA_BUF_SIZE (10 * 1024) 3564441979SMauro Carvalho Chehab #define CODA7_PS_BUF_SIZE 0x28000 3664441979SMauro Carvalho Chehab #define CODA9_PS_SAVE_SIZE (512 * 1024) 3764441979SMauro Carvalho Chehab 3864441979SMauro Carvalho Chehab #define CODA_DEFAULT_GAMMA 4096 3964441979SMauro Carvalho Chehab #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ 4064441979SMauro Carvalho Chehab 4164441979SMauro Carvalho Chehab static void coda_free_bitstream_buffer(struct coda_ctx *ctx); 4264441979SMauro Carvalho Chehab 4364441979SMauro Carvalho Chehab static inline int coda_is_initialized(struct coda_dev *dev) 4464441979SMauro Carvalho Chehab { 4564441979SMauro Carvalho Chehab return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; 4664441979SMauro Carvalho Chehab } 4764441979SMauro Carvalho Chehab 4864441979SMauro Carvalho Chehab static inline unsigned long coda_isbusy(struct coda_dev *dev) 4964441979SMauro Carvalho Chehab { 5064441979SMauro Carvalho Chehab return coda_read(dev, CODA_REG_BIT_BUSY); 5164441979SMauro Carvalho Chehab } 5264441979SMauro Carvalho Chehab 5364441979SMauro Carvalho Chehab static int coda_wait_timeout(struct coda_dev *dev) 5464441979SMauro Carvalho Chehab { 5564441979SMauro Carvalho Chehab unsigned long timeout = jiffies + msecs_to_jiffies(1000); 5664441979SMauro Carvalho Chehab 5764441979SMauro Carvalho Chehab while (coda_isbusy(dev)) { 5864441979SMauro Carvalho Chehab if (time_after(jiffies, timeout)) 5964441979SMauro Carvalho Chehab return -ETIMEDOUT; 6064441979SMauro Carvalho Chehab } 6164441979SMauro Carvalho Chehab return 0; 6264441979SMauro Carvalho Chehab } 6364441979SMauro Carvalho Chehab 6464441979SMauro Carvalho Chehab static void coda_command_async(struct coda_ctx *ctx, int cmd) 6564441979SMauro Carvalho Chehab { 6664441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 6764441979SMauro Carvalho Chehab 6864441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 6964441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541 || 7064441979SMauro Carvalho Chehab dev->devtype->product == CODA_960) { 7164441979SMauro Carvalho Chehab /* Restore context related registers to CODA */ 7264441979SMauro Carvalho Chehab coda_write(dev, ctx->bit_stream_param, 7364441979SMauro Carvalho Chehab CODA_REG_BIT_BIT_STREAM_PARAM); 7464441979SMauro Carvalho Chehab coda_write(dev, ctx->frm_dis_flg, 7564441979SMauro Carvalho Chehab CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 7664441979SMauro Carvalho Chehab coda_write(dev, ctx->frame_mem_ctrl, 7764441979SMauro Carvalho Chehab CODA_REG_BIT_FRAME_MEM_CTRL); 7864441979SMauro Carvalho Chehab coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); 7964441979SMauro Carvalho Chehab } 8064441979SMauro Carvalho Chehab 8164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 8264441979SMauro Carvalho Chehab coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); 8364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 8464441979SMauro Carvalho Chehab } 8564441979SMauro Carvalho Chehab 8664441979SMauro Carvalho Chehab coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 8764441979SMauro Carvalho Chehab 8864441979SMauro Carvalho Chehab coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); 8964441979SMauro Carvalho Chehab coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); 9064441979SMauro Carvalho Chehab coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); 9164441979SMauro Carvalho Chehab 9264441979SMauro Carvalho Chehab trace_coda_bit_run(ctx, cmd); 9364441979SMauro Carvalho Chehab 9464441979SMauro Carvalho Chehab coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); 9564441979SMauro Carvalho Chehab } 9664441979SMauro Carvalho Chehab 9764441979SMauro Carvalho Chehab static int coda_command_sync(struct coda_ctx *ctx, int cmd) 9864441979SMauro Carvalho Chehab { 9964441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 10064441979SMauro Carvalho Chehab int ret; 10164441979SMauro Carvalho Chehab 10264441979SMauro Carvalho Chehab lockdep_assert_held(&dev->coda_mutex); 10364441979SMauro Carvalho Chehab 10464441979SMauro Carvalho Chehab coda_command_async(ctx, cmd); 10564441979SMauro Carvalho Chehab ret = coda_wait_timeout(dev); 10664441979SMauro Carvalho Chehab trace_coda_bit_done(ctx); 10764441979SMauro Carvalho Chehab 10864441979SMauro Carvalho Chehab return ret; 10964441979SMauro Carvalho Chehab } 11064441979SMauro Carvalho Chehab 11164441979SMauro Carvalho Chehab int coda_hw_reset(struct coda_ctx *ctx) 11264441979SMauro Carvalho Chehab { 11364441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 11464441979SMauro Carvalho Chehab unsigned long timeout; 11564441979SMauro Carvalho Chehab unsigned int idx; 11664441979SMauro Carvalho Chehab int ret; 11764441979SMauro Carvalho Chehab 11864441979SMauro Carvalho Chehab lockdep_assert_held(&dev->coda_mutex); 11964441979SMauro Carvalho Chehab 12064441979SMauro Carvalho Chehab if (!dev->rstc) 12164441979SMauro Carvalho Chehab return -ENOENT; 12264441979SMauro Carvalho Chehab 12364441979SMauro Carvalho Chehab idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); 12464441979SMauro Carvalho Chehab 12564441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 12664441979SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(100); 12764441979SMauro Carvalho Chehab coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); 12864441979SMauro Carvalho Chehab while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { 12964441979SMauro Carvalho Chehab if (time_after(jiffies, timeout)) 13064441979SMauro Carvalho Chehab return -ETIME; 13164441979SMauro Carvalho Chehab cpu_relax(); 13264441979SMauro Carvalho Chehab } 13364441979SMauro Carvalho Chehab } 13464441979SMauro Carvalho Chehab 13564441979SMauro Carvalho Chehab ret = reset_control_reset(dev->rstc); 13664441979SMauro Carvalho Chehab if (ret < 0) 13764441979SMauro Carvalho Chehab return ret; 13864441979SMauro Carvalho Chehab 13964441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 14064441979SMauro Carvalho Chehab coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); 14164441979SMauro Carvalho Chehab coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 14264441979SMauro Carvalho Chehab coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); 14364441979SMauro Carvalho Chehab ret = coda_wait_timeout(dev); 14464441979SMauro Carvalho Chehab coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); 14564441979SMauro Carvalho Chehab 14664441979SMauro Carvalho Chehab return ret; 14764441979SMauro Carvalho Chehab } 14864441979SMauro Carvalho Chehab 14964441979SMauro Carvalho Chehab static void coda_kfifo_sync_from_device(struct coda_ctx *ctx) 15064441979SMauro Carvalho Chehab { 15164441979SMauro Carvalho Chehab struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 15264441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 15364441979SMauro Carvalho Chehab u32 rd_ptr; 15464441979SMauro Carvalho Chehab 15564441979SMauro Carvalho Chehab rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 15664441979SMauro Carvalho Chehab kfifo->out = (kfifo->in & ~kfifo->mask) | 15764441979SMauro Carvalho Chehab (rd_ptr - ctx->bitstream.paddr); 15864441979SMauro Carvalho Chehab if (kfifo->out > kfifo->in) 15964441979SMauro Carvalho Chehab kfifo->out -= kfifo->mask + 1; 16064441979SMauro Carvalho Chehab } 16164441979SMauro Carvalho Chehab 16264441979SMauro Carvalho Chehab static void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) 16364441979SMauro Carvalho Chehab { 16464441979SMauro Carvalho Chehab struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 16564441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 16664441979SMauro Carvalho Chehab u32 rd_ptr, wr_ptr; 16764441979SMauro Carvalho Chehab 16864441979SMauro Carvalho Chehab rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); 16964441979SMauro Carvalho Chehab coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 17064441979SMauro Carvalho Chehab wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 17164441979SMauro Carvalho Chehab coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 17264441979SMauro Carvalho Chehab } 17364441979SMauro Carvalho Chehab 17464441979SMauro Carvalho Chehab static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) 17564441979SMauro Carvalho Chehab { 17664441979SMauro Carvalho Chehab struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 17764441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 17864441979SMauro Carvalho Chehab u32 wr_ptr; 17964441979SMauro Carvalho Chehab 18064441979SMauro Carvalho Chehab wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 18164441979SMauro Carvalho Chehab coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 18264441979SMauro Carvalho Chehab } 18364441979SMauro Carvalho Chehab 18464441979SMauro Carvalho Chehab static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) 18564441979SMauro Carvalho Chehab { 18664441979SMauro Carvalho Chehab unsigned char *buf; 18764441979SMauro Carvalho Chehab u32 n; 18864441979SMauro Carvalho Chehab 18964441979SMauro Carvalho Chehab if (size < 6) 19064441979SMauro Carvalho Chehab size = 6; 19164441979SMauro Carvalho Chehab 19264441979SMauro Carvalho Chehab buf = kmalloc(size, GFP_KERNEL); 19364441979SMauro Carvalho Chehab if (!buf) 19464441979SMauro Carvalho Chehab return -ENOMEM; 19564441979SMauro Carvalho Chehab 19664441979SMauro Carvalho Chehab coda_h264_filler_nal(size, buf); 19764441979SMauro Carvalho Chehab n = kfifo_in(&ctx->bitstream_fifo, buf, size); 19864441979SMauro Carvalho Chehab kfree(buf); 19964441979SMauro Carvalho Chehab 20064441979SMauro Carvalho Chehab return (n < size) ? -ENOSPC : 0; 20164441979SMauro Carvalho Chehab } 20264441979SMauro Carvalho Chehab 20364441979SMauro Carvalho Chehab int coda_bitstream_flush(struct coda_ctx *ctx) 20464441979SMauro Carvalho Chehab { 20564441979SMauro Carvalho Chehab int ret; 20664441979SMauro Carvalho Chehab 20764441979SMauro Carvalho Chehab if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) 20864441979SMauro Carvalho Chehab return 0; 20964441979SMauro Carvalho Chehab 21064441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); 21164441979SMauro Carvalho Chehab if (ret < 0) { 21264441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); 21364441979SMauro Carvalho Chehab return ret; 21464441979SMauro Carvalho Chehab } 21564441979SMauro Carvalho Chehab 21664441979SMauro Carvalho Chehab kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, 21764441979SMauro Carvalho Chehab ctx->bitstream.size); 21864441979SMauro Carvalho Chehab coda_kfifo_sync_to_device_full(ctx); 21964441979SMauro Carvalho Chehab 22064441979SMauro Carvalho Chehab return 0; 22164441979SMauro Carvalho Chehab } 22264441979SMauro Carvalho Chehab 22364441979SMauro Carvalho Chehab static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) 22464441979SMauro Carvalho Chehab { 22564441979SMauro Carvalho Chehab u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); 22664441979SMauro Carvalho Chehab 22764441979SMauro Carvalho Chehab return (n < size) ? -ENOSPC : 0; 22864441979SMauro Carvalho Chehab } 22964441979SMauro Carvalho Chehab 23064441979SMauro Carvalho Chehab static u32 coda_buffer_parse_headers(struct coda_ctx *ctx, 23164441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf, 23264441979SMauro Carvalho Chehab u32 payload) 23364441979SMauro Carvalho Chehab { 23464441979SMauro Carvalho Chehab u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 23564441979SMauro Carvalho Chehab u32 size = 0; 23664441979SMauro Carvalho Chehab 23764441979SMauro Carvalho Chehab switch (ctx->codec->src_fourcc) { 23864441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG2: 23964441979SMauro Carvalho Chehab size = coda_mpeg2_parse_headers(ctx, vaddr, payload); 24064441979SMauro Carvalho Chehab break; 24164441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG4: 24264441979SMauro Carvalho Chehab size = coda_mpeg4_parse_headers(ctx, vaddr, payload); 24364441979SMauro Carvalho Chehab break; 24464441979SMauro Carvalho Chehab default: 24564441979SMauro Carvalho Chehab break; 24664441979SMauro Carvalho Chehab } 24764441979SMauro Carvalho Chehab 24864441979SMauro Carvalho Chehab return size; 24964441979SMauro Carvalho Chehab } 25064441979SMauro Carvalho Chehab 25164441979SMauro Carvalho Chehab static bool coda_bitstream_try_queue(struct coda_ctx *ctx, 25264441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf) 25364441979SMauro Carvalho Chehab { 25464441979SMauro Carvalho Chehab unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); 25564441979SMauro Carvalho Chehab u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 25664441979SMauro Carvalho Chehab int ret; 25764441979SMauro Carvalho Chehab int i; 25864441979SMauro Carvalho Chehab 25964441979SMauro Carvalho Chehab if (coda_get_bitstream_payload(ctx) + payload + 512 >= 26064441979SMauro Carvalho Chehab ctx->bitstream.size) 26164441979SMauro Carvalho Chehab return false; 26264441979SMauro Carvalho Chehab 26364441979SMauro Carvalho Chehab if (!vaddr) { 26464441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); 26564441979SMauro Carvalho Chehab return true; 26664441979SMauro Carvalho Chehab } 26764441979SMauro Carvalho Chehab 26864441979SMauro Carvalho Chehab if (ctx->qsequence == 0 && payload < 512) { 26964441979SMauro Carvalho Chehab /* 27064441979SMauro Carvalho Chehab * Add padding after the first buffer, if it is too small to be 27164441979SMauro Carvalho Chehab * fetched by the CODA, by repeating the headers. Without 27264441979SMauro Carvalho Chehab * repeated headers, or the first frame already queued, decoder 27364441979SMauro Carvalho Chehab * sequence initialization fails with error code 0x2000 on i.MX6 27464441979SMauro Carvalho Chehab * or error code 0x1 on i.MX51. 27564441979SMauro Carvalho Chehab */ 27664441979SMauro Carvalho Chehab u32 header_size = coda_buffer_parse_headers(ctx, src_buf, 27764441979SMauro Carvalho Chehab payload); 27864441979SMauro Carvalho Chehab 27964441979SMauro Carvalho Chehab if (header_size) { 28064441979SMauro Carvalho Chehab coda_dbg(1, ctx, "pad with %u-byte header\n", 28164441979SMauro Carvalho Chehab header_size); 28264441979SMauro Carvalho Chehab for (i = payload; i < 512; i += header_size) { 28364441979SMauro Carvalho Chehab ret = coda_bitstream_queue(ctx, vaddr, 28464441979SMauro Carvalho Chehab header_size); 28564441979SMauro Carvalho Chehab if (ret < 0) { 28664441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, 28764441979SMauro Carvalho Chehab "bitstream buffer overflow\n"); 28864441979SMauro Carvalho Chehab return false; 28964441979SMauro Carvalho Chehab } 29064441979SMauro Carvalho Chehab if (ctx->dev->devtype->product == CODA_960) 29164441979SMauro Carvalho Chehab break; 29264441979SMauro Carvalho Chehab } 29364441979SMauro Carvalho Chehab } else { 29464441979SMauro Carvalho Chehab coda_dbg(1, ctx, 29564441979SMauro Carvalho Chehab "could not parse header, sequence initialization might fail\n"); 29664441979SMauro Carvalho Chehab } 29764441979SMauro Carvalho Chehab 29864441979SMauro Carvalho Chehab /* Add padding before the first buffer, if it is too small */ 29964441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 30064441979SMauro Carvalho Chehab coda_h264_bitstream_pad(ctx, 512 - payload); 30164441979SMauro Carvalho Chehab } 30264441979SMauro Carvalho Chehab 30364441979SMauro Carvalho Chehab ret = coda_bitstream_queue(ctx, vaddr, payload); 30464441979SMauro Carvalho Chehab if (ret < 0) { 30564441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); 30664441979SMauro Carvalho Chehab return false; 30764441979SMauro Carvalho Chehab } 30864441979SMauro Carvalho Chehab 30964441979SMauro Carvalho Chehab src_buf->sequence = ctx->qsequence++; 31064441979SMauro Carvalho Chehab 31164441979SMauro Carvalho Chehab /* Sync read pointer to device */ 31264441979SMauro Carvalho Chehab if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) 31364441979SMauro Carvalho Chehab coda_kfifo_sync_to_device_write(ctx); 31464441979SMauro Carvalho Chehab 31564441979SMauro Carvalho Chehab /* Set the stream-end flag after the last buffer is queued */ 31664441979SMauro Carvalho Chehab if (src_buf->flags & V4L2_BUF_FLAG_LAST) 31764441979SMauro Carvalho Chehab coda_bit_stream_end_flag(ctx); 31864441979SMauro Carvalho Chehab ctx->hold = false; 31964441979SMauro Carvalho Chehab 32064441979SMauro Carvalho Chehab return true; 32164441979SMauro Carvalho Chehab } 32264441979SMauro Carvalho Chehab 32364441979SMauro Carvalho Chehab void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) 32464441979SMauro Carvalho Chehab { 32564441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf; 32664441979SMauro Carvalho Chehab struct coda_buffer_meta *meta; 32764441979SMauro Carvalho Chehab u32 start; 32864441979SMauro Carvalho Chehab 32987e0ce68SPhilipp Zabel lockdep_assert_held(&ctx->bitstream_mutex); 33087e0ce68SPhilipp Zabel 33164441979SMauro Carvalho Chehab if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) 33264441979SMauro Carvalho Chehab return; 33364441979SMauro Carvalho Chehab 33464441979SMauro Carvalho Chehab while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { 33564441979SMauro Carvalho Chehab /* 33664441979SMauro Carvalho Chehab * Only queue two JPEGs into the bitstream buffer to keep 33764441979SMauro Carvalho Chehab * latency low. We need at least one complete buffer and the 33864441979SMauro Carvalho Chehab * header of another buffer (for prescan) in the bitstream. 33964441979SMauro Carvalho Chehab */ 34064441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 34164441979SMauro Carvalho Chehab ctx->num_metas > 1) 34264441979SMauro Carvalho Chehab break; 34364441979SMauro Carvalho Chehab 34464441979SMauro Carvalho Chehab if (ctx->num_internal_frames && 34564441979SMauro Carvalho Chehab ctx->num_metas >= ctx->num_internal_frames) { 34664441979SMauro Carvalho Chehab meta = list_first_entry(&ctx->buffer_meta_list, 34764441979SMauro Carvalho Chehab struct coda_buffer_meta, list); 34864441979SMauro Carvalho Chehab 34964441979SMauro Carvalho Chehab /* 35064441979SMauro Carvalho Chehab * If we managed to fill in at least a full reorder 35164441979SMauro Carvalho Chehab * window of buffers (num_internal_frames is a 35264441979SMauro Carvalho Chehab * conservative estimate for this) and the bitstream 35364441979SMauro Carvalho Chehab * prefetcher has at least 2 256 bytes periods beyond 35464441979SMauro Carvalho Chehab * the first buffer to fetch, we can safely stop queuing 35564441979SMauro Carvalho Chehab * in order to limit the decoder drain latency. 35664441979SMauro Carvalho Chehab */ 35764441979SMauro Carvalho Chehab if (coda_bitstream_can_fetch_past(ctx, meta->end)) 35864441979SMauro Carvalho Chehab break; 35964441979SMauro Carvalho Chehab } 36064441979SMauro Carvalho Chehab 36164441979SMauro Carvalho Chehab src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 36264441979SMauro Carvalho Chehab 36364441979SMauro Carvalho Chehab /* Drop frames that do not start/end with a SOI/EOI markers */ 36464441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 36564441979SMauro Carvalho Chehab !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { 36664441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, 36764441979SMauro Carvalho Chehab "dropping invalid JPEG frame %d\n", 36864441979SMauro Carvalho Chehab ctx->qsequence); 36964441979SMauro Carvalho Chehab src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 37064441979SMauro Carvalho Chehab if (buffer_list) { 37164441979SMauro Carvalho Chehab struct v4l2_m2m_buffer *m2m_buf; 37264441979SMauro Carvalho Chehab 37364441979SMauro Carvalho Chehab m2m_buf = container_of(src_buf, 37464441979SMauro Carvalho Chehab struct v4l2_m2m_buffer, 37564441979SMauro Carvalho Chehab vb); 37664441979SMauro Carvalho Chehab list_add_tail(&m2m_buf->list, buffer_list); 37764441979SMauro Carvalho Chehab } else { 37864441979SMauro Carvalho Chehab v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); 37964441979SMauro Carvalho Chehab } 38064441979SMauro Carvalho Chehab continue; 38164441979SMauro Carvalho Chehab } 38264441979SMauro Carvalho Chehab 38364441979SMauro Carvalho Chehab /* Dump empty buffers */ 38464441979SMauro Carvalho Chehab if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) { 38564441979SMauro Carvalho Chehab src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 38664441979SMauro Carvalho Chehab v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 38764441979SMauro Carvalho Chehab continue; 38864441979SMauro Carvalho Chehab } 38964441979SMauro Carvalho Chehab 39064441979SMauro Carvalho Chehab /* Buffer start position */ 39164441979SMauro Carvalho Chehab start = ctx->bitstream_fifo.kfifo.in; 39264441979SMauro Carvalho Chehab 39364441979SMauro Carvalho Chehab if (coda_bitstream_try_queue(ctx, src_buf)) { 39464441979SMauro Carvalho Chehab /* 39564441979SMauro Carvalho Chehab * Source buffer is queued in the bitstream ringbuffer; 39664441979SMauro Carvalho Chehab * queue the timestamp and mark source buffer as done 39764441979SMauro Carvalho Chehab */ 39864441979SMauro Carvalho Chehab src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 39964441979SMauro Carvalho Chehab 40064441979SMauro Carvalho Chehab meta = kmalloc(sizeof(*meta), GFP_KERNEL); 40164441979SMauro Carvalho Chehab if (meta) { 40264441979SMauro Carvalho Chehab meta->sequence = src_buf->sequence; 40364441979SMauro Carvalho Chehab meta->timecode = src_buf->timecode; 40464441979SMauro Carvalho Chehab meta->timestamp = src_buf->vb2_buf.timestamp; 40564441979SMauro Carvalho Chehab meta->start = start; 40664441979SMauro Carvalho Chehab meta->end = ctx->bitstream_fifo.kfifo.in; 40764441979SMauro Carvalho Chehab meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; 40864441979SMauro Carvalho Chehab if (meta->last) 40964441979SMauro Carvalho Chehab coda_dbg(1, ctx, "marking last meta"); 41064441979SMauro Carvalho Chehab spin_lock(&ctx->buffer_meta_lock); 41164441979SMauro Carvalho Chehab list_add_tail(&meta->list, 41264441979SMauro Carvalho Chehab &ctx->buffer_meta_list); 41364441979SMauro Carvalho Chehab ctx->num_metas++; 41464441979SMauro Carvalho Chehab spin_unlock(&ctx->buffer_meta_lock); 41564441979SMauro Carvalho Chehab 41664441979SMauro Carvalho Chehab trace_coda_bit_queue(ctx, src_buf, meta); 41764441979SMauro Carvalho Chehab } 41864441979SMauro Carvalho Chehab 41964441979SMauro Carvalho Chehab if (buffer_list) { 42064441979SMauro Carvalho Chehab struct v4l2_m2m_buffer *m2m_buf; 42164441979SMauro Carvalho Chehab 42264441979SMauro Carvalho Chehab m2m_buf = container_of(src_buf, 42364441979SMauro Carvalho Chehab struct v4l2_m2m_buffer, 42464441979SMauro Carvalho Chehab vb); 42564441979SMauro Carvalho Chehab list_add_tail(&m2m_buf->list, buffer_list); 42664441979SMauro Carvalho Chehab } else { 42764441979SMauro Carvalho Chehab v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 42864441979SMauro Carvalho Chehab } 42964441979SMauro Carvalho Chehab } else { 43064441979SMauro Carvalho Chehab break; 43164441979SMauro Carvalho Chehab } 43264441979SMauro Carvalho Chehab } 43364441979SMauro Carvalho Chehab } 43464441979SMauro Carvalho Chehab 43564441979SMauro Carvalho Chehab void coda_bit_stream_end_flag(struct coda_ctx *ctx) 43664441979SMauro Carvalho Chehab { 43764441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 43864441979SMauro Carvalho Chehab 43964441979SMauro Carvalho Chehab ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 44064441979SMauro Carvalho Chehab 44164441979SMauro Carvalho Chehab /* If this context is currently running, update the hardware flag */ 44264441979SMauro Carvalho Chehab if ((dev->devtype->product == CODA_960) && 44364441979SMauro Carvalho Chehab coda_isbusy(dev) && 44464441979SMauro Carvalho Chehab (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { 44564441979SMauro Carvalho Chehab coda_write(dev, ctx->bit_stream_param, 44664441979SMauro Carvalho Chehab CODA_REG_BIT_BIT_STREAM_PARAM); 44764441979SMauro Carvalho Chehab } 44864441979SMauro Carvalho Chehab } 44964441979SMauro Carvalho Chehab 45064441979SMauro Carvalho Chehab static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) 45164441979SMauro Carvalho Chehab { 45264441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 45364441979SMauro Carvalho Chehab u32 *p = ctx->parabuf.vaddr; 45464441979SMauro Carvalho Chehab 45564441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) 45664441979SMauro Carvalho Chehab p[index] = value; 45764441979SMauro Carvalho Chehab else 45864441979SMauro Carvalho Chehab p[index ^ 1] = value; 45964441979SMauro Carvalho Chehab } 46064441979SMauro Carvalho Chehab 46164441979SMauro Carvalho Chehab static inline int coda_alloc_context_buf(struct coda_ctx *ctx, 46264441979SMauro Carvalho Chehab struct coda_aux_buf *buf, size_t size, 46364441979SMauro Carvalho Chehab const char *name) 46464441979SMauro Carvalho Chehab { 46564441979SMauro Carvalho Chehab return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); 46664441979SMauro Carvalho Chehab } 46764441979SMauro Carvalho Chehab 46864441979SMauro Carvalho Chehab 46964441979SMauro Carvalho Chehab static void coda_free_framebuffers(struct coda_ctx *ctx) 47064441979SMauro Carvalho Chehab { 47164441979SMauro Carvalho Chehab int i; 47264441979SMauro Carvalho Chehab 47364441979SMauro Carvalho Chehab for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) 47464441979SMauro Carvalho Chehab coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); 47564441979SMauro Carvalho Chehab } 47664441979SMauro Carvalho Chehab 47764441979SMauro Carvalho Chehab static int coda_alloc_framebuffers(struct coda_ctx *ctx, 47864441979SMauro Carvalho Chehab struct coda_q_data *q_data, u32 fourcc) 47964441979SMauro Carvalho Chehab { 48064441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 48164441979SMauro Carvalho Chehab unsigned int ysize, ycbcr_size; 48264441979SMauro Carvalho Chehab int ret; 48364441979SMauro Carvalho Chehab int i; 48464441979SMauro Carvalho Chehab 48564441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 48664441979SMauro Carvalho Chehab ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || 48764441979SMauro Carvalho Chehab ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || 48864441979SMauro Carvalho Chehab ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) 48964441979SMauro Carvalho Chehab ysize = round_up(q_data->rect.width, 16) * 49064441979SMauro Carvalho Chehab round_up(q_data->rect.height, 16); 49164441979SMauro Carvalho Chehab else 49264441979SMauro Carvalho Chehab ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; 49364441979SMauro Carvalho Chehab 49464441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 49564441979SMauro Carvalho Chehab ycbcr_size = round_up(ysize, 4096) + ysize / 2; 49664441979SMauro Carvalho Chehab else 49764441979SMauro Carvalho Chehab ycbcr_size = ysize + ysize / 2; 49864441979SMauro Carvalho Chehab 49964441979SMauro Carvalho Chehab /* Allocate frame buffers */ 50064441979SMauro Carvalho Chehab for (i = 0; i < ctx->num_internal_frames; i++) { 50164441979SMauro Carvalho Chehab size_t size = ycbcr_size; 50264441979SMauro Carvalho Chehab char *name; 50364441979SMauro Carvalho Chehab 50464441979SMauro Carvalho Chehab /* Add space for mvcol buffers */ 50564441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6 && 50664441979SMauro Carvalho Chehab (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 50764441979SMauro Carvalho Chehab (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0))) 50864441979SMauro Carvalho Chehab size += ysize / 4; 50964441979SMauro Carvalho Chehab name = kasprintf(GFP_KERNEL, "fb%d", i); 51064441979SMauro Carvalho Chehab if (!name) { 51164441979SMauro Carvalho Chehab coda_free_framebuffers(ctx); 51264441979SMauro Carvalho Chehab return -ENOMEM; 51364441979SMauro Carvalho Chehab } 51464441979SMauro Carvalho Chehab ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, 51564441979SMauro Carvalho Chehab size, name); 51664441979SMauro Carvalho Chehab kfree(name); 51764441979SMauro Carvalho Chehab if (ret < 0) { 51864441979SMauro Carvalho Chehab coda_free_framebuffers(ctx); 51964441979SMauro Carvalho Chehab return ret; 52064441979SMauro Carvalho Chehab } 52164441979SMauro Carvalho Chehab } 52264441979SMauro Carvalho Chehab 52364441979SMauro Carvalho Chehab /* Register frame buffers in the parameter buffer */ 52464441979SMauro Carvalho Chehab for (i = 0; i < ctx->num_internal_frames; i++) { 52564441979SMauro Carvalho Chehab u32 y, cb, cr, mvcol; 52664441979SMauro Carvalho Chehab 52764441979SMauro Carvalho Chehab /* Start addresses of Y, Cb, Cr planes */ 52864441979SMauro Carvalho Chehab y = ctx->internal_frames[i].buf.paddr; 52964441979SMauro Carvalho Chehab cb = y + ysize; 53064441979SMauro Carvalho Chehab cr = y + ysize + ysize/4; 53164441979SMauro Carvalho Chehab mvcol = y + ysize + ysize/4 + ysize/4; 53264441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { 53364441979SMauro Carvalho Chehab cb = round_up(cb, 4096); 53464441979SMauro Carvalho Chehab mvcol = cb + ysize/2; 53564441979SMauro Carvalho Chehab cr = 0; 53664441979SMauro Carvalho Chehab /* Packed 20-bit MSB of base addresses */ 53764441979SMauro Carvalho Chehab /* YYYYYCCC, CCyyyyyc, cccc.... */ 53864441979SMauro Carvalho Chehab y = (y & 0xfffff000) | cb >> 20; 53964441979SMauro Carvalho Chehab cb = (cb & 0x000ff000) << 12; 54064441979SMauro Carvalho Chehab } 54164441979SMauro Carvalho Chehab coda_parabuf_write(ctx, i * 3 + 0, y); 54264441979SMauro Carvalho Chehab coda_parabuf_write(ctx, i * 3 + 1, cb); 54364441979SMauro Carvalho Chehab coda_parabuf_write(ctx, i * 3 + 2, cr); 54464441979SMauro Carvalho Chehab 54564441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) 54664441979SMauro Carvalho Chehab continue; 54764441979SMauro Carvalho Chehab 54864441979SMauro Carvalho Chehab /* mvcol buffer for h.264 and mpeg4 */ 54964441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 55064441979SMauro Carvalho Chehab coda_parabuf_write(ctx, 96 + i, mvcol); 55164441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0) 55264441979SMauro Carvalho Chehab coda_parabuf_write(ctx, 97, mvcol); 55364441979SMauro Carvalho Chehab } 55464441979SMauro Carvalho Chehab 55564441979SMauro Carvalho Chehab return 0; 55664441979SMauro Carvalho Chehab } 55764441979SMauro Carvalho Chehab 55864441979SMauro Carvalho Chehab static void coda_free_context_buffers(struct coda_ctx *ctx) 55964441979SMauro Carvalho Chehab { 56064441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 56164441979SMauro Carvalho Chehab 56264441979SMauro Carvalho Chehab coda_free_aux_buf(dev, &ctx->slicebuf); 56364441979SMauro Carvalho Chehab coda_free_aux_buf(dev, &ctx->psbuf); 56464441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) 56564441979SMauro Carvalho Chehab coda_free_aux_buf(dev, &ctx->workbuf); 56664441979SMauro Carvalho Chehab coda_free_aux_buf(dev, &ctx->parabuf); 56764441979SMauro Carvalho Chehab } 56864441979SMauro Carvalho Chehab 56964441979SMauro Carvalho Chehab static int coda_alloc_context_buffers(struct coda_ctx *ctx, 57064441979SMauro Carvalho Chehab struct coda_q_data *q_data) 57164441979SMauro Carvalho Chehab { 57264441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 57364441979SMauro Carvalho Chehab size_t size; 57464441979SMauro Carvalho Chehab int ret; 57564441979SMauro Carvalho Chehab 57664441979SMauro Carvalho Chehab if (!ctx->parabuf.vaddr) { 57764441979SMauro Carvalho Chehab ret = coda_alloc_context_buf(ctx, &ctx->parabuf, 57864441979SMauro Carvalho Chehab CODA_PARA_BUF_SIZE, "parabuf"); 57964441979SMauro Carvalho Chehab if (ret < 0) 58064441979SMauro Carvalho Chehab return ret; 58164441979SMauro Carvalho Chehab } 58264441979SMauro Carvalho Chehab 58364441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) 58464441979SMauro Carvalho Chehab return 0; 58564441979SMauro Carvalho Chehab 58664441979SMauro Carvalho Chehab if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { 58764441979SMauro Carvalho Chehab /* worst case slice size */ 58864441979SMauro Carvalho Chehab size = (DIV_ROUND_UP(q_data->rect.width, 16) * 58964441979SMauro Carvalho Chehab DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512; 59064441979SMauro Carvalho Chehab ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, 59164441979SMauro Carvalho Chehab "slicebuf"); 59264441979SMauro Carvalho Chehab if (ret < 0) 59364441979SMauro Carvalho Chehab goto err; 59464441979SMauro Carvalho Chehab } 59564441979SMauro Carvalho Chehab 59664441979SMauro Carvalho Chehab if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || 59764441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541)) { 59864441979SMauro Carvalho Chehab ret = coda_alloc_context_buf(ctx, &ctx->psbuf, 59964441979SMauro Carvalho Chehab CODA7_PS_BUF_SIZE, "psbuf"); 60064441979SMauro Carvalho Chehab if (ret < 0) 60164441979SMauro Carvalho Chehab goto err; 60264441979SMauro Carvalho Chehab } 60364441979SMauro Carvalho Chehab 60464441979SMauro Carvalho Chehab if (!ctx->workbuf.vaddr) { 60564441979SMauro Carvalho Chehab size = dev->devtype->workbuf_size; 60664441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960 && 60764441979SMauro Carvalho Chehab q_data->fourcc == V4L2_PIX_FMT_H264) 60864441979SMauro Carvalho Chehab size += CODA9_PS_SAVE_SIZE; 60964441979SMauro Carvalho Chehab ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, 61064441979SMauro Carvalho Chehab "workbuf"); 61164441979SMauro Carvalho Chehab if (ret < 0) 61264441979SMauro Carvalho Chehab goto err; 61364441979SMauro Carvalho Chehab } 61464441979SMauro Carvalho Chehab 61564441979SMauro Carvalho Chehab return 0; 61664441979SMauro Carvalho Chehab 61764441979SMauro Carvalho Chehab err: 61864441979SMauro Carvalho Chehab coda_free_context_buffers(ctx); 61964441979SMauro Carvalho Chehab return ret; 62064441979SMauro Carvalho Chehab } 62164441979SMauro Carvalho Chehab 62264441979SMauro Carvalho Chehab static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, 62364441979SMauro Carvalho Chehab int header_code, u8 *header, int *size) 62464441979SMauro Carvalho Chehab { 62564441979SMauro Carvalho Chehab struct vb2_buffer *vb = &buf->vb2_buf; 62664441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 62764441979SMauro Carvalho Chehab struct coda_q_data *q_data_src; 62864441979SMauro Carvalho Chehab struct v4l2_rect *r; 62964441979SMauro Carvalho Chehab size_t bufsize; 63064441979SMauro Carvalho Chehab int ret; 63164441979SMauro Carvalho Chehab int i; 63264441979SMauro Carvalho Chehab 63364441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 63464441979SMauro Carvalho Chehab memset(vb2_plane_vaddr(vb, 0), 0, 64); 63564441979SMauro Carvalho Chehab 63664441979SMauro Carvalho Chehab coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0), 63764441979SMauro Carvalho Chehab CODA_CMD_ENC_HEADER_BB_START); 63864441979SMauro Carvalho Chehab bufsize = vb2_plane_size(vb, 0); 63964441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 64064441979SMauro Carvalho Chehab bufsize /= 1024; 64164441979SMauro Carvalho Chehab coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); 64264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960 && 64364441979SMauro Carvalho Chehab ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && 64464441979SMauro Carvalho Chehab header_code == CODA_HEADER_H264_SPS) { 64564441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 64664441979SMauro Carvalho Chehab r = &q_data_src->rect; 64764441979SMauro Carvalho Chehab 64864441979SMauro Carvalho Chehab if (r->width % 16 || r->height % 16) { 64964441979SMauro Carvalho Chehab u32 crop_right = round_up(r->width, 16) - r->width; 65064441979SMauro Carvalho Chehab u32 crop_bottom = round_up(r->height, 16) - r->height; 65164441979SMauro Carvalho Chehab 65264441979SMauro Carvalho Chehab coda_write(dev, crop_right, 65364441979SMauro Carvalho Chehab CODA9_CMD_ENC_HEADER_FRAME_CROP_H); 65464441979SMauro Carvalho Chehab coda_write(dev, crop_bottom, 65564441979SMauro Carvalho Chehab CODA9_CMD_ENC_HEADER_FRAME_CROP_V); 65664441979SMauro Carvalho Chehab header_code |= CODA9_HEADER_FRAME_CROP; 65764441979SMauro Carvalho Chehab } 65864441979SMauro Carvalho Chehab } 65964441979SMauro Carvalho Chehab coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); 66064441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); 66164441979SMauro Carvalho Chehab if (ret < 0) { 66264441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); 66364441979SMauro Carvalho Chehab return ret; 66464441979SMauro Carvalho Chehab } 66564441979SMauro Carvalho Chehab 66664441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 66764441979SMauro Carvalho Chehab for (i = 63; i > 0; i--) 66864441979SMauro Carvalho Chehab if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0) 66964441979SMauro Carvalho Chehab break; 67064441979SMauro Carvalho Chehab *size = i + 1; 67164441979SMauro Carvalho Chehab } else { 67264441979SMauro Carvalho Chehab *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - 67364441979SMauro Carvalho Chehab coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); 67464441979SMauro Carvalho Chehab } 67564441979SMauro Carvalho Chehab memcpy(header, vb2_plane_vaddr(vb, 0), *size); 67664441979SMauro Carvalho Chehab 67764441979SMauro Carvalho Chehab return 0; 67864441979SMauro Carvalho Chehab } 67964441979SMauro Carvalho Chehab 68064441979SMauro Carvalho Chehab static u32 coda_slice_mode(struct coda_ctx *ctx) 68164441979SMauro Carvalho Chehab { 68264441979SMauro Carvalho Chehab int size, unit; 68364441979SMauro Carvalho Chehab 68464441979SMauro Carvalho Chehab switch (ctx->params.slice_mode) { 68564441979SMauro Carvalho Chehab case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: 68664441979SMauro Carvalho Chehab default: 68764441979SMauro Carvalho Chehab return 0; 68864441979SMauro Carvalho Chehab case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: 68964441979SMauro Carvalho Chehab size = ctx->params.slice_max_mb; 69064441979SMauro Carvalho Chehab unit = 1; 69164441979SMauro Carvalho Chehab break; 69264441979SMauro Carvalho Chehab case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: 69364441979SMauro Carvalho Chehab size = ctx->params.slice_max_bits; 69464441979SMauro Carvalho Chehab unit = 0; 69564441979SMauro Carvalho Chehab break; 69664441979SMauro Carvalho Chehab } 69764441979SMauro Carvalho Chehab 69864441979SMauro Carvalho Chehab return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | 69964441979SMauro Carvalho Chehab ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | 70064441979SMauro Carvalho Chehab ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); 70164441979SMauro Carvalho Chehab } 70264441979SMauro Carvalho Chehab 70364441979SMauro Carvalho Chehab static int coda_enc_param_change(struct coda_ctx *ctx) 70464441979SMauro Carvalho Chehab { 70564441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 70664441979SMauro Carvalho Chehab u32 change_enable = 0; 70764441979SMauro Carvalho Chehab u32 success; 70864441979SMauro Carvalho Chehab int ret; 70964441979SMauro Carvalho Chehab 71064441979SMauro Carvalho Chehab if (ctx->params.gop_size_changed) { 71164441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_RC_GOP; 71264441979SMauro Carvalho Chehab coda_write(dev, ctx->params.gop_size, 71364441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_RC_GOP); 71464441979SMauro Carvalho Chehab ctx->gopcounter = ctx->params.gop_size - 1; 71564441979SMauro Carvalho Chehab ctx->params.gop_size_changed = false; 71664441979SMauro Carvalho Chehab } 71764441979SMauro Carvalho Chehab if (ctx->params.h264_intra_qp_changed) { 71864441979SMauro Carvalho Chehab coda_dbg(1, ctx, "parameter change: intra Qp %u\n", 71964441979SMauro Carvalho Chehab ctx->params.h264_intra_qp); 72064441979SMauro Carvalho Chehab 72164441979SMauro Carvalho Chehab if (ctx->params.bitrate) { 72264441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; 72364441979SMauro Carvalho Chehab coda_write(dev, ctx->params.h264_intra_qp, 72464441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_RC_INTRA_QP); 72564441979SMauro Carvalho Chehab } 72664441979SMauro Carvalho Chehab ctx->params.h264_intra_qp_changed = false; 72764441979SMauro Carvalho Chehab } 72864441979SMauro Carvalho Chehab if (ctx->params.bitrate_changed) { 72964441979SMauro Carvalho Chehab coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", 73064441979SMauro Carvalho Chehab ctx->params.bitrate); 73164441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; 73264441979SMauro Carvalho Chehab coda_write(dev, ctx->params.bitrate, 73364441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_RC_BITRATE); 73464441979SMauro Carvalho Chehab ctx->params.bitrate_changed = false; 73564441979SMauro Carvalho Chehab } 73664441979SMauro Carvalho Chehab if (ctx->params.framerate_changed) { 73764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", 73864441979SMauro Carvalho Chehab ctx->params.framerate & 0xffff, 73964441979SMauro Carvalho Chehab (ctx->params.framerate >> 16) + 1); 74064441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; 74164441979SMauro Carvalho Chehab coda_write(dev, ctx->params.framerate, 74264441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_RC_FRAME_RATE); 74364441979SMauro Carvalho Chehab ctx->params.framerate_changed = false; 74464441979SMauro Carvalho Chehab } 74564441979SMauro Carvalho Chehab if (ctx->params.intra_refresh_changed) { 74664441979SMauro Carvalho Chehab coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", 74764441979SMauro Carvalho Chehab ctx->params.intra_refresh); 74864441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; 74964441979SMauro Carvalho Chehab coda_write(dev, ctx->params.intra_refresh, 75064441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_INTRA_MB_NUM); 75164441979SMauro Carvalho Chehab ctx->params.intra_refresh_changed = false; 75264441979SMauro Carvalho Chehab } 75364441979SMauro Carvalho Chehab if (ctx->params.slice_mode_changed) { 75464441979SMauro Carvalho Chehab change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; 75564441979SMauro Carvalho Chehab coda_write(dev, coda_slice_mode(ctx), 75664441979SMauro Carvalho Chehab CODA_CMD_ENC_PARAM_SLICE_MODE); 75764441979SMauro Carvalho Chehab ctx->params.slice_mode_changed = false; 75864441979SMauro Carvalho Chehab } 75964441979SMauro Carvalho Chehab 76064441979SMauro Carvalho Chehab if (!change_enable) 76164441979SMauro Carvalho Chehab return 0; 76264441979SMauro Carvalho Chehab 76364441979SMauro Carvalho Chehab coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); 76464441979SMauro Carvalho Chehab 76564441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); 76664441979SMauro Carvalho Chehab if (ret < 0) 76764441979SMauro Carvalho Chehab return ret; 76864441979SMauro Carvalho Chehab 76964441979SMauro Carvalho Chehab success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); 77064441979SMauro Carvalho Chehab if (success != 1) 77164441979SMauro Carvalho Chehab coda_dbg(1, ctx, "parameter change failed: %u\n", success); 77264441979SMauro Carvalho Chehab 77364441979SMauro Carvalho Chehab return 0; 77464441979SMauro Carvalho Chehab } 77564441979SMauro Carvalho Chehab 77664441979SMauro Carvalho Chehab static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) 77764441979SMauro Carvalho Chehab { 77864441979SMauro Carvalho Chehab phys_addr_t ret; 77964441979SMauro Carvalho Chehab 78064441979SMauro Carvalho Chehab size = round_up(size, 1024); 78164441979SMauro Carvalho Chehab if (size > iram->remaining) 78264441979SMauro Carvalho Chehab return 0; 78364441979SMauro Carvalho Chehab iram->remaining -= size; 78464441979SMauro Carvalho Chehab 78564441979SMauro Carvalho Chehab ret = iram->next_paddr; 78664441979SMauro Carvalho Chehab iram->next_paddr += size; 78764441979SMauro Carvalho Chehab 78864441979SMauro Carvalho Chehab return ret; 78964441979SMauro Carvalho Chehab } 79064441979SMauro Carvalho Chehab 79164441979SMauro Carvalho Chehab static void coda_setup_iram(struct coda_ctx *ctx) 79264441979SMauro Carvalho Chehab { 79364441979SMauro Carvalho Chehab struct coda_iram_info *iram_info = &ctx->iram_info; 79464441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 79564441979SMauro Carvalho Chehab int w64, w128; 79664441979SMauro Carvalho Chehab int mb_width; 79764441979SMauro Carvalho Chehab int dbk_bits; 79864441979SMauro Carvalho Chehab int bit_bits; 79964441979SMauro Carvalho Chehab int ip_bits; 80064441979SMauro Carvalho Chehab int me_bits; 80164441979SMauro Carvalho Chehab 80264441979SMauro Carvalho Chehab memset(iram_info, 0, sizeof(*iram_info)); 80364441979SMauro Carvalho Chehab iram_info->next_paddr = dev->iram.paddr; 80464441979SMauro Carvalho Chehab iram_info->remaining = dev->iram.size; 80564441979SMauro Carvalho Chehab 80664441979SMauro Carvalho Chehab if (!dev->iram.vaddr) 80764441979SMauro Carvalho Chehab return; 80864441979SMauro Carvalho Chehab 80964441979SMauro Carvalho Chehab switch (dev->devtype->product) { 81064441979SMauro Carvalho Chehab case CODA_HX4: 81164441979SMauro Carvalho Chehab dbk_bits = CODA7_USE_HOST_DBK_ENABLE; 81264441979SMauro Carvalho Chehab bit_bits = CODA7_USE_HOST_BIT_ENABLE; 81364441979SMauro Carvalho Chehab ip_bits = CODA7_USE_HOST_IP_ENABLE; 81464441979SMauro Carvalho Chehab me_bits = CODA7_USE_HOST_ME_ENABLE; 81564441979SMauro Carvalho Chehab break; 81664441979SMauro Carvalho Chehab case CODA_7541: 81764441979SMauro Carvalho Chehab dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; 81864441979SMauro Carvalho Chehab bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 81964441979SMauro Carvalho Chehab ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 82064441979SMauro Carvalho Chehab me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; 82164441979SMauro Carvalho Chehab break; 82264441979SMauro Carvalho Chehab case CODA_960: 82364441979SMauro Carvalho Chehab dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; 82464441979SMauro Carvalho Chehab bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 82564441979SMauro Carvalho Chehab ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 82664441979SMauro Carvalho Chehab me_bits = 0; 82764441979SMauro Carvalho Chehab break; 82864441979SMauro Carvalho Chehab default: /* CODA_DX6 */ 82964441979SMauro Carvalho Chehab return; 83064441979SMauro Carvalho Chehab } 83164441979SMauro Carvalho Chehab 83264441979SMauro Carvalho Chehab if (ctx->inst_type == CODA_INST_ENCODER) { 83364441979SMauro Carvalho Chehab struct coda_q_data *q_data_src; 83464441979SMauro Carvalho Chehab 83564441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 83664441979SMauro Carvalho Chehab mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16); 83764441979SMauro Carvalho Chehab w128 = mb_width * 128; 83864441979SMauro Carvalho Chehab w64 = mb_width * 64; 83964441979SMauro Carvalho Chehab 84064441979SMauro Carvalho Chehab /* Prioritize in case IRAM is too small for everything */ 84164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 84264441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 84364441979SMauro Carvalho Chehab iram_info->search_ram_size = round_up(mb_width * 16 * 84464441979SMauro Carvalho Chehab 36 + 2048, 1024); 84564441979SMauro Carvalho Chehab iram_info->search_ram_paddr = coda_iram_alloc(iram_info, 84664441979SMauro Carvalho Chehab iram_info->search_ram_size); 84764441979SMauro Carvalho Chehab if (!iram_info->search_ram_paddr) { 84864441979SMauro Carvalho Chehab pr_err("IRAM is smaller than the search ram size\n"); 84964441979SMauro Carvalho Chehab goto out; 85064441979SMauro Carvalho Chehab } 85164441979SMauro Carvalho Chehab iram_info->axi_sram_use |= me_bits; 85264441979SMauro Carvalho Chehab } 85364441979SMauro Carvalho Chehab 85464441979SMauro Carvalho Chehab /* Only H.264BP and H.263P3 are considered */ 85564441979SMauro Carvalho Chehab iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); 85664441979SMauro Carvalho Chehab iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); 857*6b808223SJiasheng Jiang if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 85864441979SMauro Carvalho Chehab goto out; 85964441979SMauro Carvalho Chehab iram_info->axi_sram_use |= dbk_bits; 86064441979SMauro Carvalho Chehab 86164441979SMauro Carvalho Chehab iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 86264441979SMauro Carvalho Chehab if (!iram_info->buf_bit_use) 86364441979SMauro Carvalho Chehab goto out; 86464441979SMauro Carvalho Chehab iram_info->axi_sram_use |= bit_bits; 86564441979SMauro Carvalho Chehab 86664441979SMauro Carvalho Chehab iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 86764441979SMauro Carvalho Chehab if (!iram_info->buf_ip_ac_dc_use) 86864441979SMauro Carvalho Chehab goto out; 86964441979SMauro Carvalho Chehab iram_info->axi_sram_use |= ip_bits; 87064441979SMauro Carvalho Chehab 87164441979SMauro Carvalho Chehab /* OVL and BTP disabled for encoder */ 87264441979SMauro Carvalho Chehab } else if (ctx->inst_type == CODA_INST_DECODER) { 87364441979SMauro Carvalho Chehab struct coda_q_data *q_data_dst; 87464441979SMauro Carvalho Chehab 87564441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 87664441979SMauro Carvalho Chehab mb_width = DIV_ROUND_UP(q_data_dst->width, 16); 87764441979SMauro Carvalho Chehab w128 = mb_width * 128; 87864441979SMauro Carvalho Chehab 87964441979SMauro Carvalho Chehab iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); 88064441979SMauro Carvalho Chehab iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); 881*6b808223SJiasheng Jiang if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 88264441979SMauro Carvalho Chehab goto out; 88364441979SMauro Carvalho Chehab iram_info->axi_sram_use |= dbk_bits; 88464441979SMauro Carvalho Chehab 88564441979SMauro Carvalho Chehab iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 88664441979SMauro Carvalho Chehab if (!iram_info->buf_bit_use) 88764441979SMauro Carvalho Chehab goto out; 88864441979SMauro Carvalho Chehab iram_info->axi_sram_use |= bit_bits; 88964441979SMauro Carvalho Chehab 89064441979SMauro Carvalho Chehab iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 89164441979SMauro Carvalho Chehab if (!iram_info->buf_ip_ac_dc_use) 89264441979SMauro Carvalho Chehab goto out; 89364441979SMauro Carvalho Chehab iram_info->axi_sram_use |= ip_bits; 89464441979SMauro Carvalho Chehab 89564441979SMauro Carvalho Chehab /* OVL and BTP unused as there is no VC1 support yet */ 89664441979SMauro Carvalho Chehab } 89764441979SMauro Carvalho Chehab 89864441979SMauro Carvalho Chehab out: 89964441979SMauro Carvalho Chehab if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) 90064441979SMauro Carvalho Chehab coda_dbg(1, ctx, "IRAM smaller than needed\n"); 90164441979SMauro Carvalho Chehab 90264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 90364441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 90464441979SMauro Carvalho Chehab /* TODO - Enabling these causes picture errors on CODA7541 */ 90564441979SMauro Carvalho Chehab if (ctx->inst_type == CODA_INST_DECODER) { 90664441979SMauro Carvalho Chehab /* fw 1.4.50 */ 90764441979SMauro Carvalho Chehab iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 90864441979SMauro Carvalho Chehab CODA7_USE_IP_ENABLE); 90964441979SMauro Carvalho Chehab } else { 91064441979SMauro Carvalho Chehab /* fw 13.4.29 */ 91164441979SMauro Carvalho Chehab iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 91264441979SMauro Carvalho Chehab CODA7_USE_HOST_DBK_ENABLE | 91364441979SMauro Carvalho Chehab CODA7_USE_IP_ENABLE | 91464441979SMauro Carvalho Chehab CODA7_USE_DBK_ENABLE); 91564441979SMauro Carvalho Chehab } 91664441979SMauro Carvalho Chehab } 91764441979SMauro Carvalho Chehab } 91864441979SMauro Carvalho Chehab 91964441979SMauro Carvalho Chehab static u32 coda_supported_firmwares[] = { 92064441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), 92164441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), 92264441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), 92364441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), 92464441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9), 92564441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), 92664441979SMauro Carvalho Chehab CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), 92764441979SMauro Carvalho Chehab }; 92864441979SMauro Carvalho Chehab 92964441979SMauro Carvalho Chehab static bool coda_firmware_supported(u32 vernum) 93064441979SMauro Carvalho Chehab { 93164441979SMauro Carvalho Chehab int i; 93264441979SMauro Carvalho Chehab 93364441979SMauro Carvalho Chehab for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) 93464441979SMauro Carvalho Chehab if (vernum == coda_supported_firmwares[i]) 93564441979SMauro Carvalho Chehab return true; 93664441979SMauro Carvalho Chehab return false; 93764441979SMauro Carvalho Chehab } 93864441979SMauro Carvalho Chehab 93964441979SMauro Carvalho Chehab int coda_check_firmware(struct coda_dev *dev) 94064441979SMauro Carvalho Chehab { 94164441979SMauro Carvalho Chehab u16 product, major, minor, release; 94264441979SMauro Carvalho Chehab u32 data; 94364441979SMauro Carvalho Chehab int ret; 94464441979SMauro Carvalho Chehab 94564441979SMauro Carvalho Chehab ret = clk_prepare_enable(dev->clk_per); 94664441979SMauro Carvalho Chehab if (ret) 94764441979SMauro Carvalho Chehab goto err_clk_per; 94864441979SMauro Carvalho Chehab 94964441979SMauro Carvalho Chehab ret = clk_prepare_enable(dev->clk_ahb); 95064441979SMauro Carvalho Chehab if (ret) 95164441979SMauro Carvalho Chehab goto err_clk_ahb; 95264441979SMauro Carvalho Chehab 95364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); 95464441979SMauro Carvalho Chehab coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 95564441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); 95664441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); 95764441979SMauro Carvalho Chehab coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); 95864441979SMauro Carvalho Chehab if (coda_wait_timeout(dev)) { 95964441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); 96064441979SMauro Carvalho Chehab ret = -EIO; 96164441979SMauro Carvalho Chehab goto err_run_cmd; 96264441979SMauro Carvalho Chehab } 96364441979SMauro Carvalho Chehab 96464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 96564441979SMauro Carvalho Chehab data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); 96664441979SMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", 96764441979SMauro Carvalho Chehab data); 96864441979SMauro Carvalho Chehab } 96964441979SMauro Carvalho Chehab 97064441979SMauro Carvalho Chehab /* Check we are compatible with the loaded firmware */ 97164441979SMauro Carvalho Chehab data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); 97264441979SMauro Carvalho Chehab product = CODA_FIRMWARE_PRODUCT(data); 97364441979SMauro Carvalho Chehab major = CODA_FIRMWARE_MAJOR(data); 97464441979SMauro Carvalho Chehab minor = CODA_FIRMWARE_MINOR(data); 97564441979SMauro Carvalho Chehab release = CODA_FIRMWARE_RELEASE(data); 97664441979SMauro Carvalho Chehab 97764441979SMauro Carvalho Chehab clk_disable_unprepare(dev->clk_per); 97864441979SMauro Carvalho Chehab clk_disable_unprepare(dev->clk_ahb); 97964441979SMauro Carvalho Chehab 98064441979SMauro Carvalho Chehab if (product != dev->devtype->product) { 98164441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 98264441979SMauro Carvalho Chehab "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", 98364441979SMauro Carvalho Chehab coda_product_name(dev->devtype->product), 98464441979SMauro Carvalho Chehab coda_product_name(product), major, minor, release); 98564441979SMauro Carvalho Chehab return -EINVAL; 98664441979SMauro Carvalho Chehab } 98764441979SMauro Carvalho Chehab 98864441979SMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", 98964441979SMauro Carvalho Chehab coda_product_name(product)); 99064441979SMauro Carvalho Chehab 99164441979SMauro Carvalho Chehab if (coda_firmware_supported(data)) { 99264441979SMauro Carvalho Chehab v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", 99364441979SMauro Carvalho Chehab major, minor, release); 99464441979SMauro Carvalho Chehab } else { 99564441979SMauro Carvalho Chehab v4l2_warn(&dev->v4l2_dev, 99664441979SMauro Carvalho Chehab "Unsupported firmware version: %u.%u.%u\n", 99764441979SMauro Carvalho Chehab major, minor, release); 99864441979SMauro Carvalho Chehab } 99964441979SMauro Carvalho Chehab 100064441979SMauro Carvalho Chehab return 0; 100164441979SMauro Carvalho Chehab 100264441979SMauro Carvalho Chehab err_run_cmd: 100364441979SMauro Carvalho Chehab clk_disable_unprepare(dev->clk_ahb); 100464441979SMauro Carvalho Chehab err_clk_ahb: 100564441979SMauro Carvalho Chehab clk_disable_unprepare(dev->clk_per); 100664441979SMauro Carvalho Chehab err_clk_per: 100764441979SMauro Carvalho Chehab return ret; 100864441979SMauro Carvalho Chehab } 100964441979SMauro Carvalho Chehab 101064441979SMauro Carvalho Chehab static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) 101164441979SMauro Carvalho Chehab { 101264441979SMauro Carvalho Chehab u32 cache_size, cache_config; 101364441979SMauro Carvalho Chehab 101464441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { 101564441979SMauro Carvalho Chehab /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ 101664441979SMauro Carvalho Chehab cache_size = 0x20262024; 101764441979SMauro Carvalho Chehab cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; 101864441979SMauro Carvalho Chehab } else { 101964441979SMauro Carvalho Chehab /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ 102064441979SMauro Carvalho Chehab cache_size = 0x02440243; 102164441979SMauro Carvalho Chehab cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; 102264441979SMauro Carvalho Chehab } 102364441979SMauro Carvalho Chehab coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); 102464441979SMauro Carvalho Chehab if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) { 102564441979SMauro Carvalho Chehab cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 102664441979SMauro Carvalho Chehab 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 102764441979SMauro Carvalho Chehab 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 102864441979SMauro Carvalho Chehab } else { 102964441979SMauro Carvalho Chehab cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 103064441979SMauro Carvalho Chehab 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 103164441979SMauro Carvalho Chehab 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 103264441979SMauro Carvalho Chehab } 103364441979SMauro Carvalho Chehab coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); 103464441979SMauro Carvalho Chehab } 103564441979SMauro Carvalho Chehab 103664441979SMauro Carvalho Chehab /* 103764441979SMauro Carvalho Chehab * Encoder context operations 103864441979SMauro Carvalho Chehab */ 103964441979SMauro Carvalho Chehab 104064441979SMauro Carvalho Chehab static int coda_encoder_reqbufs(struct coda_ctx *ctx, 104164441979SMauro Carvalho Chehab struct v4l2_requestbuffers *rb) 104264441979SMauro Carvalho Chehab { 104364441979SMauro Carvalho Chehab struct coda_q_data *q_data_src; 104464441979SMauro Carvalho Chehab int ret; 104564441979SMauro Carvalho Chehab 104664441979SMauro Carvalho Chehab if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 104764441979SMauro Carvalho Chehab return 0; 104864441979SMauro Carvalho Chehab 104964441979SMauro Carvalho Chehab if (rb->count) { 105064441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 105164441979SMauro Carvalho Chehab ret = coda_alloc_context_buffers(ctx, q_data_src); 105264441979SMauro Carvalho Chehab if (ret < 0) 105364441979SMauro Carvalho Chehab return ret; 105464441979SMauro Carvalho Chehab } else { 105564441979SMauro Carvalho Chehab coda_free_context_buffers(ctx); 105664441979SMauro Carvalho Chehab } 105764441979SMauro Carvalho Chehab 105864441979SMauro Carvalho Chehab return 0; 105964441979SMauro Carvalho Chehab } 106064441979SMauro Carvalho Chehab 106164441979SMauro Carvalho Chehab static int coda_start_encoding(struct coda_ctx *ctx) 106264441979SMauro Carvalho Chehab { 106364441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 106464441979SMauro Carvalho Chehab struct v4l2_device *v4l2_dev = &dev->v4l2_dev; 106564441979SMauro Carvalho Chehab struct coda_q_data *q_data_src, *q_data_dst; 106664441979SMauro Carvalho Chehab u32 bitstream_buf, bitstream_size; 106764441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *buf; 106864441979SMauro Carvalho Chehab int gamma, ret, value; 106964441979SMauro Carvalho Chehab u32 dst_fourcc; 107064441979SMauro Carvalho Chehab int num_fb; 107164441979SMauro Carvalho Chehab u32 stride; 107264441979SMauro Carvalho Chehab 107364441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 107464441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 107564441979SMauro Carvalho Chehab dst_fourcc = q_data_dst->fourcc; 107664441979SMauro Carvalho Chehab 107764441979SMauro Carvalho Chehab buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 107864441979SMauro Carvalho Chehab bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); 107964441979SMauro Carvalho Chehab bitstream_size = q_data_dst->sizeimage; 108064441979SMauro Carvalho Chehab 108164441979SMauro Carvalho Chehab if (!coda_is_initialized(dev)) { 108264441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, "coda is not initialized.\n"); 108364441979SMauro Carvalho Chehab return -EFAULT; 108464441979SMauro Carvalho Chehab } 108564441979SMauro Carvalho Chehab 108664441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_JPEG) { 108764441979SMauro Carvalho Chehab if (!ctx->params.jpeg_qmat_tab[0]) 108864441979SMauro Carvalho Chehab ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); 108964441979SMauro Carvalho Chehab if (!ctx->params.jpeg_qmat_tab[1]) 109064441979SMauro Carvalho Chehab ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); 109164441979SMauro Carvalho Chehab coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); 109264441979SMauro Carvalho Chehab } 109364441979SMauro Carvalho Chehab 109464441979SMauro Carvalho Chehab mutex_lock(&dev->coda_mutex); 109564441979SMauro Carvalho Chehab 109664441979SMauro Carvalho Chehab coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 109764441979SMauro Carvalho Chehab coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 109864441979SMauro Carvalho Chehab coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 109964441979SMauro Carvalho Chehab switch (dev->devtype->product) { 110064441979SMauro Carvalho Chehab case CODA_DX6: 110164441979SMauro Carvalho Chehab coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | 110264441979SMauro Carvalho Chehab CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 110364441979SMauro Carvalho Chehab break; 110464441979SMauro Carvalho Chehab case CODA_960: 110564441979SMauro Carvalho Chehab coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 110664441979SMauro Carvalho Chehab fallthrough; 110764441979SMauro Carvalho Chehab case CODA_HX4: 110864441979SMauro Carvalho Chehab case CODA_7541: 110964441979SMauro Carvalho Chehab coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | 111064441979SMauro Carvalho Chehab CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 111164441979SMauro Carvalho Chehab break; 111264441979SMauro Carvalho Chehab } 111364441979SMauro Carvalho Chehab 111464441979SMauro Carvalho Chehab ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 111564441979SMauro Carvalho Chehab CODA9_FRAME_TILED2LINEAR); 111664441979SMauro Carvalho Chehab if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) 111764441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 111864441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 111964441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; 112064441979SMauro Carvalho Chehab coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 112164441979SMauro Carvalho Chehab 112264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) { 112364441979SMauro Carvalho Chehab /* Configure the coda */ 112464441979SMauro Carvalho Chehab coda_write(dev, dev->iram.paddr, 112564441979SMauro Carvalho Chehab CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); 112664441979SMauro Carvalho Chehab } 112764441979SMauro Carvalho Chehab 112864441979SMauro Carvalho Chehab /* Could set rotation here if needed */ 112964441979SMauro Carvalho Chehab value = 0; 113064441979SMauro Carvalho Chehab switch (dev->devtype->product) { 113164441979SMauro Carvalho Chehab case CODA_DX6: 113264441979SMauro Carvalho Chehab value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK) 113364441979SMauro Carvalho Chehab << CODADX6_PICWIDTH_OFFSET; 113464441979SMauro Carvalho Chehab value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK) 113564441979SMauro Carvalho Chehab << CODA_PICHEIGHT_OFFSET; 113664441979SMauro Carvalho Chehab break; 113764441979SMauro Carvalho Chehab case CODA_HX4: 113864441979SMauro Carvalho Chehab case CODA_7541: 113964441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_H264) { 114064441979SMauro Carvalho Chehab value = (round_up(q_data_src->rect.width, 16) & 114164441979SMauro Carvalho Chehab CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; 114264441979SMauro Carvalho Chehab value |= (round_up(q_data_src->rect.height, 16) & 114364441979SMauro Carvalho Chehab CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; 114464441979SMauro Carvalho Chehab break; 114564441979SMauro Carvalho Chehab } 114664441979SMauro Carvalho Chehab fallthrough; 114764441979SMauro Carvalho Chehab case CODA_960: 114864441979SMauro Carvalho Chehab value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) 114964441979SMauro Carvalho Chehab << CODA7_PICWIDTH_OFFSET; 115064441979SMauro Carvalho Chehab value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK) 115164441979SMauro Carvalho Chehab << CODA_PICHEIGHT_OFFSET; 115264441979SMauro Carvalho Chehab } 115364441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); 115464441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_JPEG) 115564441979SMauro Carvalho Chehab ctx->params.framerate = 0; 115664441979SMauro Carvalho Chehab coda_write(dev, ctx->params.framerate, 115764441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_SRC_F_RATE); 115864441979SMauro Carvalho Chehab 115964441979SMauro Carvalho Chehab ctx->params.codec_mode = ctx->codec->mode; 116064441979SMauro Carvalho Chehab switch (dst_fourcc) { 116164441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG4: 116264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 116364441979SMauro Carvalho Chehab coda_write(dev, CODA9_STD_MPEG4, 116464441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_COD_STD); 116564441979SMauro Carvalho Chehab else 116664441979SMauro Carvalho Chehab coda_write(dev, CODA_STD_MPEG4, 116764441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_COD_STD); 116864441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); 116964441979SMauro Carvalho Chehab break; 117064441979SMauro Carvalho Chehab case V4L2_PIX_FMT_H264: 117164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 117264441979SMauro Carvalho Chehab coda_write(dev, CODA9_STD_H264, 117364441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_COD_STD); 117464441979SMauro Carvalho Chehab else 117564441979SMauro Carvalho Chehab coda_write(dev, CODA_STD_H264, 117664441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_COD_STD); 117764441979SMauro Carvalho Chehab value = ((ctx->params.h264_disable_deblocking_filter_idc & 117864441979SMauro Carvalho Chehab CODA_264PARAM_DISABLEDEBLK_MASK) << 117964441979SMauro Carvalho Chehab CODA_264PARAM_DISABLEDEBLK_OFFSET) | 118064441979SMauro Carvalho Chehab ((ctx->params.h264_slice_alpha_c0_offset_div2 & 118164441979SMauro Carvalho Chehab CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << 118264441979SMauro Carvalho Chehab CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | 118364441979SMauro Carvalho Chehab ((ctx->params.h264_slice_beta_offset_div2 & 118464441979SMauro Carvalho Chehab CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << 118564441979SMauro Carvalho Chehab CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | 118664441979SMauro Carvalho Chehab (ctx->params.h264_constrained_intra_pred_flag << 118764441979SMauro Carvalho Chehab CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | 118864441979SMauro Carvalho Chehab (ctx->params.h264_chroma_qp_index_offset & 118964441979SMauro Carvalho Chehab CODA_264PARAM_CHROMAQPOFFSET_MASK); 119064441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); 119164441979SMauro Carvalho Chehab break; 119264441979SMauro Carvalho Chehab case V4L2_PIX_FMT_JPEG: 119364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); 119464441979SMauro Carvalho Chehab coda_write(dev, ctx->params.jpeg_restart_interval, 119564441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); 119664441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); 119764441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); 119864441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); 119964441979SMauro Carvalho Chehab 120064441979SMauro Carvalho Chehab coda_jpeg_write_tables(ctx); 120164441979SMauro Carvalho Chehab break; 120264441979SMauro Carvalho Chehab default: 120364441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, 120464441979SMauro Carvalho Chehab "dst format (0x%08x) invalid.\n", dst_fourcc); 120564441979SMauro Carvalho Chehab ret = -EINVAL; 120664441979SMauro Carvalho Chehab goto out; 120764441979SMauro Carvalho Chehab } 120864441979SMauro Carvalho Chehab 120964441979SMauro Carvalho Chehab /* 121064441979SMauro Carvalho Chehab * slice mode and GOP size registers are used for thumb size/offset 121164441979SMauro Carvalho Chehab * in JPEG mode 121264441979SMauro Carvalho Chehab */ 121364441979SMauro Carvalho Chehab if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 121464441979SMauro Carvalho Chehab value = coda_slice_mode(ctx); 121564441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); 121664441979SMauro Carvalho Chehab value = ctx->params.gop_size; 121764441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); 121864441979SMauro Carvalho Chehab } 121964441979SMauro Carvalho Chehab 122064441979SMauro Carvalho Chehab if (ctx->params.bitrate && (ctx->params.frame_rc_enable || 122164441979SMauro Carvalho Chehab ctx->params.mb_rc_enable)) { 122264441979SMauro Carvalho Chehab ctx->params.bitrate_changed = false; 122364441979SMauro Carvalho Chehab ctx->params.h264_intra_qp_changed = false; 122464441979SMauro Carvalho Chehab 122564441979SMauro Carvalho Chehab /* Rate control enabled */ 122664441979SMauro Carvalho Chehab value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) 122764441979SMauro Carvalho Chehab << CODA_RATECONTROL_BITRATE_OFFSET; 122864441979SMauro Carvalho Chehab value |= 1 & CODA_RATECONTROL_ENABLE_MASK; 122964441979SMauro Carvalho Chehab value |= (ctx->params.vbv_delay & 123064441979SMauro Carvalho Chehab CODA_RATECONTROL_INITIALDELAY_MASK) 123164441979SMauro Carvalho Chehab << CODA_RATECONTROL_INITIALDELAY_OFFSET; 123264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 123364441979SMauro Carvalho Chehab value |= BIT(31); /* disable autoskip */ 123464441979SMauro Carvalho Chehab } else { 123564441979SMauro Carvalho Chehab value = 0; 123664441979SMauro Carvalho Chehab } 123764441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); 123864441979SMauro Carvalho Chehab 123964441979SMauro Carvalho Chehab coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); 124064441979SMauro Carvalho Chehab coda_write(dev, ctx->params.intra_refresh, 124164441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_INTRA_REFRESH); 124264441979SMauro Carvalho Chehab 124364441979SMauro Carvalho Chehab coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); 124464441979SMauro Carvalho Chehab coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); 124564441979SMauro Carvalho Chehab 124664441979SMauro Carvalho Chehab 124764441979SMauro Carvalho Chehab value = 0; 124864441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 124964441979SMauro Carvalho Chehab gamma = CODA9_DEFAULT_GAMMA; 125064441979SMauro Carvalho Chehab else 125164441979SMauro Carvalho Chehab gamma = CODA_DEFAULT_GAMMA; 125264441979SMauro Carvalho Chehab if (gamma > 0) { 125364441979SMauro Carvalho Chehab coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, 125464441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_RC_GAMMA); 125564441979SMauro Carvalho Chehab } 125664441979SMauro Carvalho Chehab 125764441979SMauro Carvalho Chehab if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { 125864441979SMauro Carvalho Chehab coda_write(dev, 125964441979SMauro Carvalho Chehab ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | 126064441979SMauro Carvalho Chehab ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, 126164441979SMauro Carvalho Chehab CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); 126264441979SMauro Carvalho Chehab } 126364441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 126464441979SMauro Carvalho Chehab if (ctx->params.h264_max_qp) 126564441979SMauro Carvalho Chehab value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; 126664441979SMauro Carvalho Chehab if (CODA_DEFAULT_GAMMA > 0) 126764441979SMauro Carvalho Chehab value |= 1 << CODA9_OPTION_GAMMA_OFFSET; 126864441979SMauro Carvalho Chehab } else { 126964441979SMauro Carvalho Chehab if (CODA_DEFAULT_GAMMA > 0) { 127064441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) 127164441979SMauro Carvalho Chehab value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; 127264441979SMauro Carvalho Chehab else 127364441979SMauro Carvalho Chehab value |= 1 << CODA7_OPTION_GAMMA_OFFSET; 127464441979SMauro Carvalho Chehab } 127564441979SMauro Carvalho Chehab if (ctx->params.h264_min_qp) 127664441979SMauro Carvalho Chehab value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; 127764441979SMauro Carvalho Chehab if (ctx->params.h264_max_qp) 127864441979SMauro Carvalho Chehab value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; 127964441979SMauro Carvalho Chehab } 128064441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); 128164441979SMauro Carvalho Chehab 128264441979SMauro Carvalho Chehab if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable) 128364441979SMauro Carvalho Chehab value = 1; 128464441979SMauro Carvalho Chehab else 128564441979SMauro Carvalho Chehab value = 0; 128664441979SMauro Carvalho Chehab coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); 128764441979SMauro Carvalho Chehab 128864441979SMauro Carvalho Chehab coda_setup_iram(ctx); 128964441979SMauro Carvalho Chehab 129064441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_H264) { 129164441979SMauro Carvalho Chehab switch (dev->devtype->product) { 129264441979SMauro Carvalho Chehab case CODA_DX6: 129364441979SMauro Carvalho Chehab value = FMO_SLICE_SAVE_BUF_SIZE << 7; 129464441979SMauro Carvalho Chehab coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); 129564441979SMauro Carvalho Chehab break; 129664441979SMauro Carvalho Chehab case CODA_HX4: 129764441979SMauro Carvalho Chehab case CODA_7541: 129864441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.search_ram_paddr, 129964441979SMauro Carvalho Chehab CODA7_CMD_ENC_SEQ_SEARCH_BASE); 130064441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.search_ram_size, 130164441979SMauro Carvalho Chehab CODA7_CMD_ENC_SEQ_SEARCH_SIZE); 130264441979SMauro Carvalho Chehab break; 130364441979SMauro Carvalho Chehab case CODA_960: 130464441979SMauro Carvalho Chehab coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); 130564441979SMauro Carvalho Chehab coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); 130664441979SMauro Carvalho Chehab } 130764441979SMauro Carvalho Chehab } 130864441979SMauro Carvalho Chehab 130964441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 131064441979SMauro Carvalho Chehab if (ret < 0) { 131164441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 131264441979SMauro Carvalho Chehab goto out; 131364441979SMauro Carvalho Chehab } 131464441979SMauro Carvalho Chehab 131564441979SMauro Carvalho Chehab if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { 131664441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); 131764441979SMauro Carvalho Chehab ret = -EFAULT; 131864441979SMauro Carvalho Chehab goto out; 131964441979SMauro Carvalho Chehab } 132064441979SMauro Carvalho Chehab ctx->initialized = 1; 132164441979SMauro Carvalho Chehab 132264441979SMauro Carvalho Chehab if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 132364441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 132464441979SMauro Carvalho Chehab ctx->num_internal_frames = 4; 132564441979SMauro Carvalho Chehab else 132664441979SMauro Carvalho Chehab ctx->num_internal_frames = 2; 132764441979SMauro Carvalho Chehab ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); 132864441979SMauro Carvalho Chehab if (ret < 0) { 132964441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); 133064441979SMauro Carvalho Chehab goto out; 133164441979SMauro Carvalho Chehab } 133264441979SMauro Carvalho Chehab num_fb = 2; 133364441979SMauro Carvalho Chehab stride = q_data_src->bytesperline; 133464441979SMauro Carvalho Chehab } else { 133564441979SMauro Carvalho Chehab ctx->num_internal_frames = 0; 133664441979SMauro Carvalho Chehab num_fb = 0; 133764441979SMauro Carvalho Chehab stride = 0; 133864441979SMauro Carvalho Chehab } 133964441979SMauro Carvalho Chehab coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); 134064441979SMauro Carvalho Chehab coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); 134164441979SMauro Carvalho Chehab 134264441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 134364441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 134464441979SMauro Carvalho Chehab coda_write(dev, q_data_src->bytesperline, 134564441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); 134664441979SMauro Carvalho Chehab } 134764441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) { 134864441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_bit_use, 134964441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 135064441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 135164441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 135264441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_dbk_y_use, 135364441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 135464441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_dbk_c_use, 135564441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 135664441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_ovl_use, 135764441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 135864441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 135964441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_btp_use, 136064441979SMauro Carvalho Chehab CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 136164441979SMauro Carvalho Chehab 136264441979SMauro Carvalho Chehab coda9_set_frame_cache(ctx, q_data_src->fourcc); 136364441979SMauro Carvalho Chehab 136464441979SMauro Carvalho Chehab /* FIXME */ 136564441979SMauro Carvalho Chehab coda_write(dev, ctx->internal_frames[2].buf.paddr, 136664441979SMauro Carvalho Chehab CODA9_CMD_SET_FRAME_SUBSAMP_A); 136764441979SMauro Carvalho Chehab coda_write(dev, ctx->internal_frames[3].buf.paddr, 136864441979SMauro Carvalho Chehab CODA9_CMD_SET_FRAME_SUBSAMP_B); 136964441979SMauro Carvalho Chehab } 137064441979SMauro Carvalho Chehab } 137164441979SMauro Carvalho Chehab 137264441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); 137364441979SMauro Carvalho Chehab if (ret < 0) { 137464441979SMauro Carvalho Chehab v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 137564441979SMauro Carvalho Chehab goto out; 137664441979SMauro Carvalho Chehab } 137764441979SMauro Carvalho Chehab 137864441979SMauro Carvalho Chehab coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", 137964441979SMauro Carvalho Chehab q_data_src->rect.width, q_data_src->rect.height, 138064441979SMauro Carvalho Chehab (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, 138164441979SMauro Carvalho Chehab ctx->params.framerate & 0xffff, 138264441979SMauro Carvalho Chehab (ctx->params.framerate >> 16) + 1); 138364441979SMauro Carvalho Chehab 138464441979SMauro Carvalho Chehab /* Save stream headers */ 138564441979SMauro Carvalho Chehab buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 138664441979SMauro Carvalho Chehab switch (dst_fourcc) { 138764441979SMauro Carvalho Chehab case V4L2_PIX_FMT_H264: 138864441979SMauro Carvalho Chehab /* 138964441979SMauro Carvalho Chehab * Get SPS in the first frame and copy it to an 139064441979SMauro Carvalho Chehab * intermediate buffer. 139164441979SMauro Carvalho Chehab */ 139264441979SMauro Carvalho Chehab ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, 139364441979SMauro Carvalho Chehab &ctx->vpu_header[0][0], 139464441979SMauro Carvalho Chehab &ctx->vpu_header_size[0]); 139564441979SMauro Carvalho Chehab if (ret < 0) 139664441979SMauro Carvalho Chehab goto out; 139764441979SMauro Carvalho Chehab 139864441979SMauro Carvalho Chehab /* 139964441979SMauro Carvalho Chehab * If visible width or height are not aligned to macroblock 140064441979SMauro Carvalho Chehab * size, the crop_right and crop_bottom SPS fields must be set 140164441979SMauro Carvalho Chehab * to the difference between visible and coded size. This is 140264441979SMauro Carvalho Chehab * only supported by CODA960 firmware. All others do not allow 140364441979SMauro Carvalho Chehab * writing frame cropping parameters, so we have to manually 140464441979SMauro Carvalho Chehab * fix up the SPS RBSP (Sequence Parameter Set Raw Byte 140564441979SMauro Carvalho Chehab * Sequence Payload) ourselves. 140664441979SMauro Carvalho Chehab */ 140764441979SMauro Carvalho Chehab if (ctx->dev->devtype->product != CODA_960 && 140864441979SMauro Carvalho Chehab ((q_data_src->rect.width % 16) || 140964441979SMauro Carvalho Chehab (q_data_src->rect.height % 16))) { 141064441979SMauro Carvalho Chehab ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, 141164441979SMauro Carvalho Chehab q_data_src->rect.height, 141264441979SMauro Carvalho Chehab &ctx->vpu_header[0][0], 141364441979SMauro Carvalho Chehab &ctx->vpu_header_size[0], 141464441979SMauro Carvalho Chehab sizeof(ctx->vpu_header[0])); 141564441979SMauro Carvalho Chehab if (ret < 0) 141664441979SMauro Carvalho Chehab goto out; 141764441979SMauro Carvalho Chehab } 141864441979SMauro Carvalho Chehab 141964441979SMauro Carvalho Chehab /* 142064441979SMauro Carvalho Chehab * Get PPS in the first frame and copy it to an 142164441979SMauro Carvalho Chehab * intermediate buffer. 142264441979SMauro Carvalho Chehab */ 142364441979SMauro Carvalho Chehab ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, 142464441979SMauro Carvalho Chehab &ctx->vpu_header[1][0], 142564441979SMauro Carvalho Chehab &ctx->vpu_header_size[1]); 142664441979SMauro Carvalho Chehab if (ret < 0) 142764441979SMauro Carvalho Chehab goto out; 142864441979SMauro Carvalho Chehab 142964441979SMauro Carvalho Chehab /* 143064441979SMauro Carvalho Chehab * Length of H.264 headers is variable and thus it might not be 143164441979SMauro Carvalho Chehab * aligned for the coda to append the encoded frame. In that is 143264441979SMauro Carvalho Chehab * the case a filler NAL must be added to header 2. 143364441979SMauro Carvalho Chehab */ 143464441979SMauro Carvalho Chehab ctx->vpu_header_size[2] = coda_h264_padding( 143564441979SMauro Carvalho Chehab (ctx->vpu_header_size[0] + 143664441979SMauro Carvalho Chehab ctx->vpu_header_size[1]), 143764441979SMauro Carvalho Chehab ctx->vpu_header[2]); 143864441979SMauro Carvalho Chehab break; 143964441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG4: 144064441979SMauro Carvalho Chehab /* 144164441979SMauro Carvalho Chehab * Get VOS in the first frame and copy it to an 144264441979SMauro Carvalho Chehab * intermediate buffer 144364441979SMauro Carvalho Chehab */ 144464441979SMauro Carvalho Chehab ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, 144564441979SMauro Carvalho Chehab &ctx->vpu_header[0][0], 144664441979SMauro Carvalho Chehab &ctx->vpu_header_size[0]); 144764441979SMauro Carvalho Chehab if (ret < 0) 144864441979SMauro Carvalho Chehab goto out; 144964441979SMauro Carvalho Chehab 145064441979SMauro Carvalho Chehab ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, 145164441979SMauro Carvalho Chehab &ctx->vpu_header[1][0], 145264441979SMauro Carvalho Chehab &ctx->vpu_header_size[1]); 145364441979SMauro Carvalho Chehab if (ret < 0) 145464441979SMauro Carvalho Chehab goto out; 145564441979SMauro Carvalho Chehab 145664441979SMauro Carvalho Chehab ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, 145764441979SMauro Carvalho Chehab &ctx->vpu_header[2][0], 145864441979SMauro Carvalho Chehab &ctx->vpu_header_size[2]); 145964441979SMauro Carvalho Chehab if (ret < 0) 146064441979SMauro Carvalho Chehab goto out; 146164441979SMauro Carvalho Chehab break; 146264441979SMauro Carvalho Chehab default: 146364441979SMauro Carvalho Chehab /* No more formats need to save headers at the moment */ 146464441979SMauro Carvalho Chehab break; 146564441979SMauro Carvalho Chehab } 146664441979SMauro Carvalho Chehab 146764441979SMauro Carvalho Chehab out: 146864441979SMauro Carvalho Chehab mutex_unlock(&dev->coda_mutex); 146964441979SMauro Carvalho Chehab return ret; 147064441979SMauro Carvalho Chehab } 147164441979SMauro Carvalho Chehab 147264441979SMauro Carvalho Chehab static int coda_prepare_encode(struct coda_ctx *ctx) 147364441979SMauro Carvalho Chehab { 147464441979SMauro Carvalho Chehab struct coda_q_data *q_data_src, *q_data_dst; 147564441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf, *dst_buf; 147664441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 147764441979SMauro Carvalho Chehab int force_ipicture; 147864441979SMauro Carvalho Chehab int quant_param = 0; 147964441979SMauro Carvalho Chehab u32 pic_stream_buffer_addr, pic_stream_buffer_size; 148064441979SMauro Carvalho Chehab u32 rot_mode = 0; 148164441979SMauro Carvalho Chehab u32 dst_fourcc; 148264441979SMauro Carvalho Chehab u32 reg; 148364441979SMauro Carvalho Chehab int ret; 148464441979SMauro Carvalho Chehab 148564441979SMauro Carvalho Chehab ret = coda_enc_param_change(ctx); 148664441979SMauro Carvalho Chehab if (ret < 0) { 148764441979SMauro Carvalho Chehab v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", 148864441979SMauro Carvalho Chehab ret); 148964441979SMauro Carvalho Chehab } 149064441979SMauro Carvalho Chehab 149164441979SMauro Carvalho Chehab src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 149264441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 149364441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 149464441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 149564441979SMauro Carvalho Chehab dst_fourcc = q_data_dst->fourcc; 149664441979SMauro Carvalho Chehab 149764441979SMauro Carvalho Chehab src_buf->sequence = ctx->osequence; 149864441979SMauro Carvalho Chehab dst_buf->sequence = ctx->osequence; 149964441979SMauro Carvalho Chehab ctx->osequence++; 150064441979SMauro Carvalho Chehab 150164441979SMauro Carvalho Chehab force_ipicture = ctx->params.force_ipicture; 150264441979SMauro Carvalho Chehab if (force_ipicture) 150364441979SMauro Carvalho Chehab ctx->params.force_ipicture = false; 150464441979SMauro Carvalho Chehab else if (ctx->params.gop_size != 0 && 150564441979SMauro Carvalho Chehab (src_buf->sequence % ctx->params.gop_size) == 0) 150664441979SMauro Carvalho Chehab force_ipicture = 1; 150764441979SMauro Carvalho Chehab 150864441979SMauro Carvalho Chehab /* 150964441979SMauro Carvalho Chehab * Workaround coda firmware BUG that only marks the first 151064441979SMauro Carvalho Chehab * frame as IDR. This is a problem for some decoders that can't 151164441979SMauro Carvalho Chehab * recover when a frame is lost. 151264441979SMauro Carvalho Chehab */ 151364441979SMauro Carvalho Chehab if (!force_ipicture) { 151464441979SMauro Carvalho Chehab src_buf->flags |= V4L2_BUF_FLAG_PFRAME; 151564441979SMauro Carvalho Chehab src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; 151664441979SMauro Carvalho Chehab } else { 151764441979SMauro Carvalho Chehab src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 151864441979SMauro Carvalho Chehab src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; 151964441979SMauro Carvalho Chehab } 152064441979SMauro Carvalho Chehab 152164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 152264441979SMauro Carvalho Chehab coda_set_gdi_regs(ctx); 152364441979SMauro Carvalho Chehab 152464441979SMauro Carvalho Chehab /* 152564441979SMauro Carvalho Chehab * Copy headers in front of the first frame and forced I frames for 152664441979SMauro Carvalho Chehab * H.264 only. In MPEG4 they are already copied by the CODA. 152764441979SMauro Carvalho Chehab */ 152864441979SMauro Carvalho Chehab if (src_buf->sequence == 0 || force_ipicture) { 152964441979SMauro Carvalho Chehab pic_stream_buffer_addr = 153064441979SMauro Carvalho Chehab vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) + 153164441979SMauro Carvalho Chehab ctx->vpu_header_size[0] + 153264441979SMauro Carvalho Chehab ctx->vpu_header_size[1] + 153364441979SMauro Carvalho Chehab ctx->vpu_header_size[2]; 153464441979SMauro Carvalho Chehab pic_stream_buffer_size = q_data_dst->sizeimage - 153564441979SMauro Carvalho Chehab ctx->vpu_header_size[0] - 153664441979SMauro Carvalho Chehab ctx->vpu_header_size[1] - 153764441979SMauro Carvalho Chehab ctx->vpu_header_size[2]; 153864441979SMauro Carvalho Chehab memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0), 153964441979SMauro Carvalho Chehab &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); 154064441979SMauro Carvalho Chehab memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 154164441979SMauro Carvalho Chehab + ctx->vpu_header_size[0], &ctx->vpu_header[1][0], 154264441979SMauro Carvalho Chehab ctx->vpu_header_size[1]); 154364441979SMauro Carvalho Chehab memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 154464441979SMauro Carvalho Chehab + ctx->vpu_header_size[0] + ctx->vpu_header_size[1], 154564441979SMauro Carvalho Chehab &ctx->vpu_header[2][0], ctx->vpu_header_size[2]); 154664441979SMauro Carvalho Chehab } else { 154764441979SMauro Carvalho Chehab pic_stream_buffer_addr = 154864441979SMauro Carvalho Chehab vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); 154964441979SMauro Carvalho Chehab pic_stream_buffer_size = q_data_dst->sizeimage; 155064441979SMauro Carvalho Chehab } 155164441979SMauro Carvalho Chehab 155264441979SMauro Carvalho Chehab if (force_ipicture) { 155364441979SMauro Carvalho Chehab switch (dst_fourcc) { 155464441979SMauro Carvalho Chehab case V4L2_PIX_FMT_H264: 155564441979SMauro Carvalho Chehab quant_param = ctx->params.h264_intra_qp; 155664441979SMauro Carvalho Chehab break; 155764441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG4: 155864441979SMauro Carvalho Chehab quant_param = ctx->params.mpeg4_intra_qp; 155964441979SMauro Carvalho Chehab break; 156064441979SMauro Carvalho Chehab case V4L2_PIX_FMT_JPEG: 156164441979SMauro Carvalho Chehab quant_param = 30; 156264441979SMauro Carvalho Chehab break; 156364441979SMauro Carvalho Chehab default: 156464441979SMauro Carvalho Chehab v4l2_warn(&ctx->dev->v4l2_dev, 156564441979SMauro Carvalho Chehab "cannot set intra qp, fmt not supported\n"); 156664441979SMauro Carvalho Chehab break; 156764441979SMauro Carvalho Chehab } 156864441979SMauro Carvalho Chehab } else { 156964441979SMauro Carvalho Chehab switch (dst_fourcc) { 157064441979SMauro Carvalho Chehab case V4L2_PIX_FMT_H264: 157164441979SMauro Carvalho Chehab quant_param = ctx->params.h264_inter_qp; 157264441979SMauro Carvalho Chehab break; 157364441979SMauro Carvalho Chehab case V4L2_PIX_FMT_MPEG4: 157464441979SMauro Carvalho Chehab quant_param = ctx->params.mpeg4_inter_qp; 157564441979SMauro Carvalho Chehab break; 157664441979SMauro Carvalho Chehab default: 157764441979SMauro Carvalho Chehab v4l2_warn(&ctx->dev->v4l2_dev, 157864441979SMauro Carvalho Chehab "cannot set inter qp, fmt not supported\n"); 157964441979SMauro Carvalho Chehab break; 158064441979SMauro Carvalho Chehab } 158164441979SMauro Carvalho Chehab } 158264441979SMauro Carvalho Chehab 158364441979SMauro Carvalho Chehab /* submit */ 158464441979SMauro Carvalho Chehab if (ctx->params.rot_mode) 158564441979SMauro Carvalho Chehab rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 158664441979SMauro Carvalho Chehab coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); 158764441979SMauro Carvalho Chehab coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); 158864441979SMauro Carvalho Chehab 158964441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 159064441979SMauro Carvalho Chehab coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); 159164441979SMauro Carvalho Chehab coda_write(dev, q_data_src->bytesperline, 159264441979SMauro Carvalho Chehab CODA9_CMD_ENC_PIC_SRC_STRIDE); 159364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); 159464441979SMauro Carvalho Chehab 159564441979SMauro Carvalho Chehab reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; 159664441979SMauro Carvalho Chehab } else { 159764441979SMauro Carvalho Chehab reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; 159864441979SMauro Carvalho Chehab } 159964441979SMauro Carvalho Chehab coda_write_base(ctx, q_data_src, src_buf, reg); 160064441979SMauro Carvalho Chehab 160164441979SMauro Carvalho Chehab coda_write(dev, force_ipicture << 1 & 0x2, 160264441979SMauro Carvalho Chehab CODA_CMD_ENC_PIC_OPTION); 160364441979SMauro Carvalho Chehab 160464441979SMauro Carvalho Chehab coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); 160564441979SMauro Carvalho Chehab coda_write(dev, pic_stream_buffer_size / 1024, 160664441979SMauro Carvalho Chehab CODA_CMD_ENC_PIC_BB_SIZE); 160764441979SMauro Carvalho Chehab 160864441979SMauro Carvalho Chehab if (!ctx->streamon_out) { 160964441979SMauro Carvalho Chehab /* After streamoff on the output side, set stream end flag */ 161064441979SMauro Carvalho Chehab ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 161164441979SMauro Carvalho Chehab coda_write(dev, ctx->bit_stream_param, 161264441979SMauro Carvalho Chehab CODA_REG_BIT_BIT_STREAM_PARAM); 161364441979SMauro Carvalho Chehab } 161464441979SMauro Carvalho Chehab 161564441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) 161664441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.axi_sram_use, 161764441979SMauro Carvalho Chehab CODA7_REG_BIT_AXI_SRAM_USE); 161864441979SMauro Carvalho Chehab 161964441979SMauro Carvalho Chehab trace_coda_enc_pic_run(ctx, src_buf); 162064441979SMauro Carvalho Chehab 162164441979SMauro Carvalho Chehab coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 162264441979SMauro Carvalho Chehab 162364441979SMauro Carvalho Chehab return 0; 162464441979SMauro Carvalho Chehab } 162564441979SMauro Carvalho Chehab 162664441979SMauro Carvalho Chehab static char coda_frame_type_char(u32 flags) 162764441979SMauro Carvalho Chehab { 162864441979SMauro Carvalho Chehab return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 162964441979SMauro Carvalho Chehab (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 163064441979SMauro Carvalho Chehab (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; 163164441979SMauro Carvalho Chehab } 163264441979SMauro Carvalho Chehab 163364441979SMauro Carvalho Chehab static void coda_finish_encode(struct coda_ctx *ctx) 163464441979SMauro Carvalho Chehab { 163564441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *src_buf, *dst_buf; 163664441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 163764441979SMauro Carvalho Chehab u32 wr_ptr, start_ptr; 163864441979SMauro Carvalho Chehab 163964441979SMauro Carvalho Chehab if (ctx->aborting) 164064441979SMauro Carvalho Chehab return; 164164441979SMauro Carvalho Chehab 164264441979SMauro Carvalho Chehab /* 164364441979SMauro Carvalho Chehab * Lock to make sure that an encoder stop command running in parallel 164464441979SMauro Carvalho Chehab * will either already have marked src_buf as last, or it will wake up 164564441979SMauro Carvalho Chehab * the capture queue after the buffers are returned. 164664441979SMauro Carvalho Chehab */ 164764441979SMauro Carvalho Chehab mutex_lock(&ctx->wakeup_mutex); 164864441979SMauro Carvalho Chehab src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 164964441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 165064441979SMauro Carvalho Chehab 165164441979SMauro Carvalho Chehab trace_coda_enc_pic_done(ctx, dst_buf); 165264441979SMauro Carvalho Chehab 165364441979SMauro Carvalho Chehab /* Get results from the coda */ 165464441979SMauro Carvalho Chehab start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); 165564441979SMauro Carvalho Chehab wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 165664441979SMauro Carvalho Chehab 165764441979SMauro Carvalho Chehab /* Calculate bytesused field */ 165864441979SMauro Carvalho Chehab if (dst_buf->sequence == 0 || 165964441979SMauro Carvalho Chehab src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { 166064441979SMauro Carvalho Chehab vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr + 166164441979SMauro Carvalho Chehab ctx->vpu_header_size[0] + 166264441979SMauro Carvalho Chehab ctx->vpu_header_size[1] + 166364441979SMauro Carvalho Chehab ctx->vpu_header_size[2]); 166464441979SMauro Carvalho Chehab } else { 166564441979SMauro Carvalho Chehab vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); 166664441979SMauro Carvalho Chehab } 166764441979SMauro Carvalho Chehab 166864441979SMauro Carvalho Chehab coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); 166964441979SMauro Carvalho Chehab 167064441979SMauro Carvalho Chehab coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); 167164441979SMauro Carvalho Chehab coda_read(dev, CODA_RET_ENC_PIC_FLAG); 167264441979SMauro Carvalho Chehab 167364441979SMauro Carvalho Chehab dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 167464441979SMauro Carvalho Chehab V4L2_BUF_FLAG_PFRAME | 167564441979SMauro Carvalho Chehab V4L2_BUF_FLAG_LAST); 167664441979SMauro Carvalho Chehab if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) 167764441979SMauro Carvalho Chehab dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 167864441979SMauro Carvalho Chehab else 167964441979SMauro Carvalho Chehab dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; 168064441979SMauro Carvalho Chehab dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; 168164441979SMauro Carvalho Chehab 168264441979SMauro Carvalho Chehab v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); 168364441979SMauro Carvalho Chehab 168464441979SMauro Carvalho Chehab v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 168564441979SMauro Carvalho Chehab 168664441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 168764441979SMauro Carvalho Chehab coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 168864441979SMauro Carvalho Chehab mutex_unlock(&ctx->wakeup_mutex); 168964441979SMauro Carvalho Chehab 169064441979SMauro Carvalho Chehab ctx->gopcounter--; 169164441979SMauro Carvalho Chehab if (ctx->gopcounter < 0) 169264441979SMauro Carvalho Chehab ctx->gopcounter = ctx->params.gop_size - 1; 169364441979SMauro Carvalho Chehab 169464441979SMauro Carvalho Chehab coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", 169564441979SMauro Carvalho Chehab coda_frame_type_char(dst_buf->flags), dst_buf->sequence, 169664441979SMauro Carvalho Chehab (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); 169764441979SMauro Carvalho Chehab } 169864441979SMauro Carvalho Chehab 169964441979SMauro Carvalho Chehab static void coda_seq_end_work(struct work_struct *work) 170064441979SMauro Carvalho Chehab { 170164441979SMauro Carvalho Chehab struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); 170264441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 170364441979SMauro Carvalho Chehab 170464441979SMauro Carvalho Chehab mutex_lock(&ctx->buffer_mutex); 170564441979SMauro Carvalho Chehab mutex_lock(&dev->coda_mutex); 170664441979SMauro Carvalho Chehab 170764441979SMauro Carvalho Chehab if (ctx->initialized == 0) 170864441979SMauro Carvalho Chehab goto out; 170964441979SMauro Carvalho Chehab 171064441979SMauro Carvalho Chehab coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); 171164441979SMauro Carvalho Chehab if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { 171264441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 171364441979SMauro Carvalho Chehab "CODA_COMMAND_SEQ_END failed\n"); 171464441979SMauro Carvalho Chehab } 171564441979SMauro Carvalho Chehab 171664441979SMauro Carvalho Chehab /* 171764441979SMauro Carvalho Chehab * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing 171864441979SMauro Carvalho Chehab * from the output stream after the h.264 decoder has run. Resetting the 171964441979SMauro Carvalho Chehab * hardware after the decoder has finished seems to help. 172064441979SMauro Carvalho Chehab */ 172164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 172264441979SMauro Carvalho Chehab coda_hw_reset(ctx); 172364441979SMauro Carvalho Chehab 172464441979SMauro Carvalho Chehab kfifo_init(&ctx->bitstream_fifo, 172564441979SMauro Carvalho Chehab ctx->bitstream.vaddr, ctx->bitstream.size); 172664441979SMauro Carvalho Chehab 172764441979SMauro Carvalho Chehab coda_free_framebuffers(ctx); 172864441979SMauro Carvalho Chehab 172964441979SMauro Carvalho Chehab ctx->initialized = 0; 173064441979SMauro Carvalho Chehab 173164441979SMauro Carvalho Chehab out: 173264441979SMauro Carvalho Chehab mutex_unlock(&dev->coda_mutex); 173364441979SMauro Carvalho Chehab mutex_unlock(&ctx->buffer_mutex); 173464441979SMauro Carvalho Chehab } 173564441979SMauro Carvalho Chehab 173664441979SMauro Carvalho Chehab static void coda_bit_release(struct coda_ctx *ctx) 173764441979SMauro Carvalho Chehab { 173864441979SMauro Carvalho Chehab mutex_lock(&ctx->buffer_mutex); 173964441979SMauro Carvalho Chehab coda_free_framebuffers(ctx); 174064441979SMauro Carvalho Chehab coda_free_context_buffers(ctx); 174164441979SMauro Carvalho Chehab coda_free_bitstream_buffer(ctx); 174264441979SMauro Carvalho Chehab mutex_unlock(&ctx->buffer_mutex); 174364441979SMauro Carvalho Chehab } 174464441979SMauro Carvalho Chehab 174564441979SMauro Carvalho Chehab const struct coda_context_ops coda_bit_encode_ops = { 174664441979SMauro Carvalho Chehab .queue_init = coda_encoder_queue_init, 174764441979SMauro Carvalho Chehab .reqbufs = coda_encoder_reqbufs, 174864441979SMauro Carvalho Chehab .start_streaming = coda_start_encoding, 174964441979SMauro Carvalho Chehab .prepare_run = coda_prepare_encode, 175064441979SMauro Carvalho Chehab .finish_run = coda_finish_encode, 175164441979SMauro Carvalho Chehab .seq_end_work = coda_seq_end_work, 175264441979SMauro Carvalho Chehab .release = coda_bit_release, 175364441979SMauro Carvalho Chehab }; 175464441979SMauro Carvalho Chehab 175564441979SMauro Carvalho Chehab /* 175664441979SMauro Carvalho Chehab * Decoder context operations 175764441979SMauro Carvalho Chehab */ 175864441979SMauro Carvalho Chehab 175964441979SMauro Carvalho Chehab static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, 176064441979SMauro Carvalho Chehab struct coda_q_data *q_data) 176164441979SMauro Carvalho Chehab { 176264441979SMauro Carvalho Chehab if (ctx->bitstream.vaddr) 176364441979SMauro Carvalho Chehab return 0; 176464441979SMauro Carvalho Chehab 176564441979SMauro Carvalho Chehab ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); 176664441979SMauro Carvalho Chehab ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, 176764441979SMauro Carvalho Chehab &ctx->bitstream.paddr, GFP_KERNEL); 176864441979SMauro Carvalho Chehab if (!ctx->bitstream.vaddr) { 176964441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, 177064441979SMauro Carvalho Chehab "failed to allocate bitstream ringbuffer"); 177164441979SMauro Carvalho Chehab return -ENOMEM; 177264441979SMauro Carvalho Chehab } 177364441979SMauro Carvalho Chehab kfifo_init(&ctx->bitstream_fifo, 177464441979SMauro Carvalho Chehab ctx->bitstream.vaddr, ctx->bitstream.size); 177564441979SMauro Carvalho Chehab 177664441979SMauro Carvalho Chehab return 0; 177764441979SMauro Carvalho Chehab } 177864441979SMauro Carvalho Chehab 177964441979SMauro Carvalho Chehab static void coda_free_bitstream_buffer(struct coda_ctx *ctx) 178064441979SMauro Carvalho Chehab { 178164441979SMauro Carvalho Chehab if (ctx->bitstream.vaddr == NULL) 178264441979SMauro Carvalho Chehab return; 178364441979SMauro Carvalho Chehab 178464441979SMauro Carvalho Chehab dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, 178564441979SMauro Carvalho Chehab ctx->bitstream.paddr); 178664441979SMauro Carvalho Chehab ctx->bitstream.vaddr = NULL; 178764441979SMauro Carvalho Chehab kfifo_init(&ctx->bitstream_fifo, NULL, 0); 178864441979SMauro Carvalho Chehab } 178964441979SMauro Carvalho Chehab 179064441979SMauro Carvalho Chehab static int coda_decoder_reqbufs(struct coda_ctx *ctx, 179164441979SMauro Carvalho Chehab struct v4l2_requestbuffers *rb) 179264441979SMauro Carvalho Chehab { 179364441979SMauro Carvalho Chehab struct coda_q_data *q_data_src; 179464441979SMauro Carvalho Chehab int ret; 179564441979SMauro Carvalho Chehab 179664441979SMauro Carvalho Chehab if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 179764441979SMauro Carvalho Chehab return 0; 179864441979SMauro Carvalho Chehab 179964441979SMauro Carvalho Chehab if (rb->count) { 180064441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 180164441979SMauro Carvalho Chehab ret = coda_alloc_context_buffers(ctx, q_data_src); 180264441979SMauro Carvalho Chehab if (ret < 0) 180364441979SMauro Carvalho Chehab return ret; 180464441979SMauro Carvalho Chehab ret = coda_alloc_bitstream_buffer(ctx, q_data_src); 180564441979SMauro Carvalho Chehab if (ret < 0) { 180664441979SMauro Carvalho Chehab coda_free_context_buffers(ctx); 180764441979SMauro Carvalho Chehab return ret; 180864441979SMauro Carvalho Chehab } 180964441979SMauro Carvalho Chehab } else { 181064441979SMauro Carvalho Chehab coda_free_bitstream_buffer(ctx); 181164441979SMauro Carvalho Chehab coda_free_context_buffers(ctx); 181264441979SMauro Carvalho Chehab } 181364441979SMauro Carvalho Chehab 181464441979SMauro Carvalho Chehab return 0; 181564441979SMauro Carvalho Chehab } 181664441979SMauro Carvalho Chehab 181764441979SMauro Carvalho Chehab static bool coda_reorder_enable(struct coda_ctx *ctx) 181864441979SMauro Carvalho Chehab { 181964441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 182064441979SMauro Carvalho Chehab int profile; 182164441979SMauro Carvalho Chehab 182264441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_HX4 && 182364441979SMauro Carvalho Chehab dev->devtype->product != CODA_7541 && 182464441979SMauro Carvalho Chehab dev->devtype->product != CODA_960) 182564441979SMauro Carvalho Chehab return false; 182664441979SMauro Carvalho Chehab 182764441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 182864441979SMauro Carvalho Chehab return false; 182964441979SMauro Carvalho Chehab 183064441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) 183164441979SMauro Carvalho Chehab return true; 183264441979SMauro Carvalho Chehab 183364441979SMauro Carvalho Chehab profile = coda_h264_profile(ctx->params.h264_profile_idc); 183464441979SMauro Carvalho Chehab if (profile < 0) 183564441979SMauro Carvalho Chehab v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", 183664441979SMauro Carvalho Chehab ctx->params.h264_profile_idc); 183764441979SMauro Carvalho Chehab 183864441979SMauro Carvalho Chehab /* Baseline profile does not support reordering */ 183964441979SMauro Carvalho Chehab return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; 184064441979SMauro Carvalho Chehab } 184164441979SMauro Carvalho Chehab 184264441979SMauro Carvalho Chehab static void coda_decoder_drop_used_metas(struct coda_ctx *ctx) 184364441979SMauro Carvalho Chehab { 184464441979SMauro Carvalho Chehab struct coda_buffer_meta *meta, *tmp; 184564441979SMauro Carvalho Chehab 184664441979SMauro Carvalho Chehab /* 184764441979SMauro Carvalho Chehab * All metas that end at or before the RD pointer (fifo out), 184864441979SMauro Carvalho Chehab * are now consumed by the VPU and should be released. 184964441979SMauro Carvalho Chehab */ 185064441979SMauro Carvalho Chehab spin_lock(&ctx->buffer_meta_lock); 185164441979SMauro Carvalho Chehab list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) { 185264441979SMauro Carvalho Chehab if (ctx->bitstream_fifo.kfifo.out >= meta->end) { 185364441979SMauro Carvalho Chehab coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n", 185464441979SMauro Carvalho Chehab meta->sequence, meta->start, meta->end); 185564441979SMauro Carvalho Chehab 185664441979SMauro Carvalho Chehab list_del(&meta->list); 185764441979SMauro Carvalho Chehab ctx->num_metas--; 185864441979SMauro Carvalho Chehab ctx->first_frame_sequence++; 185964441979SMauro Carvalho Chehab kfree(meta); 186064441979SMauro Carvalho Chehab } 186164441979SMauro Carvalho Chehab } 186264441979SMauro Carvalho Chehab spin_unlock(&ctx->buffer_meta_lock); 186364441979SMauro Carvalho Chehab } 186464441979SMauro Carvalho Chehab 186564441979SMauro Carvalho Chehab static int __coda_decoder_seq_init(struct coda_ctx *ctx) 186664441979SMauro Carvalho Chehab { 186764441979SMauro Carvalho Chehab struct coda_q_data *q_data_src, *q_data_dst; 186864441979SMauro Carvalho Chehab u32 bitstream_buf, bitstream_size; 186964441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 187064441979SMauro Carvalho Chehab int width, height; 187164441979SMauro Carvalho Chehab u32 src_fourcc, dst_fourcc; 187264441979SMauro Carvalho Chehab u32 val; 187364441979SMauro Carvalho Chehab int ret; 187464441979SMauro Carvalho Chehab 187564441979SMauro Carvalho Chehab lockdep_assert_held(&dev->coda_mutex); 187664441979SMauro Carvalho Chehab 187764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", 187864441979SMauro Carvalho Chehab ctx->use_vdoa ? "Enabled" : "Disabled"); 187964441979SMauro Carvalho Chehab 188064441979SMauro Carvalho Chehab /* Start decoding */ 188164441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 188264441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 188364441979SMauro Carvalho Chehab bitstream_buf = ctx->bitstream.paddr; 188464441979SMauro Carvalho Chehab bitstream_size = ctx->bitstream.size; 188564441979SMauro Carvalho Chehab src_fourcc = q_data_src->fourcc; 188664441979SMauro Carvalho Chehab dst_fourcc = q_data_dst->fourcc; 188764441979SMauro Carvalho Chehab 188864441979SMauro Carvalho Chehab /* Update coda bitstream read and write pointers from kfifo */ 188964441979SMauro Carvalho Chehab coda_kfifo_sync_to_device_full(ctx); 189064441979SMauro Carvalho Chehab 189164441979SMauro Carvalho Chehab ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 189264441979SMauro Carvalho Chehab CODA9_FRAME_TILED2LINEAR); 189364441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 189464441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 189564441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 189664441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= (0x3 << 9) | 189764441979SMauro Carvalho Chehab ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 189864441979SMauro Carvalho Chehab coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 189964441979SMauro Carvalho Chehab 190064441979SMauro Carvalho Chehab ctx->display_idx = -1; 190164441979SMauro Carvalho Chehab ctx->frm_dis_flg = 0; 190264441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 190364441979SMauro Carvalho Chehab 190464441979SMauro Carvalho Chehab coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); 190564441979SMauro Carvalho Chehab coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); 190664441979SMauro Carvalho Chehab val = 0; 190764441979SMauro Carvalho Chehab if (coda_reorder_enable(ctx)) 190864441979SMauro Carvalho Chehab val |= CODA_REORDER_ENABLE; 190964441979SMauro Carvalho Chehab if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 191064441979SMauro Carvalho Chehab val |= CODA_NO_INT_ENABLE; 191164441979SMauro Carvalho Chehab coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); 191264441979SMauro Carvalho Chehab 191364441979SMauro Carvalho Chehab ctx->params.codec_mode = ctx->codec->mode; 191464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960 && 191564441979SMauro Carvalho Chehab src_fourcc == V4L2_PIX_FMT_MPEG4) 191664441979SMauro Carvalho Chehab ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; 191764441979SMauro Carvalho Chehab else 191864441979SMauro Carvalho Chehab ctx->params.codec_mode_aux = 0; 191964441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_MPEG4) { 192064441979SMauro Carvalho Chehab coda_write(dev, CODA_MP4_CLASS_MPEG4, 192164441979SMauro Carvalho Chehab CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); 192264441979SMauro Carvalho Chehab } 192364441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_H264) { 192464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 192564441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 192664441979SMauro Carvalho Chehab coda_write(dev, ctx->psbuf.paddr, 192764441979SMauro Carvalho Chehab CODA_CMD_DEC_SEQ_PS_BB_START); 192864441979SMauro Carvalho Chehab coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), 192964441979SMauro Carvalho Chehab CODA_CMD_DEC_SEQ_PS_BB_SIZE); 193064441979SMauro Carvalho Chehab } 193164441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 193264441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); 193364441979SMauro Carvalho Chehab coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); 193464441979SMauro Carvalho Chehab } 193564441979SMauro Carvalho Chehab } 193664441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_JPEG) 193764441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN); 193864441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_960) 193964441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); 194064441979SMauro Carvalho Chehab 194164441979SMauro Carvalho Chehab ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; 194264441979SMauro Carvalho Chehab ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 194364441979SMauro Carvalho Chehab ctx->bit_stream_param = 0; 194464441979SMauro Carvalho Chehab if (ret) { 194564441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 194664441979SMauro Carvalho Chehab return ret; 194764441979SMauro Carvalho Chehab } 194864441979SMauro Carvalho Chehab ctx->sequence_offset = ~0U; 194964441979SMauro Carvalho Chehab ctx->initialized = 1; 195064441979SMauro Carvalho Chehab ctx->first_frame_sequence = 0; 195164441979SMauro Carvalho Chehab 195264441979SMauro Carvalho Chehab /* Update kfifo out pointer from coda bitstream read pointer */ 195364441979SMauro Carvalho Chehab coda_kfifo_sync_from_device(ctx); 195464441979SMauro Carvalho Chehab 195564441979SMauro Carvalho Chehab /* 195664441979SMauro Carvalho Chehab * After updating the read pointer, we need to check if 195764441979SMauro Carvalho Chehab * any metas are consumed and should be released. 195864441979SMauro Carvalho Chehab */ 195964441979SMauro Carvalho Chehab coda_decoder_drop_used_metas(ctx); 196064441979SMauro Carvalho Chehab 196164441979SMauro Carvalho Chehab if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { 196264441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 196364441979SMauro Carvalho Chehab "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", 196464441979SMauro Carvalho Chehab coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); 196564441979SMauro Carvalho Chehab return -EAGAIN; 196664441979SMauro Carvalho Chehab } 196764441979SMauro Carvalho Chehab 196864441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); 196964441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_DX6) { 197064441979SMauro Carvalho Chehab width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; 197164441979SMauro Carvalho Chehab height = val & CODADX6_PICHEIGHT_MASK; 197264441979SMauro Carvalho Chehab } else { 197364441979SMauro Carvalho Chehab width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; 197464441979SMauro Carvalho Chehab height = val & CODA7_PICHEIGHT_MASK; 197564441979SMauro Carvalho Chehab } 197664441979SMauro Carvalho Chehab 197764441979SMauro Carvalho Chehab if (width > q_data_dst->bytesperline || height > q_data_dst->height) { 197864441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", 197964441979SMauro Carvalho Chehab width, height, q_data_dst->bytesperline, 198064441979SMauro Carvalho Chehab q_data_dst->height); 198164441979SMauro Carvalho Chehab return -EINVAL; 198264441979SMauro Carvalho Chehab } 198364441979SMauro Carvalho Chehab 198464441979SMauro Carvalho Chehab width = round_up(width, 16); 198564441979SMauro Carvalho Chehab height = round_up(height, 16); 198664441979SMauro Carvalho Chehab 198764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); 198864441979SMauro Carvalho Chehab 198964441979SMauro Carvalho Chehab ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); 199064441979SMauro Carvalho Chehab /* 199164441979SMauro Carvalho Chehab * If the VDOA is used, the decoder needs one additional frame, 199264441979SMauro Carvalho Chehab * because the frames are freed when the next frame is decoded. 199364441979SMauro Carvalho Chehab * Otherwise there are visible errors in the decoded frames (green 199464441979SMauro Carvalho Chehab * regions in displayed frames) and a broken order of frames (earlier 199564441979SMauro Carvalho Chehab * frames are sporadically displayed after later frames). 199664441979SMauro Carvalho Chehab */ 199764441979SMauro Carvalho Chehab if (ctx->use_vdoa) 199864441979SMauro Carvalho Chehab ctx->num_internal_frames += 1; 199964441979SMauro Carvalho Chehab if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { 200064441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 200164441979SMauro Carvalho Chehab "not enough framebuffers to decode (%d < %d)\n", 200264441979SMauro Carvalho Chehab CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); 200364441979SMauro Carvalho Chehab return -EINVAL; 200464441979SMauro Carvalho Chehab } 200564441979SMauro Carvalho Chehab 200664441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_H264) { 200764441979SMauro Carvalho Chehab u32 left_right; 200864441979SMauro Carvalho Chehab u32 top_bottom; 200964441979SMauro Carvalho Chehab 201064441979SMauro Carvalho Chehab left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); 201164441979SMauro Carvalho Chehab top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); 201264441979SMauro Carvalho Chehab 201364441979SMauro Carvalho Chehab q_data_dst->rect.left = (left_right >> 10) & 0x3ff; 201464441979SMauro Carvalho Chehab q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; 201564441979SMauro Carvalho Chehab q_data_dst->rect.width = width - q_data_dst->rect.left - 201664441979SMauro Carvalho Chehab (left_right & 0x3ff); 201764441979SMauro Carvalho Chehab q_data_dst->rect.height = height - q_data_dst->rect.top - 201864441979SMauro Carvalho Chehab (top_bottom & 0x3ff); 201964441979SMauro Carvalho Chehab } 202064441979SMauro Carvalho Chehab 202164441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) { 202264441979SMauro Carvalho Chehab u8 profile, level; 202364441979SMauro Carvalho Chehab 202464441979SMauro Carvalho Chehab val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); 202564441979SMauro Carvalho Chehab profile = val & 0xff; 202664441979SMauro Carvalho Chehab level = (val >> 8) & 0x7f; 202764441979SMauro Carvalho Chehab 202864441979SMauro Carvalho Chehab if (profile || level) 202964441979SMauro Carvalho Chehab coda_update_profile_level_ctrls(ctx, profile, level); 203064441979SMauro Carvalho Chehab } 203164441979SMauro Carvalho Chehab 203264441979SMauro Carvalho Chehab return 0; 203364441979SMauro Carvalho Chehab } 203464441979SMauro Carvalho Chehab 203564441979SMauro Carvalho Chehab static void coda_dec_seq_init_work(struct work_struct *work) 203664441979SMauro Carvalho Chehab { 203764441979SMauro Carvalho Chehab struct coda_ctx *ctx = container_of(work, 203864441979SMauro Carvalho Chehab struct coda_ctx, seq_init_work); 203964441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 204064441979SMauro Carvalho Chehab 204164441979SMauro Carvalho Chehab mutex_lock(&ctx->buffer_mutex); 204264441979SMauro Carvalho Chehab mutex_lock(&dev->coda_mutex); 204364441979SMauro Carvalho Chehab 204464441979SMauro Carvalho Chehab if (!ctx->initialized) 204564441979SMauro Carvalho Chehab __coda_decoder_seq_init(ctx); 204664441979SMauro Carvalho Chehab 204764441979SMauro Carvalho Chehab mutex_unlock(&dev->coda_mutex); 204864441979SMauro Carvalho Chehab mutex_unlock(&ctx->buffer_mutex); 204964441979SMauro Carvalho Chehab } 205064441979SMauro Carvalho Chehab 205164441979SMauro Carvalho Chehab static int __coda_start_decoding(struct coda_ctx *ctx) 205264441979SMauro Carvalho Chehab { 205364441979SMauro Carvalho Chehab struct coda_q_data *q_data_src, *q_data_dst; 205464441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 205564441979SMauro Carvalho Chehab u32 src_fourcc, dst_fourcc; 205664441979SMauro Carvalho Chehab int ret; 205764441979SMauro Carvalho Chehab 205864441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 205964441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 206064441979SMauro Carvalho Chehab src_fourcc = q_data_src->fourcc; 206164441979SMauro Carvalho Chehab dst_fourcc = q_data_dst->fourcc; 206264441979SMauro Carvalho Chehab 206364441979SMauro Carvalho Chehab if (!ctx->initialized) { 206464441979SMauro Carvalho Chehab ret = __coda_decoder_seq_init(ctx); 206564441979SMauro Carvalho Chehab if (ret < 0) 206664441979SMauro Carvalho Chehab return ret; 206764441979SMauro Carvalho Chehab } else { 206864441979SMauro Carvalho Chehab ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 206964441979SMauro Carvalho Chehab CODA9_FRAME_TILED2LINEAR); 207064441979SMauro Carvalho Chehab if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 207164441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 207264441979SMauro Carvalho Chehab if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 207364441979SMauro Carvalho Chehab ctx->frame_mem_ctrl |= (0x3 << 9) | 207464441979SMauro Carvalho Chehab ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 207564441979SMauro Carvalho Chehab } 207664441979SMauro Carvalho Chehab 207764441979SMauro Carvalho Chehab coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 207864441979SMauro Carvalho Chehab 207964441979SMauro Carvalho Chehab ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); 208064441979SMauro Carvalho Chehab if (ret < 0) { 208164441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); 208264441979SMauro Carvalho Chehab return ret; 208364441979SMauro Carvalho Chehab } 208464441979SMauro Carvalho Chehab 208564441979SMauro Carvalho Chehab /* Tell the decoder how many frame buffers we allocated. */ 208664441979SMauro Carvalho Chehab coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); 208764441979SMauro Carvalho Chehab coda_write(dev, round_up(q_data_dst->rect.width, 16), 208864441979SMauro Carvalho Chehab CODA_CMD_SET_FRAME_BUF_STRIDE); 208964441979SMauro Carvalho Chehab 209064441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) { 209164441979SMauro Carvalho Chehab /* Set secondary AXI IRAM */ 209264441979SMauro Carvalho Chehab coda_setup_iram(ctx); 209364441979SMauro Carvalho Chehab 209464441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_bit_use, 209564441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 209664441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 209764441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 209864441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_dbk_y_use, 209964441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 210064441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_dbk_c_use, 210164441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 210264441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_ovl_use, 210364441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 210464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 210564441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.buf_btp_use, 210664441979SMauro Carvalho Chehab CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 210764441979SMauro Carvalho Chehab 210864441979SMauro Carvalho Chehab coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); 210964441979SMauro Carvalho Chehab coda9_set_frame_cache(ctx, dst_fourcc); 211064441979SMauro Carvalho Chehab } 211164441979SMauro Carvalho Chehab } 211264441979SMauro Carvalho Chehab 211364441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_H264) { 211464441979SMauro Carvalho Chehab coda_write(dev, ctx->slicebuf.paddr, 211564441979SMauro Carvalho Chehab CODA_CMD_SET_FRAME_SLICE_BB_START); 211664441979SMauro Carvalho Chehab coda_write(dev, ctx->slicebuf.size / 1024, 211764441979SMauro Carvalho Chehab CODA_CMD_SET_FRAME_SLICE_BB_SIZE); 211864441979SMauro Carvalho Chehab } 211964441979SMauro Carvalho Chehab 212064441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 212164441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 212264441979SMauro Carvalho Chehab int max_mb_x = 1920 / 16; 212364441979SMauro Carvalho Chehab int max_mb_y = 1088 / 16; 212464441979SMauro Carvalho Chehab int max_mb_num = max_mb_x * max_mb_y; 212564441979SMauro Carvalho Chehab 212664441979SMauro Carvalho Chehab coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 212764441979SMauro Carvalho Chehab CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); 212864441979SMauro Carvalho Chehab } else if (dev->devtype->product == CODA_960) { 212964441979SMauro Carvalho Chehab int max_mb_x = 1920 / 16; 213064441979SMauro Carvalho Chehab int max_mb_y = 1088 / 16; 213164441979SMauro Carvalho Chehab int max_mb_num = max_mb_x * max_mb_y; 213264441979SMauro Carvalho Chehab 213364441979SMauro Carvalho Chehab coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 213464441979SMauro Carvalho Chehab CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); 213564441979SMauro Carvalho Chehab } 213664441979SMauro Carvalho Chehab 213764441979SMauro Carvalho Chehab if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { 213864441979SMauro Carvalho Chehab v4l2_err(&ctx->dev->v4l2_dev, 213964441979SMauro Carvalho Chehab "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 214064441979SMauro Carvalho Chehab return -ETIMEDOUT; 214164441979SMauro Carvalho Chehab } 214264441979SMauro Carvalho Chehab 214364441979SMauro Carvalho Chehab return 0; 214464441979SMauro Carvalho Chehab } 214564441979SMauro Carvalho Chehab 214664441979SMauro Carvalho Chehab static int coda_start_decoding(struct coda_ctx *ctx) 214764441979SMauro Carvalho Chehab { 214864441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 214964441979SMauro Carvalho Chehab int ret; 215064441979SMauro Carvalho Chehab 215164441979SMauro Carvalho Chehab mutex_lock(&dev->coda_mutex); 215264441979SMauro Carvalho Chehab ret = __coda_start_decoding(ctx); 215364441979SMauro Carvalho Chehab mutex_unlock(&dev->coda_mutex); 215464441979SMauro Carvalho Chehab 215564441979SMauro Carvalho Chehab return ret; 215664441979SMauro Carvalho Chehab } 215764441979SMauro Carvalho Chehab 215864441979SMauro Carvalho Chehab static int coda_prepare_decode(struct coda_ctx *ctx) 215964441979SMauro Carvalho Chehab { 216064441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *dst_buf; 216164441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 216264441979SMauro Carvalho Chehab struct coda_q_data *q_data_dst; 216364441979SMauro Carvalho Chehab struct coda_buffer_meta *meta; 216464441979SMauro Carvalho Chehab u32 rot_mode = 0; 216564441979SMauro Carvalho Chehab u32 reg_addr, reg_stride; 216664441979SMauro Carvalho Chehab 216764441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 216864441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 216964441979SMauro Carvalho Chehab 217064441979SMauro Carvalho Chehab /* Try to copy source buffer contents into the bitstream ringbuffer */ 217164441979SMauro Carvalho Chehab mutex_lock(&ctx->bitstream_mutex); 217264441979SMauro Carvalho Chehab coda_fill_bitstream(ctx, NULL); 217364441979SMauro Carvalho Chehab mutex_unlock(&ctx->bitstream_mutex); 217464441979SMauro Carvalho Chehab 217564441979SMauro Carvalho Chehab if (coda_get_bitstream_payload(ctx) < 512 && 217664441979SMauro Carvalho Chehab (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { 217764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", 217864441979SMauro Carvalho Chehab coda_get_bitstream_payload(ctx)); 217964441979SMauro Carvalho Chehab return -EAGAIN; 218064441979SMauro Carvalho Chehab } 218164441979SMauro Carvalho Chehab 218264441979SMauro Carvalho Chehab /* Run coda_start_decoding (again) if not yet initialized */ 218364441979SMauro Carvalho Chehab if (!ctx->initialized) { 218464441979SMauro Carvalho Chehab int ret = __coda_start_decoding(ctx); 218564441979SMauro Carvalho Chehab 218664441979SMauro Carvalho Chehab if (ret < 0) { 218764441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); 218864441979SMauro Carvalho Chehab return -EAGAIN; 218964441979SMauro Carvalho Chehab } else { 219064441979SMauro Carvalho Chehab ctx->initialized = 1; 219164441979SMauro Carvalho Chehab } 219264441979SMauro Carvalho Chehab } 219364441979SMauro Carvalho Chehab 219464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) 219564441979SMauro Carvalho Chehab coda_set_gdi_regs(ctx); 219664441979SMauro Carvalho Chehab 219764441979SMauro Carvalho Chehab if (ctx->use_vdoa && 219864441979SMauro Carvalho Chehab ctx->display_idx >= 0 && 219964441979SMauro Carvalho Chehab ctx->display_idx < ctx->num_internal_frames) { 220064441979SMauro Carvalho Chehab vdoa_device_run(ctx->vdoa, 220164441979SMauro Carvalho Chehab vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), 220264441979SMauro Carvalho Chehab ctx->internal_frames[ctx->display_idx].buf.paddr); 220364441979SMauro Carvalho Chehab } else { 220464441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_960) { 220564441979SMauro Carvalho Chehab /* 220664441979SMauro Carvalho Chehab * It was previously assumed that the CODA960 has an 220764441979SMauro Carvalho Chehab * internal list of 64 buffer entries that contains 220864441979SMauro Carvalho Chehab * both the registered internal frame buffers as well 220964441979SMauro Carvalho Chehab * as the rotator buffer output, and that the ROT_INDEX 221064441979SMauro Carvalho Chehab * register must be set to a value between the last 221164441979SMauro Carvalho Chehab * internal frame buffers' index and 64. 221264441979SMauro Carvalho Chehab * At least on firmware version 3.1.1 it turns out that 221364441979SMauro Carvalho Chehab * setting ROT_INDEX to any value >= 32 causes CODA 221464441979SMauro Carvalho Chehab * hangups that it can not recover from with the SRC VPU 221564441979SMauro Carvalho Chehab * reset. 221664441979SMauro Carvalho Chehab * It does appear to work however, to just set it to a 221764441979SMauro Carvalho Chehab * fixed value in the [ctx->num_internal_frames, 31] 221864441979SMauro Carvalho Chehab * range, for example CODA_MAX_FRAMEBUFFERS. 221964441979SMauro Carvalho Chehab */ 222064441979SMauro Carvalho Chehab coda_write(dev, CODA_MAX_FRAMEBUFFERS, 222164441979SMauro Carvalho Chehab CODA9_CMD_DEC_PIC_ROT_INDEX); 222264441979SMauro Carvalho Chehab 222364441979SMauro Carvalho Chehab reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; 222464441979SMauro Carvalho Chehab reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; 222564441979SMauro Carvalho Chehab } else { 222664441979SMauro Carvalho Chehab reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; 222764441979SMauro Carvalho Chehab reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; 222864441979SMauro Carvalho Chehab } 222964441979SMauro Carvalho Chehab coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); 223064441979SMauro Carvalho Chehab coda_write(dev, q_data_dst->bytesperline, reg_stride); 223164441979SMauro Carvalho Chehab 223264441979SMauro Carvalho Chehab rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 223364441979SMauro Carvalho Chehab } 223464441979SMauro Carvalho Chehab 223564441979SMauro Carvalho Chehab coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); 223664441979SMauro Carvalho Chehab 223764441979SMauro Carvalho Chehab switch (dev->devtype->product) { 223864441979SMauro Carvalho Chehab case CODA_DX6: 223964441979SMauro Carvalho Chehab /* TBD */ 224064441979SMauro Carvalho Chehab case CODA_HX4: 224164441979SMauro Carvalho Chehab case CODA_7541: 224264441979SMauro Carvalho Chehab coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); 224364441979SMauro Carvalho Chehab break; 224464441979SMauro Carvalho Chehab case CODA_960: 224564441979SMauro Carvalho Chehab /* 'hardcode to use interrupt disable mode'? */ 224664441979SMauro Carvalho Chehab coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); 224764441979SMauro Carvalho Chehab break; 224864441979SMauro Carvalho Chehab } 224964441979SMauro Carvalho Chehab 225064441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); 225164441979SMauro Carvalho Chehab 225264441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); 225364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); 225464441979SMauro Carvalho Chehab 225564441979SMauro Carvalho Chehab if (dev->devtype->product != CODA_DX6) 225664441979SMauro Carvalho Chehab coda_write(dev, ctx->iram_info.axi_sram_use, 225764441979SMauro Carvalho Chehab CODA7_REG_BIT_AXI_SRAM_USE); 225864441979SMauro Carvalho Chehab 225964441979SMauro Carvalho Chehab spin_lock(&ctx->buffer_meta_lock); 226064441979SMauro Carvalho Chehab meta = list_first_entry_or_null(&ctx->buffer_meta_list, 226164441979SMauro Carvalho Chehab struct coda_buffer_meta, list); 226264441979SMauro Carvalho Chehab 226364441979SMauro Carvalho Chehab if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { 226464441979SMauro Carvalho Chehab 226564441979SMauro Carvalho Chehab /* If this is the last buffer in the bitstream, add padding */ 226664441979SMauro Carvalho Chehab if (meta->end == ctx->bitstream_fifo.kfifo.in) { 226764441979SMauro Carvalho Chehab static unsigned char buf[512]; 226864441979SMauro Carvalho Chehab unsigned int pad; 226964441979SMauro Carvalho Chehab 227064441979SMauro Carvalho Chehab /* Pad to multiple of 256 and then add 256 more */ 227164441979SMauro Carvalho Chehab pad = ((0 - meta->end) & 0xff) + 256; 227264441979SMauro Carvalho Chehab 227364441979SMauro Carvalho Chehab memset(buf, 0xff, sizeof(buf)); 227464441979SMauro Carvalho Chehab 227564441979SMauro Carvalho Chehab kfifo_in(&ctx->bitstream_fifo, buf, pad); 227664441979SMauro Carvalho Chehab } 227764441979SMauro Carvalho Chehab } 227864441979SMauro Carvalho Chehab spin_unlock(&ctx->buffer_meta_lock); 227964441979SMauro Carvalho Chehab 228064441979SMauro Carvalho Chehab coda_kfifo_sync_to_device_full(ctx); 228164441979SMauro Carvalho Chehab 228264441979SMauro Carvalho Chehab /* Clear decode success flag */ 228364441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); 228464441979SMauro Carvalho Chehab 228564441979SMauro Carvalho Chehab /* Clear error return value */ 228664441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); 228764441979SMauro Carvalho Chehab 228864441979SMauro Carvalho Chehab trace_coda_dec_pic_run(ctx, meta); 228964441979SMauro Carvalho Chehab 229064441979SMauro Carvalho Chehab coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 229164441979SMauro Carvalho Chehab 229264441979SMauro Carvalho Chehab return 0; 229364441979SMauro Carvalho Chehab } 229464441979SMauro Carvalho Chehab 229564441979SMauro Carvalho Chehab static void coda_finish_decode(struct coda_ctx *ctx) 229664441979SMauro Carvalho Chehab { 229764441979SMauro Carvalho Chehab struct coda_dev *dev = ctx->dev; 229864441979SMauro Carvalho Chehab struct coda_q_data *q_data_src; 229964441979SMauro Carvalho Chehab struct coda_q_data *q_data_dst; 230064441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *dst_buf; 230164441979SMauro Carvalho Chehab struct coda_buffer_meta *meta; 230264441979SMauro Carvalho Chehab int width, height; 230364441979SMauro Carvalho Chehab int decoded_idx; 230464441979SMauro Carvalho Chehab int display_idx; 230564441979SMauro Carvalho Chehab struct coda_internal_frame *decoded_frame = NULL; 230664441979SMauro Carvalho Chehab u32 src_fourcc; 230764441979SMauro Carvalho Chehab int success; 230864441979SMauro Carvalho Chehab u32 err_mb; 230964441979SMauro Carvalho Chehab int err_vdoa = 0; 231064441979SMauro Carvalho Chehab u32 val; 231164441979SMauro Carvalho Chehab 231264441979SMauro Carvalho Chehab if (ctx->aborting) 231364441979SMauro Carvalho Chehab return; 231464441979SMauro Carvalho Chehab 231564441979SMauro Carvalho Chehab /* Update kfifo out pointer from coda bitstream read pointer */ 231664441979SMauro Carvalho Chehab coda_kfifo_sync_from_device(ctx); 231764441979SMauro Carvalho Chehab 231864441979SMauro Carvalho Chehab /* 231964441979SMauro Carvalho Chehab * in stream-end mode, the read pointer can overshoot the write pointer 232064441979SMauro Carvalho Chehab * by up to 512 bytes 232164441979SMauro Carvalho Chehab */ 232264441979SMauro Carvalho Chehab if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { 232364441979SMauro Carvalho Chehab if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) 232464441979SMauro Carvalho Chehab kfifo_init(&ctx->bitstream_fifo, 232564441979SMauro Carvalho Chehab ctx->bitstream.vaddr, ctx->bitstream.size); 232664441979SMauro Carvalho Chehab } 232764441979SMauro Carvalho Chehab 232864441979SMauro Carvalho Chehab q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 232964441979SMauro Carvalho Chehab src_fourcc = q_data_src->fourcc; 233064441979SMauro Carvalho Chehab 233164441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); 233264441979SMauro Carvalho Chehab if (val != 1) 233364441979SMauro Carvalho Chehab pr_err("DEC_PIC_SUCCESS = %d\n", val); 233464441979SMauro Carvalho Chehab 233564441979SMauro Carvalho Chehab success = val & 0x1; 233664441979SMauro Carvalho Chehab if (!success) 233764441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "decode failed\n"); 233864441979SMauro Carvalho Chehab 233964441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_H264) { 234064441979SMauro Carvalho Chehab if (val & (1 << 3)) 234164441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 234264441979SMauro Carvalho Chehab "insufficient PS buffer space (%d bytes)\n", 234364441979SMauro Carvalho Chehab ctx->psbuf.size); 234464441979SMauro Carvalho Chehab if (val & (1 << 2)) 234564441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 234664441979SMauro Carvalho Chehab "insufficient slice buffer space (%d bytes)\n", 234764441979SMauro Carvalho Chehab ctx->slicebuf.size); 234864441979SMauro Carvalho Chehab } 234964441979SMauro Carvalho Chehab 235064441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); 235164441979SMauro Carvalho Chehab width = (val >> 16) & 0xffff; 235264441979SMauro Carvalho Chehab height = val & 0xffff; 235364441979SMauro Carvalho Chehab 235464441979SMauro Carvalho Chehab q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 235564441979SMauro Carvalho Chehab 235664441979SMauro Carvalho Chehab /* frame crop information */ 235764441979SMauro Carvalho Chehab if (src_fourcc == V4L2_PIX_FMT_H264) { 235864441979SMauro Carvalho Chehab u32 left_right; 235964441979SMauro Carvalho Chehab u32 top_bottom; 236064441979SMauro Carvalho Chehab 236164441979SMauro Carvalho Chehab left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); 236264441979SMauro Carvalho Chehab top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); 236364441979SMauro Carvalho Chehab 236464441979SMauro Carvalho Chehab if (left_right == 0xffffffff && top_bottom == 0xffffffff) { 236564441979SMauro Carvalho Chehab /* Keep current crop information */ 236664441979SMauro Carvalho Chehab } else { 236764441979SMauro Carvalho Chehab struct v4l2_rect *rect = &q_data_dst->rect; 236864441979SMauro Carvalho Chehab 236964441979SMauro Carvalho Chehab rect->left = left_right >> 16 & 0xffff; 237064441979SMauro Carvalho Chehab rect->top = top_bottom >> 16 & 0xffff; 237164441979SMauro Carvalho Chehab rect->width = width - rect->left - 237264441979SMauro Carvalho Chehab (left_right & 0xffff); 237364441979SMauro Carvalho Chehab rect->height = height - rect->top - 237464441979SMauro Carvalho Chehab (top_bottom & 0xffff); 237564441979SMauro Carvalho Chehab } 237664441979SMauro Carvalho Chehab } else { 237764441979SMauro Carvalho Chehab /* no cropping */ 237864441979SMauro Carvalho Chehab } 237964441979SMauro Carvalho Chehab 238064441979SMauro Carvalho Chehab err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); 238164441979SMauro Carvalho Chehab if (err_mb > 0) { 238264441979SMauro Carvalho Chehab if (__ratelimit(&dev->mb_err_rs)) 238364441979SMauro Carvalho Chehab coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb); 238464441979SMauro Carvalho Chehab v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 238564441979SMauro Carvalho Chehab v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb); 238664441979SMauro Carvalho Chehab } 238764441979SMauro Carvalho Chehab 238864441979SMauro Carvalho Chehab if (dev->devtype->product == CODA_HX4 || 238964441979SMauro Carvalho Chehab dev->devtype->product == CODA_7541) { 239064441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); 239164441979SMauro Carvalho Chehab if (val == 0) { 239264441979SMauro Carvalho Chehab /* not enough bitstream data */ 239364441979SMauro Carvalho Chehab coda_dbg(1, ctx, "prescan failed: %d\n", val); 239464441979SMauro Carvalho Chehab ctx->hold = true; 239564441979SMauro Carvalho Chehab return; 239664441979SMauro Carvalho Chehab } 239764441979SMauro Carvalho Chehab } 239864441979SMauro Carvalho Chehab 239964441979SMauro Carvalho Chehab /* Wait until the VDOA finished writing the previous display frame */ 240064441979SMauro Carvalho Chehab if (ctx->use_vdoa && 240164441979SMauro Carvalho Chehab ctx->display_idx >= 0 && 240264441979SMauro Carvalho Chehab ctx->display_idx < ctx->num_internal_frames) { 240364441979SMauro Carvalho Chehab err_vdoa = vdoa_wait_for_completion(ctx->vdoa); 240464441979SMauro Carvalho Chehab } 240564441979SMauro Carvalho Chehab 240664441979SMauro Carvalho Chehab ctx->frm_dis_flg = coda_read(dev, 240764441979SMauro Carvalho Chehab CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 240864441979SMauro Carvalho Chehab 240964441979SMauro Carvalho Chehab /* The previous display frame was copied out and can be overwritten */ 241064441979SMauro Carvalho Chehab if (ctx->display_idx >= 0 && 241164441979SMauro Carvalho Chehab ctx->display_idx < ctx->num_internal_frames) { 241264441979SMauro Carvalho Chehab ctx->frm_dis_flg &= ~(1 << ctx->display_idx); 241364441979SMauro Carvalho Chehab coda_write(dev, ctx->frm_dis_flg, 241464441979SMauro Carvalho Chehab CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 241564441979SMauro Carvalho Chehab } 241664441979SMauro Carvalho Chehab 241764441979SMauro Carvalho Chehab /* 241864441979SMauro Carvalho Chehab * The index of the last decoded frame, not necessarily in 241964441979SMauro Carvalho Chehab * display order, and the index of the next display frame. 242064441979SMauro Carvalho Chehab * The latter could have been decoded in a previous run. 242164441979SMauro Carvalho Chehab */ 242264441979SMauro Carvalho Chehab decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); 242364441979SMauro Carvalho Chehab display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); 242464441979SMauro Carvalho Chehab 242564441979SMauro Carvalho Chehab if (decoded_idx == -1) { 242664441979SMauro Carvalho Chehab /* no frame was decoded, but we might have a display frame */ 242764441979SMauro Carvalho Chehab if (display_idx >= 0 && display_idx < ctx->num_internal_frames) 242864441979SMauro Carvalho Chehab ctx->sequence_offset++; 242964441979SMauro Carvalho Chehab else if (ctx->display_idx < 0) 243064441979SMauro Carvalho Chehab ctx->hold = true; 243164441979SMauro Carvalho Chehab } else if (decoded_idx == -2) { 243264441979SMauro Carvalho Chehab if (ctx->display_idx >= 0 && 243364441979SMauro Carvalho Chehab ctx->display_idx < ctx->num_internal_frames) 243464441979SMauro Carvalho Chehab ctx->sequence_offset++; 243564441979SMauro Carvalho Chehab /* no frame was decoded, we still return remaining buffers */ 243664441979SMauro Carvalho Chehab } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { 243764441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 243864441979SMauro Carvalho Chehab "decoded frame index out of range: %d\n", decoded_idx); 243964441979SMauro Carvalho Chehab } else { 244064441979SMauro Carvalho Chehab int sequence; 244164441979SMauro Carvalho Chehab 244264441979SMauro Carvalho Chehab decoded_frame = &ctx->internal_frames[decoded_idx]; 244364441979SMauro Carvalho Chehab 244464441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); 244564441979SMauro Carvalho Chehab if (ctx->sequence_offset == -1) 244664441979SMauro Carvalho Chehab ctx->sequence_offset = val; 244764441979SMauro Carvalho Chehab 244864441979SMauro Carvalho Chehab sequence = val + ctx->first_frame_sequence 244964441979SMauro Carvalho Chehab - ctx->sequence_offset; 245064441979SMauro Carvalho Chehab spin_lock(&ctx->buffer_meta_lock); 245164441979SMauro Carvalho Chehab if (!list_empty(&ctx->buffer_meta_list)) { 245264441979SMauro Carvalho Chehab meta = list_first_entry(&ctx->buffer_meta_list, 245364441979SMauro Carvalho Chehab struct coda_buffer_meta, list); 245464441979SMauro Carvalho Chehab list_del(&meta->list); 245564441979SMauro Carvalho Chehab ctx->num_metas--; 245664441979SMauro Carvalho Chehab spin_unlock(&ctx->buffer_meta_lock); 245764441979SMauro Carvalho Chehab /* 245864441979SMauro Carvalho Chehab * Clamp counters to 16 bits for comparison, as the HW 245964441979SMauro Carvalho Chehab * counter rolls over at this point for h.264. This 246064441979SMauro Carvalho Chehab * may be different for other formats, but using 16 bits 246164441979SMauro Carvalho Chehab * should be enough to detect most errors and saves us 246264441979SMauro Carvalho Chehab * from doing different things based on the format. 246364441979SMauro Carvalho Chehab */ 246464441979SMauro Carvalho Chehab if ((sequence & 0xffff) != (meta->sequence & 0xffff)) { 246564441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 246664441979SMauro Carvalho Chehab "sequence number mismatch (%d(%d) != %d)\n", 246764441979SMauro Carvalho Chehab sequence, ctx->sequence_offset, 246864441979SMauro Carvalho Chehab meta->sequence); 246964441979SMauro Carvalho Chehab } 247064441979SMauro Carvalho Chehab decoded_frame->meta = *meta; 247164441979SMauro Carvalho Chehab kfree(meta); 247264441979SMauro Carvalho Chehab } else { 247364441979SMauro Carvalho Chehab spin_unlock(&ctx->buffer_meta_lock); 247464441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); 247564441979SMauro Carvalho Chehab memset(&decoded_frame->meta, 0, 247664441979SMauro Carvalho Chehab sizeof(struct coda_buffer_meta)); 247764441979SMauro Carvalho Chehab decoded_frame->meta.sequence = sequence; 247864441979SMauro Carvalho Chehab decoded_frame->meta.last = false; 247964441979SMauro Carvalho Chehab ctx->sequence_offset++; 248064441979SMauro Carvalho Chehab } 248164441979SMauro Carvalho Chehab 248264441979SMauro Carvalho Chehab trace_coda_dec_pic_done(ctx, &decoded_frame->meta); 248364441979SMauro Carvalho Chehab 248464441979SMauro Carvalho Chehab val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; 248564441979SMauro Carvalho Chehab decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : 248664441979SMauro Carvalho Chehab (val == 1) ? V4L2_BUF_FLAG_PFRAME : 248764441979SMauro Carvalho Chehab V4L2_BUF_FLAG_BFRAME; 248864441979SMauro Carvalho Chehab 248964441979SMauro Carvalho Chehab decoded_frame->error = err_mb; 249064441979SMauro Carvalho Chehab } 249164441979SMauro Carvalho Chehab 249264441979SMauro Carvalho Chehab if (display_idx == -1) { 249364441979SMauro Carvalho Chehab /* 249464441979SMauro Carvalho Chehab * no more frames to be decoded, but there could still 249564441979SMauro Carvalho Chehab * be rotator output to dequeue 249664441979SMauro Carvalho Chehab */ 249764441979SMauro Carvalho Chehab ctx->hold = true; 249864441979SMauro Carvalho Chehab } else if (display_idx == -3) { 249964441979SMauro Carvalho Chehab /* possibly prescan failure */ 250064441979SMauro Carvalho Chehab } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { 250164441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 250264441979SMauro Carvalho Chehab "presentation frame index out of range: %d\n", 250364441979SMauro Carvalho Chehab display_idx); 250464441979SMauro Carvalho Chehab } 250564441979SMauro Carvalho Chehab 250664441979SMauro Carvalho Chehab /* If a frame was copied out, return it */ 250764441979SMauro Carvalho Chehab if (ctx->display_idx >= 0 && 250864441979SMauro Carvalho Chehab ctx->display_idx < ctx->num_internal_frames) { 250964441979SMauro Carvalho Chehab struct coda_internal_frame *ready_frame; 251064441979SMauro Carvalho Chehab 251164441979SMauro Carvalho Chehab ready_frame = &ctx->internal_frames[ctx->display_idx]; 251264441979SMauro Carvalho Chehab 251364441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 251464441979SMauro Carvalho Chehab dst_buf->sequence = ctx->osequence++; 251564441979SMauro Carvalho Chehab 251664441979SMauro Carvalho Chehab dst_buf->field = V4L2_FIELD_NONE; 251764441979SMauro Carvalho Chehab dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 251864441979SMauro Carvalho Chehab V4L2_BUF_FLAG_PFRAME | 251964441979SMauro Carvalho Chehab V4L2_BUF_FLAG_BFRAME); 252064441979SMauro Carvalho Chehab dst_buf->flags |= ready_frame->type; 252164441979SMauro Carvalho Chehab meta = &ready_frame->meta; 252264441979SMauro Carvalho Chehab if (meta->last && !coda_reorder_enable(ctx)) { 252364441979SMauro Carvalho Chehab /* 252464441979SMauro Carvalho Chehab * If this was the last decoded frame, and reordering 252564441979SMauro Carvalho Chehab * is disabled, this will be the last display frame. 252664441979SMauro Carvalho Chehab */ 252764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "last meta, marking as last frame\n"); 252864441979SMauro Carvalho Chehab dst_buf->flags |= V4L2_BUF_FLAG_LAST; 252964441979SMauro Carvalho Chehab } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && 253064441979SMauro Carvalho Chehab display_idx == -1) { 253164441979SMauro Carvalho Chehab /* 253264441979SMauro Carvalho Chehab * If there is no designated presentation frame anymore, 253364441979SMauro Carvalho Chehab * this frame has to be the last one. 253464441979SMauro Carvalho Chehab */ 253564441979SMauro Carvalho Chehab coda_dbg(1, ctx, 253664441979SMauro Carvalho Chehab "no more frames to return, marking as last frame\n"); 253764441979SMauro Carvalho Chehab dst_buf->flags |= V4L2_BUF_FLAG_LAST; 253864441979SMauro Carvalho Chehab } 253964441979SMauro Carvalho Chehab dst_buf->timecode = meta->timecode; 254064441979SMauro Carvalho Chehab dst_buf->vb2_buf.timestamp = meta->timestamp; 254164441979SMauro Carvalho Chehab 254264441979SMauro Carvalho Chehab trace_coda_dec_rot_done(ctx, dst_buf, meta); 254364441979SMauro Carvalho Chehab 254464441979SMauro Carvalho Chehab vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 254564441979SMauro Carvalho Chehab q_data_dst->sizeimage); 254664441979SMauro Carvalho Chehab 254764441979SMauro Carvalho Chehab if (ready_frame->error || err_vdoa) 254864441979SMauro Carvalho Chehab coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 254964441979SMauro Carvalho Chehab else 255064441979SMauro Carvalho Chehab coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 255164441979SMauro Carvalho Chehab 255264441979SMauro Carvalho Chehab if (decoded_frame) { 255364441979SMauro Carvalho Chehab coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", 255464441979SMauro Carvalho Chehab coda_frame_type_char(decoded_frame->type), 255564441979SMauro Carvalho Chehab decoded_frame->meta.sequence, 255664441979SMauro Carvalho Chehab coda_frame_type_char(dst_buf->flags), 255764441979SMauro Carvalho Chehab ready_frame->meta.sequence, 255864441979SMauro Carvalho Chehab dst_buf->sequence, ctx->qsequence, 255964441979SMauro Carvalho Chehab (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 256064441979SMauro Carvalho Chehab " (last)" : ""); 256164441979SMauro Carvalho Chehab } else { 256264441979SMauro Carvalho Chehab coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", 256364441979SMauro Carvalho Chehab decoded_idx, 256464441979SMauro Carvalho Chehab coda_frame_type_char(dst_buf->flags), 256564441979SMauro Carvalho Chehab ready_frame->meta.sequence, 256664441979SMauro Carvalho Chehab dst_buf->sequence, ctx->qsequence, 256764441979SMauro Carvalho Chehab (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 256864441979SMauro Carvalho Chehab " (last)" : ""); 256964441979SMauro Carvalho Chehab } 257064441979SMauro Carvalho Chehab } else { 257164441979SMauro Carvalho Chehab if (decoded_frame) { 257264441979SMauro Carvalho Chehab coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", 257364441979SMauro Carvalho Chehab coda_frame_type_char(decoded_frame->type), 257464441979SMauro Carvalho Chehab decoded_frame->meta.sequence, 257564441979SMauro Carvalho Chehab ctx->display_idx); 257664441979SMauro Carvalho Chehab } else { 257764441979SMauro Carvalho Chehab coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", 257864441979SMauro Carvalho Chehab decoded_idx, ctx->display_idx); 257964441979SMauro Carvalho Chehab } 258064441979SMauro Carvalho Chehab } 258164441979SMauro Carvalho Chehab 258264441979SMauro Carvalho Chehab /* The rotator will copy the current display frame next time */ 258364441979SMauro Carvalho Chehab ctx->display_idx = display_idx; 258464441979SMauro Carvalho Chehab 258564441979SMauro Carvalho Chehab /* 258664441979SMauro Carvalho Chehab * The current decode run might have brought the bitstream fill level 258764441979SMauro Carvalho Chehab * below the size where we can start the next decode run. As userspace 258864441979SMauro Carvalho Chehab * might have filled the output queue completely and might thus be 258964441979SMauro Carvalho Chehab * blocked, we can't rely on the next qbuf to trigger the bitstream 259064441979SMauro Carvalho Chehab * refill. Check if we have data to refill the bitstream now. 259164441979SMauro Carvalho Chehab */ 259264441979SMauro Carvalho Chehab mutex_lock(&ctx->bitstream_mutex); 259364441979SMauro Carvalho Chehab coda_fill_bitstream(ctx, NULL); 259464441979SMauro Carvalho Chehab mutex_unlock(&ctx->bitstream_mutex); 259564441979SMauro Carvalho Chehab } 259664441979SMauro Carvalho Chehab 259764441979SMauro Carvalho Chehab static void coda_decode_timeout(struct coda_ctx *ctx) 259864441979SMauro Carvalho Chehab { 259964441979SMauro Carvalho Chehab struct vb2_v4l2_buffer *dst_buf; 260064441979SMauro Carvalho Chehab 260164441979SMauro Carvalho Chehab /* 260264441979SMauro Carvalho Chehab * For now this only handles the case where we would deadlock with 260364441979SMauro Carvalho Chehab * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS, 260464441979SMauro Carvalho Chehab * but after a failed decode run we would hold the context and wait for 260564441979SMauro Carvalho Chehab * userspace to queue more buffers. 260664441979SMauro Carvalho Chehab */ 260764441979SMauro Carvalho Chehab if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)) 260864441979SMauro Carvalho Chehab return; 260964441979SMauro Carvalho Chehab 261064441979SMauro Carvalho Chehab dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 261164441979SMauro Carvalho Chehab dst_buf->sequence = ctx->qsequence - 1; 261264441979SMauro Carvalho Chehab 261364441979SMauro Carvalho Chehab coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 261464441979SMauro Carvalho Chehab } 261564441979SMauro Carvalho Chehab 261664441979SMauro Carvalho Chehab const struct coda_context_ops coda_bit_decode_ops = { 261764441979SMauro Carvalho Chehab .queue_init = coda_decoder_queue_init, 261864441979SMauro Carvalho Chehab .reqbufs = coda_decoder_reqbufs, 261964441979SMauro Carvalho Chehab .start_streaming = coda_start_decoding, 262064441979SMauro Carvalho Chehab .prepare_run = coda_prepare_decode, 262164441979SMauro Carvalho Chehab .finish_run = coda_finish_decode, 262264441979SMauro Carvalho Chehab .run_timeout = coda_decode_timeout, 262364441979SMauro Carvalho Chehab .seq_init_work = coda_dec_seq_init_work, 262464441979SMauro Carvalho Chehab .seq_end_work = coda_seq_end_work, 262564441979SMauro Carvalho Chehab .release = coda_bit_release, 262664441979SMauro Carvalho Chehab }; 262764441979SMauro Carvalho Chehab 262864441979SMauro Carvalho Chehab irqreturn_t coda_irq_handler(int irq, void *data) 262964441979SMauro Carvalho Chehab { 263064441979SMauro Carvalho Chehab struct coda_dev *dev = data; 263164441979SMauro Carvalho Chehab struct coda_ctx *ctx; 263264441979SMauro Carvalho Chehab 263364441979SMauro Carvalho Chehab /* read status register to attend the IRQ */ 263464441979SMauro Carvalho Chehab coda_read(dev, CODA_REG_BIT_INT_STATUS); 263564441979SMauro Carvalho Chehab coda_write(dev, 0, CODA_REG_BIT_INT_REASON); 263664441979SMauro Carvalho Chehab coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, 263764441979SMauro Carvalho Chehab CODA_REG_BIT_INT_CLEAR); 263864441979SMauro Carvalho Chehab 263964441979SMauro Carvalho Chehab ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); 264064441979SMauro Carvalho Chehab if (ctx == NULL) { 264164441979SMauro Carvalho Chehab v4l2_err(&dev->v4l2_dev, 264264441979SMauro Carvalho Chehab "Instance released before the end of transaction\n"); 264364441979SMauro Carvalho Chehab return IRQ_HANDLED; 264464441979SMauro Carvalho Chehab } 264564441979SMauro Carvalho Chehab 264664441979SMauro Carvalho Chehab trace_coda_bit_done(ctx); 264764441979SMauro Carvalho Chehab 264864441979SMauro Carvalho Chehab if (ctx->aborting) { 264964441979SMauro Carvalho Chehab coda_dbg(1, ctx, "task has been aborted\n"); 265064441979SMauro Carvalho Chehab } 265164441979SMauro Carvalho Chehab 265264441979SMauro Carvalho Chehab if (coda_isbusy(ctx->dev)) { 265364441979SMauro Carvalho Chehab coda_dbg(1, ctx, "coda is still busy!!!!\n"); 265464441979SMauro Carvalho Chehab return IRQ_NONE; 265564441979SMauro Carvalho Chehab } 265664441979SMauro Carvalho Chehab 265764441979SMauro Carvalho Chehab complete(&ctx->completion); 265864441979SMauro Carvalho Chehab 265964441979SMauro Carvalho Chehab return IRQ_HANDLED; 266064441979SMauro Carvalho Chehab } 2661