18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Coda multi-standard codec IP - BIT processor functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Vista Silicon S.L. 68c2ecf20Sopenharmony_ci * Javier Martin, <javier.martin@vista-silicon.com> 78c2ecf20Sopenharmony_ci * Xavier Duret 88c2ecf20Sopenharmony_ci * Copyright (C) 2012-2014 Philipp Zabel, Pengutronix 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/irqreturn.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/log2.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/reset.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-fh.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-mem2mem.h> 248c2ecf20Sopenharmony_ci#include <media/videobuf2-v4l2.h> 258c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 268c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include "coda.h" 298c2ecf20Sopenharmony_ci#include "imx-vdoa.h" 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include "trace.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define CODA_PARA_BUF_SIZE (10 * 1024) 348c2ecf20Sopenharmony_ci#define CODA7_PS_BUF_SIZE 0x28000 358c2ecf20Sopenharmony_ci#define CODA9_PS_SAVE_SIZE (512 * 1024) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define CODA_DEFAULT_GAMMA 4096 388c2ecf20Sopenharmony_ci#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic inline int coda_is_initialized(struct coda_dev *dev) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline unsigned long coda_isbusy(struct coda_dev *dev) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return coda_read(dev, CODA_REG_BIT_BUSY); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int coda_wait_timeout(struct coda_dev *dev) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci while (coda_isbusy(dev)) { 578c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 588c2ecf20Sopenharmony_ci return -ETIMEDOUT; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci return 0; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void coda_command_async(struct coda_ctx *ctx, int cmd) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 688c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541 || 698c2ecf20Sopenharmony_ci dev->devtype->product == CODA_960) { 708c2ecf20Sopenharmony_ci /* Restore context related registers to CODA */ 718c2ecf20Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 728c2ecf20Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 738c2ecf20Sopenharmony_ci coda_write(dev, ctx->frm_dis_flg, 748c2ecf20Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 758c2ecf20Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, 768c2ecf20Sopenharmony_ci CODA_REG_BIT_FRAME_MEM_CTRL); 778c2ecf20Sopenharmony_ci coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 818c2ecf20Sopenharmony_ci coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR); 828c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX); 888c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); 898c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci trace_coda_bit_run(ctx, cmd); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int coda_command_sync(struct coda_ctx *ctx, int cmd) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 998c2ecf20Sopenharmony_ci int ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci coda_command_async(ctx, cmd); 1048c2ecf20Sopenharmony_ci ret = coda_wait_timeout(dev); 1058c2ecf20Sopenharmony_ci trace_coda_bit_done(ctx); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciint coda_hw_reset(struct coda_ctx *ctx) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 1138c2ecf20Sopenharmony_ci unsigned long timeout; 1148c2ecf20Sopenharmony_ci unsigned int idx; 1158c2ecf20Sopenharmony_ci int ret; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (!dev->rstc) 1208c2ecf20Sopenharmony_ci return -ENOENT; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 1258c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(100); 1268c2ecf20Sopenharmony_ci coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL); 1278c2ecf20Sopenharmony_ci while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) { 1288c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 1298c2ecf20Sopenharmony_ci return -ETIME; 1308c2ecf20Sopenharmony_ci cpu_relax(); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = reset_control_reset(dev->rstc); 1358c2ecf20Sopenharmony_ci if (ret < 0) 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 1398c2ecf20Sopenharmony_ci coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL); 1408c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 1418c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); 1428c2ecf20Sopenharmony_ci ret = coda_wait_timeout(dev); 1438c2ecf20Sopenharmony_ci coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return ret; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void coda_kfifo_sync_from_device(struct coda_ctx *ctx) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 1518c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 1528c2ecf20Sopenharmony_ci u32 rd_ptr; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci rd_ptr = coda_read(dev, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 1558c2ecf20Sopenharmony_ci kfifo->out = (kfifo->in & ~kfifo->mask) | 1568c2ecf20Sopenharmony_ci (rd_ptr - ctx->bitstream.paddr); 1578c2ecf20Sopenharmony_ci if (kfifo->out > kfifo->in) 1588c2ecf20Sopenharmony_ci kfifo->out -= kfifo->mask + 1; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void coda_kfifo_sync_to_device_full(struct coda_ctx *ctx) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 1648c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 1658c2ecf20Sopenharmony_ci u32 rd_ptr, wr_ptr; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci rd_ptr = ctx->bitstream.paddr + (kfifo->out & kfifo->mask); 1688c2ecf20Sopenharmony_ci coda_write(dev, rd_ptr, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 1698c2ecf20Sopenharmony_ci wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 1708c2ecf20Sopenharmony_ci coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct __kfifo *kfifo = &ctx->bitstream_fifo.kfifo; 1768c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 1778c2ecf20Sopenharmony_ci u32 wr_ptr; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci wr_ptr = ctx->bitstream.paddr + (kfifo->in & kfifo->mask); 1808c2ecf20Sopenharmony_ci coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci unsigned char *buf; 1868c2ecf20Sopenharmony_ci u32 n; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (size < 6) 1898c2ecf20Sopenharmony_ci size = 6; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 1928c2ecf20Sopenharmony_ci if (!buf) 1938c2ecf20Sopenharmony_ci return -ENOMEM; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci coda_h264_filler_nal(size, buf); 1968c2ecf20Sopenharmony_ci n = kfifo_in(&ctx->bitstream_fifo, buf, size); 1978c2ecf20Sopenharmony_ci kfree(buf); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return (n < size) ? -ENOSPC : 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciint coda_bitstream_flush(struct coda_ctx *ctx) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci int ret; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); 2108c2ecf20Sopenharmony_ci if (ret < 0) { 2118c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, 2168c2ecf20Sopenharmony_ci ctx->bitstream.size); 2178c2ecf20Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return (n < size) ? -ENOSPC : 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic u32 coda_buffer_parse_headers(struct coda_ctx *ctx, 2308c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, 2318c2ecf20Sopenharmony_ci u32 payload) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 2348c2ecf20Sopenharmony_ci u32 size = 0; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci switch (ctx->codec->src_fourcc) { 2378c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 2388c2ecf20Sopenharmony_ci size = coda_mpeg2_parse_headers(ctx, vaddr, payload); 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 2418c2ecf20Sopenharmony_ci size = coda_mpeg4_parse_headers(ctx, vaddr, payload); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return size; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic bool coda_bitstream_try_queue(struct coda_ctx *ctx, 2518c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *src_buf) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); 2548c2ecf20Sopenharmony_ci u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci int i; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (coda_get_bitstream_payload(ctx) + payload + 512 >= 2598c2ecf20Sopenharmony_ci ctx->bitstream.size) 2608c2ecf20Sopenharmony_ci return false; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!vaddr) { 2638c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); 2648c2ecf20Sopenharmony_ci return true; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (ctx->qsequence == 0 && payload < 512) { 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Add padding after the first buffer, if it is too small to be 2708c2ecf20Sopenharmony_ci * fetched by the CODA, by repeating the headers. Without 2718c2ecf20Sopenharmony_ci * repeated headers, or the first frame already queued, decoder 2728c2ecf20Sopenharmony_ci * sequence initialization fails with error code 0x2000 on i.MX6 2738c2ecf20Sopenharmony_ci * or error code 0x1 on i.MX51. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci u32 header_size = coda_buffer_parse_headers(ctx, src_buf, 2768c2ecf20Sopenharmony_ci payload); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (header_size) { 2798c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "pad with %u-byte header\n", 2808c2ecf20Sopenharmony_ci header_size); 2818c2ecf20Sopenharmony_ci for (i = payload; i < 512; i += header_size) { 2828c2ecf20Sopenharmony_ci ret = coda_bitstream_queue(ctx, vaddr, 2838c2ecf20Sopenharmony_ci header_size); 2848c2ecf20Sopenharmony_ci if (ret < 0) { 2858c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 2868c2ecf20Sopenharmony_ci "bitstream buffer overflow\n"); 2878c2ecf20Sopenharmony_ci return false; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_960) 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } else { 2938c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 2948c2ecf20Sopenharmony_ci "could not parse header, sequence initialization might fail\n"); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Add padding before the first buffer, if it is too small */ 2998c2ecf20Sopenharmony_ci if (ctx->qsequence == 0 && payload < 512 && 3008c2ecf20Sopenharmony_ci ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 3018c2ecf20Sopenharmony_ci coda_h264_bitstream_pad(ctx, 512 - payload); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci ret = coda_bitstream_queue(ctx, vaddr, payload); 3048c2ecf20Sopenharmony_ci if (ret < 0) { 3058c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); 3068c2ecf20Sopenharmony_ci return false; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci src_buf->sequence = ctx->qsequence++; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Sync read pointer to device */ 3128c2ecf20Sopenharmony_ci if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) 3138c2ecf20Sopenharmony_ci coda_kfifo_sync_to_device_write(ctx); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* Set the stream-end flag after the last buffer is queued */ 3168c2ecf20Sopenharmony_ci if (src_buf->flags & V4L2_BUF_FLAG_LAST) 3178c2ecf20Sopenharmony_ci coda_bit_stream_end_flag(ctx); 3188c2ecf20Sopenharmony_ci ctx->hold = false; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return true; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_civoid coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *src_buf; 3268c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 3278c2ecf20Sopenharmony_ci u32 start; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * Only queue two JPEGs into the bitstream buffer to keep 3358c2ecf20Sopenharmony_ci * latency low. We need at least one complete buffer and the 3368c2ecf20Sopenharmony_ci * header of another buffer (for prescan) in the bitstream. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 3398c2ecf20Sopenharmony_ci ctx->num_metas > 1) 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (ctx->num_internal_frames && 3438c2ecf20Sopenharmony_ci ctx->num_metas >= ctx->num_internal_frames) { 3448c2ecf20Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 3458c2ecf20Sopenharmony_ci struct coda_buffer_meta, list); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * If we managed to fill in at least a full reorder 3498c2ecf20Sopenharmony_ci * window of buffers (num_internal_frames is a 3508c2ecf20Sopenharmony_ci * conservative estimate for this) and the bitstream 3518c2ecf20Sopenharmony_ci * prefetcher has at least 2 256 bytes periods beyond 3528c2ecf20Sopenharmony_ci * the first buffer to fetch, we can safely stop queuing 3538c2ecf20Sopenharmony_ci * in order to limit the decoder drain latency. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci if (coda_bitstream_can_fetch_past(ctx, meta->end)) 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Drop frames that do not start/end with a SOI/EOI markers */ 3628c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && 3638c2ecf20Sopenharmony_ci !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { 3648c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 3658c2ecf20Sopenharmony_ci "dropping invalid JPEG frame %d\n", 3668c2ecf20Sopenharmony_ci ctx->qsequence); 3678c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 3688c2ecf20Sopenharmony_ci if (buffer_list) { 3698c2ecf20Sopenharmony_ci struct v4l2_m2m_buffer *m2m_buf; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci m2m_buf = container_of(src_buf, 3728c2ecf20Sopenharmony_ci struct v4l2_m2m_buffer, 3738c2ecf20Sopenharmony_ci vb); 3748c2ecf20Sopenharmony_ci list_add_tail(&m2m_buf->list, buffer_list); 3758c2ecf20Sopenharmony_ci } else { 3768c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci continue; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Dump empty buffers */ 3828c2ecf20Sopenharmony_ci if (!vb2_get_plane_payload(&src_buf->vb2_buf, 0)) { 3838c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 3848c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Buffer start position */ 3898c2ecf20Sopenharmony_ci start = ctx->bitstream_fifo.kfifo.in; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (coda_bitstream_try_queue(ctx, src_buf)) { 3928c2ecf20Sopenharmony_ci /* 3938c2ecf20Sopenharmony_ci * Source buffer is queued in the bitstream ringbuffer; 3948c2ecf20Sopenharmony_ci * queue the timestamp and mark source buffer as done 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci meta = kmalloc(sizeof(*meta), GFP_KERNEL); 3998c2ecf20Sopenharmony_ci if (meta) { 4008c2ecf20Sopenharmony_ci meta->sequence = src_buf->sequence; 4018c2ecf20Sopenharmony_ci meta->timecode = src_buf->timecode; 4028c2ecf20Sopenharmony_ci meta->timestamp = src_buf->vb2_buf.timestamp; 4038c2ecf20Sopenharmony_ci meta->start = start; 4048c2ecf20Sopenharmony_ci meta->end = ctx->bitstream_fifo.kfifo.in; 4058c2ecf20Sopenharmony_ci meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; 4068c2ecf20Sopenharmony_ci if (meta->last) 4078c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "marking last meta"); 4088c2ecf20Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 4098c2ecf20Sopenharmony_ci list_add_tail(&meta->list, 4108c2ecf20Sopenharmony_ci &ctx->buffer_meta_list); 4118c2ecf20Sopenharmony_ci ctx->num_metas++; 4128c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci trace_coda_bit_queue(ctx, src_buf, meta); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (buffer_list) { 4188c2ecf20Sopenharmony_ci struct v4l2_m2m_buffer *m2m_buf; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci m2m_buf = container_of(src_buf, 4218c2ecf20Sopenharmony_ci struct v4l2_m2m_buffer, 4228c2ecf20Sopenharmony_ci vb); 4238c2ecf20Sopenharmony_ci list_add_tail(&m2m_buf->list, buffer_list); 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci } else { 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_civoid coda_bit_stream_end_flag(struct coda_ctx *ctx) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* If this context is currently running, update the hardware flag */ 4408c2ecf20Sopenharmony_ci if ((dev->devtype->product == CODA_960) && 4418c2ecf20Sopenharmony_ci coda_isbusy(dev) && 4428c2ecf20Sopenharmony_ci (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) { 4438c2ecf20Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 4448c2ecf20Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 4518c2ecf20Sopenharmony_ci u32 *p = ctx->parabuf.vaddr; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 4548c2ecf20Sopenharmony_ci p[index] = value; 4558c2ecf20Sopenharmony_ci else 4568c2ecf20Sopenharmony_ci p[index ^ 1] = value; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic inline int coda_alloc_context_buf(struct coda_ctx *ctx, 4608c2ecf20Sopenharmony_ci struct coda_aux_buf *buf, size_t size, 4618c2ecf20Sopenharmony_ci const char *name) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void coda_free_framebuffers(struct coda_ctx *ctx) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int i; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) 4728c2ecf20Sopenharmony_ci coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int coda_alloc_framebuffers(struct coda_ctx *ctx, 4768c2ecf20Sopenharmony_ci struct coda_q_data *q_data, u32 fourcc) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 4798c2ecf20Sopenharmony_ci unsigned int ysize, ycbcr_size; 4808c2ecf20Sopenharmony_ci int ret; 4818c2ecf20Sopenharmony_ci int i; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 4848c2ecf20Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 || 4858c2ecf20Sopenharmony_ci ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 || 4868c2ecf20Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_MPEG4) 4878c2ecf20Sopenharmony_ci ysize = round_up(q_data->rect.width, 16) * 4888c2ecf20Sopenharmony_ci round_up(q_data->rect.height, 16); 4898c2ecf20Sopenharmony_ci else 4908c2ecf20Sopenharmony_ci ysize = round_up(q_data->rect.width, 8) * q_data->rect.height; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 4938c2ecf20Sopenharmony_ci ycbcr_size = round_up(ysize, 4096) + ysize / 2; 4948c2ecf20Sopenharmony_ci else 4958c2ecf20Sopenharmony_ci ycbcr_size = ysize + ysize / 2; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Allocate frame buffers */ 4988c2ecf20Sopenharmony_ci for (i = 0; i < ctx->num_internal_frames; i++) { 4998c2ecf20Sopenharmony_ci size_t size = ycbcr_size; 5008c2ecf20Sopenharmony_ci char *name; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Add space for mvcol buffers */ 5038c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6 && 5048c2ecf20Sopenharmony_ci (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 || 5058c2ecf20Sopenharmony_ci (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0))) 5068c2ecf20Sopenharmony_ci size += ysize / 4; 5078c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "fb%d", i); 5088c2ecf20Sopenharmony_ci if (!name) { 5098c2ecf20Sopenharmony_ci coda_free_framebuffers(ctx); 5108c2ecf20Sopenharmony_ci return -ENOMEM; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, 5138c2ecf20Sopenharmony_ci size, name); 5148c2ecf20Sopenharmony_ci kfree(name); 5158c2ecf20Sopenharmony_ci if (ret < 0) { 5168c2ecf20Sopenharmony_ci coda_free_framebuffers(ctx); 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* Register frame buffers in the parameter buffer */ 5228c2ecf20Sopenharmony_ci for (i = 0; i < ctx->num_internal_frames; i++) { 5238c2ecf20Sopenharmony_ci u32 y, cb, cr, mvcol; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Start addresses of Y, Cb, Cr planes */ 5268c2ecf20Sopenharmony_ci y = ctx->internal_frames[i].buf.paddr; 5278c2ecf20Sopenharmony_ci cb = y + ysize; 5288c2ecf20Sopenharmony_ci cr = y + ysize + ysize/4; 5298c2ecf20Sopenharmony_ci mvcol = y + ysize + ysize/4 + ysize/4; 5308c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { 5318c2ecf20Sopenharmony_ci cb = round_up(cb, 4096); 5328c2ecf20Sopenharmony_ci mvcol = cb + ysize/2; 5338c2ecf20Sopenharmony_ci cr = 0; 5348c2ecf20Sopenharmony_ci /* Packed 20-bit MSB of base addresses */ 5358c2ecf20Sopenharmony_ci /* YYYYYCCC, CCyyyyyc, cccc.... */ 5368c2ecf20Sopenharmony_ci y = (y & 0xfffff000) | cb >> 20; 5378c2ecf20Sopenharmony_ci cb = (cb & 0x000ff000) << 12; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 0, y); 5408c2ecf20Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 1, cb); 5418c2ecf20Sopenharmony_ci coda_parabuf_write(ctx, i * 3 + 2, cr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 5448c2ecf20Sopenharmony_ci continue; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* mvcol buffer for h.264 and mpeg4 */ 5478c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) 5488c2ecf20Sopenharmony_ci coda_parabuf_write(ctx, 96 + i, mvcol); 5498c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4 && i == 0) 5508c2ecf20Sopenharmony_ci coda_parabuf_write(ctx, 97, mvcol); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic void coda_free_context_buffers(struct coda_ctx *ctx) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &ctx->slicebuf); 5618c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &ctx->psbuf); 5628c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 5638c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &ctx->workbuf); 5648c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &ctx->parabuf); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int coda_alloc_context_buffers(struct coda_ctx *ctx, 5688c2ecf20Sopenharmony_ci struct coda_q_data *q_data) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 5718c2ecf20Sopenharmony_ci size_t size; 5728c2ecf20Sopenharmony_ci int ret; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (!ctx->parabuf.vaddr) { 5758c2ecf20Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->parabuf, 5768c2ecf20Sopenharmony_ci CODA_PARA_BUF_SIZE, "parabuf"); 5778c2ecf20Sopenharmony_ci if (ret < 0) 5788c2ecf20Sopenharmony_ci return ret; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { 5858c2ecf20Sopenharmony_ci /* worst case slice size */ 5868c2ecf20Sopenharmony_ci size = (DIV_ROUND_UP(q_data->rect.width, 16) * 5878c2ecf20Sopenharmony_ci DIV_ROUND_UP(q_data->rect.height, 16)) * 3200 / 8 + 512; 5888c2ecf20Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, 5898c2ecf20Sopenharmony_ci "slicebuf"); 5908c2ecf20Sopenharmony_ci if (ret < 0) 5918c2ecf20Sopenharmony_ci goto err; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || 5958c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541)) { 5968c2ecf20Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->psbuf, 5978c2ecf20Sopenharmony_ci CODA7_PS_BUF_SIZE, "psbuf"); 5988c2ecf20Sopenharmony_ci if (ret < 0) 5998c2ecf20Sopenharmony_ci goto err; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (!ctx->workbuf.vaddr) { 6038c2ecf20Sopenharmony_ci size = dev->devtype->workbuf_size; 6048c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960 && 6058c2ecf20Sopenharmony_ci q_data->fourcc == V4L2_PIX_FMT_H264) 6068c2ecf20Sopenharmony_ci size += CODA9_PS_SAVE_SIZE; 6078c2ecf20Sopenharmony_ci ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, 6088c2ecf20Sopenharmony_ci "workbuf"); 6098c2ecf20Sopenharmony_ci if (ret < 0) 6108c2ecf20Sopenharmony_ci goto err; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cierr: 6168c2ecf20Sopenharmony_ci coda_free_context_buffers(ctx); 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, 6218c2ecf20Sopenharmony_ci int header_code, u8 *header, int *size) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct vb2_buffer *vb = &buf->vb2_buf; 6248c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 6258c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 6268c2ecf20Sopenharmony_ci struct v4l2_rect *r; 6278c2ecf20Sopenharmony_ci size_t bufsize; 6288c2ecf20Sopenharmony_ci int ret; 6298c2ecf20Sopenharmony_ci int i; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 6328c2ecf20Sopenharmony_ci memset(vb2_plane_vaddr(vb, 0), 0, 64); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci coda_write(dev, vb2_dma_contig_plane_dma_addr(vb, 0), 6358c2ecf20Sopenharmony_ci CODA_CMD_ENC_HEADER_BB_START); 6368c2ecf20Sopenharmony_ci bufsize = vb2_plane_size(vb, 0); 6378c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 6388c2ecf20Sopenharmony_ci bufsize /= 1024; 6398c2ecf20Sopenharmony_ci coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE); 6408c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960 && 6418c2ecf20Sopenharmony_ci ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264 && 6428c2ecf20Sopenharmony_ci header_code == CODA_HEADER_H264_SPS) { 6438c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 6448c2ecf20Sopenharmony_ci r = &q_data_src->rect; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (r->width % 16 || r->height % 16) { 6478c2ecf20Sopenharmony_ci u32 crop_right = round_up(r->width, 16) - r->width; 6488c2ecf20Sopenharmony_ci u32 crop_bottom = round_up(r->height, 16) - r->height; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci coda_write(dev, crop_right, 6518c2ecf20Sopenharmony_ci CODA9_CMD_ENC_HEADER_FRAME_CROP_H); 6528c2ecf20Sopenharmony_ci coda_write(dev, crop_bottom, 6538c2ecf20Sopenharmony_ci CODA9_CMD_ENC_HEADER_FRAME_CROP_V); 6548c2ecf20Sopenharmony_ci header_code |= CODA9_HEADER_FRAME_CROP; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE); 6588c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER); 6598c2ecf20Sopenharmony_ci if (ret < 0) { 6608c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n"); 6618c2ecf20Sopenharmony_ci return ret; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 6658c2ecf20Sopenharmony_ci for (i = 63; i > 0; i--) 6668c2ecf20Sopenharmony_ci if (((char *)vb2_plane_vaddr(vb, 0))[i] != 0) 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci *size = i + 1; 6698c2ecf20Sopenharmony_ci } else { 6708c2ecf20Sopenharmony_ci *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) - 6718c2ecf20Sopenharmony_ci coda_read(dev, CODA_CMD_ENC_HEADER_BB_START); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci memcpy(header, vb2_plane_vaddr(vb, 0), *size); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return 0; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic u32 coda_slice_mode(struct coda_ctx *ctx) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci int size, unit; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci switch (ctx->params.slice_mode) { 6838c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: 6848c2ecf20Sopenharmony_ci default: 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: 6878c2ecf20Sopenharmony_ci size = ctx->params.slice_max_mb; 6888c2ecf20Sopenharmony_ci unit = 1; 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: 6918c2ecf20Sopenharmony_ci size = ctx->params.slice_max_bits; 6928c2ecf20Sopenharmony_ci unit = 0; 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | 6978c2ecf20Sopenharmony_ci ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | 6988c2ecf20Sopenharmony_ci ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int coda_enc_param_change(struct coda_ctx *ctx) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 7048c2ecf20Sopenharmony_ci u32 change_enable = 0; 7058c2ecf20Sopenharmony_ci u32 success; 7068c2ecf20Sopenharmony_ci int ret; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (ctx->params.gop_size_changed) { 7098c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_GOP; 7108c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.gop_size, 7118c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_GOP); 7128c2ecf20Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 7138c2ecf20Sopenharmony_ci ctx->params.gop_size_changed = false; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci if (ctx->params.h264_intra_qp_changed) { 7168c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "parameter change: intra Qp %u\n", 7178c2ecf20Sopenharmony_ci ctx->params.h264_intra_qp); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (ctx->params.bitrate) { 7208c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; 7218c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.h264_intra_qp, 7228c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_INTRA_QP); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci ctx->params.h264_intra_qp_changed = false; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci if (ctx->params.bitrate_changed) { 7278c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", 7288c2ecf20Sopenharmony_ci ctx->params.bitrate); 7298c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; 7308c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.bitrate, 7318c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_BITRATE); 7328c2ecf20Sopenharmony_ci ctx->params.bitrate_changed = false; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci if (ctx->params.framerate_changed) { 7358c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", 7368c2ecf20Sopenharmony_ci ctx->params.framerate & 0xffff, 7378c2ecf20Sopenharmony_ci (ctx->params.framerate >> 16) + 1); 7388c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; 7398c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.framerate, 7408c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_RC_FRAME_RATE); 7418c2ecf20Sopenharmony_ci ctx->params.framerate_changed = false; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci if (ctx->params.intra_refresh_changed) { 7448c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", 7458c2ecf20Sopenharmony_ci ctx->params.intra_refresh); 7468c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; 7478c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.intra_refresh, 7488c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_INTRA_MB_NUM); 7498c2ecf20Sopenharmony_ci ctx->params.intra_refresh_changed = false; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci if (ctx->params.slice_mode_changed) { 7528c2ecf20Sopenharmony_ci change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; 7538c2ecf20Sopenharmony_ci coda_write(dev, coda_slice_mode(ctx), 7548c2ecf20Sopenharmony_ci CODA_CMD_ENC_PARAM_SLICE_MODE); 7558c2ecf20Sopenharmony_ci ctx->params.slice_mode_changed = false; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (!change_enable) 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); 7648c2ecf20Sopenharmony_ci if (ret < 0) 7658c2ecf20Sopenharmony_ci return ret; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); 7688c2ecf20Sopenharmony_ci if (success != 1) 7698c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "parameter change failed: %u\n", success); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci phys_addr_t ret; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci size = round_up(size, 1024); 7798c2ecf20Sopenharmony_ci if (size > iram->remaining) 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci iram->remaining -= size; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci ret = iram->next_paddr; 7848c2ecf20Sopenharmony_ci iram->next_paddr += size; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic void coda_setup_iram(struct coda_ctx *ctx) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct coda_iram_info *iram_info = &ctx->iram_info; 7928c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 7938c2ecf20Sopenharmony_ci int w64, w128; 7948c2ecf20Sopenharmony_ci int mb_width; 7958c2ecf20Sopenharmony_ci int dbk_bits; 7968c2ecf20Sopenharmony_ci int bit_bits; 7978c2ecf20Sopenharmony_ci int ip_bits; 7988c2ecf20Sopenharmony_ci int me_bits; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci memset(iram_info, 0, sizeof(*iram_info)); 8018c2ecf20Sopenharmony_ci iram_info->next_paddr = dev->iram.paddr; 8028c2ecf20Sopenharmony_ci iram_info->remaining = dev->iram.size; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (!dev->iram.vaddr) 8058c2ecf20Sopenharmony_ci return; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 8088c2ecf20Sopenharmony_ci case CODA_HX4: 8098c2ecf20Sopenharmony_ci dbk_bits = CODA7_USE_HOST_DBK_ENABLE; 8108c2ecf20Sopenharmony_ci bit_bits = CODA7_USE_HOST_BIT_ENABLE; 8118c2ecf20Sopenharmony_ci ip_bits = CODA7_USE_HOST_IP_ENABLE; 8128c2ecf20Sopenharmony_ci me_bits = CODA7_USE_HOST_ME_ENABLE; 8138c2ecf20Sopenharmony_ci break; 8148c2ecf20Sopenharmony_ci case CODA_7541: 8158c2ecf20Sopenharmony_ci dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; 8168c2ecf20Sopenharmony_ci bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 8178c2ecf20Sopenharmony_ci ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 8188c2ecf20Sopenharmony_ci me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci case CODA_960: 8218c2ecf20Sopenharmony_ci dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; 8228c2ecf20Sopenharmony_ci bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; 8238c2ecf20Sopenharmony_ci ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; 8248c2ecf20Sopenharmony_ci me_bits = 0; 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci default: /* CODA_DX6 */ 8278c2ecf20Sopenharmony_ci return; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_ENCODER) { 8318c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 8348c2ecf20Sopenharmony_ci mb_width = DIV_ROUND_UP(q_data_src->rect.width, 16); 8358c2ecf20Sopenharmony_ci w128 = mb_width * 128; 8368c2ecf20Sopenharmony_ci w64 = mb_width * 64; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci /* Prioritize in case IRAM is too small for everything */ 8398c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 8408c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 8418c2ecf20Sopenharmony_ci iram_info->search_ram_size = round_up(mb_width * 16 * 8428c2ecf20Sopenharmony_ci 36 + 2048, 1024); 8438c2ecf20Sopenharmony_ci iram_info->search_ram_paddr = coda_iram_alloc(iram_info, 8448c2ecf20Sopenharmony_ci iram_info->search_ram_size); 8458c2ecf20Sopenharmony_ci if (!iram_info->search_ram_paddr) { 8468c2ecf20Sopenharmony_ci pr_err("IRAM is smaller than the search ram size\n"); 8478c2ecf20Sopenharmony_ci goto out; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= me_bits; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* Only H.264BP and H.263P3 are considered */ 8538c2ecf20Sopenharmony_ci iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w64); 8548c2ecf20Sopenharmony_ci iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w64); 8558c2ecf20Sopenharmony_ci if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 8568c2ecf20Sopenharmony_ci goto out; 8578c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= dbk_bits; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 8608c2ecf20Sopenharmony_ci if (!iram_info->buf_bit_use) 8618c2ecf20Sopenharmony_ci goto out; 8628c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= bit_bits; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 8658c2ecf20Sopenharmony_ci if (!iram_info->buf_ip_ac_dc_use) 8668c2ecf20Sopenharmony_ci goto out; 8678c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= ip_bits; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci /* OVL and BTP disabled for encoder */ 8708c2ecf20Sopenharmony_ci } else if (ctx->inst_type == CODA_INST_DECODER) { 8718c2ecf20Sopenharmony_ci struct coda_q_data *q_data_dst; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 8748c2ecf20Sopenharmony_ci mb_width = DIV_ROUND_UP(q_data_dst->width, 16); 8758c2ecf20Sopenharmony_ci w128 = mb_width * 128; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, w128); 8788c2ecf20Sopenharmony_ci iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, w128); 8798c2ecf20Sopenharmony_ci if (!iram_info->buf_dbk_y_use || !iram_info->buf_dbk_c_use) 8808c2ecf20Sopenharmony_ci goto out; 8818c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= dbk_bits; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci iram_info->buf_bit_use = coda_iram_alloc(iram_info, w128); 8848c2ecf20Sopenharmony_ci if (!iram_info->buf_bit_use) 8858c2ecf20Sopenharmony_ci goto out; 8868c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= bit_bits; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, w128); 8898c2ecf20Sopenharmony_ci if (!iram_info->buf_ip_ac_dc_use) 8908c2ecf20Sopenharmony_ci goto out; 8918c2ecf20Sopenharmony_ci iram_info->axi_sram_use |= ip_bits; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci /* OVL and BTP unused as there is no VC1 support yet */ 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ciout: 8978c2ecf20Sopenharmony_ci if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)) 8988c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "IRAM smaller than needed\n"); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 9018c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 9028c2ecf20Sopenharmony_ci /* TODO - Enabling these causes picture errors on CODA7541 */ 9038c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER) { 9048c2ecf20Sopenharmony_ci /* fw 1.4.50 */ 9058c2ecf20Sopenharmony_ci iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 9068c2ecf20Sopenharmony_ci CODA7_USE_IP_ENABLE); 9078c2ecf20Sopenharmony_ci } else { 9088c2ecf20Sopenharmony_ci /* fw 13.4.29 */ 9098c2ecf20Sopenharmony_ci iram_info->axi_sram_use &= ~(CODA7_USE_HOST_IP_ENABLE | 9108c2ecf20Sopenharmony_ci CODA7_USE_HOST_DBK_ENABLE | 9118c2ecf20Sopenharmony_ci CODA7_USE_IP_ENABLE | 9128c2ecf20Sopenharmony_ci CODA7_USE_DBK_ENABLE); 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic u32 coda_supported_firmwares[] = { 9188c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), 9198c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), 9208c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), 9218c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), 9228c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 9), 9238c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), 9248c2ecf20Sopenharmony_ci CODA_FIRMWARE_VERNUM(CODA_960, 3, 1, 1), 9258c2ecf20Sopenharmony_ci}; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic bool coda_firmware_supported(u32 vernum) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci int i; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++) 9328c2ecf20Sopenharmony_ci if (vernum == coda_supported_firmwares[i]) 9338c2ecf20Sopenharmony_ci return true; 9348c2ecf20Sopenharmony_ci return false; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ciint coda_check_firmware(struct coda_dev *dev) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci u16 product, major, minor, release; 9408c2ecf20Sopenharmony_ci u32 data; 9418c2ecf20Sopenharmony_ci int ret; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_per); 9448c2ecf20Sopenharmony_ci if (ret) 9458c2ecf20Sopenharmony_ci goto err_clk_per; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_ahb); 9488c2ecf20Sopenharmony_ci if (ret) 9498c2ecf20Sopenharmony_ci goto err_clk_ahb; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM); 9528c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY); 9538c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX); 9548c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD); 9558c2ecf20Sopenharmony_ci coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND); 9568c2ecf20Sopenharmony_ci if (coda_wait_timeout(dev)) { 9578c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "firmware get command error\n"); 9588c2ecf20Sopenharmony_ci ret = -EIO; 9598c2ecf20Sopenharmony_ci goto err_run_cmd; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 9638c2ecf20Sopenharmony_ci data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV); 9648c2ecf20Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n", 9658c2ecf20Sopenharmony_ci data); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Check we are compatible with the loaded firmware */ 9698c2ecf20Sopenharmony_ci data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM); 9708c2ecf20Sopenharmony_ci product = CODA_FIRMWARE_PRODUCT(data); 9718c2ecf20Sopenharmony_ci major = CODA_FIRMWARE_MAJOR(data); 9728c2ecf20Sopenharmony_ci minor = CODA_FIRMWARE_MINOR(data); 9738c2ecf20Sopenharmony_ci release = CODA_FIRMWARE_RELEASE(data); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 9768c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (product != dev->devtype->product) { 9798c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 9808c2ecf20Sopenharmony_ci "Wrong firmware. Hw: %s, Fw: %s, Version: %u.%u.%u\n", 9818c2ecf20Sopenharmony_ci coda_product_name(dev->devtype->product), 9828c2ecf20Sopenharmony_ci coda_product_name(product), major, minor, release); 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Initialized %s.\n", 9878c2ecf20Sopenharmony_ci coda_product_name(product)); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (coda_firmware_supported(data)) { 9908c2ecf20Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n", 9918c2ecf20Sopenharmony_ci major, minor, release); 9928c2ecf20Sopenharmony_ci } else { 9938c2ecf20Sopenharmony_ci v4l2_warn(&dev->v4l2_dev, 9948c2ecf20Sopenharmony_ci "Unsupported firmware version: %u.%u.%u\n", 9958c2ecf20Sopenharmony_ci major, minor, release); 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci return 0; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cierr_run_cmd: 10018c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 10028c2ecf20Sopenharmony_cierr_clk_ahb: 10038c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 10048c2ecf20Sopenharmony_cierr_clk_per: 10058c2ecf20Sopenharmony_ci return ret; 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci u32 cache_size, cache_config; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { 10138c2ecf20Sopenharmony_ci /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ 10148c2ecf20Sopenharmony_ci cache_size = 0x20262024; 10158c2ecf20Sopenharmony_ci cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; 10168c2ecf20Sopenharmony_ci } else { 10178c2ecf20Sopenharmony_ci /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ 10188c2ecf20Sopenharmony_ci cache_size = 0x02440243; 10198c2ecf20Sopenharmony_ci cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); 10228c2ecf20Sopenharmony_ci if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_YUYV) { 10238c2ecf20Sopenharmony_ci cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 10248c2ecf20Sopenharmony_ci 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 10258c2ecf20Sopenharmony_ci 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | 10288c2ecf20Sopenharmony_ci 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | 10298c2ecf20Sopenharmony_ci 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/* 10358c2ecf20Sopenharmony_ci * Encoder context operations 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int coda_encoder_reqbufs(struct coda_ctx *ctx, 10398c2ecf20Sopenharmony_ci struct v4l2_requestbuffers *rb) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 10428c2ecf20Sopenharmony_ci int ret; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (rb->count) { 10488c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 10498c2ecf20Sopenharmony_ci ret = coda_alloc_context_buffers(ctx, q_data_src); 10508c2ecf20Sopenharmony_ci if (ret < 0) 10518c2ecf20Sopenharmony_ci return ret; 10528c2ecf20Sopenharmony_ci } else { 10538c2ecf20Sopenharmony_ci coda_free_context_buffers(ctx); 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic int coda_start_encoding(struct coda_ctx *ctx) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 10628c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = &dev->v4l2_dev; 10638c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 10648c2ecf20Sopenharmony_ci u32 bitstream_buf, bitstream_size; 10658c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 10668c2ecf20Sopenharmony_ci int gamma, ret, value; 10678c2ecf20Sopenharmony_ci u32 dst_fourcc; 10688c2ecf20Sopenharmony_ci int num_fb; 10698c2ecf20Sopenharmony_ci u32 stride; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 10728c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 10738c2ecf20Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 10768c2ecf20Sopenharmony_ci bitstream_buf = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); 10778c2ecf20Sopenharmony_ci bitstream_size = q_data_dst->sizeimage; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (!coda_is_initialized(dev)) { 10808c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "coda is not initialized.\n"); 10818c2ecf20Sopenharmony_ci return -EFAULT; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_JPEG) { 10858c2ecf20Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[0]) { 10868c2ecf20Sopenharmony_ci ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL); 10878c2ecf20Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[0]) 10888c2ecf20Sopenharmony_ci return -ENOMEM; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[1]) { 10918c2ecf20Sopenharmony_ci ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL); 10928c2ecf20Sopenharmony_ci if (!ctx->params.jpeg_qmat_tab[1]) 10938c2ecf20Sopenharmony_ci return -ENOMEM; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 11018c2ecf20Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx)); 11028c2ecf20Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 11038c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 11048c2ecf20Sopenharmony_ci case CODA_DX6: 11058c2ecf20Sopenharmony_ci coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN | 11068c2ecf20Sopenharmony_ci CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci case CODA_960: 11098c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); 11108c2ecf20Sopenharmony_ci fallthrough; 11118c2ecf20Sopenharmony_ci case CODA_HX4: 11128c2ecf20Sopenharmony_ci case CODA_7541: 11138c2ecf20Sopenharmony_ci coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | 11148c2ecf20Sopenharmony_ci CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); 11158c2ecf20Sopenharmony_ci break; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 11198c2ecf20Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 11208c2ecf20Sopenharmony_ci if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) 11218c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 11228c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 11238c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; 11248c2ecf20Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 11278c2ecf20Sopenharmony_ci /* Configure the coda */ 11288c2ecf20Sopenharmony_ci coda_write(dev, dev->iram.paddr, 11298c2ecf20Sopenharmony_ci CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR); 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci /* Could set rotation here if needed */ 11338c2ecf20Sopenharmony_ci value = 0; 11348c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 11358c2ecf20Sopenharmony_ci case CODA_DX6: 11368c2ecf20Sopenharmony_ci value = (q_data_src->rect.width & CODADX6_PICWIDTH_MASK) 11378c2ecf20Sopenharmony_ci << CODADX6_PICWIDTH_OFFSET; 11388c2ecf20Sopenharmony_ci value |= (q_data_src->rect.height & CODADX6_PICHEIGHT_MASK) 11398c2ecf20Sopenharmony_ci << CODA_PICHEIGHT_OFFSET; 11408c2ecf20Sopenharmony_ci break; 11418c2ecf20Sopenharmony_ci case CODA_HX4: 11428c2ecf20Sopenharmony_ci case CODA_7541: 11438c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_H264) { 11448c2ecf20Sopenharmony_ci value = (round_up(q_data_src->rect.width, 16) & 11458c2ecf20Sopenharmony_ci CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET; 11468c2ecf20Sopenharmony_ci value |= (round_up(q_data_src->rect.height, 16) & 11478c2ecf20Sopenharmony_ci CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci fallthrough; 11518c2ecf20Sopenharmony_ci case CODA_960: 11528c2ecf20Sopenharmony_ci value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK) 11538c2ecf20Sopenharmony_ci << CODA7_PICWIDTH_OFFSET; 11548c2ecf20Sopenharmony_ci value |= (q_data_src->rect.height & CODA7_PICHEIGHT_MASK) 11558c2ecf20Sopenharmony_ci << CODA_PICHEIGHT_OFFSET; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE); 11588c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_JPEG) 11598c2ecf20Sopenharmony_ci ctx->params.framerate = 0; 11608c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.framerate, 11618c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_SRC_F_RATE); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci ctx->params.codec_mode = ctx->codec->mode; 11648c2ecf20Sopenharmony_ci switch (dst_fourcc) { 11658c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 11668c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 11678c2ecf20Sopenharmony_ci coda_write(dev, CODA9_STD_MPEG4, 11688c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 11698c2ecf20Sopenharmony_ci else 11708c2ecf20Sopenharmony_ci coda_write(dev, CODA_STD_MPEG4, 11718c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 11728c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA); 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 11758c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 11768c2ecf20Sopenharmony_ci coda_write(dev, CODA9_STD_H264, 11778c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 11788c2ecf20Sopenharmony_ci else 11798c2ecf20Sopenharmony_ci coda_write(dev, CODA_STD_H264, 11808c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_COD_STD); 11818c2ecf20Sopenharmony_ci value = ((ctx->params.h264_disable_deblocking_filter_idc & 11828c2ecf20Sopenharmony_ci CODA_264PARAM_DISABLEDEBLK_MASK) << 11838c2ecf20Sopenharmony_ci CODA_264PARAM_DISABLEDEBLK_OFFSET) | 11848c2ecf20Sopenharmony_ci ((ctx->params.h264_slice_alpha_c0_offset_div2 & 11858c2ecf20Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) << 11868c2ecf20Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | 11878c2ecf20Sopenharmony_ci ((ctx->params.h264_slice_beta_offset_div2 & 11888c2ecf20Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << 11898c2ecf20Sopenharmony_ci CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | 11908c2ecf20Sopenharmony_ci (ctx->params.h264_constrained_intra_pred_flag << 11918c2ecf20Sopenharmony_ci CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | 11928c2ecf20Sopenharmony_ci (ctx->params.h264_chroma_qp_index_offset & 11938c2ecf20Sopenharmony_ci CODA_264PARAM_CHROMAQPOFFSET_MASK); 11948c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); 11958c2ecf20Sopenharmony_ci break; 11968c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 11978c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA); 11988c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.jpeg_restart_interval, 11998c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL); 12008c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN); 12018c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE); 12028c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci coda_jpeg_write_tables(ctx); 12058c2ecf20Sopenharmony_ci break; 12068c2ecf20Sopenharmony_ci default: 12078c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, 12088c2ecf20Sopenharmony_ci "dst format (0x%08x) invalid.\n", dst_fourcc); 12098c2ecf20Sopenharmony_ci ret = -EINVAL; 12108c2ecf20Sopenharmony_ci goto out; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci /* 12148c2ecf20Sopenharmony_ci * slice mode and GOP size registers are used for thumb size/offset 12158c2ecf20Sopenharmony_ci * in JPEG mode 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ci if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 12188c2ecf20Sopenharmony_ci value = coda_slice_mode(ctx); 12198c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); 12208c2ecf20Sopenharmony_ci value = ctx->params.gop_size; 12218c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (ctx->params.bitrate && (ctx->params.frame_rc_enable || 12258c2ecf20Sopenharmony_ci ctx->params.mb_rc_enable)) { 12268c2ecf20Sopenharmony_ci ctx->params.bitrate_changed = false; 12278c2ecf20Sopenharmony_ci ctx->params.h264_intra_qp_changed = false; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* Rate control enabled */ 12308c2ecf20Sopenharmony_ci value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) 12318c2ecf20Sopenharmony_ci << CODA_RATECONTROL_BITRATE_OFFSET; 12328c2ecf20Sopenharmony_ci value |= 1 & CODA_RATECONTROL_ENABLE_MASK; 12338c2ecf20Sopenharmony_ci value |= (ctx->params.vbv_delay & 12348c2ecf20Sopenharmony_ci CODA_RATECONTROL_INITIALDELAY_MASK) 12358c2ecf20Sopenharmony_ci << CODA_RATECONTROL_INITIALDELAY_OFFSET; 12368c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 12378c2ecf20Sopenharmony_ci value |= BIT(31); /* disable autoskip */ 12388c2ecf20Sopenharmony_ci } else { 12398c2ecf20Sopenharmony_ci value = 0; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); 12448c2ecf20Sopenharmony_ci coda_write(dev, ctx->params.intra_refresh, 12458c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_INTRA_REFRESH); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START); 12488c2ecf20Sopenharmony_ci coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci value = 0; 12528c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 12538c2ecf20Sopenharmony_ci gamma = CODA9_DEFAULT_GAMMA; 12548c2ecf20Sopenharmony_ci else 12558c2ecf20Sopenharmony_ci gamma = CODA_DEFAULT_GAMMA; 12568c2ecf20Sopenharmony_ci if (gamma > 0) { 12578c2ecf20Sopenharmony_ci coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET, 12588c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_RC_GAMMA); 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) { 12628c2ecf20Sopenharmony_ci coda_write(dev, 12638c2ecf20Sopenharmony_ci ctx->params.h264_min_qp << CODA_QPMIN_OFFSET | 12648c2ecf20Sopenharmony_ci ctx->params.h264_max_qp << CODA_QPMAX_OFFSET, 12658c2ecf20Sopenharmony_ci CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 12688c2ecf20Sopenharmony_ci if (ctx->params.h264_max_qp) 12698c2ecf20Sopenharmony_ci value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET; 12708c2ecf20Sopenharmony_ci if (CODA_DEFAULT_GAMMA > 0) 12718c2ecf20Sopenharmony_ci value |= 1 << CODA9_OPTION_GAMMA_OFFSET; 12728c2ecf20Sopenharmony_ci } else { 12738c2ecf20Sopenharmony_ci if (CODA_DEFAULT_GAMMA > 0) { 12748c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 12758c2ecf20Sopenharmony_ci value |= 1 << CODADX6_OPTION_GAMMA_OFFSET; 12768c2ecf20Sopenharmony_ci else 12778c2ecf20Sopenharmony_ci value |= 1 << CODA7_OPTION_GAMMA_OFFSET; 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci if (ctx->params.h264_min_qp) 12808c2ecf20Sopenharmony_ci value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET; 12818c2ecf20Sopenharmony_ci if (ctx->params.h264_max_qp) 12828c2ecf20Sopenharmony_ci value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET; 12838c2ecf20Sopenharmony_ci } 12848c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (ctx->params.frame_rc_enable && !ctx->params.mb_rc_enable) 12878c2ecf20Sopenharmony_ci value = 1; 12888c2ecf20Sopenharmony_ci else 12898c2ecf20Sopenharmony_ci value = 0; 12908c2ecf20Sopenharmony_ci coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci coda_setup_iram(ctx); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_H264) { 12958c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 12968c2ecf20Sopenharmony_ci case CODA_DX6: 12978c2ecf20Sopenharmony_ci value = FMO_SLICE_SAVE_BUF_SIZE << 7; 12988c2ecf20Sopenharmony_ci coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); 12998c2ecf20Sopenharmony_ci break; 13008c2ecf20Sopenharmony_ci case CODA_HX4: 13018c2ecf20Sopenharmony_ci case CODA_7541: 13028c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.search_ram_paddr, 13038c2ecf20Sopenharmony_ci CODA7_CMD_ENC_SEQ_SEARCH_BASE); 13048c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.search_ram_size, 13058c2ecf20Sopenharmony_ci CODA7_CMD_ENC_SEQ_SEARCH_SIZE); 13068c2ecf20Sopenharmony_ci break; 13078c2ecf20Sopenharmony_ci case CODA_960: 13088c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION); 13098c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 13148c2ecf20Sopenharmony_ci if (ret < 0) { 13158c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 13168c2ecf20Sopenharmony_ci goto out; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0) { 13208c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT failed\n"); 13218c2ecf20Sopenharmony_ci ret = -EFAULT; 13228c2ecf20Sopenharmony_ci goto out; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci ctx->initialized = 1; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (dst_fourcc != V4L2_PIX_FMT_JPEG) { 13278c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 13288c2ecf20Sopenharmony_ci ctx->num_internal_frames = 4; 13298c2ecf20Sopenharmony_ci else 13308c2ecf20Sopenharmony_ci ctx->num_internal_frames = 2; 13318c2ecf20Sopenharmony_ci ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc); 13328c2ecf20Sopenharmony_ci if (ret < 0) { 13338c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "failed to allocate framebuffers\n"); 13348c2ecf20Sopenharmony_ci goto out; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci num_fb = 2; 13378c2ecf20Sopenharmony_ci stride = q_data_src->bytesperline; 13388c2ecf20Sopenharmony_ci } else { 13398c2ecf20Sopenharmony_ci ctx->num_internal_frames = 0; 13408c2ecf20Sopenharmony_ci num_fb = 0; 13418c2ecf20Sopenharmony_ci stride = 0; 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); 13448c2ecf20Sopenharmony_ci coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 13478c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 13488c2ecf20Sopenharmony_ci coda_write(dev, q_data_src->bytesperline, 13498c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 13528c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_bit_use, 13538c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 13548c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 13558c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 13568c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_y_use, 13578c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 13588c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_c_use, 13598c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 13608c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ovl_use, 13618c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 13628c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 13638c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_btp_use, 13648c2ecf20Sopenharmony_ci CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci coda9_set_frame_cache(ctx, q_data_src->fourcc); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* FIXME */ 13698c2ecf20Sopenharmony_ci coda_write(dev, ctx->internal_frames[2].buf.paddr, 13708c2ecf20Sopenharmony_ci CODA9_CMD_SET_FRAME_SUBSAMP_A); 13718c2ecf20Sopenharmony_ci coda_write(dev, ctx->internal_frames[3].buf.paddr, 13728c2ecf20Sopenharmony_ci CODA9_CMD_SET_FRAME_SUBSAMP_B); 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF); 13778c2ecf20Sopenharmony_ci if (ret < 0) { 13788c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 13798c2ecf20Sopenharmony_ci goto out; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n", 13838c2ecf20Sopenharmony_ci q_data_src->rect.width, q_data_src->rect.height, 13848c2ecf20Sopenharmony_ci (char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc, 13858c2ecf20Sopenharmony_ci ctx->params.framerate & 0xffff, 13868c2ecf20Sopenharmony_ci (ctx->params.framerate >> 16) + 1); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* Save stream headers */ 13898c2ecf20Sopenharmony_ci buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 13908c2ecf20Sopenharmony_ci switch (dst_fourcc) { 13918c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 13928c2ecf20Sopenharmony_ci /* 13938c2ecf20Sopenharmony_ci * Get SPS in the first frame and copy it to an 13948c2ecf20Sopenharmony_ci * intermediate buffer. 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_SPS, 13978c2ecf20Sopenharmony_ci &ctx->vpu_header[0][0], 13988c2ecf20Sopenharmony_ci &ctx->vpu_header_size[0]); 13998c2ecf20Sopenharmony_ci if (ret < 0) 14008c2ecf20Sopenharmony_ci goto out; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* 14038c2ecf20Sopenharmony_ci * If visible width or height are not aligned to macroblock 14048c2ecf20Sopenharmony_ci * size, the crop_right and crop_bottom SPS fields must be set 14058c2ecf20Sopenharmony_ci * to the difference between visible and coded size. This is 14068c2ecf20Sopenharmony_ci * only supported by CODA960 firmware. All others do not allow 14078c2ecf20Sopenharmony_ci * writing frame cropping parameters, so we have to manually 14088c2ecf20Sopenharmony_ci * fix up the SPS RBSP (Sequence Parameter Set Raw Byte 14098c2ecf20Sopenharmony_ci * Sequence Payload) ourselves. 14108c2ecf20Sopenharmony_ci */ 14118c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product != CODA_960 && 14128c2ecf20Sopenharmony_ci ((q_data_src->rect.width % 16) || 14138c2ecf20Sopenharmony_ci (q_data_src->rect.height % 16))) { 14148c2ecf20Sopenharmony_ci ret = coda_h264_sps_fixup(ctx, q_data_src->rect.width, 14158c2ecf20Sopenharmony_ci q_data_src->rect.height, 14168c2ecf20Sopenharmony_ci &ctx->vpu_header[0][0], 14178c2ecf20Sopenharmony_ci &ctx->vpu_header_size[0], 14188c2ecf20Sopenharmony_ci sizeof(ctx->vpu_header[0])); 14198c2ecf20Sopenharmony_ci if (ret < 0) 14208c2ecf20Sopenharmony_ci goto out; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* 14248c2ecf20Sopenharmony_ci * Get PPS in the first frame and copy it to an 14258c2ecf20Sopenharmony_ci * intermediate buffer. 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_H264_PPS, 14288c2ecf20Sopenharmony_ci &ctx->vpu_header[1][0], 14298c2ecf20Sopenharmony_ci &ctx->vpu_header_size[1]); 14308c2ecf20Sopenharmony_ci if (ret < 0) 14318c2ecf20Sopenharmony_ci goto out; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* 14348c2ecf20Sopenharmony_ci * Length of H.264 headers is variable and thus it might not be 14358c2ecf20Sopenharmony_ci * aligned for the coda to append the encoded frame. In that is 14368c2ecf20Sopenharmony_ci * the case a filler NAL must be added to header 2. 14378c2ecf20Sopenharmony_ci */ 14388c2ecf20Sopenharmony_ci ctx->vpu_header_size[2] = coda_h264_padding( 14398c2ecf20Sopenharmony_ci (ctx->vpu_header_size[0] + 14408c2ecf20Sopenharmony_ci ctx->vpu_header_size[1]), 14418c2ecf20Sopenharmony_ci ctx->vpu_header[2]); 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * Get VOS in the first frame and copy it to an 14468c2ecf20Sopenharmony_ci * intermediate buffer 14478c2ecf20Sopenharmony_ci */ 14488c2ecf20Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOS, 14498c2ecf20Sopenharmony_ci &ctx->vpu_header[0][0], 14508c2ecf20Sopenharmony_ci &ctx->vpu_header_size[0]); 14518c2ecf20Sopenharmony_ci if (ret < 0) 14528c2ecf20Sopenharmony_ci goto out; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VIS, 14558c2ecf20Sopenharmony_ci &ctx->vpu_header[1][0], 14568c2ecf20Sopenharmony_ci &ctx->vpu_header_size[1]); 14578c2ecf20Sopenharmony_ci if (ret < 0) 14588c2ecf20Sopenharmony_ci goto out; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci ret = coda_encode_header(ctx, buf, CODA_HEADER_MP4V_VOL, 14618c2ecf20Sopenharmony_ci &ctx->vpu_header[2][0], 14628c2ecf20Sopenharmony_ci &ctx->vpu_header_size[2]); 14638c2ecf20Sopenharmony_ci if (ret < 0) 14648c2ecf20Sopenharmony_ci goto out; 14658c2ecf20Sopenharmony_ci break; 14668c2ecf20Sopenharmony_ci default: 14678c2ecf20Sopenharmony_ci /* No more formats need to save headers at the moment */ 14688c2ecf20Sopenharmony_ci break; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ciout: 14728c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 14738c2ecf20Sopenharmony_ci return ret; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic int coda_prepare_encode(struct coda_ctx *ctx) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 14798c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, *dst_buf; 14808c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 14818c2ecf20Sopenharmony_ci int force_ipicture; 14828c2ecf20Sopenharmony_ci int quant_param = 0; 14838c2ecf20Sopenharmony_ci u32 pic_stream_buffer_addr, pic_stream_buffer_size; 14848c2ecf20Sopenharmony_ci u32 rot_mode = 0; 14858c2ecf20Sopenharmony_ci u32 dst_fourcc; 14868c2ecf20Sopenharmony_ci u32 reg; 14878c2ecf20Sopenharmony_ci int ret; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci ret = coda_enc_param_change(ctx); 14908c2ecf20Sopenharmony_ci if (ret < 0) { 14918c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", 14928c2ecf20Sopenharmony_ci ret); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 14968c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 14978c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 14988c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 14998c2ecf20Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci src_buf->sequence = ctx->osequence; 15028c2ecf20Sopenharmony_ci dst_buf->sequence = ctx->osequence; 15038c2ecf20Sopenharmony_ci ctx->osequence++; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci force_ipicture = ctx->params.force_ipicture; 15068c2ecf20Sopenharmony_ci if (force_ipicture) 15078c2ecf20Sopenharmony_ci ctx->params.force_ipicture = false; 15088c2ecf20Sopenharmony_ci else if (ctx->params.gop_size != 0 && 15098c2ecf20Sopenharmony_ci (src_buf->sequence % ctx->params.gop_size) == 0) 15108c2ecf20Sopenharmony_ci force_ipicture = 1; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* 15138c2ecf20Sopenharmony_ci * Workaround coda firmware BUG that only marks the first 15148c2ecf20Sopenharmony_ci * frame as IDR. This is a problem for some decoders that can't 15158c2ecf20Sopenharmony_ci * recover when a frame is lost. 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_ci if (!force_ipicture) { 15188c2ecf20Sopenharmony_ci src_buf->flags |= V4L2_BUF_FLAG_PFRAME; 15198c2ecf20Sopenharmony_ci src_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; 15208c2ecf20Sopenharmony_ci } else { 15218c2ecf20Sopenharmony_ci src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 15228c2ecf20Sopenharmony_ci src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 15268c2ecf20Sopenharmony_ci coda_set_gdi_regs(ctx); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* 15298c2ecf20Sopenharmony_ci * Copy headers in front of the first frame and forced I frames for 15308c2ecf20Sopenharmony_ci * H.264 only. In MPEG4 they are already copied by the CODA. 15318c2ecf20Sopenharmony_ci */ 15328c2ecf20Sopenharmony_ci if (src_buf->sequence == 0 || force_ipicture) { 15338c2ecf20Sopenharmony_ci pic_stream_buffer_addr = 15348c2ecf20Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0) + 15358c2ecf20Sopenharmony_ci ctx->vpu_header_size[0] + 15368c2ecf20Sopenharmony_ci ctx->vpu_header_size[1] + 15378c2ecf20Sopenharmony_ci ctx->vpu_header_size[2]; 15388c2ecf20Sopenharmony_ci pic_stream_buffer_size = q_data_dst->sizeimage - 15398c2ecf20Sopenharmony_ci ctx->vpu_header_size[0] - 15408c2ecf20Sopenharmony_ci ctx->vpu_header_size[1] - 15418c2ecf20Sopenharmony_ci ctx->vpu_header_size[2]; 15428c2ecf20Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0), 15438c2ecf20Sopenharmony_ci &ctx->vpu_header[0][0], ctx->vpu_header_size[0]); 15448c2ecf20Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 15458c2ecf20Sopenharmony_ci + ctx->vpu_header_size[0], &ctx->vpu_header[1][0], 15468c2ecf20Sopenharmony_ci ctx->vpu_header_size[1]); 15478c2ecf20Sopenharmony_ci memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) 15488c2ecf20Sopenharmony_ci + ctx->vpu_header_size[0] + ctx->vpu_header_size[1], 15498c2ecf20Sopenharmony_ci &ctx->vpu_header[2][0], ctx->vpu_header_size[2]); 15508c2ecf20Sopenharmony_ci } else { 15518c2ecf20Sopenharmony_ci pic_stream_buffer_addr = 15528c2ecf20Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); 15538c2ecf20Sopenharmony_ci pic_stream_buffer_size = q_data_dst->sizeimage; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (force_ipicture) { 15578c2ecf20Sopenharmony_ci switch (dst_fourcc) { 15588c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 15598c2ecf20Sopenharmony_ci quant_param = ctx->params.h264_intra_qp; 15608c2ecf20Sopenharmony_ci break; 15618c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 15628c2ecf20Sopenharmony_ci quant_param = ctx->params.mpeg4_intra_qp; 15638c2ecf20Sopenharmony_ci break; 15648c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 15658c2ecf20Sopenharmony_ci quant_param = 30; 15668c2ecf20Sopenharmony_ci break; 15678c2ecf20Sopenharmony_ci default: 15688c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 15698c2ecf20Sopenharmony_ci "cannot set intra qp, fmt not supported\n"); 15708c2ecf20Sopenharmony_ci break; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci } else { 15738c2ecf20Sopenharmony_ci switch (dst_fourcc) { 15748c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 15758c2ecf20Sopenharmony_ci quant_param = ctx->params.h264_inter_qp; 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 15788c2ecf20Sopenharmony_ci quant_param = ctx->params.mpeg4_inter_qp; 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci default: 15818c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 15828c2ecf20Sopenharmony_ci "cannot set inter qp, fmt not supported\n"); 15838c2ecf20Sopenharmony_ci break; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci /* submit */ 15888c2ecf20Sopenharmony_ci if (ctx->params.rot_mode) 15898c2ecf20Sopenharmony_ci rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 15908c2ecf20Sopenharmony_ci coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE); 15918c2ecf20Sopenharmony_ci coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 15948c2ecf20Sopenharmony_ci coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX); 15958c2ecf20Sopenharmony_ci coda_write(dev, q_data_src->bytesperline, 15968c2ecf20Sopenharmony_ci CODA9_CMD_ENC_PIC_SRC_STRIDE); 15978c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y; 16008c2ecf20Sopenharmony_ci } else { 16018c2ecf20Sopenharmony_ci reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci coda_write_base(ctx, q_data_src, src_buf, reg); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci coda_write(dev, force_ipicture << 1 & 0x2, 16068c2ecf20Sopenharmony_ci CODA_CMD_ENC_PIC_OPTION); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START); 16098c2ecf20Sopenharmony_ci coda_write(dev, pic_stream_buffer_size / 1024, 16108c2ecf20Sopenharmony_ci CODA_CMD_ENC_PIC_BB_SIZE); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci if (!ctx->streamon_out) { 16138c2ecf20Sopenharmony_ci /* After streamoff on the output side, set stream end flag */ 16148c2ecf20Sopenharmony_ci ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 16158c2ecf20Sopenharmony_ci coda_write(dev, ctx->bit_stream_param, 16168c2ecf20Sopenharmony_ci CODA_REG_BIT_BIT_STREAM_PARAM); 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 16208c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.axi_sram_use, 16218c2ecf20Sopenharmony_ci CODA7_REG_BIT_AXI_SRAM_USE); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci trace_coda_enc_pic_run(ctx, src_buf); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci return 0; 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic char coda_frame_type_char(u32 flags) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 16338c2ecf20Sopenharmony_ci (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 16348c2ecf20Sopenharmony_ci (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic void coda_finish_encode(struct coda_ctx *ctx) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *src_buf, *dst_buf; 16408c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 16418c2ecf20Sopenharmony_ci u32 wr_ptr, start_ptr; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (ctx->aborting) 16448c2ecf20Sopenharmony_ci return; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci /* 16478c2ecf20Sopenharmony_ci * Lock to make sure that an encoder stop command running in parallel 16488c2ecf20Sopenharmony_ci * will either already have marked src_buf as last, or it will wake up 16498c2ecf20Sopenharmony_ci * the capture queue after the buffers are returned. 16508c2ecf20Sopenharmony_ci */ 16518c2ecf20Sopenharmony_ci mutex_lock(&ctx->wakeup_mutex); 16528c2ecf20Sopenharmony_ci src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 16538c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci trace_coda_enc_pic_done(ctx, dst_buf); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* Get results from the coda */ 16588c2ecf20Sopenharmony_ci start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); 16598c2ecf20Sopenharmony_ci wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci /* Calculate bytesused field */ 16628c2ecf20Sopenharmony_ci if (dst_buf->sequence == 0 || 16638c2ecf20Sopenharmony_ci src_buf->flags & V4L2_BUF_FLAG_KEYFRAME) { 16648c2ecf20Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr + 16658c2ecf20Sopenharmony_ci ctx->vpu_header_size[0] + 16668c2ecf20Sopenharmony_ci ctx->vpu_header_size[1] + 16678c2ecf20Sopenharmony_ci ctx->vpu_header_size[2]); 16688c2ecf20Sopenharmony_ci } else { 16698c2ecf20Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr); 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); 16758c2ecf20Sopenharmony_ci coda_read(dev, CODA_RET_ENC_PIC_FLAG); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 16788c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_PFRAME | 16798c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_LAST); 16808c2ecf20Sopenharmony_ci if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) 16818c2ecf20Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; 16828c2ecf20Sopenharmony_ci else 16838c2ecf20Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; 16848c2ecf20Sopenharmony_ci dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 16918c2ecf20Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 16928c2ecf20Sopenharmony_ci mutex_unlock(&ctx->wakeup_mutex); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci ctx->gopcounter--; 16958c2ecf20Sopenharmony_ci if (ctx->gopcounter < 0) 16968c2ecf20Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", 16998c2ecf20Sopenharmony_ci coda_frame_type_char(dst_buf->flags), dst_buf->sequence, 17008c2ecf20Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic void coda_seq_end_work(struct work_struct *work) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work); 17068c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 17098c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (ctx->initialized == 0) 17128c2ecf20Sopenharmony_ci goto out; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__); 17158c2ecf20Sopenharmony_ci if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) { 17168c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 17178c2ecf20Sopenharmony_ci "CODA_COMMAND_SEQ_END failed\n"); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* 17218c2ecf20Sopenharmony_ci * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing 17228c2ecf20Sopenharmony_ci * from the output stream after the h.264 decoder has run. Resetting the 17238c2ecf20Sopenharmony_ci * hardware after the decoder has finished seems to help. 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 17268c2ecf20Sopenharmony_ci coda_hw_reset(ctx); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 17298c2ecf20Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci coda_free_framebuffers(ctx); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci ctx->initialized = 0; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ciout: 17368c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 17378c2ecf20Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 17388c2ecf20Sopenharmony_ci} 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_cistatic void coda_bit_release(struct coda_ctx *ctx) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 17438c2ecf20Sopenharmony_ci coda_free_framebuffers(ctx); 17448c2ecf20Sopenharmony_ci coda_free_context_buffers(ctx); 17458c2ecf20Sopenharmony_ci coda_free_bitstream_buffer(ctx); 17468c2ecf20Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ciconst struct coda_context_ops coda_bit_encode_ops = { 17508c2ecf20Sopenharmony_ci .queue_init = coda_encoder_queue_init, 17518c2ecf20Sopenharmony_ci .reqbufs = coda_encoder_reqbufs, 17528c2ecf20Sopenharmony_ci .start_streaming = coda_start_encoding, 17538c2ecf20Sopenharmony_ci .prepare_run = coda_prepare_encode, 17548c2ecf20Sopenharmony_ci .finish_run = coda_finish_encode, 17558c2ecf20Sopenharmony_ci .seq_end_work = coda_seq_end_work, 17568c2ecf20Sopenharmony_ci .release = coda_bit_release, 17578c2ecf20Sopenharmony_ci}; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci/* 17608c2ecf20Sopenharmony_ci * Decoder context operations 17618c2ecf20Sopenharmony_ci */ 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, 17648c2ecf20Sopenharmony_ci struct coda_q_data *q_data) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci if (ctx->bitstream.vaddr) 17678c2ecf20Sopenharmony_ci return 0; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); 17708c2ecf20Sopenharmony_ci ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, 17718c2ecf20Sopenharmony_ci &ctx->bitstream.paddr, GFP_KERNEL); 17728c2ecf20Sopenharmony_ci if (!ctx->bitstream.vaddr) { 17738c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 17748c2ecf20Sopenharmony_ci "failed to allocate bitstream ringbuffer"); 17758c2ecf20Sopenharmony_ci return -ENOMEM; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 17788c2ecf20Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return 0; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic void coda_free_bitstream_buffer(struct coda_ctx *ctx) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci if (ctx->bitstream.vaddr == NULL) 17868c2ecf20Sopenharmony_ci return; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, 17898c2ecf20Sopenharmony_ci ctx->bitstream.paddr); 17908c2ecf20Sopenharmony_ci ctx->bitstream.vaddr = NULL; 17918c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, NULL, 0); 17928c2ecf20Sopenharmony_ci} 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic int coda_decoder_reqbufs(struct coda_ctx *ctx, 17958c2ecf20Sopenharmony_ci struct v4l2_requestbuffers *rb) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 17988c2ecf20Sopenharmony_ci int ret; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 18018c2ecf20Sopenharmony_ci return 0; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (rb->count) { 18048c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 18058c2ecf20Sopenharmony_ci ret = coda_alloc_context_buffers(ctx, q_data_src); 18068c2ecf20Sopenharmony_ci if (ret < 0) 18078c2ecf20Sopenharmony_ci return ret; 18088c2ecf20Sopenharmony_ci ret = coda_alloc_bitstream_buffer(ctx, q_data_src); 18098c2ecf20Sopenharmony_ci if (ret < 0) { 18108c2ecf20Sopenharmony_ci coda_free_context_buffers(ctx); 18118c2ecf20Sopenharmony_ci return ret; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci } else { 18148c2ecf20Sopenharmony_ci coda_free_bitstream_buffer(ctx); 18158c2ecf20Sopenharmony_ci coda_free_context_buffers(ctx); 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return 0; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic bool coda_reorder_enable(struct coda_ctx *ctx) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 18248c2ecf20Sopenharmony_ci int profile; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_HX4 && 18278c2ecf20Sopenharmony_ci dev->devtype->product != CODA_7541 && 18288c2ecf20Sopenharmony_ci dev->devtype->product != CODA_960) 18298c2ecf20Sopenharmony_ci return false; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 18328c2ecf20Sopenharmony_ci return false; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) 18358c2ecf20Sopenharmony_ci return true; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci profile = coda_h264_profile(ctx->params.h264_profile_idc); 18388c2ecf20Sopenharmony_ci if (profile < 0) 18398c2ecf20Sopenharmony_ci v4l2_warn(&dev->v4l2_dev, "Unknown H264 Profile: %u\n", 18408c2ecf20Sopenharmony_ci ctx->params.h264_profile_idc); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* Baseline profile does not support reordering */ 18438c2ecf20Sopenharmony_ci return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int __coda_decoder_seq_init(struct coda_ctx *ctx) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 18498c2ecf20Sopenharmony_ci u32 bitstream_buf, bitstream_size; 18508c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 18518c2ecf20Sopenharmony_ci int width, height; 18528c2ecf20Sopenharmony_ci u32 src_fourcc, dst_fourcc; 18538c2ecf20Sopenharmony_ci u32 val; 18548c2ecf20Sopenharmony_ci int ret; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci lockdep_assert_held(&dev->coda_mutex); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", 18598c2ecf20Sopenharmony_ci ctx->use_vdoa ? "Enabled" : "Disabled"); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci /* Start decoding */ 18628c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 18638c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 18648c2ecf20Sopenharmony_ci bitstream_buf = ctx->bitstream.paddr; 18658c2ecf20Sopenharmony_ci bitstream_size = ctx->bitstream.size; 18668c2ecf20Sopenharmony_ci src_fourcc = q_data_src->fourcc; 18678c2ecf20Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci /* Update coda bitstream read and write pointers from kfifo */ 18708c2ecf20Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 18738c2ecf20Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 18748c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 18758c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 18768c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 18778c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | 18788c2ecf20Sopenharmony_ci ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 18798c2ecf20Sopenharmony_ci coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci ctx->display_idx = -1; 18828c2ecf20Sopenharmony_ci ctx->frm_dis_flg = 0; 18838c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); 18868c2ecf20Sopenharmony_ci coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); 18878c2ecf20Sopenharmony_ci val = 0; 18888c2ecf20Sopenharmony_ci if (coda_reorder_enable(ctx)) 18898c2ecf20Sopenharmony_ci val |= CODA_REORDER_ENABLE; 18908c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) 18918c2ecf20Sopenharmony_ci val |= CODA_NO_INT_ENABLE; 18928c2ecf20Sopenharmony_ci coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci ctx->params.codec_mode = ctx->codec->mode; 18958c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960 && 18968c2ecf20Sopenharmony_ci src_fourcc == V4L2_PIX_FMT_MPEG4) 18978c2ecf20Sopenharmony_ci ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4; 18988c2ecf20Sopenharmony_ci else 18998c2ecf20Sopenharmony_ci ctx->params.codec_mode_aux = 0; 19008c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_MPEG4) { 19018c2ecf20Sopenharmony_ci coda_write(dev, CODA_MP4_CLASS_MPEG4, 19028c2ecf20Sopenharmony_ci CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 19058c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 19068c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 19078c2ecf20Sopenharmony_ci coda_write(dev, ctx->psbuf.paddr, 19088c2ecf20Sopenharmony_ci CODA_CMD_DEC_SEQ_PS_BB_START); 19098c2ecf20Sopenharmony_ci coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), 19108c2ecf20Sopenharmony_ci CODA_CMD_DEC_SEQ_PS_BB_SIZE); 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 19138c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN); 19148c2ecf20Sopenharmony_ci coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE); 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_JPEG) 19188c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_JPG_THUMB_EN); 19198c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_960) 19208c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE); 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci ctx->bit_stream_param = CODA_BIT_DEC_SEQ_INIT_ESCAPE; 19238c2ecf20Sopenharmony_ci ret = coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT); 19248c2ecf20Sopenharmony_ci ctx->bit_stream_param = 0; 19258c2ecf20Sopenharmony_ci if (ret) { 19268c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); 19278c2ecf20Sopenharmony_ci return ret; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci ctx->sequence_offset = ~0U; 19308c2ecf20Sopenharmony_ci ctx->initialized = 1; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* Update kfifo out pointer from coda bitstream read pointer */ 19338c2ecf20Sopenharmony_ci coda_kfifo_sync_from_device(ctx); 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) { 19368c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 19378c2ecf20Sopenharmony_ci "CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n", 19388c2ecf20Sopenharmony_ci coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON)); 19398c2ecf20Sopenharmony_ci return -EAGAIN; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_SEQ_SRC_SIZE); 19438c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 19448c2ecf20Sopenharmony_ci width = (val >> CODADX6_PICWIDTH_OFFSET) & CODADX6_PICWIDTH_MASK; 19458c2ecf20Sopenharmony_ci height = val & CODADX6_PICHEIGHT_MASK; 19468c2ecf20Sopenharmony_ci } else { 19478c2ecf20Sopenharmony_ci width = (val >> CODA7_PICWIDTH_OFFSET) & CODA7_PICWIDTH_MASK; 19488c2ecf20Sopenharmony_ci height = val & CODA7_PICHEIGHT_MASK; 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (width > q_data_dst->bytesperline || height > q_data_dst->height) { 19528c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n", 19538c2ecf20Sopenharmony_ci width, height, q_data_dst->bytesperline, 19548c2ecf20Sopenharmony_ci q_data_dst->height); 19558c2ecf20Sopenharmony_ci return -EINVAL; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci width = round_up(width, 16); 19598c2ecf20Sopenharmony_ci height = round_up(height, 16); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED); 19648c2ecf20Sopenharmony_ci /* 19658c2ecf20Sopenharmony_ci * If the VDOA is used, the decoder needs one additional frame, 19668c2ecf20Sopenharmony_ci * because the frames are freed when the next frame is decoded. 19678c2ecf20Sopenharmony_ci * Otherwise there are visible errors in the decoded frames (green 19688c2ecf20Sopenharmony_ci * regions in displayed frames) and a broken order of frames (earlier 19698c2ecf20Sopenharmony_ci * frames are sporadically displayed after later frames). 19708c2ecf20Sopenharmony_ci */ 19718c2ecf20Sopenharmony_ci if (ctx->use_vdoa) 19728c2ecf20Sopenharmony_ci ctx->num_internal_frames += 1; 19738c2ecf20Sopenharmony_ci if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) { 19748c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 19758c2ecf20Sopenharmony_ci "not enough framebuffers to decode (%d < %d)\n", 19768c2ecf20Sopenharmony_ci CODA_MAX_FRAMEBUFFERS, ctx->num_internal_frames); 19778c2ecf20Sopenharmony_ci return -EINVAL; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 19818c2ecf20Sopenharmony_ci u32 left_right; 19828c2ecf20Sopenharmony_ci u32 top_bottom; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT); 19858c2ecf20Sopenharmony_ci top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci q_data_dst->rect.left = (left_right >> 10) & 0x3ff; 19888c2ecf20Sopenharmony_ci q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff; 19898c2ecf20Sopenharmony_ci q_data_dst->rect.width = width - q_data_dst->rect.left - 19908c2ecf20Sopenharmony_ci (left_right & 0x3ff); 19918c2ecf20Sopenharmony_ci q_data_dst->rect.height = height - q_data_dst->rect.top - 19928c2ecf20Sopenharmony_ci (top_bottom & 0x3ff); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 19968c2ecf20Sopenharmony_ci u8 profile, level; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); 19998c2ecf20Sopenharmony_ci profile = val & 0xff; 20008c2ecf20Sopenharmony_ci level = (val >> 8) & 0x7f; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (profile || level) 20038c2ecf20Sopenharmony_ci coda_update_profile_level_ctrls(ctx, profile, level); 20048c2ecf20Sopenharmony_ci } 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci return 0; 20078c2ecf20Sopenharmony_ci} 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_cistatic void coda_dec_seq_init_work(struct work_struct *work) 20108c2ecf20Sopenharmony_ci{ 20118c2ecf20Sopenharmony_ci struct coda_ctx *ctx = container_of(work, 20128c2ecf20Sopenharmony_ci struct coda_ctx, seq_init_work); 20138c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 20148c2ecf20Sopenharmony_ci int ret; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 20178c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci if (ctx->initialized == 1) 20208c2ecf20Sopenharmony_ci goto out; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci ret = __coda_decoder_seq_init(ctx); 20238c2ecf20Sopenharmony_ci if (ret < 0) 20248c2ecf20Sopenharmony_ci goto out; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci ctx->initialized = 1; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ciout: 20298c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 20308c2ecf20Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic int __coda_start_decoding(struct coda_ctx *ctx) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 20368c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 20378c2ecf20Sopenharmony_ci u32 src_fourcc, dst_fourcc; 20388c2ecf20Sopenharmony_ci int ret; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 20418c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 20428c2ecf20Sopenharmony_ci src_fourcc = q_data_src->fourcc; 20438c2ecf20Sopenharmony_ci dst_fourcc = q_data_dst->fourcc; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci if (!ctx->initialized) { 20468c2ecf20Sopenharmony_ci ret = __coda_decoder_seq_init(ctx); 20478c2ecf20Sopenharmony_ci if (ret < 0) 20488c2ecf20Sopenharmony_ci return ret; 20498c2ecf20Sopenharmony_ci } else { 20508c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | 20518c2ecf20Sopenharmony_ci CODA9_FRAME_TILED2LINEAR); 20528c2ecf20Sopenharmony_ci if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) 20538c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; 20548c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) 20558c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl |= (0x3 << 9) | 20568c2ecf20Sopenharmony_ci ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); 20628c2ecf20Sopenharmony_ci if (ret < 0) { 20638c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); 20648c2ecf20Sopenharmony_ci return ret; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* Tell the decoder how many frame buffers we allocated. */ 20688c2ecf20Sopenharmony_ci coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); 20698c2ecf20Sopenharmony_ci coda_write(dev, round_up(q_data_dst->rect.width, 16), 20708c2ecf20Sopenharmony_ci CODA_CMD_SET_FRAME_BUF_STRIDE); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) { 20738c2ecf20Sopenharmony_ci /* Set secondary AXI IRAM */ 20748c2ecf20Sopenharmony_ci coda_setup_iram(ctx); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_bit_use, 20778c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_BIT_ADDR); 20788c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ip_ac_dc_use, 20798c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR); 20808c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_y_use, 20818c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR); 20828c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_dbk_c_use, 20838c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); 20848c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_ovl_use, 20858c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); 20868c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 20878c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.buf_btp_use, 20888c2ecf20Sopenharmony_ci CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); 20918c2ecf20Sopenharmony_ci coda9_set_frame_cache(ctx, dst_fourcc); 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci } 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 20968c2ecf20Sopenharmony_ci coda_write(dev, ctx->slicebuf.paddr, 20978c2ecf20Sopenharmony_ci CODA_CMD_SET_FRAME_SLICE_BB_START); 20988c2ecf20Sopenharmony_ci coda_write(dev, ctx->slicebuf.size / 1024, 20998c2ecf20Sopenharmony_ci CODA_CMD_SET_FRAME_SLICE_BB_SIZE); 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 21038c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 21048c2ecf20Sopenharmony_ci int max_mb_x = 1920 / 16; 21058c2ecf20Sopenharmony_ci int max_mb_y = 1088 / 16; 21068c2ecf20Sopenharmony_ci int max_mb_num = max_mb_x * max_mb_y; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 21098c2ecf20Sopenharmony_ci CODA7_CMD_SET_FRAME_MAX_DEC_SIZE); 21108c2ecf20Sopenharmony_ci } else if (dev->devtype->product == CODA_960) { 21118c2ecf20Sopenharmony_ci int max_mb_x = 1920 / 16; 21128c2ecf20Sopenharmony_ci int max_mb_y = 1088 / 16; 21138c2ecf20Sopenharmony_ci int max_mb_num = max_mb_x * max_mb_y; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y, 21168c2ecf20Sopenharmony_ci CODA9_CMD_SET_FRAME_MAX_DEC_SIZE); 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) { 21208c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 21218c2ecf20Sopenharmony_ci "CODA_COMMAND_SET_FRAME_BUF timeout\n"); 21228c2ecf20Sopenharmony_ci return -ETIMEDOUT; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci return 0; 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic int coda_start_decoding(struct coda_ctx *ctx) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 21318c2ecf20Sopenharmony_ci int ret; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 21348c2ecf20Sopenharmony_ci ret = __coda_start_decoding(ctx); 21358c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci return ret; 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic int coda_prepare_decode(struct coda_ctx *ctx) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 21438c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 21448c2ecf20Sopenharmony_ci struct coda_q_data *q_data_dst; 21458c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 21468c2ecf20Sopenharmony_ci u32 rot_mode = 0; 21478c2ecf20Sopenharmony_ci u32 reg_addr, reg_stride; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 21508c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci /* Try to copy source buffer contents into the bitstream ringbuffer */ 21538c2ecf20Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 21548c2ecf20Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 21558c2ecf20Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci if (coda_get_bitstream_payload(ctx) < 512 && 21588c2ecf20Sopenharmony_ci (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { 21598c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", 21608c2ecf20Sopenharmony_ci coda_get_bitstream_payload(ctx)); 21618c2ecf20Sopenharmony_ci v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); 21628c2ecf20Sopenharmony_ci return -EAGAIN; 21638c2ecf20Sopenharmony_ci } 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci /* Run coda_start_decoding (again) if not yet initialized */ 21668c2ecf20Sopenharmony_ci if (!ctx->initialized) { 21678c2ecf20Sopenharmony_ci int ret = __coda_start_decoding(ctx); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (ret < 0) { 21708c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); 21718c2ecf20Sopenharmony_ci v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); 21728c2ecf20Sopenharmony_ci return -EAGAIN; 21738c2ecf20Sopenharmony_ci } else { 21748c2ecf20Sopenharmony_ci ctx->initialized = 1; 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_ci } 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 21798c2ecf20Sopenharmony_ci coda_set_gdi_regs(ctx); 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci if (ctx->use_vdoa && 21828c2ecf20Sopenharmony_ci ctx->display_idx >= 0 && 21838c2ecf20Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 21848c2ecf20Sopenharmony_ci vdoa_device_run(ctx->vdoa, 21858c2ecf20Sopenharmony_ci vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), 21868c2ecf20Sopenharmony_ci ctx->internal_frames[ctx->display_idx].buf.paddr); 21878c2ecf20Sopenharmony_ci } else { 21888c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 21898c2ecf20Sopenharmony_ci /* 21908c2ecf20Sopenharmony_ci * It was previously assumed that the CODA960 has an 21918c2ecf20Sopenharmony_ci * internal list of 64 buffer entries that contains 21928c2ecf20Sopenharmony_ci * both the registered internal frame buffers as well 21938c2ecf20Sopenharmony_ci * as the rotator buffer output, and that the ROT_INDEX 21948c2ecf20Sopenharmony_ci * register must be set to a value between the last 21958c2ecf20Sopenharmony_ci * internal frame buffers' index and 64. 21968c2ecf20Sopenharmony_ci * At least on firmware version 3.1.1 it turns out that 21978c2ecf20Sopenharmony_ci * setting ROT_INDEX to any value >= 32 causes CODA 21988c2ecf20Sopenharmony_ci * hangups that it can not recover from with the SRC VPU 21998c2ecf20Sopenharmony_ci * reset. 22008c2ecf20Sopenharmony_ci * It does appear to work however, to just set it to a 22018c2ecf20Sopenharmony_ci * fixed value in the [ctx->num_internal_frames, 31] 22028c2ecf20Sopenharmony_ci * range, for example CODA_MAX_FRAMEBUFFERS. 22038c2ecf20Sopenharmony_ci */ 22048c2ecf20Sopenharmony_ci coda_write(dev, CODA_MAX_FRAMEBUFFERS, 22058c2ecf20Sopenharmony_ci CODA9_CMD_DEC_PIC_ROT_INDEX); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y; 22088c2ecf20Sopenharmony_ci reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE; 22098c2ecf20Sopenharmony_ci } else { 22108c2ecf20Sopenharmony_ci reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y; 22118c2ecf20Sopenharmony_ci reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE; 22128c2ecf20Sopenharmony_ci } 22138c2ecf20Sopenharmony_ci coda_write_base(ctx, q_data_dst, dst_buf, reg_addr); 22148c2ecf20Sopenharmony_ci coda_write(dev, q_data_dst->bytesperline, reg_stride); 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci coda_write(dev, rot_mode, CODA_CMD_DEC_PIC_ROT_MODE); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 22228c2ecf20Sopenharmony_ci case CODA_DX6: 22238c2ecf20Sopenharmony_ci /* TBD */ 22248c2ecf20Sopenharmony_ci case CODA_HX4: 22258c2ecf20Sopenharmony_ci case CODA_7541: 22268c2ecf20Sopenharmony_ci coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); 22278c2ecf20Sopenharmony_ci break; 22288c2ecf20Sopenharmony_ci case CODA_960: 22298c2ecf20Sopenharmony_ci /* 'hardcode to use interrupt disable mode'? */ 22308c2ecf20Sopenharmony_ci coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); 22318c2ecf20Sopenharmony_ci break; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM); 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_BB_START); 22378c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_CMD_DEC_PIC_START_BYTE); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 22408c2ecf20Sopenharmony_ci coda_write(dev, ctx->iram_info.axi_sram_use, 22418c2ecf20Sopenharmony_ci CODA7_REG_BIT_AXI_SRAM_USE); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 22448c2ecf20Sopenharmony_ci meta = list_first_entry_or_null(&ctx->buffer_meta_list, 22458c2ecf20Sopenharmony_ci struct coda_buffer_meta, list); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) { 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* If this is the last buffer in the bitstream, add padding */ 22508c2ecf20Sopenharmony_ci if (meta->end == ctx->bitstream_fifo.kfifo.in) { 22518c2ecf20Sopenharmony_ci static unsigned char buf[512]; 22528c2ecf20Sopenharmony_ci unsigned int pad; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci /* Pad to multiple of 256 and then add 256 more */ 22558c2ecf20Sopenharmony_ci pad = ((0 - meta->end) & 0xff) + 256; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci memset(buf, 0xff, sizeof(buf)); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci kfifo_in(&ctx->bitstream_fifo, buf, pad); 22608c2ecf20Sopenharmony_ci } 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci coda_kfifo_sync_to_device_full(ctx); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci /* Clear decode success flag */ 22678c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci /* Clear error return value */ 22708c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci trace_coda_dec_pic_run(ctx, meta); 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci coda_command_async(ctx, CODA_COMMAND_PIC_RUN); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci return 0; 22778c2ecf20Sopenharmony_ci} 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_cistatic void coda_finish_decode(struct coda_ctx *ctx) 22808c2ecf20Sopenharmony_ci{ 22818c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 22828c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 22838c2ecf20Sopenharmony_ci struct coda_q_data *q_data_dst; 22848c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 22858c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 22868c2ecf20Sopenharmony_ci int width, height; 22878c2ecf20Sopenharmony_ci int decoded_idx; 22888c2ecf20Sopenharmony_ci int display_idx; 22898c2ecf20Sopenharmony_ci struct coda_internal_frame *decoded_frame = NULL; 22908c2ecf20Sopenharmony_ci u32 src_fourcc; 22918c2ecf20Sopenharmony_ci int success; 22928c2ecf20Sopenharmony_ci u32 err_mb; 22938c2ecf20Sopenharmony_ci int err_vdoa = 0; 22948c2ecf20Sopenharmony_ci u32 val; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (ctx->aborting) 22978c2ecf20Sopenharmony_ci return; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* Update kfifo out pointer from coda bitstream read pointer */ 23008c2ecf20Sopenharmony_ci coda_kfifo_sync_from_device(ctx); 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* 23038c2ecf20Sopenharmony_ci * in stream-end mode, the read pointer can overshoot the write pointer 23048c2ecf20Sopenharmony_ci * by up to 512 bytes 23058c2ecf20Sopenharmony_ci */ 23068c2ecf20Sopenharmony_ci if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { 23078c2ecf20Sopenharmony_ci if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) 23088c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 23098c2ecf20Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 23138c2ecf20Sopenharmony_ci src_fourcc = q_data_src->fourcc; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_SUCCESS); 23168c2ecf20Sopenharmony_ci if (val != 1) 23178c2ecf20Sopenharmony_ci pr_err("DEC_PIC_SUCCESS = %d\n", val); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci success = val & 0x1; 23208c2ecf20Sopenharmony_ci if (!success) 23218c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "decode failed\n"); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 23248c2ecf20Sopenharmony_ci if (val & (1 << 3)) 23258c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 23268c2ecf20Sopenharmony_ci "insufficient PS buffer space (%d bytes)\n", 23278c2ecf20Sopenharmony_ci ctx->psbuf.size); 23288c2ecf20Sopenharmony_ci if (val & (1 << 2)) 23298c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 23308c2ecf20Sopenharmony_ci "insufficient slice buffer space (%d bytes)\n", 23318c2ecf20Sopenharmony_ci ctx->slicebuf.size); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_SIZE); 23358c2ecf20Sopenharmony_ci width = (val >> 16) & 0xffff; 23368c2ecf20Sopenharmony_ci height = val & 0xffff; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci /* frame crop information */ 23418c2ecf20Sopenharmony_ci if (src_fourcc == V4L2_PIX_FMT_H264) { 23428c2ecf20Sopenharmony_ci u32 left_right; 23438c2ecf20Sopenharmony_ci u32 top_bottom; 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT); 23468c2ecf20Sopenharmony_ci top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM); 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci if (left_right == 0xffffffff && top_bottom == 0xffffffff) { 23498c2ecf20Sopenharmony_ci /* Keep current crop information */ 23508c2ecf20Sopenharmony_ci } else { 23518c2ecf20Sopenharmony_ci struct v4l2_rect *rect = &q_data_dst->rect; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci rect->left = left_right >> 16 & 0xffff; 23548c2ecf20Sopenharmony_ci rect->top = top_bottom >> 16 & 0xffff; 23558c2ecf20Sopenharmony_ci rect->width = width - rect->left - 23568c2ecf20Sopenharmony_ci (left_right & 0xffff); 23578c2ecf20Sopenharmony_ci rect->height = height - rect->top - 23588c2ecf20Sopenharmony_ci (top_bottom & 0xffff); 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci } else { 23618c2ecf20Sopenharmony_ci /* no cropping */ 23628c2ecf20Sopenharmony_ci } 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB); 23658c2ecf20Sopenharmony_ci if (err_mb > 0) 23668c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 23678c2ecf20Sopenharmony_ci "errors in %d macroblocks\n", err_mb); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_HX4 || 23708c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541) { 23718c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); 23728c2ecf20Sopenharmony_ci if (val == 0) { 23738c2ecf20Sopenharmony_ci /* not enough bitstream data */ 23748c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "prescan failed: %d\n", val); 23758c2ecf20Sopenharmony_ci ctx->hold = true; 23768c2ecf20Sopenharmony_ci return; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci /* Wait until the VDOA finished writing the previous display frame */ 23818c2ecf20Sopenharmony_ci if (ctx->use_vdoa && 23828c2ecf20Sopenharmony_ci ctx->display_idx >= 0 && 23838c2ecf20Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 23848c2ecf20Sopenharmony_ci err_vdoa = vdoa_wait_for_completion(ctx->vdoa); 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci ctx->frm_dis_flg = coda_read(dev, 23888c2ecf20Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci /* The previous display frame was copied out and can be overwritten */ 23918c2ecf20Sopenharmony_ci if (ctx->display_idx >= 0 && 23928c2ecf20Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 23938c2ecf20Sopenharmony_ci ctx->frm_dis_flg &= ~(1 << ctx->display_idx); 23948c2ecf20Sopenharmony_ci coda_write(dev, ctx->frm_dis_flg, 23958c2ecf20Sopenharmony_ci CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx)); 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci /* 23998c2ecf20Sopenharmony_ci * The index of the last decoded frame, not necessarily in 24008c2ecf20Sopenharmony_ci * display order, and the index of the next display frame. 24018c2ecf20Sopenharmony_ci * The latter could have been decoded in a previous run. 24028c2ecf20Sopenharmony_ci */ 24038c2ecf20Sopenharmony_ci decoded_idx = coda_read(dev, CODA_RET_DEC_PIC_CUR_IDX); 24048c2ecf20Sopenharmony_ci display_idx = coda_read(dev, CODA_RET_DEC_PIC_FRAME_IDX); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (decoded_idx == -1) { 24078c2ecf20Sopenharmony_ci /* no frame was decoded, but we might have a display frame */ 24088c2ecf20Sopenharmony_ci if (display_idx >= 0 && display_idx < ctx->num_internal_frames) 24098c2ecf20Sopenharmony_ci ctx->sequence_offset++; 24108c2ecf20Sopenharmony_ci else if (ctx->display_idx < 0) 24118c2ecf20Sopenharmony_ci ctx->hold = true; 24128c2ecf20Sopenharmony_ci } else if (decoded_idx == -2) { 24138c2ecf20Sopenharmony_ci if (ctx->display_idx >= 0 && 24148c2ecf20Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) 24158c2ecf20Sopenharmony_ci ctx->sequence_offset++; 24168c2ecf20Sopenharmony_ci /* no frame was decoded, we still return remaining buffers */ 24178c2ecf20Sopenharmony_ci } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { 24188c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 24198c2ecf20Sopenharmony_ci "decoded frame index out of range: %d\n", decoded_idx); 24208c2ecf20Sopenharmony_ci } else { 24218c2ecf20Sopenharmony_ci decoded_frame = &ctx->internal_frames[decoded_idx]; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); 24248c2ecf20Sopenharmony_ci if (ctx->sequence_offset == -1) 24258c2ecf20Sopenharmony_ci ctx->sequence_offset = val; 24268c2ecf20Sopenharmony_ci val -= ctx->sequence_offset; 24278c2ecf20Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 24288c2ecf20Sopenharmony_ci if (!list_empty(&ctx->buffer_meta_list)) { 24298c2ecf20Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 24308c2ecf20Sopenharmony_ci struct coda_buffer_meta, list); 24318c2ecf20Sopenharmony_ci list_del(&meta->list); 24328c2ecf20Sopenharmony_ci ctx->num_metas--; 24338c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 24348c2ecf20Sopenharmony_ci /* 24358c2ecf20Sopenharmony_ci * Clamp counters to 16 bits for comparison, as the HW 24368c2ecf20Sopenharmony_ci * counter rolls over at this point for h.264. This 24378c2ecf20Sopenharmony_ci * may be different for other formats, but using 16 bits 24388c2ecf20Sopenharmony_ci * should be enough to detect most errors and saves us 24398c2ecf20Sopenharmony_ci * from doing different things based on the format. 24408c2ecf20Sopenharmony_ci */ 24418c2ecf20Sopenharmony_ci if ((val & 0xffff) != (meta->sequence & 0xffff)) { 24428c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 24438c2ecf20Sopenharmony_ci "sequence number mismatch (%d(%d) != %d)\n", 24448c2ecf20Sopenharmony_ci val, ctx->sequence_offset, 24458c2ecf20Sopenharmony_ci meta->sequence); 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci decoded_frame->meta = *meta; 24488c2ecf20Sopenharmony_ci kfree(meta); 24498c2ecf20Sopenharmony_ci } else { 24508c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 24518c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); 24528c2ecf20Sopenharmony_ci memset(&decoded_frame->meta, 0, 24538c2ecf20Sopenharmony_ci sizeof(struct coda_buffer_meta)); 24548c2ecf20Sopenharmony_ci decoded_frame->meta.sequence = val; 24558c2ecf20Sopenharmony_ci decoded_frame->meta.last = false; 24568c2ecf20Sopenharmony_ci ctx->sequence_offset++; 24578c2ecf20Sopenharmony_ci } 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci trace_coda_dec_pic_done(ctx, &decoded_frame->meta); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; 24628c2ecf20Sopenharmony_ci decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : 24638c2ecf20Sopenharmony_ci (val == 1) ? V4L2_BUF_FLAG_PFRAME : 24648c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_BFRAME; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci decoded_frame->error = err_mb; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (display_idx == -1) { 24708c2ecf20Sopenharmony_ci /* 24718c2ecf20Sopenharmony_ci * no more frames to be decoded, but there could still 24728c2ecf20Sopenharmony_ci * be rotator output to dequeue 24738c2ecf20Sopenharmony_ci */ 24748c2ecf20Sopenharmony_ci ctx->hold = true; 24758c2ecf20Sopenharmony_ci } else if (display_idx == -3) { 24768c2ecf20Sopenharmony_ci /* possibly prescan failure */ 24778c2ecf20Sopenharmony_ci } else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) { 24788c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 24798c2ecf20Sopenharmony_ci "presentation frame index out of range: %d\n", 24808c2ecf20Sopenharmony_ci display_idx); 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci /* If a frame was copied out, return it */ 24848c2ecf20Sopenharmony_ci if (ctx->display_idx >= 0 && 24858c2ecf20Sopenharmony_ci ctx->display_idx < ctx->num_internal_frames) { 24868c2ecf20Sopenharmony_ci struct coda_internal_frame *ready_frame; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci ready_frame = &ctx->internal_frames[ctx->display_idx]; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 24918c2ecf20Sopenharmony_ci dst_buf->sequence = ctx->osequence++; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci dst_buf->field = V4L2_FIELD_NONE; 24948c2ecf20Sopenharmony_ci dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | 24958c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_PFRAME | 24968c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_BFRAME); 24978c2ecf20Sopenharmony_ci dst_buf->flags |= ready_frame->type; 24988c2ecf20Sopenharmony_ci meta = &ready_frame->meta; 24998c2ecf20Sopenharmony_ci if (meta->last && !coda_reorder_enable(ctx)) { 25008c2ecf20Sopenharmony_ci /* 25018c2ecf20Sopenharmony_ci * If this was the last decoded frame, and reordering 25028c2ecf20Sopenharmony_ci * is disabled, this will be the last display frame. 25038c2ecf20Sopenharmony_ci */ 25048c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "last meta, marking as last frame\n"); 25058c2ecf20Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_LAST; 25068c2ecf20Sopenharmony_ci } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && 25078c2ecf20Sopenharmony_ci display_idx == -1) { 25088c2ecf20Sopenharmony_ci /* 25098c2ecf20Sopenharmony_ci * If there is no designated presentation frame anymore, 25108c2ecf20Sopenharmony_ci * this frame has to be the last one. 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 25138c2ecf20Sopenharmony_ci "no more frames to return, marking as last frame\n"); 25148c2ecf20Sopenharmony_ci dst_buf->flags |= V4L2_BUF_FLAG_LAST; 25158c2ecf20Sopenharmony_ci } 25168c2ecf20Sopenharmony_ci dst_buf->timecode = meta->timecode; 25178c2ecf20Sopenharmony_ci dst_buf->vb2_buf.timestamp = meta->timestamp; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci trace_coda_dec_rot_done(ctx, dst_buf, meta); 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 25228c2ecf20Sopenharmony_ci q_data_dst->sizeimage); 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci if (ready_frame->error || err_vdoa) 25258c2ecf20Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 25268c2ecf20Sopenharmony_ci else 25278c2ecf20Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (decoded_frame) { 25308c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", 25318c2ecf20Sopenharmony_ci coda_frame_type_char(decoded_frame->type), 25328c2ecf20Sopenharmony_ci decoded_frame->meta.sequence, 25338c2ecf20Sopenharmony_ci coda_frame_type_char(dst_buf->flags), 25348c2ecf20Sopenharmony_ci ready_frame->meta.sequence, 25358c2ecf20Sopenharmony_ci dst_buf->sequence, ctx->qsequence, 25368c2ecf20Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 25378c2ecf20Sopenharmony_ci " (last)" : ""); 25388c2ecf20Sopenharmony_ci } else { 25398c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", 25408c2ecf20Sopenharmony_ci decoded_idx, 25418c2ecf20Sopenharmony_ci coda_frame_type_char(dst_buf->flags), 25428c2ecf20Sopenharmony_ci ready_frame->meta.sequence, 25438c2ecf20Sopenharmony_ci dst_buf->sequence, ctx->qsequence, 25448c2ecf20Sopenharmony_ci (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? 25458c2ecf20Sopenharmony_ci " (last)" : ""); 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci } else { 25488c2ecf20Sopenharmony_ci if (decoded_frame) { 25498c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", 25508c2ecf20Sopenharmony_ci coda_frame_type_char(decoded_frame->type), 25518c2ecf20Sopenharmony_ci decoded_frame->meta.sequence, 25528c2ecf20Sopenharmony_ci ctx->display_idx); 25538c2ecf20Sopenharmony_ci } else { 25548c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", 25558c2ecf20Sopenharmony_ci decoded_idx, ctx->display_idx); 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci /* The rotator will copy the current display frame next time */ 25608c2ecf20Sopenharmony_ci ctx->display_idx = display_idx; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci /* 25638c2ecf20Sopenharmony_ci * The current decode run might have brought the bitstream fill level 25648c2ecf20Sopenharmony_ci * below the size where we can start the next decode run. As userspace 25658c2ecf20Sopenharmony_ci * might have filled the output queue completely and might thus be 25668c2ecf20Sopenharmony_ci * blocked, we can't rely on the next qbuf to trigger the bitstream 25678c2ecf20Sopenharmony_ci * refill. Check if we have data to refill the bitstream now. 25688c2ecf20Sopenharmony_ci */ 25698c2ecf20Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 25708c2ecf20Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 25718c2ecf20Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_cistatic void coda_decode_timeout(struct coda_ctx *ctx) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *dst_buf; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci /* 25798c2ecf20Sopenharmony_ci * For now this only handles the case where we would deadlock with 25808c2ecf20Sopenharmony_ci * userspace, i.e. userspace issued DEC_CMD_STOP and waits for EOS, 25818c2ecf20Sopenharmony_ci * but after a failed decode run we would hold the context and wait for 25828c2ecf20Sopenharmony_ci * userspace to queue more buffers. 25838c2ecf20Sopenharmony_ci */ 25848c2ecf20Sopenharmony_ci if (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)) 25858c2ecf20Sopenharmony_ci return; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 25888c2ecf20Sopenharmony_ci dst_buf->sequence = ctx->qsequence - 1; 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); 25918c2ecf20Sopenharmony_ci} 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ciconst struct coda_context_ops coda_bit_decode_ops = { 25948c2ecf20Sopenharmony_ci .queue_init = coda_decoder_queue_init, 25958c2ecf20Sopenharmony_ci .reqbufs = coda_decoder_reqbufs, 25968c2ecf20Sopenharmony_ci .start_streaming = coda_start_decoding, 25978c2ecf20Sopenharmony_ci .prepare_run = coda_prepare_decode, 25988c2ecf20Sopenharmony_ci .finish_run = coda_finish_decode, 25998c2ecf20Sopenharmony_ci .run_timeout = coda_decode_timeout, 26008c2ecf20Sopenharmony_ci .seq_init_work = coda_dec_seq_init_work, 26018c2ecf20Sopenharmony_ci .seq_end_work = coda_seq_end_work, 26028c2ecf20Sopenharmony_ci .release = coda_bit_release, 26038c2ecf20Sopenharmony_ci}; 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ciirqreturn_t coda_irq_handler(int irq, void *data) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci struct coda_dev *dev = data; 26088c2ecf20Sopenharmony_ci struct coda_ctx *ctx; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci /* read status register to attend the IRQ */ 26118c2ecf20Sopenharmony_ci coda_read(dev, CODA_REG_BIT_INT_STATUS); 26128c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_INT_REASON); 26138c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, 26148c2ecf20Sopenharmony_ci CODA_REG_BIT_INT_CLEAR); 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); 26178c2ecf20Sopenharmony_ci if (ctx == NULL) { 26188c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 26198c2ecf20Sopenharmony_ci "Instance released before the end of transaction\n"); 26208c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci trace_coda_bit_done(ctx); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci if (ctx->aborting) { 26268c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "task has been aborted\n"); 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci if (coda_isbusy(ctx->dev)) { 26308c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "coda is still busy!!!!\n"); 26318c2ecf20Sopenharmony_ci return IRQ_NONE; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci complete(&ctx->completion); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26378c2ecf20Sopenharmony_ci} 2638