162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Coda multi-standard codec IP - BIT processor functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Vista Silicon S.L. 662306a36Sopenharmony_ci * Javier Martin, <javier.martin@vista-silicon.com> 762306a36Sopenharmony_ci * Xavier Duret 862306a36Sopenharmony_ci * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/irqreturn.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/log2.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/ratelimit.h> 1762306a36Sopenharmony_ci#include <linux/reset.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/videodev2.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <media/v4l2-common.h> 2262306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2362306a36Sopenharmony_ci#include <media/v4l2-fh.h> 2462306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h> 2562306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h> 2662306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 2762306a36Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "coda.h" 3062306a36Sopenharmony_ci#include "imx-vdoa.h" 3162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 3262306a36Sopenharmony_ci#include "trace.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define CODA_PARA_BUF_SIZE (10 * 1024) 3562306a36Sopenharmony_ci#define CODA7_PS_BUF_SIZE 0x28000 3662306a36Sopenharmony_ci#define CODA9_PS_SAVE_SIZE (512 * 1024) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define CODA_DEFAULT_GAMMA 4096 3962306a36Sopenharmony_ci#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline int coda_is_initialized(struct coda_dev *dev) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic inline unsigned long coda_isbusy(struct coda_dev *dev) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci return coda_read(dev, CODA_REG_BIT_BUSY); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int coda_wait_timeout(struct coda_dev *dev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci while (coda_isbusy(dev)) { 5862306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 5962306a36Sopenharmony_ci return -ETIMEDOUT; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void coda_command_async(struct coda_ctx *ctx, int cmd) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 6962306a36Sopenharmony_ci dev->devtype->product == CODA_7541 || 7062306a36Sopenharmony_ci dev->devtype->product == CODA_960) { 7162306a36Sopenharmony_ci /* Restore context related registers to CODA */ 7262306a36Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 7362306a36Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 7462306a36Sopenharmony_ci coda_write(dev, ctx->frm_dis_flg, 7562306a36Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 7662306a36Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, 7762306a36Sopenharmony_ci CODA_REG_BIT_FRAME_MEM_CTRL); 7862306a36Sopenharmony_ci coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 8262306a36Sopenharmony_ci coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); 8362306a36Sopenharmony_ci coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); 8962306a36Sopenharmony_ci coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); 9062306a36Sopenharmony_ci coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci trace_coda_bit_run(ctx, cmd); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int coda_command_sync(struct coda_ctx *ctx, int cmd) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 10062306a36Sopenharmony_ci int ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci coda_command_async(ctx, cmd); 10562306a36Sopenharmony_ci ret = coda_wait_timeout(dev); 10662306a36Sopenharmony_ci trace_coda_bit_done(ctx); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint coda_hw_reset(struct coda_ctx *ctx) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 11462306a36Sopenharmony_ci unsigned long timeout; 11562306a36Sopenharmony_ci unsigned int idx; 11662306a36Sopenharmony_ci int ret; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (!dev->rstc) 12162306a36Sopenharmony_ci return -ENOENT; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 12662306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(100); 12762306a36Sopenharmony_ci coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); 12862306a36Sopenharmony_ci while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { 12962306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 13062306a36Sopenharmony_ci return -ETIME; 13162306a36Sopenharmony_ci cpu_relax(); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci ret = reset_control_reset(dev->rstc); 13662306a36Sopenharmony_ci if (ret < 0) 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 14062306a36Sopenharmony_ci coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); 14162306a36Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 14262306a36Sopenharmony_ci coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); 14362306a36Sopenharmony_ci ret = coda_wait_timeout(dev); 14462306a36Sopenharmony_ci coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void coda_kfifo_sync_from_device(struct coda_ctx *ctx) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 15262306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 15362306a36Sopenharmony_ci u32 rd_ptr; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 15662306a36Sopenharmony_ci kfifo->out = (kfifo->in & ~kfifo->mask) | 15762306a36Sopenharmony_ci (rd_ptr - ctx->bitstream.paddr); 15862306a36Sopenharmony_ci if (kfifo->out > kfifo->in) 15962306a36Sopenharmony_ci kfifo->out -= kfifo->mask + 1; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 16562306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 16662306a36Sopenharmony_ci u32 rd_ptr, wr_ptr; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); 16962306a36Sopenharmony_ci coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 17062306a36Sopenharmony_ci wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 17162306a36Sopenharmony_ci coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 17762306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 17862306a36Sopenharmony_ci u32 wr_ptr; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 18162306a36Sopenharmony_ci coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci unsigned char *buf; 18762306a36Sopenharmony_ci u32 n; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (size < 6) 19062306a36Sopenharmony_ci size = 6; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 19362306a36Sopenharmony_ci if (!buf) 19462306a36Sopenharmony_ci return -ENOMEM; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci coda_h264_filler_nal(size, buf); 19762306a36Sopenharmony_ci n = kfifo_in(&ctx->bitstream_fifo, buf, size); 19862306a36Sopenharmony_ci kfree(buf); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return (n < size) ? -ENOSPC : 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciint coda_bitstream_flush(struct coda_ctx *ctx) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci int ret; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); 21162306a36Sopenharmony_ci if (ret < 0) { 21262306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); 21362306a36Sopenharmony_ci return ret; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, 21762306a36Sopenharmony_ci ctx->bitstream.size); 21862306a36Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return (n < size) ? -ENOSPC : 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic u32 coda_buffer_parse_headers(struct coda_ctx *ctx, 23162306a36Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, 23262306a36Sopenharmony_ci u32 payload) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 23562306a36Sopenharmony_ci u32 size = 0; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci switch (ctx->codec->src_fourcc) { 23862306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 23962306a36Sopenharmony_ci size = coda_mpeg2_parse_headers(ctx, vaddr, payload); 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 24262306a36Sopenharmony_ci size = coda_mpeg4_parse_headers(ctx, vaddr, payload); 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci default: 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return size; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic bool coda_bitstream_try_queue(struct coda_ctx *ctx, 25262306a36Sopenharmony_ci struct vb2_v4l2_buffer *src_buf) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); 25562306a36Sopenharmony_ci u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 25662306a36Sopenharmony_ci int ret; 25762306a36Sopenharmony_ci int i; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (coda_get_bitstream_payload(ctx) + payload + 512 >= 26062306a36Sopenharmony_ci ctx->bitstream.size) 26162306a36Sopenharmony_ci return false; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!vaddr) { 26462306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); 26562306a36Sopenharmony_ci return true; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (ctx->qsequence == 0 && payload < 512) { 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * Add padding after the first buffer, if it is too small to be 27162306a36Sopenharmony_ci * fetched by the CODA, by repeating the headers. Without 27262306a36Sopenharmony_ci * repeated headers, or the first frame already queued, decoder 27362306a36Sopenharmony_ci * sequence initialization fails with error code 0x2000 on i.MX6 27462306a36Sopenharmony_ci * or error code 0x1 on i.MX51. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci u32 header_size = coda_buffer_parse_headers(ctx, src_buf, 27762306a36Sopenharmony_ci payload); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (header_size) { 28062306a36Sopenharmony_ci coda_dbg(1, ctx, "pad with %u-byte header\n", 28162306a36Sopenharmony_ci header_size); 28262306a36Sopenharmony_ci for (i = payload; i < 512; i += header_size) { 28362306a36Sopenharmony_ci ret = coda_bitstream_queue(ctx, vaddr, 28462306a36Sopenharmony_ci header_size); 28562306a36Sopenharmony_ci if (ret < 0) { 28662306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 28762306a36Sopenharmony_ci "bitstream buffer overflow\n"); 28862306a36Sopenharmony_ci return false; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci if (ctx->dev->devtype->product == CODA_960) 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci } else { 29462306a36Sopenharmony_ci coda_dbg(1, ctx, 29562306a36Sopenharmony_ci "could not parse header, sequence initialization might fail\n"); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* Add padding before the first buffer, if it is too small */ 29962306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 30062306a36Sopenharmony_ci coda_h264_bitstream_pad(ctx, 512 - payload); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = coda_bitstream_queue(ctx, vaddr, payload); 30462306a36Sopenharmony_ci if (ret < 0) { 30562306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); 30662306a36Sopenharmony_ci return false; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci src_buf->sequence = ctx->qsequence++; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* Sync read pointer to device */ 31262306a36Sopenharmony_ci if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) 31362306a36Sopenharmony_ci coda_kfifo_sync_to_device_write(ctx); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Set the stream-end flag after the last buffer is queued */ 31662306a36Sopenharmony_ci if (src_buf->flags & V4L2_BUF_FLAG_LAST) 31762306a36Sopenharmony_ci coda_bit_stream_end_flag(ctx); 31862306a36Sopenharmony_ci ctx->hold = false; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return true; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_civoid coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct vb2_v4l2_buffer *src_buf; 32662306a36Sopenharmony_ci struct coda_buffer_meta *meta; 32762306a36Sopenharmony_ci u32 start; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci lockdep_assert_held(&ctx->bitstream_mutex); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) 33262306a36Sopenharmony_ci return; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * Only queue two JPEGs into the bitstream buffer to keep 33762306a36Sopenharmony_ci * latency low. We need at least one complete buffer and the 33862306a36Sopenharmony_ci * header of another buffer (for prescan) in the bitstream. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 34162306a36Sopenharmony_ci ctx->num_metas > 1) 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (ctx->num_internal_frames && 34562306a36Sopenharmony_ci ctx->num_metas >= ctx->num_internal_frames) { 34662306a36Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 34762306a36Sopenharmony_ci struct coda_buffer_meta, list); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * If we managed to fill in at least a full reorder 35162306a36Sopenharmony_ci * window of buffers (num_internal_frames is a 35262306a36Sopenharmony_ci * conservative estimate for this) and the bitstream 35362306a36Sopenharmony_ci * prefetcher has at least 2 256 bytes periods beyond 35462306a36Sopenharmony_ci * the first buffer to fetch, we can safely stop queuing 35562306a36Sopenharmony_ci * in order to limit the decoder drain latency. 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (coda_bitstream_can_fetch_past(ctx, meta->end)) 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Drop frames that do not start/end with a SOI/EOI markers */ 36462306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 36562306a36Sopenharmony_ci !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { 36662306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 36762306a36Sopenharmony_ci "dropping invalid JPEG frame %d\n", 36862306a36Sopenharmony_ci ctx->qsequence); 36962306a36Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 37062306a36Sopenharmony_ci if (buffer_list) { 37162306a36Sopenharmony_ci struct v4l2_m2m_buffer *m2m_buf; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci m2m_buf = container_of(src_buf, 37462306a36Sopenharmony_ci struct v4l2_m2m_buffer, 37562306a36Sopenharmony_ci vb); 37662306a36Sopenharmony_ci list_add_tail(&m2m_buf->list, buffer_list); 37762306a36Sopenharmony_ci } else { 37862306a36Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci continue; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Dump empty buffers */ 38462306a36Sopenharmony_ci if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) { 38562306a36Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 38662306a36Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 38762306a36Sopenharmony_ci continue; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Buffer start position */ 39162306a36Sopenharmony_ci start = ctx->bitstream_fifo.kfifo.in; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (coda_bitstream_try_queue(ctx, src_buf)) { 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * Source buffer is queued in the bitstream ringbuffer; 39662306a36Sopenharmony_ci * queue the timestamp and mark source buffer as done 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci meta = kmalloc(sizeof(*meta), GFP_KERNEL); 40162306a36Sopenharmony_ci if (meta) { 40262306a36Sopenharmony_ci meta->sequence = src_buf->sequence; 40362306a36Sopenharmony_ci meta->timecode = src_buf->timecode; 40462306a36Sopenharmony_ci meta->timestamp = src_buf->vb2_buf.timestamp; 40562306a36Sopenharmony_ci meta->start = start; 40662306a36Sopenharmony_ci meta->end = ctx->bitstream_fifo.kfifo.in; 40762306a36Sopenharmony_ci meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; 40862306a36Sopenharmony_ci if (meta->last) 40962306a36Sopenharmony_ci coda_dbg(1, ctx, "marking last meta"); 41062306a36Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 41162306a36Sopenharmony_ci list_add_tail(&meta->list, 41262306a36Sopenharmony_ci &ctx->buffer_meta_list); 41362306a36Sopenharmony_ci ctx->num_metas++; 41462306a36Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci trace_coda_bit_queue(ctx, src_buf, meta); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (buffer_list) { 42062306a36Sopenharmony_ci struct v4l2_m2m_buffer *m2m_buf; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci m2m_buf = container_of(src_buf, 42362306a36Sopenharmony_ci struct v4l2_m2m_buffer, 42462306a36Sopenharmony_ci vb); 42562306a36Sopenharmony_ci list_add_tail(&m2m_buf->list, buffer_list); 42662306a36Sopenharmony_ci } else { 42762306a36Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } else { 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_civoid coda_bit_stream_end_flag(struct coda_ctx *ctx) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* If this context is currently running, update the hardware flag */ 44262306a36Sopenharmony_ci if ((dev->devtype->product == CODA_960) && 44362306a36Sopenharmony_ci coda_isbusy(dev) && 44462306a36Sopenharmony_ci (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { 44562306a36Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 44662306a36Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 45362306a36Sopenharmony_ci u32 *p = ctx->parabuf.vaddr; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 45662306a36Sopenharmony_ci p[index] = value; 45762306a36Sopenharmony_ci else 45862306a36Sopenharmony_ci p[index ^ 1] = value; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic inline int coda_alloc_context_buf(struct coda_ctx *ctx, 46262306a36Sopenharmony_ci struct coda_aux_buf *buf, size_t size, 46362306a36Sopenharmony_ci const char *name) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void coda_free_framebuffers(struct coda_ctx *ctx) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci int i; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) 47462306a36Sopenharmony_ci coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int coda_alloc_framebuffers(struct coda_ctx *ctx, 47862306a36Sopenharmony_ci struct coda_q_data *q_data, u32 fourcc) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 48162306a36Sopenharmony_ci unsigned int ysize, ycbcr_size; 48262306a36Sopenharmony_ci int ret; 48362306a36Sopenharmony_ci int i; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 48662306a36Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || 48762306a36Sopenharmony_ci ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || 48862306a36Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) 48962306a36Sopenharmony_ci ysize = round_up(q_data->rect.width, 16) * 49062306a36Sopenharmony_ci round_up(q_data->rect.height, 16); 49162306a36Sopenharmony_ci else 49262306a36Sopenharmony_ci ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 49562306a36Sopenharmony_ci ycbcr_size = round_up(ysize, 4096) + ysize / 2; 49662306a36Sopenharmony_ci else 49762306a36Sopenharmony_ci ycbcr_size = ysize + ysize / 2; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Allocate frame buffers */ 50062306a36Sopenharmony_ci for (i = 0; i < ctx->num_internal_frames; i++) { 50162306a36Sopenharmony_ci size_t size = ycbcr_size; 50262306a36Sopenharmony_ci char *name; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Add space for mvcol buffers */ 50562306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6 && 50662306a36Sopenharmony_ci (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 50762306a36Sopenharmony_ci (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0))) 50862306a36Sopenharmony_ci size += ysize / 4; 50962306a36Sopenharmony_ci name = kasprintf(GFP_KERNEL, "fb%d", i); 51062306a36Sopenharmony_ci if (!name) { 51162306a36Sopenharmony_ci coda_free_framebuffers(ctx); 51262306a36Sopenharmony_ci return -ENOMEM; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, 51562306a36Sopenharmony_ci size, name); 51662306a36Sopenharmony_ci kfree(name); 51762306a36Sopenharmony_ci if (ret < 0) { 51862306a36Sopenharmony_ci coda_free_framebuffers(ctx); 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Register frame buffers in the parameter buffer */ 52462306a36Sopenharmony_ci for (i = 0; i < ctx->num_internal_frames; i++) { 52562306a36Sopenharmony_ci u32 y, cb, cr, mvcol; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Start addresses of Y, Cb, Cr planes */ 52862306a36Sopenharmony_ci y = ctx->internal_frames[i].buf.paddr; 52962306a36Sopenharmony_ci cb = y + ysize; 53062306a36Sopenharmony_ci cr = y + ysize + ysize/4; 53162306a36Sopenharmony_ci mvcol = y + ysize + ysize/4 + ysize/4; 53262306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { 53362306a36Sopenharmony_ci cb = round_up(cb, 4096); 53462306a36Sopenharmony_ci mvcol = cb + ysize/2; 53562306a36Sopenharmony_ci cr = 0; 53662306a36Sopenharmony_ci /* Packed 20-bit MSB of base addresses */ 53762306a36Sopenharmony_ci /* YYYYYCCC, CCyyyyyc, cccc.... */ 53862306a36Sopenharmony_ci y = (y & 0xfffff000) | cb >> 20; 53962306a36Sopenharmony_ci cb = (cb & 0x000ff000) << 12; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 0, y); 54262306a36Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 1, cb); 54362306a36Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 2, cr); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 54662306a36Sopenharmony_ci continue; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* mvcol buffer for h.264 and mpeg4 */ 54962306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 55062306a36Sopenharmony_ci coda_parabuf_write(ctx, 96 + i, mvcol); 55162306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0) 55262306a36Sopenharmony_ci coda_parabuf_write(ctx, 97, mvcol); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void coda_free_context_buffers(struct coda_ctx *ctx) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci coda_free_aux_buf(dev, &ctx->slicebuf); 56362306a36Sopenharmony_ci coda_free_aux_buf(dev, &ctx->psbuf); 56462306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 56562306a36Sopenharmony_ci coda_free_aux_buf(dev, &ctx->workbuf); 56662306a36Sopenharmony_ci coda_free_aux_buf(dev, &ctx->parabuf); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int coda_alloc_context_buffers(struct coda_ctx *ctx, 57062306a36Sopenharmony_ci struct coda_q_data *q_data) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 57362306a36Sopenharmony_ci size_t size; 57462306a36Sopenharmony_ci int ret; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!ctx->parabuf.vaddr) { 57762306a36Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->parabuf, 57862306a36Sopenharmony_ci CODA_PARA_BUF_SIZE, "parabuf"); 57962306a36Sopenharmony_ci if (ret < 0) 58062306a36Sopenharmony_ci return ret; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { 58762306a36Sopenharmony_ci /* worst case slice size */ 58862306a36Sopenharmony_ci size = (DIV_ROUND_UP(q_data->rect.width, 16) * 58962306a36Sopenharmony_ci DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512; 59062306a36Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, 59162306a36Sopenharmony_ci "slicebuf"); 59262306a36Sopenharmony_ci if (ret < 0) 59362306a36Sopenharmony_ci goto err; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || 59762306a36Sopenharmony_ci dev->devtype->product == CODA_7541)) { 59862306a36Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->psbuf, 59962306a36Sopenharmony_ci CODA7_PS_BUF_SIZE, "psbuf"); 60062306a36Sopenharmony_ci if (ret < 0) 60162306a36Sopenharmony_ci goto err; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!ctx->workbuf.vaddr) { 60562306a36Sopenharmony_ci size = dev->devtype->workbuf_size; 60662306a36Sopenharmony_ci if (dev->devtype->product == CODA_960 && 60762306a36Sopenharmony_ci q_data->fourcc == V4L2_PIX_FMT_H264) 60862306a36Sopenharmony_ci size += CODA9_PS_SAVE_SIZE; 60962306a36Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, 61062306a36Sopenharmony_ci "workbuf"); 61162306a36Sopenharmony_ci if (ret < 0) 61262306a36Sopenharmony_ci goto err; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cierr: 61862306a36Sopenharmony_ci coda_free_context_buffers(ctx); 61962306a36Sopenharmony_ci return ret; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, 62362306a36Sopenharmony_ci int header_code, u8 *header, int *size) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct vb2_buffer *vb = &buf->vb2_buf; 62662306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 62762306a36Sopenharmony_ci struct coda_q_data *q_data_src; 62862306a36Sopenharmony_ci struct v4l2_rect *r; 62962306a36Sopenharmony_ci size_t bufsize; 63062306a36Sopenharmony_ci int ret; 63162306a36Sopenharmony_ci int i; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 63462306a36Sopenharmony_ci memset(vb2_plane_vaddr(vb, 0), 0, 64); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0), 63762306a36Sopenharmony_ci CODA_CMD_ENC_HEADER_BB_START); 63862306a36Sopenharmony_ci bufsize = vb2_plane_size(vb, 0); 63962306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 64062306a36Sopenharmony_ci bufsize /= 1024; 64162306a36Sopenharmony_ci coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); 64262306a36Sopenharmony_ci if (dev->devtype->product == CODA_960 && 64362306a36Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && 64462306a36Sopenharmony_ci header_code == CODA_HEADER_H264_SPS) { 64562306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 64662306a36Sopenharmony_ci r = &q_data_src->rect; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (r->width % 16 || r->height % 16) { 64962306a36Sopenharmony_ci u32 crop_right = round_up(r->width, 16) - r->width; 65062306a36Sopenharmony_ci u32 crop_bottom = round_up(r->height, 16) - r->height; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci coda_write(dev, crop_right, 65362306a36Sopenharmony_ci CODA9_CMD_ENC_HEADER_FRAME_CROP_H); 65462306a36Sopenharmony_ci coda_write(dev, crop_bottom, 65562306a36Sopenharmony_ci CODA9_CMD_ENC_HEADER_FRAME_CROP_V); 65662306a36Sopenharmony_ci header_code |= CODA9_HEADER_FRAME_CROP; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); 66062306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); 66162306a36Sopenharmony_ci if (ret < 0) { 66262306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); 66362306a36Sopenharmony_ci return ret; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 66762306a36Sopenharmony_ci for (i = 63; i > 0; i--) 66862306a36Sopenharmony_ci if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0) 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci *size = i + 1; 67162306a36Sopenharmony_ci } else { 67262306a36Sopenharmony_ci *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - 67362306a36Sopenharmony_ci coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci memcpy(header, vb2_plane_vaddr(vb, 0), *size); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic u32 coda_slice_mode(struct coda_ctx *ctx) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci int size, unit; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci switch (ctx->params.slice_mode) { 68562306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: 68662306a36Sopenharmony_ci default: 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: 68962306a36Sopenharmony_ci size = ctx->params.slice_max_mb; 69062306a36Sopenharmony_ci unit = 1; 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: 69362306a36Sopenharmony_ci size = ctx->params.slice_max_bits; 69462306a36Sopenharmony_ci unit = 0; 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | 69962306a36Sopenharmony_ci ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | 70062306a36Sopenharmony_ci ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int coda_enc_param_change(struct coda_ctx *ctx) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 70662306a36Sopenharmony_ci u32 change_enable = 0; 70762306a36Sopenharmony_ci u32 success; 70862306a36Sopenharmony_ci int ret; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (ctx->params.gop_size_changed) { 71162306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_GOP; 71262306a36Sopenharmony_ci coda_write(dev, ctx->params.gop_size, 71362306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_GOP); 71462306a36Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 71562306a36Sopenharmony_ci ctx->params.gop_size_changed = false; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci if (ctx->params.h264_intra_qp_changed) { 71862306a36Sopenharmony_ci coda_dbg(1, ctx, "parameter change: intra Qp %u\n", 71962306a36Sopenharmony_ci ctx->params.h264_intra_qp); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (ctx->params.bitrate) { 72262306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; 72362306a36Sopenharmony_ci coda_write(dev, ctx->params.h264_intra_qp, 72462306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_INTRA_QP); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci ctx->params.h264_intra_qp_changed = false; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci if (ctx->params.bitrate_changed) { 72962306a36Sopenharmony_ci coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", 73062306a36Sopenharmony_ci ctx->params.bitrate); 73162306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; 73262306a36Sopenharmony_ci coda_write(dev, ctx->params.bitrate, 73362306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_BITRATE); 73462306a36Sopenharmony_ci ctx->params.bitrate_changed = false; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci if (ctx->params.framerate_changed) { 73762306a36Sopenharmony_ci coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", 73862306a36Sopenharmony_ci ctx->params.framerate & 0xffff, 73962306a36Sopenharmony_ci (ctx->params.framerate >> 16) + 1); 74062306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; 74162306a36Sopenharmony_ci coda_write(dev, ctx->params.framerate, 74262306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_FRAME_RATE); 74362306a36Sopenharmony_ci ctx->params.framerate_changed = false; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (ctx->params.intra_refresh_changed) { 74662306a36Sopenharmony_ci coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", 74762306a36Sopenharmony_ci ctx->params.intra_refresh); 74862306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; 74962306a36Sopenharmony_ci coda_write(dev, ctx->params.intra_refresh, 75062306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_INTRA_MB_NUM); 75162306a36Sopenharmony_ci ctx->params.intra_refresh_changed = false; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci if (ctx->params.slice_mode_changed) { 75462306a36Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; 75562306a36Sopenharmony_ci coda_write(dev, coda_slice_mode(ctx), 75662306a36Sopenharmony_ci CODA_CMD_ENC_PARAM_SLICE_MODE); 75762306a36Sopenharmony_ci ctx->params.slice_mode_changed = false; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (!change_enable) 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); 76662306a36Sopenharmony_ci if (ret < 0) 76762306a36Sopenharmony_ci return ret; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); 77062306a36Sopenharmony_ci if (success != 1) 77162306a36Sopenharmony_ci coda_dbg(1, ctx, "parameter change failed: %u\n", success); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci phys_addr_t ret; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci size = round_up(size, 1024); 78162306a36Sopenharmony_ci if (size > iram->remaining) 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci iram->remaining -= size; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci ret = iram->next_paddr; 78662306a36Sopenharmony_ci iram->next_paddr += size; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return ret; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic void coda_setup_iram(struct coda_ctx *ctx) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct coda_iram_info *iram_info = &ctx->iram_info; 79462306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 79562306a36Sopenharmony_ci int w64, w128; 79662306a36Sopenharmony_ci int mb_width; 79762306a36Sopenharmony_ci int dbk_bits; 79862306a36Sopenharmony_ci int bit_bits; 79962306a36Sopenharmony_ci int ip_bits; 80062306a36Sopenharmony_ci int me_bits; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci memset(iram_info, 0, sizeof(*iram_info)); 80362306a36Sopenharmony_ci iram_info->next_paddr = dev->iram.paddr; 80462306a36Sopenharmony_ci iram_info->remaining = dev->iram.size; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (!dev->iram.vaddr) 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci switch (dev->devtype->product) { 81062306a36Sopenharmony_ci case CODA_HX4: 81162306a36Sopenharmony_ci dbk_bits = CODA7_USE_HOST_DBK_ENABLE; 81262306a36Sopenharmony_ci bit_bits = CODA7_USE_HOST_BIT_ENABLE; 81362306a36Sopenharmony_ci ip_bits = CODA7_USE_HOST_IP_ENABLE; 81462306a36Sopenharmony_ci me_bits = CODA7_USE_HOST_ME_ENABLE; 81562306a36Sopenharmony_ci break; 81662306a36Sopenharmony_ci case CODA_7541: 81762306a36Sopenharmony_ci dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; 81862306a36Sopenharmony_ci bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 81962306a36Sopenharmony_ci ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 82062306a36Sopenharmony_ci me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci case CODA_960: 82362306a36Sopenharmony_ci dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; 82462306a36Sopenharmony_ci bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 82562306a36Sopenharmony_ci ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 82662306a36Sopenharmony_ci me_bits = 0; 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci default: /* CODA_DX6 */ 82962306a36Sopenharmony_ci return; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (ctx->inst_type == CODA_INST_ENCODER) { 83362306a36Sopenharmony_ci struct coda_q_data *q_data_src; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 83662306a36Sopenharmony_ci mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16); 83762306a36Sopenharmony_ci w128 = mb_width * 128; 83862306a36Sopenharmony_ci w64 = mb_width * 64; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Prioritize in case IRAM is too small for everything */ 84162306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 84262306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 84362306a36Sopenharmony_ci iram_info->search_ram_size = round_up(mb_width * 16 * 84462306a36Sopenharmony_ci 36 + 2048, 1024); 84562306a36Sopenharmony_ci iram_info->search_ram_paddr = coda_iram_alloc(iram_info, 84662306a36Sopenharmony_ci iram_info->search_ram_size); 84762306a36Sopenharmony_ci if (!iram_info->search_ram_paddr) { 84862306a36Sopenharmony_ci pr_err("IRAM is smaller than the search ram size\n"); 84962306a36Sopenharmony_ci goto out; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci iram_info->axi_sram_use |= me_bits; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Only H.264BP and H.263P3 are considered */ 85562306a36Sopenharmony_ci iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); 85662306a36Sopenharmony_ci iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); 85762306a36Sopenharmony_ci if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 85862306a36Sopenharmony_ci goto out; 85962306a36Sopenharmony_ci iram_info->axi_sram_use |= dbk_bits; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 86262306a36Sopenharmony_ci if (!iram_info->buf_bit_use) 86362306a36Sopenharmony_ci goto out; 86462306a36Sopenharmony_ci iram_info->axi_sram_use |= bit_bits; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 86762306a36Sopenharmony_ci if (!iram_info->buf_ip_ac_dc_use) 86862306a36Sopenharmony_ci goto out; 86962306a36Sopenharmony_ci iram_info->axi_sram_use |= ip_bits; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* OVL and BTP disabled for encoder */ 87262306a36Sopenharmony_ci } else if (ctx->inst_type == CODA_INST_DECODER) { 87362306a36Sopenharmony_ci struct coda_q_data *q_data_dst; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 87662306a36Sopenharmony_ci mb_width = DIV_ROUND_UP(q_data_dst->width, 16); 87762306a36Sopenharmony_ci w128 = mb_width * 128; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); 88062306a36Sopenharmony_ci iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); 88162306a36Sopenharmony_ci if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 88262306a36Sopenharmony_ci goto out; 88362306a36Sopenharmony_ci iram_info->axi_sram_use |= dbk_bits; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 88662306a36Sopenharmony_ci if (!iram_info->buf_bit_use) 88762306a36Sopenharmony_ci goto out; 88862306a36Sopenharmony_ci iram_info->axi_sram_use |= bit_bits; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 89162306a36Sopenharmony_ci if (!iram_info->buf_ip_ac_dc_use) 89262306a36Sopenharmony_ci goto out; 89362306a36Sopenharmony_ci iram_info->axi_sram_use |= ip_bits; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* OVL and BTP unused as there is no VC1 support yet */ 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ciout: 89962306a36Sopenharmony_ci if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) 90062306a36Sopenharmony_ci coda_dbg(1, ctx, "IRAM smaller than needed\n"); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 90362306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 90462306a36Sopenharmony_ci /* TODO - Enabling these causes picture errors on CODA7541 */ 90562306a36Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER) { 90662306a36Sopenharmony_ci /* fw 1.4.50 */ 90762306a36Sopenharmony_ci iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 90862306a36Sopenharmony_ci CODA7_USE_IP_ENABLE); 90962306a36Sopenharmony_ci } else { 91062306a36Sopenharmony_ci /* fw 13.4.29 */ 91162306a36Sopenharmony_ci iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 91262306a36Sopenharmony_ci CODA7_USE_HOST_DBK_ENABLE | 91362306a36Sopenharmony_ci CODA7_USE_IP_ENABLE | 91462306a36Sopenharmony_ci CODA7_USE_DBK_ENABLE); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic u32 coda_supported_firmwares[] = { 92062306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), 92162306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), 92262306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), 92362306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), 92462306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9), 92562306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), 92662306a36Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), 92762306a36Sopenharmony_ci}; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic bool coda_firmware_supported(u32 vernum) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci int i; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) 93462306a36Sopenharmony_ci if (vernum == coda_supported_firmwares[i]) 93562306a36Sopenharmony_ci return true; 93662306a36Sopenharmony_ci return false; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ciint coda_check_firmware(struct coda_dev *dev) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci u16 product, major, minor, release; 94262306a36Sopenharmony_ci u32 data; 94362306a36Sopenharmony_ci int ret; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci ret = clk_prepare_enable(dev->clk_per); 94662306a36Sopenharmony_ci if (ret) 94762306a36Sopenharmony_ci goto err_clk_per; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci ret = clk_prepare_enable(dev->clk_ahb); 95062306a36Sopenharmony_ci if (ret) 95162306a36Sopenharmony_ci goto err_clk_ahb; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); 95462306a36Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 95562306a36Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); 95662306a36Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); 95762306a36Sopenharmony_ci coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); 95862306a36Sopenharmony_ci if (coda_wait_timeout(dev)) { 95962306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); 96062306a36Sopenharmony_ci ret = -EIO; 96162306a36Sopenharmony_ci goto err_run_cmd; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 96562306a36Sopenharmony_ci data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); 96662306a36Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", 96762306a36Sopenharmony_ci data); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Check we are compatible with the loaded firmware */ 97162306a36Sopenharmony_ci data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); 97262306a36Sopenharmony_ci product = CODA_FIRMWARE_PRODUCT(data); 97362306a36Sopenharmony_ci major = CODA_FIRMWARE_MAJOR(data); 97462306a36Sopenharmony_ci minor = CODA_FIRMWARE_MINOR(data); 97562306a36Sopenharmony_ci release = CODA_FIRMWARE_RELEASE(data); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 97862306a36Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (product != dev->devtype->product) { 98162306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 98262306a36Sopenharmony_ci "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", 98362306a36Sopenharmony_ci coda_product_name(dev->devtype->product), 98462306a36Sopenharmony_ci coda_product_name(product), major, minor, release); 98562306a36Sopenharmony_ci return -EINVAL; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", 98962306a36Sopenharmony_ci coda_product_name(product)); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (coda_firmware_supported(data)) { 99262306a36Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", 99362306a36Sopenharmony_ci major, minor, release); 99462306a36Sopenharmony_ci } else { 99562306a36Sopenharmony_ci v4l2_warn(&dev->v4l2_dev, 99662306a36Sopenharmony_ci "Unsupported firmware version: %u.%u.%u\n", 99762306a36Sopenharmony_ci major, minor, release); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cierr_run_cmd: 100362306a36Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 100462306a36Sopenharmony_cierr_clk_ahb: 100562306a36Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 100662306a36Sopenharmony_cierr_clk_per: 100762306a36Sopenharmony_ci return ret; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci u32 cache_size, cache_config; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { 101562306a36Sopenharmony_ci /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ 101662306a36Sopenharmony_ci cache_size = 0x20262024; 101762306a36Sopenharmony_ci cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; 101862306a36Sopenharmony_ci } else { 101962306a36Sopenharmony_ci /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ 102062306a36Sopenharmony_ci cache_size = 0x02440243; 102162306a36Sopenharmony_ci cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); 102462306a36Sopenharmony_ci if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) { 102562306a36Sopenharmony_ci cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 102662306a36Sopenharmony_ci 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 102762306a36Sopenharmony_ci 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 102862306a36Sopenharmony_ci } else { 102962306a36Sopenharmony_ci cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 103062306a36Sopenharmony_ci 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 103162306a36Sopenharmony_ci 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/* 103762306a36Sopenharmony_ci * Encoder context operations 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic int coda_encoder_reqbufs(struct coda_ctx *ctx, 104162306a36Sopenharmony_ci struct v4l2_requestbuffers *rb) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct coda_q_data *q_data_src; 104462306a36Sopenharmony_ci int ret; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (rb->count) { 105062306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 105162306a36Sopenharmony_ci ret = coda_alloc_context_buffers(ctx, q_data_src); 105262306a36Sopenharmony_ci if (ret < 0) 105362306a36Sopenharmony_ci return ret; 105462306a36Sopenharmony_ci } else { 105562306a36Sopenharmony_ci coda_free_context_buffers(ctx); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int coda_start_encoding(struct coda_ctx *ctx) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 106462306a36Sopenharmony_ci struct v4l2_device *v4l2_dev = &dev->v4l2_dev; 106562306a36Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 106662306a36Sopenharmony_ci u32 bitstream_buf, bitstream_size; 106762306a36Sopenharmony_ci struct vb2_v4l2_buffer *buf; 106862306a36Sopenharmony_ci int gamma, ret, value; 106962306a36Sopenharmony_ci u32 dst_fourcc; 107062306a36Sopenharmony_ci int num_fb; 107162306a36Sopenharmony_ci u32 stride; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 107462306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 107562306a36Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 107862306a36Sopenharmony_ci bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); 107962306a36Sopenharmony_ci bitstream_size = q_data_dst->sizeimage; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (!coda_is_initialized(dev)) { 108262306a36Sopenharmony_ci v4l2_err(v4l2_dev, "coda is not initialized.\n"); 108362306a36Sopenharmony_ci return -EFAULT; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_JPEG) { 108762306a36Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[0]) { 108862306a36Sopenharmony_ci ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); 108962306a36Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[0]) 109062306a36Sopenharmony_ci return -ENOMEM; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[1]) { 109362306a36Sopenharmony_ci ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); 109462306a36Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[1]) 109562306a36Sopenharmony_ci return -ENOMEM; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci mutex_lock(&dev->coda_mutex); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 110362306a36Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 110462306a36Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 110562306a36Sopenharmony_ci switch (dev->devtype->product) { 110662306a36Sopenharmony_ci case CODA_DX6: 110762306a36Sopenharmony_ci coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | 110862306a36Sopenharmony_ci CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 110962306a36Sopenharmony_ci break; 111062306a36Sopenharmony_ci case CODA_960: 111162306a36Sopenharmony_ci coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 111262306a36Sopenharmony_ci fallthrough; 111362306a36Sopenharmony_ci case CODA_HX4: 111462306a36Sopenharmony_ci case CODA_7541: 111562306a36Sopenharmony_ci coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | 111662306a36Sopenharmony_ci CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 112162306a36Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 112262306a36Sopenharmony_ci if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) 112362306a36Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 112462306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 112562306a36Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; 112662306a36Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 112962306a36Sopenharmony_ci /* Configure the coda */ 113062306a36Sopenharmony_ci coda_write(dev, dev->iram.paddr, 113162306a36Sopenharmony_ci CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* Could set rotation here if needed */ 113562306a36Sopenharmony_ci value = 0; 113662306a36Sopenharmony_ci switch (dev->devtype->product) { 113762306a36Sopenharmony_ci case CODA_DX6: 113862306a36Sopenharmony_ci value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK) 113962306a36Sopenharmony_ci << CODADX6_PICWIDTH_OFFSET; 114062306a36Sopenharmony_ci value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK) 114162306a36Sopenharmony_ci << CODA_PICHEIGHT_OFFSET; 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci case CODA_HX4: 114462306a36Sopenharmony_ci case CODA_7541: 114562306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_H264) { 114662306a36Sopenharmony_ci value = (round_up(q_data_src->rect.width, 16) & 114762306a36Sopenharmony_ci CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; 114862306a36Sopenharmony_ci value |= (round_up(q_data_src->rect.height, 16) & 114962306a36Sopenharmony_ci CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; 115062306a36Sopenharmony_ci break; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci fallthrough; 115362306a36Sopenharmony_ci case CODA_960: 115462306a36Sopenharmony_ci value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) 115562306a36Sopenharmony_ci << CODA7_PICWIDTH_OFFSET; 115662306a36Sopenharmony_ci value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK) 115762306a36Sopenharmony_ci << CODA_PICHEIGHT_OFFSET; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); 116062306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_JPEG) 116162306a36Sopenharmony_ci ctx->params.framerate = 0; 116262306a36Sopenharmony_ci coda_write(dev, ctx->params.framerate, 116362306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_SRC_F_RATE); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci ctx->params.codec_mode = ctx->codec->mode; 116662306a36Sopenharmony_ci switch (dst_fourcc) { 116762306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 116862306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 116962306a36Sopenharmony_ci coda_write(dev, CODA9_STD_MPEG4, 117062306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 117162306a36Sopenharmony_ci else 117262306a36Sopenharmony_ci coda_write(dev, CODA_STD_MPEG4, 117362306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 117462306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 117762306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 117862306a36Sopenharmony_ci coda_write(dev, CODA9_STD_H264, 117962306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 118062306a36Sopenharmony_ci else 118162306a36Sopenharmony_ci coda_write(dev, CODA_STD_H264, 118262306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 118362306a36Sopenharmony_ci value = ((ctx->params.h264_disable_deblocking_filter_idc & 118462306a36Sopenharmony_ci CODA_264PARAM_DISABLEDEBLK_MASK) << 118562306a36Sopenharmony_ci CODA_264PARAM_DISABLEDEBLK_OFFSET) | 118662306a36Sopenharmony_ci ((ctx->params.h264_slice_alpha_c0_offset_div2 & 118762306a36Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << 118862306a36Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | 118962306a36Sopenharmony_ci ((ctx->params.h264_slice_beta_offset_div2 & 119062306a36Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << 119162306a36Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | 119262306a36Sopenharmony_ci (ctx->params.h264_constrained_intra_pred_flag << 119362306a36Sopenharmony_ci CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | 119462306a36Sopenharmony_ci (ctx->params.h264_chroma_qp_index_offset & 119562306a36Sopenharmony_ci CODA_264PARAM_CHROMAQPOFFSET_MASK); 119662306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 119962306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); 120062306a36Sopenharmony_ci coda_write(dev, ctx->params.jpeg_restart_interval, 120162306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); 120262306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); 120362306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); 120462306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci coda_jpeg_write_tables(ctx); 120762306a36Sopenharmony_ci break; 120862306a36Sopenharmony_ci default: 120962306a36Sopenharmony_ci v4l2_err(v4l2_dev, 121062306a36Sopenharmony_ci "dst format (0x%08x) invalid.\n", dst_fourcc); 121162306a36Sopenharmony_ci ret = -EINVAL; 121262306a36Sopenharmony_ci goto out; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci /* 121662306a36Sopenharmony_ci * slice mode and GOP size registers are used for thumb size/offset 121762306a36Sopenharmony_ci * in JPEG mode 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_ci if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 122062306a36Sopenharmony_ci value = coda_slice_mode(ctx); 122162306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); 122262306a36Sopenharmony_ci value = ctx->params.gop_size; 122362306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (ctx->params.bitrate && (ctx->params.frame_rc_enable || 122762306a36Sopenharmony_ci ctx->params.mb_rc_enable)) { 122862306a36Sopenharmony_ci ctx->params.bitrate_changed = false; 122962306a36Sopenharmony_ci ctx->params.h264_intra_qp_changed = false; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci /* Rate control enabled */ 123262306a36Sopenharmony_ci value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) 123362306a36Sopenharmony_ci << CODA_RATECONTROL_BITRATE_OFFSET; 123462306a36Sopenharmony_ci value |= 1 & CODA_RATECONTROL_ENABLE_MASK; 123562306a36Sopenharmony_ci value |= (ctx->params.vbv_delay & 123662306a36Sopenharmony_ci CODA_RATECONTROL_INITIALDELAY_MASK) 123762306a36Sopenharmony_ci << CODA_RATECONTROL_INITIALDELAY_OFFSET; 123862306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 123962306a36Sopenharmony_ci value |= BIT(31); /* disable autoskip */ 124062306a36Sopenharmony_ci } else { 124162306a36Sopenharmony_ci value = 0; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); 124662306a36Sopenharmony_ci coda_write(dev, ctx->params.intra_refresh, 124762306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_INTRA_REFRESH); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); 125062306a36Sopenharmony_ci coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci value = 0; 125462306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 125562306a36Sopenharmony_ci gamma = CODA9_DEFAULT_GAMMA; 125662306a36Sopenharmony_ci else 125762306a36Sopenharmony_ci gamma = CODA_DEFAULT_GAMMA; 125862306a36Sopenharmony_ci if (gamma > 0) { 125962306a36Sopenharmony_ci coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, 126062306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_RC_GAMMA); 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { 126462306a36Sopenharmony_ci coda_write(dev, 126562306a36Sopenharmony_ci ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | 126662306a36Sopenharmony_ci ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, 126762306a36Sopenharmony_ci CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 127062306a36Sopenharmony_ci if (ctx->params.h264_max_qp) 127162306a36Sopenharmony_ci value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; 127262306a36Sopenharmony_ci if (CODA_DEFAULT_GAMMA > 0) 127362306a36Sopenharmony_ci value |= 1 << CODA9_OPTION_GAMMA_OFFSET; 127462306a36Sopenharmony_ci } else { 127562306a36Sopenharmony_ci if (CODA_DEFAULT_GAMMA > 0) { 127662306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 127762306a36Sopenharmony_ci value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; 127862306a36Sopenharmony_ci else 127962306a36Sopenharmony_ci value |= 1 << CODA7_OPTION_GAMMA_OFFSET; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci if (ctx->params.h264_min_qp) 128262306a36Sopenharmony_ci value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; 128362306a36Sopenharmony_ci if (ctx->params.h264_max_qp) 128462306a36Sopenharmony_ci value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable) 128962306a36Sopenharmony_ci value = 1; 129062306a36Sopenharmony_ci else 129162306a36Sopenharmony_ci value = 0; 129262306a36Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci coda_setup_iram(ctx); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_H264) { 129762306a36Sopenharmony_ci switch (dev->devtype->product) { 129862306a36Sopenharmony_ci case CODA_DX6: 129962306a36Sopenharmony_ci value = FMO_SLICE_SAVE_BUF_SIZE << 7; 130062306a36Sopenharmony_ci coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); 130162306a36Sopenharmony_ci break; 130262306a36Sopenharmony_ci case CODA_HX4: 130362306a36Sopenharmony_ci case CODA_7541: 130462306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.search_ram_paddr, 130562306a36Sopenharmony_ci CODA7_CMD_ENC_SEQ_SEARCH_BASE); 130662306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.search_ram_size, 130762306a36Sopenharmony_ci CODA7_CMD_ENC_SEQ_SEARCH_SIZE); 130862306a36Sopenharmony_ci break; 130962306a36Sopenharmony_ci case CODA_960: 131062306a36Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); 131162306a36Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 131662306a36Sopenharmony_ci if (ret < 0) { 131762306a36Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 131862306a36Sopenharmony_ci goto out; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { 132262306a36Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); 132362306a36Sopenharmony_ci ret = -EFAULT; 132462306a36Sopenharmony_ci goto out; 132562306a36Sopenharmony_ci } 132662306a36Sopenharmony_ci ctx->initialized = 1; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 132962306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 133062306a36Sopenharmony_ci ctx->num_internal_frames = 4; 133162306a36Sopenharmony_ci else 133262306a36Sopenharmony_ci ctx->num_internal_frames = 2; 133362306a36Sopenharmony_ci ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); 133462306a36Sopenharmony_ci if (ret < 0) { 133562306a36Sopenharmony_ci v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); 133662306a36Sopenharmony_ci goto out; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci num_fb = 2; 133962306a36Sopenharmony_ci stride = q_data_src->bytesperline; 134062306a36Sopenharmony_ci } else { 134162306a36Sopenharmony_ci ctx->num_internal_frames = 0; 134262306a36Sopenharmony_ci num_fb = 0; 134362306a36Sopenharmony_ci stride = 0; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); 134662306a36Sopenharmony_ci coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 134962306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 135062306a36Sopenharmony_ci coda_write(dev, q_data_src->bytesperline, 135162306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 135462306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_bit_use, 135562306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 135662306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 135762306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 135862306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_y_use, 135962306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 136062306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_c_use, 136162306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 136262306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ovl_use, 136362306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 136462306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 136562306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_btp_use, 136662306a36Sopenharmony_ci CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci coda9_set_frame_cache(ctx, q_data_src->fourcc); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* FIXME */ 137162306a36Sopenharmony_ci coda_write(dev, ctx->internal_frames[2].buf.paddr, 137262306a36Sopenharmony_ci CODA9_CMD_SET_FRAME_SUBSAMP_A); 137362306a36Sopenharmony_ci coda_write(dev, ctx->internal_frames[3].buf.paddr, 137462306a36Sopenharmony_ci CODA9_CMD_SET_FRAME_SUBSAMP_B); 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); 137962306a36Sopenharmony_ci if (ret < 0) { 138062306a36Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 138162306a36Sopenharmony_ci goto out; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", 138562306a36Sopenharmony_ci q_data_src->rect.width, q_data_src->rect.height, 138662306a36Sopenharmony_ci (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, 138762306a36Sopenharmony_ci ctx->params.framerate & 0xffff, 138862306a36Sopenharmony_ci (ctx->params.framerate >> 16) + 1); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Save stream headers */ 139162306a36Sopenharmony_ci buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 139262306a36Sopenharmony_ci switch (dst_fourcc) { 139362306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 139462306a36Sopenharmony_ci /* 139562306a36Sopenharmony_ci * Get SPS in the first frame and copy it to an 139662306a36Sopenharmony_ci * intermediate buffer. 139762306a36Sopenharmony_ci */ 139862306a36Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, 139962306a36Sopenharmony_ci &ctx->vpu_header[0][0], 140062306a36Sopenharmony_ci &ctx->vpu_header_size[0]); 140162306a36Sopenharmony_ci if (ret < 0) 140262306a36Sopenharmony_ci goto out; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci /* 140562306a36Sopenharmony_ci * If visible width or height are not aligned to macroblock 140662306a36Sopenharmony_ci * size, the crop_right and crop_bottom SPS fields must be set 140762306a36Sopenharmony_ci * to the difference between visible and coded size. This is 140862306a36Sopenharmony_ci * only supported by CODA960 firmware. All others do not allow 140962306a36Sopenharmony_ci * writing frame cropping parameters, so we have to manually 141062306a36Sopenharmony_ci * fix up the SPS RBSP (Sequence Parameter Set Raw Byte 141162306a36Sopenharmony_ci * Sequence Payload) ourselves. 141262306a36Sopenharmony_ci */ 141362306a36Sopenharmony_ci if (ctx->dev->devtype->product != CODA_960 && 141462306a36Sopenharmony_ci ((q_data_src->rect.width % 16) || 141562306a36Sopenharmony_ci (q_data_src->rect.height % 16))) { 141662306a36Sopenharmony_ci ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, 141762306a36Sopenharmony_ci q_data_src->rect.height, 141862306a36Sopenharmony_ci &ctx->vpu_header[0][0], 141962306a36Sopenharmony_ci &ctx->vpu_header_size[0], 142062306a36Sopenharmony_ci sizeof(ctx->vpu_header[0])); 142162306a36Sopenharmony_ci if (ret < 0) 142262306a36Sopenharmony_ci goto out; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci /* 142662306a36Sopenharmony_ci * Get PPS in the first frame and copy it to an 142762306a36Sopenharmony_ci * intermediate buffer. 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, 143062306a36Sopenharmony_ci &ctx->vpu_header[1][0], 143162306a36Sopenharmony_ci &ctx->vpu_header_size[1]); 143262306a36Sopenharmony_ci if (ret < 0) 143362306a36Sopenharmony_ci goto out; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci /* 143662306a36Sopenharmony_ci * Length of H.264 headers is variable and thus it might not be 143762306a36Sopenharmony_ci * aligned for the coda to append the encoded frame. In that is 143862306a36Sopenharmony_ci * the case a filler NAL must be added to header 2. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci ctx->vpu_header_size[2] = coda_h264_padding( 144162306a36Sopenharmony_ci (ctx->vpu_header_size[0] + 144262306a36Sopenharmony_ci ctx->vpu_header_size[1]), 144362306a36Sopenharmony_ci ctx->vpu_header[2]); 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 144662306a36Sopenharmony_ci /* 144762306a36Sopenharmony_ci * Get VOS in the first frame and copy it to an 144862306a36Sopenharmony_ci * intermediate buffer 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, 145162306a36Sopenharmony_ci &ctx->vpu_header[0][0], 145262306a36Sopenharmony_ci &ctx->vpu_header_size[0]); 145362306a36Sopenharmony_ci if (ret < 0) 145462306a36Sopenharmony_ci goto out; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, 145762306a36Sopenharmony_ci &ctx->vpu_header[1][0], 145862306a36Sopenharmony_ci &ctx->vpu_header_size[1]); 145962306a36Sopenharmony_ci if (ret < 0) 146062306a36Sopenharmony_ci goto out; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, 146362306a36Sopenharmony_ci &ctx->vpu_header[2][0], 146462306a36Sopenharmony_ci &ctx->vpu_header_size[2]); 146562306a36Sopenharmony_ci if (ret < 0) 146662306a36Sopenharmony_ci goto out; 146762306a36Sopenharmony_ci break; 146862306a36Sopenharmony_ci default: 146962306a36Sopenharmony_ci /* No more formats need to save headers at the moment */ 147062306a36Sopenharmony_ci break; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ciout: 147462306a36Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 147562306a36Sopenharmony_ci return ret; 147662306a36Sopenharmony_ci} 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_cistatic int coda_prepare_encode(struct coda_ctx *ctx) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 148162306a36Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, *dst_buf; 148262306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 148362306a36Sopenharmony_ci int force_ipicture; 148462306a36Sopenharmony_ci int quant_param = 0; 148562306a36Sopenharmony_ci u32 pic_stream_buffer_addr, pic_stream_buffer_size; 148662306a36Sopenharmony_ci u32 rot_mode = 0; 148762306a36Sopenharmony_ci u32 dst_fourcc; 148862306a36Sopenharmony_ci u32 reg; 148962306a36Sopenharmony_ci int ret; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci ret = coda_enc_param_change(ctx); 149262306a36Sopenharmony_ci if (ret < 0) { 149362306a36Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", 149462306a36Sopenharmony_ci ret); 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 149862306a36Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 149962306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 150062306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 150162306a36Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci src_buf->sequence = ctx->osequence; 150462306a36Sopenharmony_ci dst_buf->sequence = ctx->osequence; 150562306a36Sopenharmony_ci ctx->osequence++; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci force_ipicture = ctx->params.force_ipicture; 150862306a36Sopenharmony_ci if (force_ipicture) 150962306a36Sopenharmony_ci ctx->params.force_ipicture = false; 151062306a36Sopenharmony_ci else if (ctx->params.gop_size != 0 && 151162306a36Sopenharmony_ci (src_buf->sequence % ctx->params.gop_size) == 0) 151262306a36Sopenharmony_ci force_ipicture = 1; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci /* 151562306a36Sopenharmony_ci * Workaround coda firmware BUG that only marks the first 151662306a36Sopenharmony_ci * frame as IDR. This is a problem for some decoders that can't 151762306a36Sopenharmony_ci * recover when a frame is lost. 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ci if (!force_ipicture) { 152062306a36Sopenharmony_ci src_buf->flags |= V4L2_BUF_FLAG_PFRAME; 152162306a36Sopenharmony_ci src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; 152262306a36Sopenharmony_ci } else { 152362306a36Sopenharmony_ci src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 152462306a36Sopenharmony_ci src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 152862306a36Sopenharmony_ci coda_set_gdi_regs(ctx); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* 153162306a36Sopenharmony_ci * Copy headers in front of the first frame and forced I frames for 153262306a36Sopenharmony_ci * H.264 only. In MPEG4 they are already copied by the CODA. 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci if (src_buf->sequence == 0 || force_ipicture) { 153562306a36Sopenharmony_ci pic_stream_buffer_addr = 153662306a36Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) + 153762306a36Sopenharmony_ci ctx->vpu_header_size[0] + 153862306a36Sopenharmony_ci ctx->vpu_header_size[1] + 153962306a36Sopenharmony_ci ctx->vpu_header_size[2]; 154062306a36Sopenharmony_ci pic_stream_buffer_size = q_data_dst->sizeimage - 154162306a36Sopenharmony_ci ctx->vpu_header_size[0] - 154262306a36Sopenharmony_ci ctx->vpu_header_size[1] - 154362306a36Sopenharmony_ci ctx->vpu_header_size[2]; 154462306a36Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0), 154562306a36Sopenharmony_ci &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); 154662306a36Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 154762306a36Sopenharmony_ci + ctx->vpu_header_size[0], &ctx->vpu_header[1][0], 154862306a36Sopenharmony_ci ctx->vpu_header_size[1]); 154962306a36Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 155062306a36Sopenharmony_ci + ctx->vpu_header_size[0] + ctx->vpu_header_size[1], 155162306a36Sopenharmony_ci &ctx->vpu_header[2][0], ctx->vpu_header_size[2]); 155262306a36Sopenharmony_ci } else { 155362306a36Sopenharmony_ci pic_stream_buffer_addr = 155462306a36Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); 155562306a36Sopenharmony_ci pic_stream_buffer_size = q_data_dst->sizeimage; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (force_ipicture) { 155962306a36Sopenharmony_ci switch (dst_fourcc) { 156062306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 156162306a36Sopenharmony_ci quant_param = ctx->params.h264_intra_qp; 156262306a36Sopenharmony_ci break; 156362306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 156462306a36Sopenharmony_ci quant_param = ctx->params.mpeg4_intra_qp; 156562306a36Sopenharmony_ci break; 156662306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 156762306a36Sopenharmony_ci quant_param = 30; 156862306a36Sopenharmony_ci break; 156962306a36Sopenharmony_ci default: 157062306a36Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 157162306a36Sopenharmony_ci "cannot set intra qp, fmt not supported\n"); 157262306a36Sopenharmony_ci break; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci } else { 157562306a36Sopenharmony_ci switch (dst_fourcc) { 157662306a36Sopenharmony_ci case V4L2_PIX_FMT_H264: 157762306a36Sopenharmony_ci quant_param = ctx->params.h264_inter_qp; 157862306a36Sopenharmony_ci break; 157962306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 158062306a36Sopenharmony_ci quant_param = ctx->params.mpeg4_inter_qp; 158162306a36Sopenharmony_ci break; 158262306a36Sopenharmony_ci default: 158362306a36Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 158462306a36Sopenharmony_ci "cannot set inter qp, fmt not supported\n"); 158562306a36Sopenharmony_ci break; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* submit */ 159062306a36Sopenharmony_ci if (ctx->params.rot_mode) 159162306a36Sopenharmony_ci rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 159262306a36Sopenharmony_ci coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); 159362306a36Sopenharmony_ci coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 159662306a36Sopenharmony_ci coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); 159762306a36Sopenharmony_ci coda_write(dev, q_data_src->bytesperline, 159862306a36Sopenharmony_ci CODA9_CMD_ENC_PIC_SRC_STRIDE); 159962306a36Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; 160262306a36Sopenharmony_ci } else { 160362306a36Sopenharmony_ci reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci coda_write_base(ctx, q_data_src, src_buf, reg); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci coda_write(dev, force_ipicture << 1 & 0x2, 160862306a36Sopenharmony_ci CODA_CMD_ENC_PIC_OPTION); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); 161162306a36Sopenharmony_ci coda_write(dev, pic_stream_buffer_size / 1024, 161262306a36Sopenharmony_ci CODA_CMD_ENC_PIC_BB_SIZE); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (!ctx->streamon_out) { 161562306a36Sopenharmony_ci /* After streamoff on the output side, set stream end flag */ 161662306a36Sopenharmony_ci ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 161762306a36Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 161862306a36Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 162262306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.axi_sram_use, 162362306a36Sopenharmony_ci CODA7_REG_BIT_AXI_SRAM_USE); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci trace_coda_enc_pic_run(ctx, src_buf); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci return 0; 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic char coda_frame_type_char(u32 flags) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 163562306a36Sopenharmony_ci (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 163662306a36Sopenharmony_ci (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic void coda_finish_encode(struct coda_ctx *ctx) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, *dst_buf; 164262306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 164362306a36Sopenharmony_ci u32 wr_ptr, start_ptr; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (ctx->aborting) 164662306a36Sopenharmony_ci return; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* 164962306a36Sopenharmony_ci * Lock to make sure that an encoder stop command running in parallel 165062306a36Sopenharmony_ci * will either already have marked src_buf as last, or it will wake up 165162306a36Sopenharmony_ci * the capture queue after the buffers are returned. 165262306a36Sopenharmony_ci */ 165362306a36Sopenharmony_ci mutex_lock(&ctx->wakeup_mutex); 165462306a36Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 165562306a36Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci trace_coda_enc_pic_done(ctx, dst_buf); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* Get results from the coda */ 166062306a36Sopenharmony_ci start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); 166162306a36Sopenharmony_ci wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* Calculate bytesused field */ 166462306a36Sopenharmony_ci if (dst_buf->sequence == 0 || 166562306a36Sopenharmony_ci src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { 166662306a36Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr + 166762306a36Sopenharmony_ci ctx->vpu_header_size[0] + 166862306a36Sopenharmony_ci ctx->vpu_header_size[1] + 166962306a36Sopenharmony_ci ctx->vpu_header_size[2]); 167062306a36Sopenharmony_ci } else { 167162306a36Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); 167762306a36Sopenharmony_ci coda_read(dev, CODA_RET_ENC_PIC_FLAG); 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 168062306a36Sopenharmony_ci V4L2_BUF_FLAG_PFRAME | 168162306a36Sopenharmony_ci V4L2_BUF_FLAG_LAST); 168262306a36Sopenharmony_ci if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) 168362306a36Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 168462306a36Sopenharmony_ci else 168562306a36Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; 168662306a36Sopenharmony_ci dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 169362306a36Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 169462306a36Sopenharmony_ci mutex_unlock(&ctx->wakeup_mutex); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci ctx->gopcounter--; 169762306a36Sopenharmony_ci if (ctx->gopcounter < 0) 169862306a36Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", 170162306a36Sopenharmony_ci coda_frame_type_char(dst_buf->flags), dst_buf->sequence, 170262306a36Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void coda_seq_end_work(struct work_struct *work) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); 170862306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 171162306a36Sopenharmony_ci mutex_lock(&dev->coda_mutex); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (ctx->initialized == 0) 171462306a36Sopenharmony_ci goto out; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); 171762306a36Sopenharmony_ci if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { 171862306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 171962306a36Sopenharmony_ci "CODA_COMMAND_SEQ_END failed\n"); 172062306a36Sopenharmony_ci } 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci /* 172362306a36Sopenharmony_ci * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing 172462306a36Sopenharmony_ci * from the output stream after the h.264 decoder has run. Resetting the 172562306a36Sopenharmony_ci * hardware after the decoder has finished seems to help. 172662306a36Sopenharmony_ci */ 172762306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 172862306a36Sopenharmony_ci coda_hw_reset(ctx); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 173162306a36Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci coda_free_framebuffers(ctx); 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci ctx->initialized = 0; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ciout: 173862306a36Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 173962306a36Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic void coda_bit_release(struct coda_ctx *ctx) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 174562306a36Sopenharmony_ci coda_free_framebuffers(ctx); 174662306a36Sopenharmony_ci coda_free_context_buffers(ctx); 174762306a36Sopenharmony_ci coda_free_bitstream_buffer(ctx); 174862306a36Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ciconst struct coda_context_ops coda_bit_encode_ops = { 175262306a36Sopenharmony_ci .queue_init = coda_encoder_queue_init, 175362306a36Sopenharmony_ci .reqbufs = coda_encoder_reqbufs, 175462306a36Sopenharmony_ci .start_streaming = coda_start_encoding, 175562306a36Sopenharmony_ci .prepare_run = coda_prepare_encode, 175662306a36Sopenharmony_ci .finish_run = coda_finish_encode, 175762306a36Sopenharmony_ci .seq_end_work = coda_seq_end_work, 175862306a36Sopenharmony_ci .release = coda_bit_release, 175962306a36Sopenharmony_ci}; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci/* 176262306a36Sopenharmony_ci * Decoder context operations 176362306a36Sopenharmony_ci */ 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, 176662306a36Sopenharmony_ci struct coda_q_data *q_data) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci if (ctx->bitstream.vaddr) 176962306a36Sopenharmony_ci return 0; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); 177262306a36Sopenharmony_ci ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, 177362306a36Sopenharmony_ci &ctx->bitstream.paddr, GFP_KERNEL); 177462306a36Sopenharmony_ci if (!ctx->bitstream.vaddr) { 177562306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 177662306a36Sopenharmony_ci "failed to allocate bitstream ringbuffer"); 177762306a36Sopenharmony_ci return -ENOMEM; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 178062306a36Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci return 0; 178362306a36Sopenharmony_ci} 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx) 178662306a36Sopenharmony_ci{ 178762306a36Sopenharmony_ci if (ctx->bitstream.vaddr == NULL) 178862306a36Sopenharmony_ci return; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, 179162306a36Sopenharmony_ci ctx->bitstream.paddr); 179262306a36Sopenharmony_ci ctx->bitstream.vaddr = NULL; 179362306a36Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, NULL, 0); 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_cistatic int coda_decoder_reqbufs(struct coda_ctx *ctx, 179762306a36Sopenharmony_ci struct v4l2_requestbuffers *rb) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci struct coda_q_data *q_data_src; 180062306a36Sopenharmony_ci int ret; 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 180362306a36Sopenharmony_ci return 0; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci if (rb->count) { 180662306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 180762306a36Sopenharmony_ci ret = coda_alloc_context_buffers(ctx, q_data_src); 180862306a36Sopenharmony_ci if (ret < 0) 180962306a36Sopenharmony_ci return ret; 181062306a36Sopenharmony_ci ret = coda_alloc_bitstream_buffer(ctx, q_data_src); 181162306a36Sopenharmony_ci if (ret < 0) { 181262306a36Sopenharmony_ci coda_free_context_buffers(ctx); 181362306a36Sopenharmony_ci return ret; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci } else { 181662306a36Sopenharmony_ci coda_free_bitstream_buffer(ctx); 181762306a36Sopenharmony_ci coda_free_context_buffers(ctx); 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci return 0; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic bool coda_reorder_enable(struct coda_ctx *ctx) 182462306a36Sopenharmony_ci{ 182562306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 182662306a36Sopenharmony_ci int profile; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (dev->devtype->product != CODA_HX4 && 182962306a36Sopenharmony_ci dev->devtype->product != CODA_7541 && 183062306a36Sopenharmony_ci dev->devtype->product != CODA_960) 183162306a36Sopenharmony_ci return false; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 183462306a36Sopenharmony_ci return false; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) 183762306a36Sopenharmony_ci return true; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci profile = coda_h264_profile(ctx->params.h264_profile_idc); 184062306a36Sopenharmony_ci if (profile < 0) 184162306a36Sopenharmony_ci v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", 184262306a36Sopenharmony_ci ctx->params.h264_profile_idc); 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* Baseline profile does not support reordering */ 184562306a36Sopenharmony_ci return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic void coda_decoder_drop_used_metas(struct coda_ctx *ctx) 184962306a36Sopenharmony_ci{ 185062306a36Sopenharmony_ci struct coda_buffer_meta *meta, *tmp; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci /* 185362306a36Sopenharmony_ci * All metas that end at or before the RD pointer (fifo out), 185462306a36Sopenharmony_ci * are now consumed by the VPU and should be released. 185562306a36Sopenharmony_ci */ 185662306a36Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 185762306a36Sopenharmony_ci list_for_each_entry_safe(meta, tmp, &ctx->buffer_meta_list, list) { 185862306a36Sopenharmony_ci if (ctx->bitstream_fifo.kfifo.out >= meta->end) { 185962306a36Sopenharmony_ci coda_dbg(2, ctx, "releasing meta: seq=%d start=%d end=%d\n", 186062306a36Sopenharmony_ci meta->sequence, meta->start, meta->end); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci list_del(&meta->list); 186362306a36Sopenharmony_ci ctx->num_metas--; 186462306a36Sopenharmony_ci ctx->first_frame_sequence++; 186562306a36Sopenharmony_ci kfree(meta); 186662306a36Sopenharmony_ci } 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 186962306a36Sopenharmony_ci} 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_cistatic int __coda_decoder_seq_init(struct coda_ctx *ctx) 187262306a36Sopenharmony_ci{ 187362306a36Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 187462306a36Sopenharmony_ci u32 bitstream_buf, bitstream_size; 187562306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 187662306a36Sopenharmony_ci int width, height; 187762306a36Sopenharmony_ci u32 src_fourcc, dst_fourcc; 187862306a36Sopenharmony_ci u32 val; 187962306a36Sopenharmony_ci int ret; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", 188462306a36Sopenharmony_ci ctx->use_vdoa ? "Enabled" : "Disabled"); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* Start decoding */ 188762306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 188862306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 188962306a36Sopenharmony_ci bitstream_buf = ctx->bitstream.paddr; 189062306a36Sopenharmony_ci bitstream_size = ctx->bitstream.size; 189162306a36Sopenharmony_ci src_fourcc = q_data_src->fourcc; 189262306a36Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci /* Update coda bitstream read and write pointers from kfifo */ 189562306a36Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 189862306a36Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 189962306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 190062306a36Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 190162306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 190262306a36Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | 190362306a36Sopenharmony_ci ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 190462306a36Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci ctx->display_idx = -1; 190762306a36Sopenharmony_ci ctx->frm_dis_flg = 0; 190862306a36Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); 191162306a36Sopenharmony_ci coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); 191262306a36Sopenharmony_ci val = 0; 191362306a36Sopenharmony_ci if (coda_reorder_enable(ctx)) 191462306a36Sopenharmony_ci val |= CODA_REORDER_ENABLE; 191562306a36Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 191662306a36Sopenharmony_ci val |= CODA_NO_INT_ENABLE; 191762306a36Sopenharmony_ci coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci ctx->params.codec_mode = ctx->codec->mode; 192062306a36Sopenharmony_ci if (dev->devtype->product == CODA_960 && 192162306a36Sopenharmony_ci src_fourcc == V4L2_PIX_FMT_MPEG4) 192262306a36Sopenharmony_ci ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; 192362306a36Sopenharmony_ci else 192462306a36Sopenharmony_ci ctx->params.codec_mode_aux = 0; 192562306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_MPEG4) { 192662306a36Sopenharmony_ci coda_write(dev, CODA_MP4_CLASS_MPEG4, 192762306a36Sopenharmony_ci CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 193062306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 193162306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 193262306a36Sopenharmony_ci coda_write(dev, ctx->psbuf.paddr, 193362306a36Sopenharmony_ci CODA_CMD_DEC_SEQ_PS_BB_START); 193462306a36Sopenharmony_ci coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), 193562306a36Sopenharmony_ci CODA_CMD_DEC_SEQ_PS_BB_SIZE); 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 193862306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); 193962306a36Sopenharmony_ci coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_JPEG) 194362306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN); 194462306a36Sopenharmony_ci if (dev->devtype->product != CODA_960) 194562306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; 194862306a36Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 194962306a36Sopenharmony_ci ctx->bit_stream_param = 0; 195062306a36Sopenharmony_ci if (ret) { 195162306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 195262306a36Sopenharmony_ci return ret; 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci ctx->sequence_offset = ~0U; 195562306a36Sopenharmony_ci ctx->initialized = 1; 195662306a36Sopenharmony_ci ctx->first_frame_sequence = 0; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci /* Update kfifo out pointer from coda bitstream read pointer */ 195962306a36Sopenharmony_ci coda_kfifo_sync_from_device(ctx); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci /* 196262306a36Sopenharmony_ci * After updating the read pointer, we need to check if 196362306a36Sopenharmony_ci * any metas are consumed and should be released. 196462306a36Sopenharmony_ci */ 196562306a36Sopenharmony_ci coda_decoder_drop_used_metas(ctx); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { 196862306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 196962306a36Sopenharmony_ci "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", 197062306a36Sopenharmony_ci coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); 197162306a36Sopenharmony_ci return -EAGAIN; 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); 197562306a36Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 197662306a36Sopenharmony_ci width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; 197762306a36Sopenharmony_ci height = val & CODADX6_PICHEIGHT_MASK; 197862306a36Sopenharmony_ci } else { 197962306a36Sopenharmony_ci width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; 198062306a36Sopenharmony_ci height = val & CODA7_PICHEIGHT_MASK; 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (width > q_data_dst->bytesperline || height > q_data_dst->height) { 198462306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", 198562306a36Sopenharmony_ci width, height, q_data_dst->bytesperline, 198662306a36Sopenharmony_ci q_data_dst->height); 198762306a36Sopenharmony_ci return -EINVAL; 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci width = round_up(width, 16); 199162306a36Sopenharmony_ci height = round_up(height, 16); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); 199662306a36Sopenharmony_ci /* 199762306a36Sopenharmony_ci * If the VDOA is used, the decoder needs one additional frame, 199862306a36Sopenharmony_ci * because the frames are freed when the next frame is decoded. 199962306a36Sopenharmony_ci * Otherwise there are visible errors in the decoded frames (green 200062306a36Sopenharmony_ci * regions in displayed frames) and a broken order of frames (earlier 200162306a36Sopenharmony_ci * frames are sporadically displayed after later frames). 200262306a36Sopenharmony_ci */ 200362306a36Sopenharmony_ci if (ctx->use_vdoa) 200462306a36Sopenharmony_ci ctx->num_internal_frames += 1; 200562306a36Sopenharmony_ci if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { 200662306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 200762306a36Sopenharmony_ci "not enough framebuffers to decode (%d < %d)\n", 200862306a36Sopenharmony_ci CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); 200962306a36Sopenharmony_ci return -EINVAL; 201062306a36Sopenharmony_ci } 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 201362306a36Sopenharmony_ci u32 left_right; 201462306a36Sopenharmony_ci u32 top_bottom; 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); 201762306a36Sopenharmony_ci top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci q_data_dst->rect.left = (left_right >> 10) & 0x3ff; 202062306a36Sopenharmony_ci q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; 202162306a36Sopenharmony_ci q_data_dst->rect.width = width - q_data_dst->rect.left - 202262306a36Sopenharmony_ci (left_right & 0x3ff); 202362306a36Sopenharmony_ci q_data_dst->rect.height = height - q_data_dst->rect.top - 202462306a36Sopenharmony_ci (top_bottom & 0x3ff); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 202862306a36Sopenharmony_ci u8 profile, level; 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); 203162306a36Sopenharmony_ci profile = val & 0xff; 203262306a36Sopenharmony_ci level = (val >> 8) & 0x7f; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (profile || level) 203562306a36Sopenharmony_ci coda_update_profile_level_ctrls(ctx, profile, level); 203662306a36Sopenharmony_ci } 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci return 0; 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic void coda_dec_seq_init_work(struct work_struct *work) 204262306a36Sopenharmony_ci{ 204362306a36Sopenharmony_ci struct coda_ctx *ctx = container_of(work, 204462306a36Sopenharmony_ci struct coda_ctx, seq_init_work); 204562306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 204862306a36Sopenharmony_ci mutex_lock(&dev->coda_mutex); 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci if (!ctx->initialized) 205162306a36Sopenharmony_ci __coda_decoder_seq_init(ctx); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 205462306a36Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cistatic int __coda_start_decoding(struct coda_ctx *ctx) 205862306a36Sopenharmony_ci{ 205962306a36Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 206062306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 206162306a36Sopenharmony_ci u32 src_fourcc, dst_fourcc; 206262306a36Sopenharmony_ci int ret; 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 206562306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 206662306a36Sopenharmony_ci src_fourcc = q_data_src->fourcc; 206762306a36Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci if (!ctx->initialized) { 207062306a36Sopenharmony_ci ret = __coda_decoder_seq_init(ctx); 207162306a36Sopenharmony_ci if (ret < 0) 207262306a36Sopenharmony_ci return ret; 207362306a36Sopenharmony_ci } else { 207462306a36Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 207562306a36Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 207662306a36Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 207762306a36Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 207862306a36Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 207962306a36Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | 208062306a36Sopenharmony_ci ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); 208662306a36Sopenharmony_ci if (ret < 0) { 208762306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); 208862306a36Sopenharmony_ci return ret; 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* Tell the decoder how many frame buffers we allocated. */ 209262306a36Sopenharmony_ci coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); 209362306a36Sopenharmony_ci coda_write(dev, round_up(q_data_dst->rect.width, 16), 209462306a36Sopenharmony_ci CODA_CMD_SET_FRAME_BUF_STRIDE); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 209762306a36Sopenharmony_ci /* Set secondary AXI IRAM */ 209862306a36Sopenharmony_ci coda_setup_iram(ctx); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_bit_use, 210162306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 210262306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 210362306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 210462306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_y_use, 210562306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 210662306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_c_use, 210762306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 210862306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ovl_use, 210962306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 211062306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 211162306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_btp_use, 211262306a36Sopenharmony_ci CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); 211562306a36Sopenharmony_ci coda9_set_frame_cache(ctx, dst_fourcc); 211662306a36Sopenharmony_ci } 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 212062306a36Sopenharmony_ci coda_write(dev, ctx->slicebuf.paddr, 212162306a36Sopenharmony_ci CODA_CMD_SET_FRAME_SLICE_BB_START); 212262306a36Sopenharmony_ci coda_write(dev, ctx->slicebuf.size / 1024, 212362306a36Sopenharmony_ci CODA_CMD_SET_FRAME_SLICE_BB_SIZE); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 212762306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 212862306a36Sopenharmony_ci int max_mb_x = 1920 / 16; 212962306a36Sopenharmony_ci int max_mb_y = 1088 / 16; 213062306a36Sopenharmony_ci int max_mb_num = max_mb_x * max_mb_y; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 213362306a36Sopenharmony_ci CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); 213462306a36Sopenharmony_ci } else if (dev->devtype->product == CODA_960) { 213562306a36Sopenharmony_ci int max_mb_x = 1920 / 16; 213662306a36Sopenharmony_ci int max_mb_y = 1088 / 16; 213762306a36Sopenharmony_ci int max_mb_num = max_mb_x * max_mb_y; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 214062306a36Sopenharmony_ci CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { 214462306a36Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 214562306a36Sopenharmony_ci "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 214662306a36Sopenharmony_ci return -ETIMEDOUT; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic int coda_start_decoding(struct coda_ctx *ctx) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 215562306a36Sopenharmony_ci int ret; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci mutex_lock(&dev->coda_mutex); 215862306a36Sopenharmony_ci ret = __coda_start_decoding(ctx); 215962306a36Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci return ret; 216262306a36Sopenharmony_ci} 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_cistatic int coda_prepare_decode(struct coda_ctx *ctx) 216562306a36Sopenharmony_ci{ 216662306a36Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 216762306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 216862306a36Sopenharmony_ci struct coda_q_data *q_data_dst; 216962306a36Sopenharmony_ci struct coda_buffer_meta *meta; 217062306a36Sopenharmony_ci u32 rot_mode = 0; 217162306a36Sopenharmony_ci u32 reg_addr, reg_stride; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 217462306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci /* Try to copy source buffer contents into the bitstream ringbuffer */ 217762306a36Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 217862306a36Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 217962306a36Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if (coda_get_bitstream_payload(ctx) < 512 && 218262306a36Sopenharmony_ci (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { 218362306a36Sopenharmony_ci coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", 218462306a36Sopenharmony_ci coda_get_bitstream_payload(ctx)); 218562306a36Sopenharmony_ci return -EAGAIN; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* Run coda_start_decoding (again) if not yet initialized */ 218962306a36Sopenharmony_ci if (!ctx->initialized) { 219062306a36Sopenharmony_ci int ret = __coda_start_decoding(ctx); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if (ret < 0) { 219362306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); 219462306a36Sopenharmony_ci return -EAGAIN; 219562306a36Sopenharmony_ci } else { 219662306a36Sopenharmony_ci ctx->initialized = 1; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) 220162306a36Sopenharmony_ci coda_set_gdi_regs(ctx); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci if (ctx->use_vdoa && 220462306a36Sopenharmony_ci ctx->display_idx >= 0 && 220562306a36Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 220662306a36Sopenharmony_ci vdoa_device_run(ctx->vdoa, 220762306a36Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), 220862306a36Sopenharmony_ci ctx->internal_frames[ctx->display_idx].buf.paddr); 220962306a36Sopenharmony_ci } else { 221062306a36Sopenharmony_ci if (dev->devtype->product == CODA_960) { 221162306a36Sopenharmony_ci /* 221262306a36Sopenharmony_ci * It was previously assumed that the CODA960 has an 221362306a36Sopenharmony_ci * internal list of 64 buffer entries that contains 221462306a36Sopenharmony_ci * both the registered internal frame buffers as well 221562306a36Sopenharmony_ci * as the rotator buffer output, and that the ROT_INDEX 221662306a36Sopenharmony_ci * register must be set to a value between the last 221762306a36Sopenharmony_ci * internal frame buffers' index and 64. 221862306a36Sopenharmony_ci * At least on firmware version 3.1.1 it turns out that 221962306a36Sopenharmony_ci * setting ROT_INDEX to any value >= 32 causes CODA 222062306a36Sopenharmony_ci * hangups that it can not recover from with the SRC VPU 222162306a36Sopenharmony_ci * reset. 222262306a36Sopenharmony_ci * It does appear to work however, to just set it to a 222362306a36Sopenharmony_ci * fixed value in the [ctx->num_internal_frames, 31] 222462306a36Sopenharmony_ci * range, for example CODA_MAX_FRAMEBUFFERS. 222562306a36Sopenharmony_ci */ 222662306a36Sopenharmony_ci coda_write(dev, CODA_MAX_FRAMEBUFFERS, 222762306a36Sopenharmony_ci CODA9_CMD_DEC_PIC_ROT_INDEX); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; 223062306a36Sopenharmony_ci reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; 223162306a36Sopenharmony_ci } else { 223262306a36Sopenharmony_ci reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; 223362306a36Sopenharmony_ci reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; 223462306a36Sopenharmony_ci } 223562306a36Sopenharmony_ci coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); 223662306a36Sopenharmony_ci coda_write(dev, q_data_dst->bytesperline, reg_stride); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); 224262306a36Sopenharmony_ci 224362306a36Sopenharmony_ci switch (dev->devtype->product) { 224462306a36Sopenharmony_ci case CODA_DX6: 224562306a36Sopenharmony_ci /* TBD */ 224662306a36Sopenharmony_ci case CODA_HX4: 224762306a36Sopenharmony_ci case CODA_7541: 224862306a36Sopenharmony_ci coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); 224962306a36Sopenharmony_ci break; 225062306a36Sopenharmony_ci case CODA_960: 225162306a36Sopenharmony_ci /* 'hardcode to use interrupt disable mode'? */ 225262306a36Sopenharmony_ci coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); 225362306a36Sopenharmony_ci break; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); 225962306a36Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 226262306a36Sopenharmony_ci coda_write(dev, ctx->iram_info.axi_sram_use, 226362306a36Sopenharmony_ci CODA7_REG_BIT_AXI_SRAM_USE); 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 226662306a36Sopenharmony_ci meta = list_first_entry_or_null(&ctx->buffer_meta_list, 226762306a36Sopenharmony_ci struct coda_buffer_meta, list); 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* If this is the last buffer in the bitstream, add padding */ 227262306a36Sopenharmony_ci if (meta->end == ctx->bitstream_fifo.kfifo.in) { 227362306a36Sopenharmony_ci static unsigned char buf[512]; 227462306a36Sopenharmony_ci unsigned int pad; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci /* Pad to multiple of 256 and then add 256 more */ 227762306a36Sopenharmony_ci pad = ((0 - meta->end) & 0xff) + 256; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci memset(buf, 0xff, sizeof(buf)); 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci kfifo_in(&ctx->bitstream_fifo, buf, pad); 228262306a36Sopenharmony_ci } 228362306a36Sopenharmony_ci } 228462306a36Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci /* Clear decode success flag */ 228962306a36Sopenharmony_ci coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* Clear error return value */ 229262306a36Sopenharmony_ci coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci trace_coda_dec_pic_run(ctx, meta); 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci return 0; 229962306a36Sopenharmony_ci} 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_cistatic void coda_finish_decode(struct coda_ctx *ctx) 230262306a36Sopenharmony_ci{ 230362306a36Sopenharmony_ci struct coda_dev *dev = ctx->dev; 230462306a36Sopenharmony_ci struct coda_q_data *q_data_src; 230562306a36Sopenharmony_ci struct coda_q_data *q_data_dst; 230662306a36Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 230762306a36Sopenharmony_ci struct coda_buffer_meta *meta; 230862306a36Sopenharmony_ci int width, height; 230962306a36Sopenharmony_ci int decoded_idx; 231062306a36Sopenharmony_ci int display_idx; 231162306a36Sopenharmony_ci struct coda_internal_frame *decoded_frame = NULL; 231262306a36Sopenharmony_ci u32 src_fourcc; 231362306a36Sopenharmony_ci int success; 231462306a36Sopenharmony_ci u32 err_mb; 231562306a36Sopenharmony_ci int err_vdoa = 0; 231662306a36Sopenharmony_ci u32 val; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci if (ctx->aborting) 231962306a36Sopenharmony_ci return; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci /* Update kfifo out pointer from coda bitstream read pointer */ 232262306a36Sopenharmony_ci coda_kfifo_sync_from_device(ctx); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci /* 232562306a36Sopenharmony_ci * in stream-end mode, the read pointer can overshoot the write pointer 232662306a36Sopenharmony_ci * by up to 512 bytes 232762306a36Sopenharmony_ci */ 232862306a36Sopenharmony_ci if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { 232962306a36Sopenharmony_ci if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) 233062306a36Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 233162306a36Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 233562306a36Sopenharmony_ci src_fourcc = q_data_src->fourcc; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); 233862306a36Sopenharmony_ci if (val != 1) 233962306a36Sopenharmony_ci pr_err("DEC_PIC_SUCCESS = %d\n", val); 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci success = val & 0x1; 234262306a36Sopenharmony_ci if (!success) 234362306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "decode failed\n"); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 234662306a36Sopenharmony_ci if (val & (1 << 3)) 234762306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 234862306a36Sopenharmony_ci "insufficient PS buffer space (%d bytes)\n", 234962306a36Sopenharmony_ci ctx->psbuf.size); 235062306a36Sopenharmony_ci if (val & (1 << 2)) 235162306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 235262306a36Sopenharmony_ci "insufficient slice buffer space (%d bytes)\n", 235362306a36Sopenharmony_ci ctx->slicebuf.size); 235462306a36Sopenharmony_ci } 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); 235762306a36Sopenharmony_ci width = (val >> 16) & 0xffff; 235862306a36Sopenharmony_ci height = val & 0xffff; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci /* frame crop information */ 236362306a36Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 236462306a36Sopenharmony_ci u32 left_right; 236562306a36Sopenharmony_ci u32 top_bottom; 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); 236862306a36Sopenharmony_ci top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci if (left_right == 0xffffffff && top_bottom == 0xffffffff) { 237162306a36Sopenharmony_ci /* Keep current crop information */ 237262306a36Sopenharmony_ci } else { 237362306a36Sopenharmony_ci struct v4l2_rect *rect = &q_data_dst->rect; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci rect->left = left_right >> 16 & 0xffff; 237662306a36Sopenharmony_ci rect->top = top_bottom >> 16 & 0xffff; 237762306a36Sopenharmony_ci rect->width = width - rect->left - 237862306a36Sopenharmony_ci (left_right & 0xffff); 237962306a36Sopenharmony_ci rect->height = height - rect->top - 238062306a36Sopenharmony_ci (top_bottom & 0xffff); 238162306a36Sopenharmony_ci } 238262306a36Sopenharmony_ci } else { 238362306a36Sopenharmony_ci /* no cropping */ 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); 238762306a36Sopenharmony_ci if (err_mb > 0) { 238862306a36Sopenharmony_ci if (__ratelimit(&dev->mb_err_rs)) 238962306a36Sopenharmony_ci coda_dbg(1, ctx, "errors in %d macroblocks\n", err_mb); 239062306a36Sopenharmony_ci v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 239162306a36Sopenharmony_ci v4l2_ctrl_g_ctrl(ctx->mb_err_cnt_ctrl) + err_mb); 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 239562306a36Sopenharmony_ci dev->devtype->product == CODA_7541) { 239662306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); 239762306a36Sopenharmony_ci if (val == 0) { 239862306a36Sopenharmony_ci /* not enough bitstream data */ 239962306a36Sopenharmony_ci coda_dbg(1, ctx, "prescan failed: %d\n", val); 240062306a36Sopenharmony_ci ctx->hold = true; 240162306a36Sopenharmony_ci return; 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* Wait until the VDOA finished writing the previous display frame */ 240662306a36Sopenharmony_ci if (ctx->use_vdoa && 240762306a36Sopenharmony_ci ctx->display_idx >= 0 && 240862306a36Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 240962306a36Sopenharmony_ci err_vdoa = vdoa_wait_for_completion(ctx->vdoa); 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci ctx->frm_dis_flg = coda_read(dev, 241362306a36Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci /* The previous display frame was copied out and can be overwritten */ 241662306a36Sopenharmony_ci if (ctx->display_idx >= 0 && 241762306a36Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 241862306a36Sopenharmony_ci ctx->frm_dis_flg &= ~(1 << ctx->display_idx); 241962306a36Sopenharmony_ci coda_write(dev, ctx->frm_dis_flg, 242062306a36Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 242162306a36Sopenharmony_ci } 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci /* 242462306a36Sopenharmony_ci * The index of the last decoded frame, not necessarily in 242562306a36Sopenharmony_ci * display order, and the index of the next display frame. 242662306a36Sopenharmony_ci * The latter could have been decoded in a previous run. 242762306a36Sopenharmony_ci */ 242862306a36Sopenharmony_ci decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); 242962306a36Sopenharmony_ci display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci if (decoded_idx == -1) { 243262306a36Sopenharmony_ci /* no frame was decoded, but we might have a display frame */ 243362306a36Sopenharmony_ci if (display_idx >= 0 && display_idx < ctx->num_internal_frames) 243462306a36Sopenharmony_ci ctx->sequence_offset++; 243562306a36Sopenharmony_ci else if (ctx->display_idx < 0) 243662306a36Sopenharmony_ci ctx->hold = true; 243762306a36Sopenharmony_ci } else if (decoded_idx == -2) { 243862306a36Sopenharmony_ci if (ctx->display_idx >= 0 && 243962306a36Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) 244062306a36Sopenharmony_ci ctx->sequence_offset++; 244162306a36Sopenharmony_ci /* no frame was decoded, we still return remaining buffers */ 244262306a36Sopenharmony_ci } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { 244362306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 244462306a36Sopenharmony_ci "decoded frame index out of range: %d\n", decoded_idx); 244562306a36Sopenharmony_ci } else { 244662306a36Sopenharmony_ci int sequence; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci decoded_frame = &ctx->internal_frames[decoded_idx]; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); 245162306a36Sopenharmony_ci if (ctx->sequence_offset == -1) 245262306a36Sopenharmony_ci ctx->sequence_offset = val; 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci sequence = val + ctx->first_frame_sequence 245562306a36Sopenharmony_ci - ctx->sequence_offset; 245662306a36Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 245762306a36Sopenharmony_ci if (!list_empty(&ctx->buffer_meta_list)) { 245862306a36Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 245962306a36Sopenharmony_ci struct coda_buffer_meta, list); 246062306a36Sopenharmony_ci list_del(&meta->list); 246162306a36Sopenharmony_ci ctx->num_metas--; 246262306a36Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 246362306a36Sopenharmony_ci /* 246462306a36Sopenharmony_ci * Clamp counters to 16 bits for comparison, as the HW 246562306a36Sopenharmony_ci * counter rolls over at this point for h.264. This 246662306a36Sopenharmony_ci * may be different for other formats, but using 16 bits 246762306a36Sopenharmony_ci * should be enough to detect most errors and saves us 246862306a36Sopenharmony_ci * from doing different things based on the format. 246962306a36Sopenharmony_ci */ 247062306a36Sopenharmony_ci if ((sequence & 0xffff) != (meta->sequence & 0xffff)) { 247162306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 247262306a36Sopenharmony_ci "sequence number mismatch (%d(%d) != %d)\n", 247362306a36Sopenharmony_ci sequence, ctx->sequence_offset, 247462306a36Sopenharmony_ci meta->sequence); 247562306a36Sopenharmony_ci } 247662306a36Sopenharmony_ci decoded_frame->meta = *meta; 247762306a36Sopenharmony_ci kfree(meta); 247862306a36Sopenharmony_ci } else { 247962306a36Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 248062306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); 248162306a36Sopenharmony_ci memset(&decoded_frame->meta, 0, 248262306a36Sopenharmony_ci sizeof(struct coda_buffer_meta)); 248362306a36Sopenharmony_ci decoded_frame->meta.sequence = sequence; 248462306a36Sopenharmony_ci decoded_frame->meta.last = false; 248562306a36Sopenharmony_ci ctx->sequence_offset++; 248662306a36Sopenharmony_ci } 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci trace_coda_dec_pic_done(ctx, &decoded_frame->meta); 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; 249162306a36Sopenharmony_ci decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : 249262306a36Sopenharmony_ci (val == 1) ? V4L2_BUF_FLAG_PFRAME : 249362306a36Sopenharmony_ci V4L2_BUF_FLAG_BFRAME; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci decoded_frame->error = err_mb; 249662306a36Sopenharmony_ci } 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (display_idx == -1) { 249962306a36Sopenharmony_ci /* 250062306a36Sopenharmony_ci * no more frames to be decoded, but there could still 250162306a36Sopenharmony_ci * be rotator output to dequeue 250262306a36Sopenharmony_ci */ 250362306a36Sopenharmony_ci ctx->hold = true; 250462306a36Sopenharmony_ci } else if (display_idx == -3) { 250562306a36Sopenharmony_ci /* possibly prescan failure */ 250662306a36Sopenharmony_ci } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { 250762306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 250862306a36Sopenharmony_ci "presentation frame index out of range: %d\n", 250962306a36Sopenharmony_ci display_idx); 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci /* If a frame was copied out, return it */ 251362306a36Sopenharmony_ci if (ctx->display_idx >= 0 && 251462306a36Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 251562306a36Sopenharmony_ci struct coda_internal_frame *ready_frame; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci ready_frame = &ctx->internal_frames[ctx->display_idx]; 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 252062306a36Sopenharmony_ci dst_buf->sequence = ctx->osequence++; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci dst_buf->field = V4L2_FIELD_NONE; 252362306a36Sopenharmony_ci dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 252462306a36Sopenharmony_ci V4L2_BUF_FLAG_PFRAME | 252562306a36Sopenharmony_ci V4L2_BUF_FLAG_BFRAME); 252662306a36Sopenharmony_ci dst_buf->flags |= ready_frame->type; 252762306a36Sopenharmony_ci meta = &ready_frame->meta; 252862306a36Sopenharmony_ci if (meta->last && !coda_reorder_enable(ctx)) { 252962306a36Sopenharmony_ci /* 253062306a36Sopenharmony_ci * If this was the last decoded frame, and reordering 253162306a36Sopenharmony_ci * is disabled, this will be the last display frame. 253262306a36Sopenharmony_ci */ 253362306a36Sopenharmony_ci coda_dbg(1, ctx, "last meta, marking as last frame\n"); 253462306a36Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_LAST; 253562306a36Sopenharmony_ci } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && 253662306a36Sopenharmony_ci display_idx == -1) { 253762306a36Sopenharmony_ci /* 253862306a36Sopenharmony_ci * If there is no designated presentation frame anymore, 253962306a36Sopenharmony_ci * this frame has to be the last one. 254062306a36Sopenharmony_ci */ 254162306a36Sopenharmony_ci coda_dbg(1, ctx, 254262306a36Sopenharmony_ci "no more frames to return, marking as last frame\n"); 254362306a36Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_LAST; 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci dst_buf->timecode = meta->timecode; 254662306a36Sopenharmony_ci dst_buf->vb2_buf.timestamp = meta->timestamp; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci trace_coda_dec_rot_done(ctx, dst_buf, meta); 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 255162306a36Sopenharmony_ci q_data_dst->sizeimage); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (ready_frame->error || err_vdoa) 255462306a36Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 255562306a36Sopenharmony_ci else 255662306a36Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (decoded_frame) { 255962306a36Sopenharmony_ci coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", 256062306a36Sopenharmony_ci coda_frame_type_char(decoded_frame->type), 256162306a36Sopenharmony_ci decoded_frame->meta.sequence, 256262306a36Sopenharmony_ci coda_frame_type_char(dst_buf->flags), 256362306a36Sopenharmony_ci ready_frame->meta.sequence, 256462306a36Sopenharmony_ci dst_buf->sequence, ctx->qsequence, 256562306a36Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 256662306a36Sopenharmony_ci " (last)" : ""); 256762306a36Sopenharmony_ci } else { 256862306a36Sopenharmony_ci coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", 256962306a36Sopenharmony_ci decoded_idx, 257062306a36Sopenharmony_ci coda_frame_type_char(dst_buf->flags), 257162306a36Sopenharmony_ci ready_frame->meta.sequence, 257262306a36Sopenharmony_ci dst_buf->sequence, ctx->qsequence, 257362306a36Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 257462306a36Sopenharmony_ci " (last)" : ""); 257562306a36Sopenharmony_ci } 257662306a36Sopenharmony_ci } else { 257762306a36Sopenharmony_ci if (decoded_frame) { 257862306a36Sopenharmony_ci coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", 257962306a36Sopenharmony_ci coda_frame_type_char(decoded_frame->type), 258062306a36Sopenharmony_ci decoded_frame->meta.sequence, 258162306a36Sopenharmony_ci ctx->display_idx); 258262306a36Sopenharmony_ci } else { 258362306a36Sopenharmony_ci coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", 258462306a36Sopenharmony_ci decoded_idx, ctx->display_idx); 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci } 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci /* The rotator will copy the current display frame next time */ 258962306a36Sopenharmony_ci ctx->display_idx = display_idx; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci /* 259262306a36Sopenharmony_ci * The current decode run might have brought the bitstream fill level 259362306a36Sopenharmony_ci * below the size where we can start the next decode run. As userspace 259462306a36Sopenharmony_ci * might have filled the output queue completely and might thus be 259562306a36Sopenharmony_ci * blocked, we can't rely on the next qbuf to trigger the bitstream 259662306a36Sopenharmony_ci * refill. Check if we have data to refill the bitstream now. 259762306a36Sopenharmony_ci */ 259862306a36Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 259962306a36Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 260062306a36Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 260162306a36Sopenharmony_ci} 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_cistatic void coda_decode_timeout(struct coda_ctx *ctx) 260462306a36Sopenharmony_ci{ 260562306a36Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci /* 260862306a36Sopenharmony_ci * For now this only handles the case where we would deadlock with 260962306a36Sopenharmony_ci * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS, 261062306a36Sopenharmony_ci * but after a failed decode run we would hold the context and wait for 261162306a36Sopenharmony_ci * userspace to queue more buffers. 261262306a36Sopenharmony_ci */ 261362306a36Sopenharmony_ci if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)) 261462306a36Sopenharmony_ci return; 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 261762306a36Sopenharmony_ci dst_buf->sequence = ctx->qsequence - 1; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 262062306a36Sopenharmony_ci} 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ciconst struct coda_context_ops coda_bit_decode_ops = { 262362306a36Sopenharmony_ci .queue_init = coda_decoder_queue_init, 262462306a36Sopenharmony_ci .reqbufs = coda_decoder_reqbufs, 262562306a36Sopenharmony_ci .start_streaming = coda_start_decoding, 262662306a36Sopenharmony_ci .prepare_run = coda_prepare_decode, 262762306a36Sopenharmony_ci .finish_run = coda_finish_decode, 262862306a36Sopenharmony_ci .run_timeout = coda_decode_timeout, 262962306a36Sopenharmony_ci .seq_init_work = coda_dec_seq_init_work, 263062306a36Sopenharmony_ci .seq_end_work = coda_seq_end_work, 263162306a36Sopenharmony_ci .release = coda_bit_release, 263262306a36Sopenharmony_ci}; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ciirqreturn_t coda_irq_handler(int irq, void *data) 263562306a36Sopenharmony_ci{ 263662306a36Sopenharmony_ci struct coda_dev *dev = data; 263762306a36Sopenharmony_ci struct coda_ctx *ctx; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci /* read status register to attend the IRQ */ 264062306a36Sopenharmony_ci coda_read(dev, CODA_REG_BIT_INT_STATUS); 264162306a36Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_INT_REASON); 264262306a36Sopenharmony_ci coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, 264362306a36Sopenharmony_ci CODA_REG_BIT_INT_CLEAR); 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); 264662306a36Sopenharmony_ci if (ctx == NULL) { 264762306a36Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 264862306a36Sopenharmony_ci "Instance released before the end of transaction\n"); 264962306a36Sopenharmony_ci return IRQ_HANDLED; 265062306a36Sopenharmony_ci } 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci trace_coda_bit_done(ctx); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci if (ctx->aborting) { 265562306a36Sopenharmony_ci coda_dbg(1, ctx, "task has been aborted\n"); 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci if (coda_isbusy(ctx->dev)) { 265962306a36Sopenharmony_ci coda_dbg(1, ctx, "coda is still busy!!!!\n"); 266062306a36Sopenharmony_ci return IRQ_NONE; 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci complete(&ctx->completion); 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci return IRQ_HANDLED; 266662306a36Sopenharmony_ci} 2667