18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Coda multi-standard codec IP 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 */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/firmware.h> 148c2ecf20Sopenharmony_ci#include <linux/gcd.h> 158c2ecf20Sopenharmony_ci#include <linux/genalloc.h> 168c2ecf20Sopenharmony_ci#include <linux/idr.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/irq.h> 208c2ecf20Sopenharmony_ci#include <linux/kfifo.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 278c2ecf20Sopenharmony_ci#include <linux/of.h> 288c2ecf20Sopenharmony_ci#include <linux/platform_data/media/coda.h> 298c2ecf20Sopenharmony_ci#include <linux/reset.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 328c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 338c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 348c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 358c2ecf20Sopenharmony_ci#include <media/v4l2-mem2mem.h> 368c2ecf20Sopenharmony_ci#include <media/videobuf2-v4l2.h> 378c2ecf20Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 388c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "coda.h" 418c2ecf20Sopenharmony_ci#include "imx-vdoa.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define CODA_NAME "coda" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define CODADX6_MAX_INSTANCES 4 468c2ecf20Sopenharmony_ci#define CODA_MAX_FORMATS 4 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define CODA_ISRAM_SIZE (2048 * 2) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define MIN_W 48 518c2ecf20Sopenharmony_ci#define MIN_H 16 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define S_ALIGN 1 /* multiple of 2 */ 548c2ecf20Sopenharmony_ci#define W_ALIGN 1 /* multiple of 2 */ 558c2ecf20Sopenharmony_ci#define H_ALIGN 1 /* multiple of 2 */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint coda_debug; 608c2ecf20Sopenharmony_cimodule_param(coda_debug, int, 0644); 618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int disable_tiling; 648c2ecf20Sopenharmony_cimodule_param(disable_tiling, int, 0644); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int disable_vdoa; 688c2ecf20Sopenharmony_cimodule_param(disable_vdoa, int, 0644); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion"); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int enable_bwb = 0; 728c2ecf20Sopenharmony_cimodule_param(enable_bwb, int, 0644); 738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain streams"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid coda_write(struct coda_dev *dev, u32 data, u32 reg) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci v4l2_dbg(3, coda_debug, &dev->v4l2_dev, 788c2ecf20Sopenharmony_ci "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); 798c2ecf20Sopenharmony_ci writel(data, dev->regs_base + reg); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciunsigned int coda_read(struct coda_dev *dev, u32 reg) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u32 data; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci data = readl(dev->regs_base + reg); 878c2ecf20Sopenharmony_ci v4l2_dbg(3, coda_debug, &dev->v4l2_dev, 888c2ecf20Sopenharmony_ci "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); 898c2ecf20Sopenharmony_ci return data; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_civoid coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, 938c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf, unsigned int reg_y) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci u32 base_y = vb2_dma_contig_plane_dma_addr(&buf->vb2_buf, 0); 968c2ecf20Sopenharmony_ci u32 base_cb, base_cr; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci switch (q_data->fourcc) { 998c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 1008c2ecf20Sopenharmony_ci /* Fallthrough: IN -H264-> CODA -NV12 MB-> VDOA -YUYV-> OUT */ 1018c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 1028c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 1038c2ecf20Sopenharmony_ci default: 1048c2ecf20Sopenharmony_ci base_cb = base_y + q_data->bytesperline * q_data->height; 1058c2ecf20Sopenharmony_ci base_cr = base_cb + q_data->bytesperline * q_data->height / 4; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 1088c2ecf20Sopenharmony_ci /* Switch Cb and Cr for YVU420 format */ 1098c2ecf20Sopenharmony_ci base_cr = base_y + q_data->bytesperline * q_data->height; 1108c2ecf20Sopenharmony_ci base_cb = base_cr + q_data->bytesperline * q_data->height / 4; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 1138c2ecf20Sopenharmony_ci base_cb = base_y + q_data->bytesperline * q_data->height; 1148c2ecf20Sopenharmony_ci base_cr = base_cb + q_data->bytesperline * q_data->height / 2; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci coda_write(ctx->dev, base_y, reg_y); 1188c2ecf20Sopenharmony_ci coda_write(ctx->dev, base_cb, reg_y + 4); 1198c2ecf20Sopenharmony_ci coda_write(ctx->dev, base_cr, reg_y + 8); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ 1238c2ecf20Sopenharmony_ci { mode, src_fourcc, dst_fourcc, max_w, max_h } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* 1268c2ecf20Sopenharmony_ci * Arrays of codecs supported by each given version of Coda: 1278c2ecf20Sopenharmony_ci * i.MX27 -> codadx6 1288c2ecf20Sopenharmony_ci * i.MX51 -> codahx4 1298c2ecf20Sopenharmony_ci * i.MX53 -> coda7 1308c2ecf20Sopenharmony_ci * i.MX6 -> coda960 1318c2ecf20Sopenharmony_ci * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic const struct coda_codec codadx6_codecs[] = { 1348c2ecf20Sopenharmony_ci CODA_CODEC(CODADX6_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), 1358c2ecf20Sopenharmony_ci CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic const struct coda_codec codahx4_codecs[] = { 1398c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), 1408c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), 1418c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), 1428c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic const struct coda_codec coda7_codecs[] = { 1468c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), 1478c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), 1488c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), 1498c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), 1508c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), 1518c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), 1528c2ecf20Sopenharmony_ci CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const struct coda_codec coda9_codecs[] = { 1568c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), 1578c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), 1588c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), 1598c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), 1608c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), 1618c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), 1628c2ecf20Sopenharmony_ci CODA_CODEC(CODA9_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistruct coda_video_device { 1668c2ecf20Sopenharmony_ci const char *name; 1678c2ecf20Sopenharmony_ci enum coda_inst_type type; 1688c2ecf20Sopenharmony_ci const struct coda_context_ops *ops; 1698c2ecf20Sopenharmony_ci bool direct; 1708c2ecf20Sopenharmony_ci u32 src_formats[CODA_MAX_FORMATS]; 1718c2ecf20Sopenharmony_ci u32 dst_formats[CODA_MAX_FORMATS]; 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct coda_video_device coda_bit_encoder = { 1758c2ecf20Sopenharmony_ci .name = "coda-encoder", 1768c2ecf20Sopenharmony_ci .type = CODA_INST_ENCODER, 1778c2ecf20Sopenharmony_ci .ops = &coda_bit_encode_ops, 1788c2ecf20Sopenharmony_ci .src_formats = { 1798c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 1808c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 1818c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 1828c2ecf20Sopenharmony_ci }, 1838c2ecf20Sopenharmony_ci .dst_formats = { 1848c2ecf20Sopenharmony_ci V4L2_PIX_FMT_H264, 1858c2ecf20Sopenharmony_ci V4L2_PIX_FMT_MPEG4, 1868c2ecf20Sopenharmony_ci }, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic const struct coda_video_device coda_bit_jpeg_encoder = { 1908c2ecf20Sopenharmony_ci .name = "coda-jpeg-encoder", 1918c2ecf20Sopenharmony_ci .type = CODA_INST_ENCODER, 1928c2ecf20Sopenharmony_ci .ops = &coda_bit_encode_ops, 1938c2ecf20Sopenharmony_ci .src_formats = { 1948c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 1958c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 1968c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 1978c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV422P, 1988c2ecf20Sopenharmony_ci }, 1998c2ecf20Sopenharmony_ci .dst_formats = { 2008c2ecf20Sopenharmony_ci V4L2_PIX_FMT_JPEG, 2018c2ecf20Sopenharmony_ci }, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct coda_video_device coda_bit_decoder = { 2058c2ecf20Sopenharmony_ci .name = "coda-decoder", 2068c2ecf20Sopenharmony_ci .type = CODA_INST_DECODER, 2078c2ecf20Sopenharmony_ci .ops = &coda_bit_decode_ops, 2088c2ecf20Sopenharmony_ci .src_formats = { 2098c2ecf20Sopenharmony_ci V4L2_PIX_FMT_H264, 2108c2ecf20Sopenharmony_ci V4L2_PIX_FMT_MPEG2, 2118c2ecf20Sopenharmony_ci V4L2_PIX_FMT_MPEG4, 2128c2ecf20Sopenharmony_ci }, 2138c2ecf20Sopenharmony_ci .dst_formats = { 2148c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 2158c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 2168c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * If V4L2_PIX_FMT_YUYV should be default, 2198c2ecf20Sopenharmony_ci * set_default_params() must be adjusted. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUYV, 2228c2ecf20Sopenharmony_ci }, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const struct coda_video_device coda_bit_jpeg_decoder = { 2268c2ecf20Sopenharmony_ci .name = "coda-jpeg-decoder", 2278c2ecf20Sopenharmony_ci .type = CODA_INST_DECODER, 2288c2ecf20Sopenharmony_ci .ops = &coda_bit_decode_ops, 2298c2ecf20Sopenharmony_ci .src_formats = { 2308c2ecf20Sopenharmony_ci V4L2_PIX_FMT_JPEG, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci .dst_formats = { 2338c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 2348c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 2358c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 2368c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV422P, 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic const struct coda_video_device coda9_jpeg_encoder = { 2418c2ecf20Sopenharmony_ci .name = "coda-jpeg-encoder", 2428c2ecf20Sopenharmony_ci .type = CODA_INST_ENCODER, 2438c2ecf20Sopenharmony_ci .ops = &coda9_jpeg_encode_ops, 2448c2ecf20Sopenharmony_ci .direct = true, 2458c2ecf20Sopenharmony_ci .src_formats = { 2468c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 2478c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 2488c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 2498c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV422P, 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci .dst_formats = { 2528c2ecf20Sopenharmony_ci V4L2_PIX_FMT_JPEG, 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct coda_video_device coda9_jpeg_decoder = { 2578c2ecf20Sopenharmony_ci .name = "coda-jpeg-decoder", 2588c2ecf20Sopenharmony_ci .type = CODA_INST_DECODER, 2598c2ecf20Sopenharmony_ci .ops = &coda9_jpeg_decode_ops, 2608c2ecf20Sopenharmony_ci .direct = true, 2618c2ecf20Sopenharmony_ci .src_formats = { 2628c2ecf20Sopenharmony_ci V4L2_PIX_FMT_JPEG, 2638c2ecf20Sopenharmony_ci }, 2648c2ecf20Sopenharmony_ci .dst_formats = { 2658c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 2668c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 2678c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 2688c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV422P, 2698c2ecf20Sopenharmony_ci }, 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic const struct coda_video_device *codadx6_video_devices[] = { 2738c2ecf20Sopenharmony_ci &coda_bit_encoder, 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const struct coda_video_device *codahx4_video_devices[] = { 2778c2ecf20Sopenharmony_ci &coda_bit_encoder, 2788c2ecf20Sopenharmony_ci &coda_bit_decoder, 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const struct coda_video_device *coda7_video_devices[] = { 2828c2ecf20Sopenharmony_ci &coda_bit_jpeg_encoder, 2838c2ecf20Sopenharmony_ci &coda_bit_jpeg_decoder, 2848c2ecf20Sopenharmony_ci &coda_bit_encoder, 2858c2ecf20Sopenharmony_ci &coda_bit_decoder, 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic const struct coda_video_device *coda9_video_devices[] = { 2898c2ecf20Sopenharmony_ci &coda9_jpeg_encoder, 2908c2ecf20Sopenharmony_ci &coda9_jpeg_decoder, 2918c2ecf20Sopenharmony_ci &coda_bit_encoder, 2928c2ecf20Sopenharmony_ci &coda_bit_decoder, 2938c2ecf20Sopenharmony_ci}; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * Normalize all supported YUV 4:2:0 formats to the value used in the codec 2978c2ecf20Sopenharmony_ci * tables. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic u32 coda_format_normalize_yuv(u32 fourcc) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci switch (fourcc) { 3028c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 3038c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 3048c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 3058c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 3068c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 3078c2ecf20Sopenharmony_ci return V4L2_PIX_FMT_YUV420; 3088c2ecf20Sopenharmony_ci default: 3098c2ecf20Sopenharmony_ci return fourcc; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic const struct coda_codec *coda_find_codec(struct coda_dev *dev, 3148c2ecf20Sopenharmony_ci int src_fourcc, int dst_fourcc) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci const struct coda_codec *codecs = dev->devtype->codecs; 3178c2ecf20Sopenharmony_ci int num_codecs = dev->devtype->num_codecs; 3188c2ecf20Sopenharmony_ci int k; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci src_fourcc = coda_format_normalize_yuv(src_fourcc); 3218c2ecf20Sopenharmony_ci dst_fourcc = coda_format_normalize_yuv(dst_fourcc); 3228c2ecf20Sopenharmony_ci if (src_fourcc == dst_fourcc) 3238c2ecf20Sopenharmony_ci return NULL; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci for (k = 0; k < num_codecs; k++) { 3268c2ecf20Sopenharmony_ci if (codecs[k].src_fourcc == src_fourcc && 3278c2ecf20Sopenharmony_ci codecs[k].dst_fourcc == dst_fourcc) 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (k == num_codecs) 3328c2ecf20Sopenharmony_ci return NULL; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return &codecs[k]; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void coda_get_max_dimensions(struct coda_dev *dev, 3388c2ecf20Sopenharmony_ci const struct coda_codec *codec, 3398c2ecf20Sopenharmony_ci int *max_w, int *max_h) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci const struct coda_codec *codecs = dev->devtype->codecs; 3428c2ecf20Sopenharmony_ci int num_codecs = dev->devtype->num_codecs; 3438c2ecf20Sopenharmony_ci unsigned int w, h; 3448c2ecf20Sopenharmony_ci int k; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (codec) { 3478c2ecf20Sopenharmony_ci w = codec->max_w; 3488c2ecf20Sopenharmony_ci h = codec->max_h; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci for (k = 0, w = 0, h = 0; k < num_codecs; k++) { 3518c2ecf20Sopenharmony_ci w = max(w, codecs[k].max_w); 3528c2ecf20Sopenharmony_ci h = max(h, codecs[k].max_h); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (max_w) 3578c2ecf20Sopenharmony_ci *max_w = w; 3588c2ecf20Sopenharmony_ci if (max_h) 3598c2ecf20Sopenharmony_ci *max_h = h; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic const struct coda_video_device *to_coda_video_device(struct video_device 3638c2ecf20Sopenharmony_ci *vdev) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct coda_dev *dev = video_get_drvdata(vdev); 3668c2ecf20Sopenharmony_ci unsigned int i = vdev - dev->vfd; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (i >= dev->devtype->num_vdevs) 3698c2ecf20Sopenharmony_ci return NULL; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return dev->devtype->vdevs[i]; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciconst char *coda_product_name(int product) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci static char buf[9]; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci switch (product) { 3798c2ecf20Sopenharmony_ci case CODA_DX6: 3808c2ecf20Sopenharmony_ci return "CodaDx6"; 3818c2ecf20Sopenharmony_ci case CODA_HX4: 3828c2ecf20Sopenharmony_ci return "CodaHx4"; 3838c2ecf20Sopenharmony_ci case CODA_7541: 3848c2ecf20Sopenharmony_ci return "CODA7541"; 3858c2ecf20Sopenharmony_ci case CODA_960: 3868c2ecf20Sopenharmony_ci return "CODA960"; 3878c2ecf20Sopenharmony_ci default: 3888c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "(0x%04x)", product); 3898c2ecf20Sopenharmony_ci return buf; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct vdoa_data *coda_get_vdoa_data(void) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct device_node *vdoa_node; 3968c2ecf20Sopenharmony_ci struct platform_device *vdoa_pdev; 3978c2ecf20Sopenharmony_ci struct vdoa_data *vdoa_data = NULL; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci vdoa_node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-vdoa"); 4008c2ecf20Sopenharmony_ci if (!vdoa_node) 4018c2ecf20Sopenharmony_ci return NULL; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci vdoa_pdev = of_find_device_by_node(vdoa_node); 4048c2ecf20Sopenharmony_ci if (!vdoa_pdev) 4058c2ecf20Sopenharmony_ci goto out; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci vdoa_data = platform_get_drvdata(vdoa_pdev); 4088c2ecf20Sopenharmony_ci if (!vdoa_data) 4098c2ecf20Sopenharmony_ci vdoa_data = ERR_PTR(-EPROBE_DEFER); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci put_device(&vdoa_pdev->dev); 4128c2ecf20Sopenharmony_ciout: 4138c2ecf20Sopenharmony_ci of_node_put(vdoa_node); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return vdoa_data; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* 4198c2ecf20Sopenharmony_ci * V4L2 ioctl() operations. 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_cistatic int coda_querycap(struct file *file, void *priv, 4228c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci strscpy(cap->driver, CODA_NAME, sizeof(cap->driver)); 4278c2ecf20Sopenharmony_ci strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), 4288c2ecf20Sopenharmony_ci sizeof(cap->card)); 4298c2ecf20Sopenharmony_ci strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info)); 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic const u32 coda_formats_420[CODA_MAX_FORMATS] = { 4348c2ecf20Sopenharmony_ci V4L2_PIX_FMT_NV12, 4358c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420, 4368c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YVU420, 4378c2ecf20Sopenharmony_ci}; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int coda_enum_fmt(struct file *file, void *priv, 4408c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(file); 4438c2ecf20Sopenharmony_ci const struct coda_video_device *cvd = to_coda_video_device(vdev); 4448c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 4458c2ecf20Sopenharmony_ci const u32 *formats; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 4488c2ecf20Sopenharmony_ci formats = cvd->src_formats; 4498c2ecf20Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { 4508c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 4518c2ecf20Sopenharmony_ci struct vb2_queue *src_vq; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci formats = cvd->dst_formats; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* 4568c2ecf20Sopenharmony_ci * If the source format is already fixed, only allow the same 4578c2ecf20Sopenharmony_ci * chroma subsampling. 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 4608c2ecf20Sopenharmony_ci src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 4618c2ecf20Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT); 4628c2ecf20Sopenharmony_ci if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && 4638c2ecf20Sopenharmony_ci vb2_is_streaming(src_vq)) { 4648c2ecf20Sopenharmony_ci if (ctx->params.jpeg_chroma_subsampling == 4658c2ecf20Sopenharmony_ci V4L2_JPEG_CHROMA_SUBSAMPLING_420) { 4668c2ecf20Sopenharmony_ci formats = coda_formats_420; 4678c2ecf20Sopenharmony_ci } else if (ctx->params.jpeg_chroma_subsampling == 4688c2ecf20Sopenharmony_ci V4L2_JPEG_CHROMA_SUBSAMPLING_422) { 4698c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_YUV422P; 4708c2ecf20Sopenharmony_ci return f->index ? -EINVAL : 0; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* Skip YUYV if the vdoa is not available */ 4818c2ecf20Sopenharmony_ci if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && 4828c2ecf20Sopenharmony_ci formats[f->index] == V4L2_PIX_FMT_YUYV) 4838c2ecf20Sopenharmony_ci return -EINVAL; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci f->pixelformat = formats[f->index]; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int coda_g_fmt(struct file *file, void *priv, 4918c2ecf20Sopenharmony_ci struct v4l2_format *f) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 4948c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, f->type); 4978c2ecf20Sopenharmony_ci if (!q_data) 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 5018c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = q_data->fourcc; 5028c2ecf20Sopenharmony_ci f->fmt.pix.width = q_data->width; 5038c2ecf20Sopenharmony_ci f->fmt.pix.height = q_data->height; 5048c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = q_data->bytesperline; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = q_data->sizeimage; 5078c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = ctx->colorspace; 5088c2ecf20Sopenharmony_ci f->fmt.pix.xfer_func = ctx->xfer_func; 5098c2ecf20Sopenharmony_ci f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; 5108c2ecf20Sopenharmony_ci f->fmt.pix.quantization = ctx->quantization; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 5188c2ecf20Sopenharmony_ci const u32 *formats; 5198c2ecf20Sopenharmony_ci int i; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 5228c2ecf20Sopenharmony_ci formats = ctx->cvd->src_formats; 5238c2ecf20Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 5248c2ecf20Sopenharmony_ci formats = ctx->cvd->dst_formats; 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci return -EINVAL; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci for (i = 0; i < CODA_MAX_FORMATS; i++) { 5298c2ecf20Sopenharmony_ci /* Skip YUYV if the vdoa is not available */ 5308c2ecf20Sopenharmony_ci if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && 5318c2ecf20Sopenharmony_ci formats[i] == V4L2_PIX_FMT_YUYV) 5328c2ecf20Sopenharmony_ci continue; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (formats[i] == f->fmt.pix.pixelformat) { 5358c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = formats[i]; 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* Fall back to currently set pixelformat */ 5418c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, f->type); 5428c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = q_data->fourcc; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic int coda_try_fmt_vdoa(struct coda_ctx *ctx, struct v4l2_format *f, 5488c2ecf20Sopenharmony_ci bool *use_vdoa) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci int err; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 5538c2ecf20Sopenharmony_ci return -EINVAL; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (!use_vdoa) 5568c2ecf20Sopenharmony_ci return -EINVAL; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!ctx->vdoa) { 5598c2ecf20Sopenharmony_ci *use_vdoa = false; 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci err = vdoa_context_configure(NULL, round_up(f->fmt.pix.width, 16), 5648c2ecf20Sopenharmony_ci f->fmt.pix.height, f->fmt.pix.pixelformat); 5658c2ecf20Sopenharmony_ci if (err) { 5668c2ecf20Sopenharmony_ci *use_vdoa = false; 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci *use_vdoa = true; 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage, 5758c2ecf20Sopenharmony_ci u32 width, u32 height) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci /* 5788c2ecf20Sopenharmony_ci * This is a rough estimate for sensible compressed buffer 5798c2ecf20Sopenharmony_ci * sizes (between 1 and 16 bits per pixel). This could be 5808c2ecf20Sopenharmony_ci * improved by better format specific worst case estimates. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci return round_up(clamp(sizeimage, width * height / 8, 5838c2ecf20Sopenharmony_ci width * height * 2), PAGE_SIZE); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, 5878c2ecf20Sopenharmony_ci struct v4l2_format *f) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 5908c2ecf20Sopenharmony_ci unsigned int max_w, max_h; 5918c2ecf20Sopenharmony_ci enum v4l2_field field; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci field = f->fmt.pix.field; 5948c2ecf20Sopenharmony_ci if (field == V4L2_FIELD_ANY) 5958c2ecf20Sopenharmony_ci field = V4L2_FIELD_NONE; 5968c2ecf20Sopenharmony_ci else if (V4L2_FIELD_NONE != field) 5978c2ecf20Sopenharmony_ci return -EINVAL; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* V4L2 specification suggests the driver corrects the format struct 6008c2ecf20Sopenharmony_ci * if any of the dimensions is unsupported */ 6018c2ecf20Sopenharmony_ci f->fmt.pix.field = field; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci coda_get_max_dimensions(dev, codec, &max_w, &max_h); 6048c2ecf20Sopenharmony_ci v4l_bound_align_image(&f->fmt.pix.width, MIN_W, max_w, W_ALIGN, 6058c2ecf20Sopenharmony_ci &f->fmt.pix.height, MIN_H, max_h, H_ALIGN, 6068c2ecf20Sopenharmony_ci S_ALIGN); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci switch (f->fmt.pix.pixelformat) { 6098c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 6108c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 6118c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 6128c2ecf20Sopenharmony_ci /* 6138c2ecf20Sopenharmony_ci * Frame stride must be at least multiple of 8, 6148c2ecf20Sopenharmony_ci * but multiple of 16 for h.264 or JPEG 4:2:x 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); 6178c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 6188c2ecf20Sopenharmony_ci f->fmt.pix.height * 3 / 2; 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 6218c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; 6228c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 6238c2ecf20Sopenharmony_ci f->fmt.pix.height; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 6268c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); 6278c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 6288c2ecf20Sopenharmony_ci f->fmt.pix.height * 2; 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 6318c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 6328c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 6338c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 6348c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 6358c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, 6368c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage, 6378c2ecf20Sopenharmony_ci f->fmt.pix.width, 6388c2ecf20Sopenharmony_ci f->fmt.pix.height); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci default: 6418c2ecf20Sopenharmony_ci BUG(); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic int coda_try_fmt_vid_cap(struct file *file, void *priv, 6488c2ecf20Sopenharmony_ci struct v4l2_format *f) 6498c2ecf20Sopenharmony_ci{ 6508c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 6518c2ecf20Sopenharmony_ci const struct coda_q_data *q_data_src; 6528c2ecf20Sopenharmony_ci const struct coda_codec *codec; 6538c2ecf20Sopenharmony_ci struct vb2_queue *src_vq; 6548c2ecf20Sopenharmony_ci int ret; 6558c2ecf20Sopenharmony_ci bool use_vdoa; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci ret = coda_try_pixelformat(ctx, f); 6588c2ecf20Sopenharmony_ci if (ret < 0) 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 6648c2ecf20Sopenharmony_ci * If the source format is already fixed, only allow the same output 6658c2ecf20Sopenharmony_ci * resolution. When decoding JPEG images, we also have to make sure to 6668c2ecf20Sopenharmony_ci * use the same chroma subsampling. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 6698c2ecf20Sopenharmony_ci if (vb2_is_streaming(src_vq)) { 6708c2ecf20Sopenharmony_ci f->fmt.pix.width = q_data_src->width; 6718c2ecf20Sopenharmony_ci f->fmt.pix.height = q_data_src->height; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { 6748c2ecf20Sopenharmony_ci if (ctx->params.jpeg_chroma_subsampling == 6758c2ecf20Sopenharmony_ci V4L2_JPEG_CHROMA_SUBSAMPLING_420 && 6768c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) 6778c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; 6788c2ecf20Sopenharmony_ci else if (ctx->params.jpeg_chroma_subsampling == 6798c2ecf20Sopenharmony_ci V4L2_JPEG_CHROMA_SUBSAMPLING_422) 6808c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = ctx->colorspace; 6858c2ecf20Sopenharmony_ci f->fmt.pix.xfer_func = ctx->xfer_func; 6868c2ecf20Sopenharmony_ci f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; 6878c2ecf20Sopenharmony_ci f->fmt.pix.quantization = ctx->quantization; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 6908c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, q_data_src->fourcc, 6918c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat); 6928c2ecf20Sopenharmony_ci if (!codec) 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ret = coda_try_fmt(ctx, codec, f); 6968c2ecf20Sopenharmony_ci if (ret < 0) 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* The decoders always write complete macroblocks or MCUs */ 7008c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER) { 7018c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); 7028c2ecf20Sopenharmony_ci f->fmt.pix.height = round_up(f->fmt.pix.height, 16); 7038c2ecf20Sopenharmony_ci if (codec->src_fourcc == V4L2_PIX_FMT_JPEG && 7048c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { 7058c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 7068c2ecf20Sopenharmony_ci f->fmt.pix.height * 2; 7078c2ecf20Sopenharmony_ci } else { 7088c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 7098c2ecf20Sopenharmony_ci f->fmt.pix.height * 3 / 2; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci ret = coda_try_fmt_vdoa(ctx, f, &use_vdoa); 7138c2ecf20Sopenharmony_ci if (ret < 0) 7148c2ecf20Sopenharmony_ci return ret; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { 7178c2ecf20Sopenharmony_ci if (!use_vdoa) 7188c2ecf20Sopenharmony_ci return -EINVAL; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16) * 2; 7218c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * 7228c2ecf20Sopenharmony_ci f->fmt.pix.height; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void coda_set_default_colorspace(struct v4l2_pix_format *fmt) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci enum v4l2_colorspace colorspace; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (fmt->pixelformat == V4L2_PIX_FMT_JPEG) 7348c2ecf20Sopenharmony_ci colorspace = V4L2_COLORSPACE_JPEG; 7358c2ecf20Sopenharmony_ci else if (fmt->width <= 720 && fmt->height <= 576) 7368c2ecf20Sopenharmony_ci colorspace = V4L2_COLORSPACE_SMPTE170M; 7378c2ecf20Sopenharmony_ci else 7388c2ecf20Sopenharmony_ci colorspace = V4L2_COLORSPACE_REC709; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci fmt->colorspace = colorspace; 7418c2ecf20Sopenharmony_ci fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; 7428c2ecf20Sopenharmony_ci fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 7438c2ecf20Sopenharmony_ci fmt->quantization = V4L2_QUANTIZATION_DEFAULT; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int coda_try_fmt_vid_out(struct file *file, void *priv, 7478c2ecf20Sopenharmony_ci struct v4l2_format *f) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 7508c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 7518c2ecf20Sopenharmony_ci const struct coda_q_data *q_data_dst; 7528c2ecf20Sopenharmony_ci const struct coda_codec *codec; 7538c2ecf20Sopenharmony_ci int ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ret = coda_try_pixelformat(ctx, f); 7568c2ecf20Sopenharmony_ci if (ret < 0) 7578c2ecf20Sopenharmony_ci return ret; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (f->fmt.pix.colorspace == V4L2_COLORSPACE_DEFAULT) 7608c2ecf20Sopenharmony_ci coda_set_default_colorspace(&f->fmt.pix); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 7638c2ecf20Sopenharmony_ci codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return coda_try_fmt(ctx, codec, f); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, 7698c2ecf20Sopenharmony_ci struct v4l2_rect *r) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 7728c2ecf20Sopenharmony_ci struct vb2_queue *vq; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 7758c2ecf20Sopenharmony_ci if (!vq) 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, f->type); 7798c2ecf20Sopenharmony_ci if (!q_data) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (vb2_is_busy(vq)) { 7838c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n", 7848c2ecf20Sopenharmony_ci __func__, v4l2_type_names[f->type], vq->num_buffers); 7858c2ecf20Sopenharmony_ci return -EBUSY; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci q_data->fourcc = f->fmt.pix.pixelformat; 7898c2ecf20Sopenharmony_ci q_data->width = f->fmt.pix.width; 7908c2ecf20Sopenharmony_ci q_data->height = f->fmt.pix.height; 7918c2ecf20Sopenharmony_ci q_data->bytesperline = f->fmt.pix.bytesperline; 7928c2ecf20Sopenharmony_ci q_data->sizeimage = f->fmt.pix.sizeimage; 7938c2ecf20Sopenharmony_ci if (r) { 7948c2ecf20Sopenharmony_ci q_data->rect = *r; 7958c2ecf20Sopenharmony_ci } else { 7968c2ecf20Sopenharmony_ci q_data->rect.left = 0; 7978c2ecf20Sopenharmony_ci q_data->rect.top = 0; 7988c2ecf20Sopenharmony_ci q_data->rect.width = f->fmt.pix.width; 7998c2ecf20Sopenharmony_ci q_data->rect.height = f->fmt.pix.height; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci switch (f->fmt.pix.pixelformat) { 8038c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 8048c2ecf20Sopenharmony_ci ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_NV12: 8078c2ecf20Sopenharmony_ci if (!disable_tiling && ctx->use_bit && 8088c2ecf20Sopenharmony_ci ctx->dev->devtype->product == CODA_960) { 8098c2ecf20Sopenharmony_ci ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci fallthrough; 8138c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV420: 8148c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YVU420: 8158c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 8168c2ecf20Sopenharmony_ci ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; 8178c2ecf20Sopenharmony_ci break; 8188c2ecf20Sopenharmony_ci default: 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP && 8238c2ecf20Sopenharmony_ci !coda_try_fmt_vdoa(ctx, f, &ctx->use_vdoa) && 8248c2ecf20Sopenharmony_ci ctx->use_vdoa) 8258c2ecf20Sopenharmony_ci vdoa_context_configure(ctx->vdoa, 8268c2ecf20Sopenharmony_ci round_up(f->fmt.pix.width, 16), 8278c2ecf20Sopenharmony_ci f->fmt.pix.height, 8288c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat); 8298c2ecf20Sopenharmony_ci else 8308c2ecf20Sopenharmony_ci ctx->use_vdoa = false; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n", 8338c2ecf20Sopenharmony_ci v4l2_type_names[f->type], q_data->width, q_data->height, 8348c2ecf20Sopenharmony_ci (char *)&q_data->fourcc, 8358c2ecf20Sopenharmony_ci (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T'); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int coda_s_fmt_vid_cap(struct file *file, void *priv, 8418c2ecf20Sopenharmony_ci struct v4l2_format *f) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 8448c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src; 8458c2ecf20Sopenharmony_ci const struct coda_codec *codec; 8468c2ecf20Sopenharmony_ci struct v4l2_rect r; 8478c2ecf20Sopenharmony_ci int ret; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ret = coda_try_fmt_vid_cap(file, priv, f); 8508c2ecf20Sopenharmony_ci if (ret) 8518c2ecf20Sopenharmony_ci return ret; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 8548c2ecf20Sopenharmony_ci r.left = 0; 8558c2ecf20Sopenharmony_ci r.top = 0; 8568c2ecf20Sopenharmony_ci r.width = q_data_src->width; 8578c2ecf20Sopenharmony_ci r.height = q_data_src->height; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci ret = coda_s_fmt(ctx, f, &r); 8608c2ecf20Sopenharmony_ci if (ret) 8618c2ecf20Sopenharmony_ci return ret; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_ENCODER) 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Setting the coded format determines the selected codec */ 8678c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, q_data_src->fourcc, 8688c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat); 8698c2ecf20Sopenharmony_ci if (!codec) { 8708c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); 8718c2ecf20Sopenharmony_ci return -EINVAL; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci ctx->codec = codec; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci ctx->colorspace = f->fmt.pix.colorspace; 8768c2ecf20Sopenharmony_ci ctx->xfer_func = f->fmt.pix.xfer_func; 8778c2ecf20Sopenharmony_ci ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; 8788c2ecf20Sopenharmony_ci ctx->quantization = f->fmt.pix.quantization; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci return 0; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int coda_s_fmt_vid_out(struct file *file, void *priv, 8848c2ecf20Sopenharmony_ci struct v4l2_format *f) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 8878c2ecf20Sopenharmony_ci const struct coda_codec *codec; 8888c2ecf20Sopenharmony_ci struct v4l2_format f_cap; 8898c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq; 8908c2ecf20Sopenharmony_ci int ret; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ret = coda_try_fmt_vid_out(file, priv, f); 8938c2ecf20Sopenharmony_ci if (ret) 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci ret = coda_s_fmt(ctx, f, NULL); 8978c2ecf20Sopenharmony_ci if (ret) 8988c2ecf20Sopenharmony_ci return ret; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci ctx->colorspace = f->fmt.pix.colorspace; 9018c2ecf20Sopenharmony_ci ctx->xfer_func = f->fmt.pix.xfer_func; 9028c2ecf20Sopenharmony_ci ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; 9038c2ecf20Sopenharmony_ci ctx->quantization = f->fmt.pix.quantization; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_DECODER) 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Setting the coded format determines the selected codec */ 9098c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, 9108c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420); 9118c2ecf20Sopenharmony_ci if (!codec) { 9128c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); 9138c2ecf20Sopenharmony_ci return -EINVAL; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci ctx->codec = codec; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 9188c2ecf20Sopenharmony_ci if (!dst_vq) 9198c2ecf20Sopenharmony_ci return -EINVAL; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* 9228c2ecf20Sopenharmony_ci * Setting the capture queue format is not possible while the capture 9238c2ecf20Sopenharmony_ci * queue is still busy. This is not an error, but the user will have to 9248c2ecf20Sopenharmony_ci * make sure themselves that the capture format is set correctly before 9258c2ecf20Sopenharmony_ci * starting the output queue again. 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ci if (vb2_is_busy(dst_vq)) 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci memset(&f_cap, 0, sizeof(f_cap)); 9318c2ecf20Sopenharmony_ci f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 9328c2ecf20Sopenharmony_ci coda_g_fmt(file, priv, &f_cap); 9338c2ecf20Sopenharmony_ci f_cap.fmt.pix.width = f->fmt.pix.width; 9348c2ecf20Sopenharmony_ci f_cap.fmt.pix.height = f->fmt.pix.height; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return coda_s_fmt_vid_cap(file, priv, &f_cap); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic int coda_reqbufs(struct file *file, void *priv, 9408c2ecf20Sopenharmony_ci struct v4l2_requestbuffers *rb) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 9438c2ecf20Sopenharmony_ci int ret; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); 9468c2ecf20Sopenharmony_ci if (ret) 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * Allow to allocate instance specific per-context buffers, such as 9518c2ecf20Sopenharmony_ci * bitstream ringbuffer, slice buffer, work buffer, etc. if needed. 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs) 9548c2ecf20Sopenharmony_ci return ctx->ops->reqbufs(ctx, rb); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic int coda_qbuf(struct file *file, void *priv, 9608c2ecf20Sopenharmony_ci struct v4l2_buffer *buf) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && 9658c2ecf20Sopenharmony_ci buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 9668c2ecf20Sopenharmony_ci buf->flags &= ~V4L2_BUF_FLAG_LAST; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(priv); 9748c2ecf20Sopenharmony_ci int ret; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && 9798c2ecf20Sopenharmony_ci buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 9808c2ecf20Sopenharmony_ci buf->flags &= ~V4L2_BUF_FLAG_LAST; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci return ret; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_civoid coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, 9868c2ecf20Sopenharmony_ci enum vb2_buffer_state state) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci const struct v4l2_event eos_event = { 9898c2ecf20Sopenharmony_ci .type = V4L2_EVENT_EOS 9908c2ecf20Sopenharmony_ci }; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (buf->flags & V4L2_BUF_FLAG_LAST) 9938c2ecf20Sopenharmony_ci v4l2_event_queue_fh(&ctx->fh, &eos_event); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(buf, state); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int coda_g_selection(struct file *file, void *fh, 9998c2ecf20Sopenharmony_ci struct v4l2_selection *s) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 10028c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 10038c2ecf20Sopenharmony_ci struct v4l2_rect r, *rsel; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, s->type); 10068c2ecf20Sopenharmony_ci if (!q_data) 10078c2ecf20Sopenharmony_ci return -EINVAL; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci r.left = 0; 10108c2ecf20Sopenharmony_ci r.top = 0; 10118c2ecf20Sopenharmony_ci r.width = q_data->width; 10128c2ecf20Sopenharmony_ci r.height = q_data->height; 10138c2ecf20Sopenharmony_ci rsel = &q_data->rect; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci switch (s->target) { 10168c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 10178c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 10188c2ecf20Sopenharmony_ci rsel = &r; 10198c2ecf20Sopenharmony_ci fallthrough; 10208c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP: 10218c2ecf20Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || 10228c2ecf20Sopenharmony_ci ctx->inst_type == CODA_INST_DECODER) 10238c2ecf20Sopenharmony_ci return -EINVAL; 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_BOUNDS: 10268c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_PADDED: 10278c2ecf20Sopenharmony_ci rsel = &r; 10288c2ecf20Sopenharmony_ci fallthrough; 10298c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 10308c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_DEFAULT: 10318c2ecf20Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 10328c2ecf20Sopenharmony_ci ctx->inst_type == CODA_INST_ENCODER) 10338c2ecf20Sopenharmony_ci return -EINVAL; 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci default: 10368c2ecf20Sopenharmony_ci return -EINVAL; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci s->r = *rsel; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return 0; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_cistatic int coda_s_selection(struct file *file, void *fh, 10458c2ecf20Sopenharmony_ci struct v4l2_selection *s) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 10488c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci switch (s->target) { 10518c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP: 10528c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_ENCODER && 10538c2ecf20Sopenharmony_ci s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 10548c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, s->type); 10558c2ecf20Sopenharmony_ci if (!q_data) 10568c2ecf20Sopenharmony_ci return -EINVAL; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci s->r.left = 0; 10598c2ecf20Sopenharmony_ci s->r.top = 0; 10608c2ecf20Sopenharmony_ci s->r.width = clamp(s->r.width, 2U, q_data->width); 10618c2ecf20Sopenharmony_ci s->r.height = clamp(s->r.height, 2U, q_data->height); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (s->flags & V4L2_SEL_FLAG_LE) { 10648c2ecf20Sopenharmony_ci s->r.width = round_up(s->r.width, 2); 10658c2ecf20Sopenharmony_ci s->r.height = round_up(s->r.height, 2); 10668c2ecf20Sopenharmony_ci } else { 10678c2ecf20Sopenharmony_ci s->r.width = round_down(s->r.width, 2); 10688c2ecf20Sopenharmony_ci s->r.height = round_down(s->r.height, 2); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci q_data->rect = s->r; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n", 10748c2ecf20Sopenharmony_ci s->r.width, s->r.height); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return 0; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci fallthrough; 10798c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_NATIVE_SIZE: 10808c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 10818c2ecf20Sopenharmony_ci return coda_g_selection(file, fh, s); 10828c2ecf20Sopenharmony_ci default: 10838c2ecf20Sopenharmony_ci /* v4l2-compliance expects this to fail for read-only targets */ 10848c2ecf20Sopenharmony_ci return -EINVAL; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int coda_try_encoder_cmd(struct file *file, void *fh, 10898c2ecf20Sopenharmony_ci struct v4l2_encoder_cmd *ec) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_ENCODER) 10948c2ecf20Sopenharmony_ci return -ENOTTY; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic void coda_wake_up_capture_queue(struct coda_ctx *ctx) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "waking up capture queue\n"); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 11068c2ecf20Sopenharmony_ci dst_vq->last_buffer_dequeued = true; 11078c2ecf20Sopenharmony_ci wake_up(&dst_vq->done_wq); 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic int coda_encoder_cmd(struct file *file, void *fh, 11118c2ecf20Sopenharmony_ci struct v4l2_encoder_cmd *ec) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 11148c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 11158c2ecf20Sopenharmony_ci int ret; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = coda_try_encoder_cmd(file, fh, ec); 11188c2ecf20Sopenharmony_ci if (ret < 0) 11198c2ecf20Sopenharmony_ci return ret; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci mutex_lock(&ctx->wakeup_mutex); 11228c2ecf20Sopenharmony_ci buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); 11238c2ecf20Sopenharmony_ci if (buf) { 11248c2ecf20Sopenharmony_ci /* 11258c2ecf20Sopenharmony_ci * If the last output buffer is still on the queue, make sure 11268c2ecf20Sopenharmony_ci * that decoder finish_run will see the last flag and report it 11278c2ecf20Sopenharmony_ci * to userspace. 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_ci buf->flags |= V4L2_BUF_FLAG_LAST; 11308c2ecf20Sopenharmony_ci } else { 11318c2ecf20Sopenharmony_ci /* Set the stream-end flag on this context */ 11328c2ecf20Sopenharmony_ci ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* 11358c2ecf20Sopenharmony_ci * If the last output buffer has already been taken from the 11368c2ecf20Sopenharmony_ci * queue, wake up the capture queue and signal end of stream 11378c2ecf20Sopenharmony_ci * via the -EPIPE mechanism. 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_ci coda_wake_up_capture_queue(ctx); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci mutex_unlock(&ctx->wakeup_mutex); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci return 0; 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int coda_try_decoder_cmd(struct file *file, void *fh, 11478c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd *dc) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_DECODER) 11528c2ecf20Sopenharmony_ci return -ENOTTY; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic bool coda_mark_last_meta(struct coda_ctx *ctx) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "marking last meta\n"); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 11648c2ecf20Sopenharmony_ci if (list_empty(&ctx->buffer_meta_list)) { 11658c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 11668c2ecf20Sopenharmony_ci return false; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci meta = list_last_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, 11708c2ecf20Sopenharmony_ci list); 11718c2ecf20Sopenharmony_ci meta->last = true; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 11748c2ecf20Sopenharmony_ci return true; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic bool coda_mark_last_dst_buf(struct coda_ctx *ctx) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 11808c2ecf20Sopenharmony_ci struct vb2_buffer *dst_vb; 11818c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq; 11828c2ecf20Sopenharmony_ci unsigned long flags; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "marking last capture buffer\n"); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 11878c2ecf20Sopenharmony_ci spin_lock_irqsave(&dst_vq->done_lock, flags); 11888c2ecf20Sopenharmony_ci if (list_empty(&dst_vq->done_list)) { 11898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dst_vq->done_lock, flags); 11908c2ecf20Sopenharmony_ci return false; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci dst_vb = list_last_entry(&dst_vq->done_list, struct vb2_buffer, 11948c2ecf20Sopenharmony_ci done_entry); 11958c2ecf20Sopenharmony_ci buf = to_vb2_v4l2_buffer(dst_vb); 11968c2ecf20Sopenharmony_ci buf->flags |= V4L2_BUF_FLAG_LAST; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dst_vq->done_lock, flags); 11998c2ecf20Sopenharmony_ci return true; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int coda_decoder_cmd(struct file *file, void *fh, 12038c2ecf20Sopenharmony_ci struct v4l2_decoder_cmd *dc) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 12068c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 12078c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 12088c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq; 12098c2ecf20Sopenharmony_ci bool stream_end; 12108c2ecf20Sopenharmony_ci bool wakeup; 12118c2ecf20Sopenharmony_ci int ret; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci ret = coda_try_decoder_cmd(file, fh, dc); 12148c2ecf20Sopenharmony_ci if (ret < 0) 12158c2ecf20Sopenharmony_ci return ret; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci switch (dc->cmd) { 12188c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_START: 12198c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 12208c2ecf20Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 12218c2ecf20Sopenharmony_ci coda_bitstream_flush(ctx); 12228c2ecf20Sopenharmony_ci dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 12238c2ecf20Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE); 12248c2ecf20Sopenharmony_ci vb2_clear_last_buffer_dequeued(dst_vq); 12258c2ecf20Sopenharmony_ci ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; 12268c2ecf20Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 12278c2ecf20Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 12288c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci case V4L2_DEC_CMD_STOP: 12318c2ecf20Sopenharmony_ci stream_end = false; 12328c2ecf20Sopenharmony_ci wakeup = false; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci mutex_lock(&ctx->wakeup_mutex); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); 12378c2ecf20Sopenharmony_ci if (buf) { 12388c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "marking last pending buffer\n"); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Mark last buffer */ 12418c2ecf20Sopenharmony_ci buf->flags |= V4L2_BUF_FLAG_LAST; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { 12448c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "all remaining buffers queued\n"); 12458c2ecf20Sopenharmony_ci stream_end = true; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci } else { 12488c2ecf20Sopenharmony_ci if (ctx->use_bit) 12498c2ecf20Sopenharmony_ci if (coda_mark_last_meta(ctx)) 12508c2ecf20Sopenharmony_ci stream_end = true; 12518c2ecf20Sopenharmony_ci else 12528c2ecf20Sopenharmony_ci wakeup = true; 12538c2ecf20Sopenharmony_ci else 12548c2ecf20Sopenharmony_ci if (!coda_mark_last_dst_buf(ctx)) 12558c2ecf20Sopenharmony_ci wakeup = true; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (stream_end) { 12598c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "all remaining buffers queued\n"); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Set the stream-end flag on this context */ 12628c2ecf20Sopenharmony_ci coda_bit_stream_end_flag(ctx); 12638c2ecf20Sopenharmony_ci ctx->hold = false; 12648c2ecf20Sopenharmony_ci v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (wakeup) { 12688c2ecf20Sopenharmony_ci /* If there is no buffer in flight, wake up */ 12698c2ecf20Sopenharmony_ci coda_wake_up_capture_queue(ctx); 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci mutex_unlock(&ctx->wakeup_mutex); 12738c2ecf20Sopenharmony_ci break; 12748c2ecf20Sopenharmony_ci default: 12758c2ecf20Sopenharmony_ci return -EINVAL; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci return 0; 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic int coda_enum_framesizes(struct file *file, void *fh, 12828c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 12858c2ecf20Sopenharmony_ci struct coda_q_data *q_data_dst; 12868c2ecf20Sopenharmony_ci const struct coda_codec *codec; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (ctx->inst_type != CODA_INST_ENCODER) 12898c2ecf20Sopenharmony_ci return -ENOTTY; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (fsize->index) 12928c2ecf20Sopenharmony_ci return -EINVAL; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (coda_format_normalize_yuv(fsize->pixel_format) == 12958c2ecf20Sopenharmony_ci V4L2_PIX_FMT_YUV420) { 12968c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 12978c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, fsize->pixel_format, 12988c2ecf20Sopenharmony_ci q_data_dst->fourcc); 12998c2ecf20Sopenharmony_ci } else { 13008c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, 13018c2ecf20Sopenharmony_ci fsize->pixel_format); 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci if (!codec) 13048c2ecf20Sopenharmony_ci return -EINVAL; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; 13078c2ecf20Sopenharmony_ci fsize->stepwise.min_width = MIN_W; 13088c2ecf20Sopenharmony_ci fsize->stepwise.max_width = codec->max_w; 13098c2ecf20Sopenharmony_ci fsize->stepwise.step_width = 1; 13108c2ecf20Sopenharmony_ci fsize->stepwise.min_height = MIN_H; 13118c2ecf20Sopenharmony_ci fsize->stepwise.max_height = codec->max_h; 13128c2ecf20Sopenharmony_ci fsize->stepwise.step_height = 1; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return 0; 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic int coda_enum_frameintervals(struct file *file, void *fh, 13188c2ecf20Sopenharmony_ci struct v4l2_frmivalenum *f) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 13218c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 13228c2ecf20Sopenharmony_ci const struct coda_codec *codec; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (f->index) 13258c2ecf20Sopenharmony_ci return -EINVAL; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Disallow YUYV if the vdoa is not available */ 13288c2ecf20Sopenharmony_ci if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) 13298c2ecf20Sopenharmony_ci return -EINVAL; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) { 13328c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 13338c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, f->pixel_format, 13348c2ecf20Sopenharmony_ci q_data->fourcc); 13358c2ecf20Sopenharmony_ci } else { 13368c2ecf20Sopenharmony_ci codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, 13378c2ecf20Sopenharmony_ci f->pixel_format); 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci if (!codec) 13408c2ecf20Sopenharmony_ci return -EINVAL; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci if (f->width < MIN_W || f->width > codec->max_w || 13438c2ecf20Sopenharmony_ci f->height < MIN_H || f->height > codec->max_h) 13448c2ecf20Sopenharmony_ci return -EINVAL; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; 13478c2ecf20Sopenharmony_ci f->stepwise.min.numerator = 1; 13488c2ecf20Sopenharmony_ci f->stepwise.min.denominator = 65535; 13498c2ecf20Sopenharmony_ci f->stepwise.max.numerator = 65536; 13508c2ecf20Sopenharmony_ci f->stepwise.max.denominator = 1; 13518c2ecf20Sopenharmony_ci f->stepwise.step.numerator = 1; 13528c2ecf20Sopenharmony_ci f->stepwise.step.denominator = 1; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci return 0; 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 13608c2ecf20Sopenharmony_ci struct v4l2_fract *tpf; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 13638c2ecf20Sopenharmony_ci return -EINVAL; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; 13668c2ecf20Sopenharmony_ci tpf = &a->parm.output.timeperframe; 13678c2ecf20Sopenharmony_ci tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; 13688c2ecf20Sopenharmony_ci tpf->numerator = 1 + (ctx->params.framerate >> 13698c2ecf20Sopenharmony_ci CODA_FRATE_DIV_OFFSET); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci/* 13758c2ecf20Sopenharmony_ci * Approximate timeperframe v4l2_fract with values that can be written 13768c2ecf20Sopenharmony_ci * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_cistatic void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct v4l2_fract s = *timeperframe; 13818c2ecf20Sopenharmony_ci struct v4l2_fract f0; 13828c2ecf20Sopenharmony_ci struct v4l2_fract f1 = { 1, 0 }; 13838c2ecf20Sopenharmony_ci struct v4l2_fract f2 = { 0, 1 }; 13848c2ecf20Sopenharmony_ci unsigned int i, div, s_denominator; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci /* Lower bound is 1/65535 */ 13878c2ecf20Sopenharmony_ci if (s.numerator == 0 || s.denominator / s.numerator > 65535) { 13888c2ecf20Sopenharmony_ci timeperframe->numerator = 1; 13898c2ecf20Sopenharmony_ci timeperframe->denominator = 65535; 13908c2ecf20Sopenharmony_ci return; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci /* Upper bound is 65536/1 */ 13948c2ecf20Sopenharmony_ci if (s.denominator == 0 || s.numerator / s.denominator > 65536) { 13958c2ecf20Sopenharmony_ci timeperframe->numerator = 65536; 13968c2ecf20Sopenharmony_ci timeperframe->denominator = 1; 13978c2ecf20Sopenharmony_ci return; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* Reduce fraction to lowest terms */ 14018c2ecf20Sopenharmony_ci div = gcd(s.numerator, s.denominator); 14028c2ecf20Sopenharmony_ci if (div > 1) { 14038c2ecf20Sopenharmony_ci s.numerator /= div; 14048c2ecf20Sopenharmony_ci s.denominator /= div; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (s.numerator <= 65536 && s.denominator < 65536) { 14088c2ecf20Sopenharmony_ci *timeperframe = s; 14098c2ecf20Sopenharmony_ci return; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* Find successive convergents from continued fraction expansion */ 14138c2ecf20Sopenharmony_ci while (f2.numerator <= 65536 && f2.denominator < 65536) { 14148c2ecf20Sopenharmony_ci f0 = f1; 14158c2ecf20Sopenharmony_ci f1 = f2; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* Stop when f2 exactly equals timeperframe */ 14188c2ecf20Sopenharmony_ci if (s.numerator == 0) 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci i = s.denominator / s.numerator; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci f2.numerator = f0.numerator + i * f1.numerator; 14248c2ecf20Sopenharmony_ci f2.denominator = f0.denominator + i * f2.denominator; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci s_denominator = s.numerator; 14278c2ecf20Sopenharmony_ci s.numerator = s.denominator % s.numerator; 14288c2ecf20Sopenharmony_ci s.denominator = s_denominator; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci *timeperframe = f1; 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | 14378c2ecf20Sopenharmony_ci timeperframe->denominator; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 14438c2ecf20Sopenharmony_ci struct v4l2_fract *tpf; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 14468c2ecf20Sopenharmony_ci return -EINVAL; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; 14498c2ecf20Sopenharmony_ci tpf = &a->parm.output.timeperframe; 14508c2ecf20Sopenharmony_ci coda_approximate_timeperframe(tpf); 14518c2ecf20Sopenharmony_ci ctx->params.framerate = coda_timeperframe_to_frate(tpf); 14528c2ecf20Sopenharmony_ci ctx->params.framerate_changed = true; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return 0; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic int coda_subscribe_event(struct v4l2_fh *fh, 14588c2ecf20Sopenharmony_ci const struct v4l2_event_subscription *sub) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(fh); 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci switch (sub->type) { 14638c2ecf20Sopenharmony_ci case V4L2_EVENT_EOS: 14648c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 0, NULL); 14658c2ecf20Sopenharmony_ci case V4L2_EVENT_SOURCE_CHANGE: 14668c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER) 14678c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 0, NULL); 14688c2ecf20Sopenharmony_ci else 14698c2ecf20Sopenharmony_ci return -EINVAL; 14708c2ecf20Sopenharmony_ci default: 14718c2ecf20Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops coda_ioctl_ops = { 14768c2ecf20Sopenharmony_ci .vidioc_querycap = coda_querycap, 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = coda_enum_fmt, 14798c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = coda_g_fmt, 14808c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = coda_try_fmt_vid_cap, 14818c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = coda_s_fmt_vid_cap, 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_out = coda_enum_fmt, 14848c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_out = coda_g_fmt, 14858c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, 14868c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci .vidioc_reqbufs = coda_reqbufs, 14898c2ecf20Sopenharmony_ci .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci .vidioc_qbuf = coda_qbuf, 14928c2ecf20Sopenharmony_ci .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 14938c2ecf20Sopenharmony_ci .vidioc_dqbuf = coda_dqbuf, 14948c2ecf20Sopenharmony_ci .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 14958c2ecf20Sopenharmony_ci .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci .vidioc_streamon = v4l2_m2m_ioctl_streamon, 14988c2ecf20Sopenharmony_ci .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci .vidioc_g_selection = coda_g_selection, 15018c2ecf20Sopenharmony_ci .vidioc_s_selection = coda_s_selection, 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci .vidioc_try_encoder_cmd = coda_try_encoder_cmd, 15048c2ecf20Sopenharmony_ci .vidioc_encoder_cmd = coda_encoder_cmd, 15058c2ecf20Sopenharmony_ci .vidioc_try_decoder_cmd = coda_try_decoder_cmd, 15068c2ecf20Sopenharmony_ci .vidioc_decoder_cmd = coda_decoder_cmd, 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci .vidioc_g_parm = coda_g_parm, 15098c2ecf20Sopenharmony_ci .vidioc_s_parm = coda_s_parm, 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci .vidioc_enum_framesizes = coda_enum_framesizes, 15128c2ecf20Sopenharmony_ci .vidioc_enum_frameintervals = coda_enum_frameintervals, 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci .vidioc_subscribe_event = coda_subscribe_event, 15158c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 15168c2ecf20Sopenharmony_ci}; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci/* 15198c2ecf20Sopenharmony_ci * Mem-to-mem operations. 15208c2ecf20Sopenharmony_ci */ 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic void coda_device_run(void *m2m_priv) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci struct coda_ctx *ctx = m2m_priv; 15258c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci queue_work(dev->workqueue, &ctx->pic_run_work); 15288c2ecf20Sopenharmony_ci} 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic void coda_pic_run_work(struct work_struct *work) 15318c2ecf20Sopenharmony_ci{ 15328c2ecf20Sopenharmony_ci struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work); 15338c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 15348c2ecf20Sopenharmony_ci int ret; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci mutex_lock(&ctx->buffer_mutex); 15378c2ecf20Sopenharmony_ci mutex_lock(&dev->coda_mutex); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci ret = ctx->ops->prepare_run(ctx); 15408c2ecf20Sopenharmony_ci if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) { 15418c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 15428c2ecf20Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 15438c2ecf20Sopenharmony_ci /* job_finish scheduled by prepare_decode */ 15448c2ecf20Sopenharmony_ci return; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&ctx->completion, 15488c2ecf20Sopenharmony_ci msecs_to_jiffies(1000))) { 15498c2ecf20Sopenharmony_ci if (ctx->use_bit) { 15508c2ecf20Sopenharmony_ci dev_err(dev->dev, "CODA PIC_RUN timeout\n"); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci ctx->hold = true; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci coda_hw_reset(ctx); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci if (ctx->ops->run_timeout) 15588c2ecf20Sopenharmony_ci ctx->ops->run_timeout(ctx); 15598c2ecf20Sopenharmony_ci } else { 15608c2ecf20Sopenharmony_ci ctx->ops->finish_run(ctx); 15618c2ecf20Sopenharmony_ci } 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) && 15648c2ecf20Sopenharmony_ci ctx->ops->seq_end_work) 15658c2ecf20Sopenharmony_ci queue_work(dev->workqueue, &ctx->seq_end_work); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci mutex_unlock(&dev->coda_mutex); 15688c2ecf20Sopenharmony_ci mutex_unlock(&ctx->buffer_mutex); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic int coda_job_ready(void *m2m_priv) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct coda_ctx *ctx = m2m_priv; 15768c2ecf20Sopenharmony_ci int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* 15798c2ecf20Sopenharmony_ci * For both 'P' and 'key' frame cases 1 picture 15808c2ecf20Sopenharmony_ci * and 1 frame are needed. In the decoder case, 15818c2ecf20Sopenharmony_ci * the compressed frame can be in the bitstream. 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_ci if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { 15848c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n"); 15858c2ecf20Sopenharmony_ci return 0; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) { 15898c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n"); 15908c2ecf20Sopenharmony_ci return 0; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { 15948c2ecf20Sopenharmony_ci bool stream_end = ctx->bit_stream_param & 15958c2ecf20Sopenharmony_ci CODA_BIT_STREAM_END_FLAG; 15968c2ecf20Sopenharmony_ci int num_metas = ctx->num_metas; 15978c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 15988c2ecf20Sopenharmony_ci unsigned int count; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci count = hweight32(ctx->frm_dis_flg); 16018c2ecf20Sopenharmony_ci if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) { 16028c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 16038c2ecf20Sopenharmony_ci "not ready: all internal buffers in use: %d/%d (0x%x)", 16048c2ecf20Sopenharmony_ci count, ctx->num_internal_frames, 16058c2ecf20Sopenharmony_ci ctx->frm_dis_flg); 16068c2ecf20Sopenharmony_ci return 0; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (ctx->hold && !src_bufs) { 16108c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 16118c2ecf20Sopenharmony_ci "not ready: on hold for more buffers.\n"); 16128c2ecf20Sopenharmony_ci return 0; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (!stream_end && (num_metas + src_bufs) < 2) { 16168c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 16178c2ecf20Sopenharmony_ci "not ready: need 2 buffers available (queue:%d + bitstream:%d)\n", 16188c2ecf20Sopenharmony_ci num_metas, src_bufs); 16198c2ecf20Sopenharmony_ci return 0; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 16238c2ecf20Sopenharmony_ci struct coda_buffer_meta, list); 16248c2ecf20Sopenharmony_ci if (!coda_bitstream_can_fetch_past(ctx, meta->end) && 16258c2ecf20Sopenharmony_ci !stream_end) { 16268c2ecf20Sopenharmony_ci coda_dbg(1, ctx, 16278c2ecf20Sopenharmony_ci "not ready: not enough bitstream data to read past %u (%u)\n", 16288c2ecf20Sopenharmony_ci meta->end, ctx->bitstream_fifo.kfifo.in); 16298c2ecf20Sopenharmony_ci return 0; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (ctx->aborting) { 16348c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "not ready: aborting\n"); 16358c2ecf20Sopenharmony_ci return 0; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci coda_dbg(2, ctx, "job ready\n"); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return 1; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic void coda_job_abort(void *priv) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct coda_ctx *ctx = priv; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci ctx->aborting = 1; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "job abort\n"); 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic const struct v4l2_m2m_ops coda_m2m_ops = { 16538c2ecf20Sopenharmony_ci .device_run = coda_device_run, 16548c2ecf20Sopenharmony_ci .job_ready = coda_job_ready, 16558c2ecf20Sopenharmony_ci .job_abort = coda_job_abort, 16568c2ecf20Sopenharmony_ci}; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic void set_default_params(struct coda_ctx *ctx) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci unsigned int max_w, max_h, usize, csize; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0], 16638c2ecf20Sopenharmony_ci ctx->cvd->dst_formats[0]); 16648c2ecf20Sopenharmony_ci max_w = min(ctx->codec->max_w, 1920U); 16658c2ecf20Sopenharmony_ci max_h = min(ctx->codec->max_h, 1088U); 16668c2ecf20Sopenharmony_ci usize = max_w * max_h * 3 / 2; 16678c2ecf20Sopenharmony_ci csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci ctx->params.codec_mode = ctx->codec->mode; 16708c2ecf20Sopenharmony_ci if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG) 16718c2ecf20Sopenharmony_ci ctx->colorspace = V4L2_COLORSPACE_JPEG; 16728c2ecf20Sopenharmony_ci else 16738c2ecf20Sopenharmony_ci ctx->colorspace = V4L2_COLORSPACE_REC709; 16748c2ecf20Sopenharmony_ci ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; 16758c2ecf20Sopenharmony_ci ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 16768c2ecf20Sopenharmony_ci ctx->quantization = V4L2_QUANTIZATION_DEFAULT; 16778c2ecf20Sopenharmony_ci ctx->params.framerate = 30; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci /* Default formats for output and input queues */ 16808c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; 16818c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; 16828c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].width = max_w; 16838c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].height = max_h; 16848c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].width = max_w; 16858c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].height = max_h; 16868c2ecf20Sopenharmony_ci if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) { 16878c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w; 16888c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].sizeimage = usize; 16898c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].bytesperline = 0; 16908c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].sizeimage = csize; 16918c2ecf20Sopenharmony_ci } else { 16928c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].bytesperline = 0; 16938c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].sizeimage = csize; 16948c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].bytesperline = max_w; 16958c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].sizeimage = usize; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].rect.width = max_w; 16988c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_SRC].rect.height = max_h; 16998c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].rect.width = max_w; 17008c2ecf20Sopenharmony_ci ctx->q_data[V4L2_M2M_DST].rect.height = max_h; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* 17038c2ecf20Sopenharmony_ci * Since the RBC2AXI logic only supports a single chroma plane, 17048c2ecf20Sopenharmony_ci * macroblock tiling only works for to NV12 pixel format. 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci/* 17108c2ecf20Sopenharmony_ci * Queue operations 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_cistatic int coda_queue_setup(struct vb2_queue *vq, 17138c2ecf20Sopenharmony_ci unsigned int *nbuffers, unsigned int *nplanes, 17148c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci struct coda_ctx *ctx = vb2_get_drv_priv(vq); 17178c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 17188c2ecf20Sopenharmony_ci unsigned int size; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, vq->type); 17218c2ecf20Sopenharmony_ci size = q_data->sizeimage; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (*nplanes) 17248c2ecf20Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci *nplanes = 1; 17278c2ecf20Sopenharmony_ci sizes[0] = size; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers, 17308c2ecf20Sopenharmony_ci size); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci return 0; 17338c2ecf20Sopenharmony_ci} 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_cistatic int coda_buf_prepare(struct vb2_buffer *vb) 17368c2ecf20Sopenharmony_ci{ 17378c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 17388c2ecf20Sopenharmony_ci struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 17398c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, vb->vb2_queue->type); 17428c2ecf20Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { 17438c2ecf20Sopenharmony_ci if (vbuf->field == V4L2_FIELD_ANY) 17448c2ecf20Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 17458c2ecf20Sopenharmony_ci if (vbuf->field != V4L2_FIELD_NONE) { 17468c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 17478c2ecf20Sopenharmony_ci "%s field isn't supported\n", __func__); 17488c2ecf20Sopenharmony_ci return -EINVAL; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci if (vb2_plane_size(vb, 0) < q_data->sizeimage) { 17538c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, 17548c2ecf20Sopenharmony_ci "%s data will not fit into plane (%lu < %lu)\n", 17558c2ecf20Sopenharmony_ci __func__, vb2_plane_size(vb, 0), 17568c2ecf20Sopenharmony_ci (long)q_data->sizeimage); 17578c2ecf20Sopenharmony_ci return -EINVAL; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return 0; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value) 17648c2ecf20Sopenharmony_ci{ 17658c2ecf20Sopenharmony_ci if (!ctrl) 17668c2ecf20Sopenharmony_ci return; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci v4l2_ctrl_lock(ctrl); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci /* 17718c2ecf20Sopenharmony_ci * Extend the control range if the parsed stream contains a known but 17728c2ecf20Sopenharmony_ci * unsupported value or level. 17738c2ecf20Sopenharmony_ci */ 17748c2ecf20Sopenharmony_ci if (value > ctrl->maximum) { 17758c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, value, 17768c2ecf20Sopenharmony_ci ctrl->menu_skip_mask & ~(1 << value), 17778c2ecf20Sopenharmony_ci ctrl->default_value); 17788c2ecf20Sopenharmony_ci } else if (value < ctrl->minimum) { 17798c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(ctrl, value, ctrl->maximum, 17808c2ecf20Sopenharmony_ci ctrl->menu_skip_mask & ~(1 << value), 17818c2ecf20Sopenharmony_ci ctrl->default_value); 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl(ctrl, value); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci v4l2_ctrl_unlock(ctrl); 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_civoid coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, 17908c2ecf20Sopenharmony_ci u8 level_idc) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci const char * const *profile_names; 17938c2ecf20Sopenharmony_ci const char * const *level_names; 17948c2ecf20Sopenharmony_ci struct v4l2_ctrl *profile_ctrl; 17958c2ecf20Sopenharmony_ci struct v4l2_ctrl *level_ctrl; 17968c2ecf20Sopenharmony_ci const char *codec_name; 17978c2ecf20Sopenharmony_ci u32 profile_cid; 17988c2ecf20Sopenharmony_ci u32 level_cid; 17998c2ecf20Sopenharmony_ci int profile; 18008c2ecf20Sopenharmony_ci int level; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci switch (ctx->codec->src_fourcc) { 18038c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_H264: 18048c2ecf20Sopenharmony_ci codec_name = "H264"; 18058c2ecf20Sopenharmony_ci profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; 18068c2ecf20Sopenharmony_ci level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; 18078c2ecf20Sopenharmony_ci profile_ctrl = ctx->h264_profile_ctrl; 18088c2ecf20Sopenharmony_ci level_ctrl = ctx->h264_level_ctrl; 18098c2ecf20Sopenharmony_ci profile = coda_h264_profile(profile_idc); 18108c2ecf20Sopenharmony_ci level = coda_h264_level(level_idc); 18118c2ecf20Sopenharmony_ci break; 18128c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 18138c2ecf20Sopenharmony_ci codec_name = "MPEG-2"; 18148c2ecf20Sopenharmony_ci profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; 18158c2ecf20Sopenharmony_ci level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL; 18168c2ecf20Sopenharmony_ci profile_ctrl = ctx->mpeg2_profile_ctrl; 18178c2ecf20Sopenharmony_ci level_ctrl = ctx->mpeg2_level_ctrl; 18188c2ecf20Sopenharmony_ci profile = coda_mpeg2_profile(profile_idc); 18198c2ecf20Sopenharmony_ci level = coda_mpeg2_level(level_idc); 18208c2ecf20Sopenharmony_ci break; 18218c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 18228c2ecf20Sopenharmony_ci codec_name = "MPEG-4"; 18238c2ecf20Sopenharmony_ci profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; 18248c2ecf20Sopenharmony_ci level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; 18258c2ecf20Sopenharmony_ci profile_ctrl = ctx->mpeg4_profile_ctrl; 18268c2ecf20Sopenharmony_ci level_ctrl = ctx->mpeg4_level_ctrl; 18278c2ecf20Sopenharmony_ci profile = coda_mpeg4_profile(profile_idc); 18288c2ecf20Sopenharmony_ci level = coda_mpeg4_level(level_idc); 18298c2ecf20Sopenharmony_ci break; 18308c2ecf20Sopenharmony_ci default: 18318c2ecf20Sopenharmony_ci return; 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci profile_names = v4l2_ctrl_get_menu(profile_cid); 18358c2ecf20Sopenharmony_ci level_names = v4l2_ctrl_get_menu(level_cid); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (profile < 0) { 18388c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n", 18398c2ecf20Sopenharmony_ci codec_name, profile_idc); 18408c2ecf20Sopenharmony_ci } else { 18418c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name, 18428c2ecf20Sopenharmony_ci profile_names[profile]); 18438c2ecf20Sopenharmony_ci coda_update_menu_ctrl(profile_ctrl, profile); 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci if (level < 0) { 18478c2ecf20Sopenharmony_ci v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n", 18488c2ecf20Sopenharmony_ci codec_name, level_idc); 18498c2ecf20Sopenharmony_ci } else { 18508c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name, 18518c2ecf20Sopenharmony_ci level_names[level]); 18528c2ecf20Sopenharmony_ci coda_update_menu_ctrl(level_ctrl, level); 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci} 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_cistatic void coda_queue_source_change_event(struct coda_ctx *ctx) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci static const struct v4l2_event source_change_event = { 18598c2ecf20Sopenharmony_ci .type = V4L2_EVENT_SOURCE_CHANGE, 18608c2ecf20Sopenharmony_ci .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 18618c2ecf20Sopenharmony_ci }; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci v4l2_event_queue_fh(&ctx->fh, &source_change_event); 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic void coda_buf_queue(struct vb2_buffer *vb) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 18698c2ecf20Sopenharmony_ci struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 18708c2ecf20Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 18718c2ecf20Sopenharmony_ci struct coda_q_data *q_data; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci q_data = get_q_data(ctx, vb->vb2_queue->type); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci /* 18768c2ecf20Sopenharmony_ci * In the decoder case, immediately try to copy the buffer into the 18778c2ecf20Sopenharmony_ci * bitstream ringbuffer and mark it as ready to be dequeued. 18788c2ecf20Sopenharmony_ci */ 18798c2ecf20Sopenharmony_ci if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 18808c2ecf20Sopenharmony_ci /* 18818c2ecf20Sopenharmony_ci * For backwards compatibility, queuing an empty buffer marks 18828c2ecf20Sopenharmony_ci * the stream end 18838c2ecf20Sopenharmony_ci */ 18848c2ecf20Sopenharmony_ci if (vb2_get_plane_payload(vb, 0) == 0) 18858c2ecf20Sopenharmony_ci coda_bit_stream_end_flag(ctx); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci if (q_data->fourcc == V4L2_PIX_FMT_H264) { 18888c2ecf20Sopenharmony_ci /* 18898c2ecf20Sopenharmony_ci * Unless already done, try to obtain profile_idc and 18908c2ecf20Sopenharmony_ci * level_idc from the SPS header. This allows to decide 18918c2ecf20Sopenharmony_ci * whether to enable reordering during sequence 18928c2ecf20Sopenharmony_ci * initialization. 18938c2ecf20Sopenharmony_ci */ 18948c2ecf20Sopenharmony_ci if (!ctx->params.h264_profile_idc) { 18958c2ecf20Sopenharmony_ci coda_sps_parse_profile(ctx, vb); 18968c2ecf20Sopenharmony_ci coda_update_profile_level_ctrls(ctx, 18978c2ecf20Sopenharmony_ci ctx->params.h264_profile_idc, 18988c2ecf20Sopenharmony_ci ctx->params.h264_level_idc); 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 19038c2ecf20Sopenharmony_ci v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 19048c2ecf20Sopenharmony_ci if (vb2_is_streaming(vb->vb2_queue)) 19058c2ecf20Sopenharmony_ci /* This set buf->sequence = ctx->qsequence++ */ 19068c2ecf20Sopenharmony_ci coda_fill_bitstream(ctx, NULL); 19078c2ecf20Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (!ctx->initialized) { 19108c2ecf20Sopenharmony_ci /* 19118c2ecf20Sopenharmony_ci * Run sequence initialization in case the queued 19128c2ecf20Sopenharmony_ci * buffer contained headers. 19138c2ecf20Sopenharmony_ci */ 19148c2ecf20Sopenharmony_ci if (vb2_is_streaming(vb->vb2_queue) && 19158c2ecf20Sopenharmony_ci ctx->ops->seq_init_work) { 19168c2ecf20Sopenharmony_ci queue_work(ctx->dev->workqueue, 19178c2ecf20Sopenharmony_ci &ctx->seq_init_work); 19188c2ecf20Sopenharmony_ci flush_work(&ctx->seq_init_work); 19198c2ecf20Sopenharmony_ci } 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (ctx->initialized) 19228c2ecf20Sopenharmony_ci coda_queue_source_change_event(ctx); 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci } else { 19258c2ecf20Sopenharmony_ci if ((ctx->inst_type == CODA_INST_ENCODER || !ctx->use_bit) && 19268c2ecf20Sopenharmony_ci vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 19278c2ecf20Sopenharmony_ci vbuf->sequence = ctx->qsequence++; 19288c2ecf20Sopenharmony_ci v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ciint coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, 19338c2ecf20Sopenharmony_ci size_t size, const char *name, struct dentry *parent) 19348c2ecf20Sopenharmony_ci{ 19358c2ecf20Sopenharmony_ci buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr, 19368c2ecf20Sopenharmony_ci GFP_KERNEL); 19378c2ecf20Sopenharmony_ci if (!buf->vaddr) { 19388c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 19398c2ecf20Sopenharmony_ci "Failed to allocate %s buffer of size %zu\n", 19408c2ecf20Sopenharmony_ci name, size); 19418c2ecf20Sopenharmony_ci return -ENOMEM; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci buf->size = size; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci if (name && parent) { 19478c2ecf20Sopenharmony_ci buf->blob.data = buf->vaddr; 19488c2ecf20Sopenharmony_ci buf->blob.size = size; 19498c2ecf20Sopenharmony_ci buf->dentry = debugfs_create_blob(name, 0644, parent, 19508c2ecf20Sopenharmony_ci &buf->blob); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci return 0; 19548c2ecf20Sopenharmony_ci} 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_civoid coda_free_aux_buf(struct coda_dev *dev, 19578c2ecf20Sopenharmony_ci struct coda_aux_buf *buf) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci if (buf->vaddr) { 19608c2ecf20Sopenharmony_ci dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr); 19618c2ecf20Sopenharmony_ci buf->vaddr = NULL; 19628c2ecf20Sopenharmony_ci buf->size = 0; 19638c2ecf20Sopenharmony_ci debugfs_remove(buf->dentry); 19648c2ecf20Sopenharmony_ci buf->dentry = NULL; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci} 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_cistatic int coda_start_streaming(struct vb2_queue *q, unsigned int count) 19698c2ecf20Sopenharmony_ci{ 19708c2ecf20Sopenharmony_ci struct coda_ctx *ctx = vb2_get_drv_priv(q); 19718c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; 19728c2ecf20Sopenharmony_ci struct coda_q_data *q_data_src, *q_data_dst; 19738c2ecf20Sopenharmony_ci struct v4l2_m2m_buffer *m2m_buf, *tmp; 19748c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 19758c2ecf20Sopenharmony_ci struct list_head list; 19768c2ecf20Sopenharmony_ci int ret = 0; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (count < 1) 19798c2ecf20Sopenharmony_ci return -EINVAL; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&list); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); 19868c2ecf20Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 19878c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { 19888c2ecf20Sopenharmony_ci /* copy the buffers that were queued before streamon */ 19898c2ecf20Sopenharmony_ci mutex_lock(&ctx->bitstream_mutex); 19908c2ecf20Sopenharmony_ci coda_fill_bitstream(ctx, &list); 19918c2ecf20Sopenharmony_ci mutex_unlock(&ctx->bitstream_mutex); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product != CODA_960 && 19948c2ecf20Sopenharmony_ci coda_get_bitstream_payload(ctx) < 512) { 19958c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "start payload < 512\n"); 19968c2ecf20Sopenharmony_ci ret = -EINVAL; 19978c2ecf20Sopenharmony_ci goto err; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (!ctx->initialized) { 20018c2ecf20Sopenharmony_ci /* Run sequence initialization */ 20028c2ecf20Sopenharmony_ci if (ctx->ops->seq_init_work) { 20038c2ecf20Sopenharmony_ci queue_work(ctx->dev->workqueue, 20048c2ecf20Sopenharmony_ci &ctx->seq_init_work); 20058c2ecf20Sopenharmony_ci flush_work(&ctx->seq_init_work); 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci } 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci /* 20118c2ecf20Sopenharmony_ci * Check the first input JPEG buffer to determine chroma 20128c2ecf20Sopenharmony_ci * subsampling. 20138c2ecf20Sopenharmony_ci */ 20148c2ecf20Sopenharmony_ci if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { 20158c2ecf20Sopenharmony_ci buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 20168c2ecf20Sopenharmony_ci ret = coda_jpeg_decode_header(ctx, &buf->vb2_buf); 20178c2ecf20Sopenharmony_ci if (ret < 0) { 20188c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, 20198c2ecf20Sopenharmony_ci "failed to decode JPEG header: %d\n", 20208c2ecf20Sopenharmony_ci ret); 20218c2ecf20Sopenharmony_ci goto err; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 20258c2ecf20Sopenharmony_ci q_data_dst->width = round_up(q_data_src->width, 16); 20268c2ecf20Sopenharmony_ci q_data_dst->height = round_up(q_data_src->height, 16); 20278c2ecf20Sopenharmony_ci q_data_dst->bytesperline = q_data_dst->width; 20288c2ecf20Sopenharmony_ci if (ctx->params.jpeg_chroma_subsampling == 20298c2ecf20Sopenharmony_ci V4L2_JPEG_CHROMA_SUBSAMPLING_420) { 20308c2ecf20Sopenharmony_ci q_data_dst->sizeimage = 20318c2ecf20Sopenharmony_ci q_data_dst->bytesperline * 20328c2ecf20Sopenharmony_ci q_data_dst->height * 3 / 2; 20338c2ecf20Sopenharmony_ci if (q_data_dst->fourcc != V4L2_PIX_FMT_YUV420) 20348c2ecf20Sopenharmony_ci q_data_dst->fourcc = V4L2_PIX_FMT_NV12; 20358c2ecf20Sopenharmony_ci } else { 20368c2ecf20Sopenharmony_ci q_data_dst->sizeimage = 20378c2ecf20Sopenharmony_ci q_data_dst->bytesperline * 20388c2ecf20Sopenharmony_ci q_data_dst->height * 2; 20398c2ecf20Sopenharmony_ci q_data_dst->fourcc = V4L2_PIX_FMT_YUV422P; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci q_data_dst->rect.left = 0; 20428c2ecf20Sopenharmony_ci q_data_dst->rect.top = 0; 20438c2ecf20Sopenharmony_ci q_data_dst->rect.width = q_data_src->width; 20448c2ecf20Sopenharmony_ci q_data_dst->rect.height = q_data_src->height; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci ctx->streamon_out = 1; 20478c2ecf20Sopenharmony_ci } else { 20488c2ecf20Sopenharmony_ci ctx->streamon_cap = 1; 20498c2ecf20Sopenharmony_ci } 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* Don't start the coda unless both queues are on */ 20528c2ecf20Sopenharmony_ci if (!(ctx->streamon_out && ctx->streamon_cap)) 20538c2ecf20Sopenharmony_ci goto out; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 20568c2ecf20Sopenharmony_ci if ((q_data_src->rect.width != q_data_dst->width && 20578c2ecf20Sopenharmony_ci round_up(q_data_src->rect.width, 16) != q_data_dst->width) || 20588c2ecf20Sopenharmony_ci (q_data_src->rect.height != q_data_dst->height && 20598c2ecf20Sopenharmony_ci round_up(q_data_src->rect.height, 16) != q_data_dst->height)) { 20608c2ecf20Sopenharmony_ci v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n", 20618c2ecf20Sopenharmony_ci q_data_src->rect.width, q_data_src->rect.height, 20628c2ecf20Sopenharmony_ci q_data_dst->width, q_data_dst->height); 20638c2ecf20Sopenharmony_ci ret = -EINVAL; 20648c2ecf20Sopenharmony_ci goto err; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci /* Allow BIT decoder device_run with no new buffers queued */ 20688c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) 20698c2ecf20Sopenharmony_ci v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) 20748c2ecf20Sopenharmony_ci ctx->params.gop_size = 1; 20758c2ecf20Sopenharmony_ci ctx->gopcounter = ctx->params.gop_size - 1; 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci ret = ctx->ops->start_streaming(ctx); 20788c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER) { 20798c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 20808c2ecf20Sopenharmony_ci goto out; 20818c2ecf20Sopenharmony_ci } 20828c2ecf20Sopenharmony_ci if (ret < 0) 20838c2ecf20Sopenharmony_ci goto err; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ciout: 20868c2ecf20Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 20878c2ecf20Sopenharmony_ci list_for_each_entry_safe(m2m_buf, tmp, &list, list) { 20888c2ecf20Sopenharmony_ci list_del(&m2m_buf->list); 20898c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_DONE); 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci return 0; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_cierr: 20958c2ecf20Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 20968c2ecf20Sopenharmony_ci list_for_each_entry_safe(m2m_buf, tmp, &list, list) { 20978c2ecf20Sopenharmony_ci list_del(&m2m_buf->list); 20988c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_QUEUED); 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) 21018c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 21028c2ecf20Sopenharmony_ci } else { 21038c2ecf20Sopenharmony_ci while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) 21048c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci return ret; 21078c2ecf20Sopenharmony_ci} 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic void coda_stop_streaming(struct vb2_queue *q) 21108c2ecf20Sopenharmony_ci{ 21118c2ecf20Sopenharmony_ci struct coda_ctx *ctx = vb2_get_drv_priv(q); 21128c2ecf20Sopenharmony_ci struct coda_dev *dev = ctx->dev; 21138c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *buf; 21148c2ecf20Sopenharmony_ci bool stop; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci stop = ctx->streamon_out && ctx->streamon_cap; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { 21218c2ecf20Sopenharmony_ci ctx->streamon_out = 0; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci coda_bit_stream_end_flag(ctx); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci ctx->qsequence = 0; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) 21288c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 21298c2ecf20Sopenharmony_ci } else { 21308c2ecf20Sopenharmony_ci ctx->streamon_cap = 0; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci ctx->osequence = 0; 21338c2ecf20Sopenharmony_ci ctx->sequence_offset = 0; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) 21368c2ecf20Sopenharmony_ci v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci if (stop) { 21408c2ecf20Sopenharmony_ci struct coda_buffer_meta *meta; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci if (ctx->ops->seq_end_work) { 21438c2ecf20Sopenharmony_ci queue_work(dev->workqueue, &ctx->seq_end_work); 21448c2ecf20Sopenharmony_ci flush_work(&ctx->seq_end_work); 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci spin_lock(&ctx->buffer_meta_lock); 21478c2ecf20Sopenharmony_ci while (!list_empty(&ctx->buffer_meta_list)) { 21488c2ecf20Sopenharmony_ci meta = list_first_entry(&ctx->buffer_meta_list, 21498c2ecf20Sopenharmony_ci struct coda_buffer_meta, list); 21508c2ecf20Sopenharmony_ci list_del(&meta->list); 21518c2ecf20Sopenharmony_ci kfree(meta); 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci ctx->num_metas = 0; 21548c2ecf20Sopenharmony_ci spin_unlock(&ctx->buffer_meta_lock); 21558c2ecf20Sopenharmony_ci kfifo_init(&ctx->bitstream_fifo, 21568c2ecf20Sopenharmony_ci ctx->bitstream.vaddr, ctx->bitstream.size); 21578c2ecf20Sopenharmony_ci ctx->runcounter = 0; 21588c2ecf20Sopenharmony_ci ctx->aborting = 0; 21598c2ecf20Sopenharmony_ci ctx->hold = false; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (!ctx->streamon_out && !ctx->streamon_cap) 21638c2ecf20Sopenharmony_ci ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic const struct vb2_ops coda_qops = { 21678c2ecf20Sopenharmony_ci .queue_setup = coda_queue_setup, 21688c2ecf20Sopenharmony_ci .buf_prepare = coda_buf_prepare, 21698c2ecf20Sopenharmony_ci .buf_queue = coda_buf_queue, 21708c2ecf20Sopenharmony_ci .start_streaming = coda_start_streaming, 21718c2ecf20Sopenharmony_ci .stop_streaming = coda_stop_streaming, 21728c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 21738c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 21748c2ecf20Sopenharmony_ci}; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic int coda_s_ctrl(struct v4l2_ctrl *ctrl) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id); 21798c2ecf20Sopenharmony_ci struct coda_ctx *ctx = 21808c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct coda_ctx, ctrls); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (val_names) 21838c2ecf20Sopenharmony_ci coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n", 21848c2ecf20Sopenharmony_ci ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]); 21858c2ecf20Sopenharmony_ci else 21868c2ecf20Sopenharmony_ci coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", 21878c2ecf20Sopenharmony_ci ctrl->id, ctrl->name, ctrl->val); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci switch (ctrl->id) { 21908c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 21918c2ecf20Sopenharmony_ci if (ctrl->val) 21928c2ecf20Sopenharmony_ci ctx->params.rot_mode |= CODA_MIR_HOR; 21938c2ecf20Sopenharmony_ci else 21948c2ecf20Sopenharmony_ci ctx->params.rot_mode &= ~CODA_MIR_HOR; 21958c2ecf20Sopenharmony_ci break; 21968c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 21978c2ecf20Sopenharmony_ci if (ctrl->val) 21988c2ecf20Sopenharmony_ci ctx->params.rot_mode |= CODA_MIR_VER; 21998c2ecf20Sopenharmony_ci else 22008c2ecf20Sopenharmony_ci ctx->params.rot_mode &= ~CODA_MIR_VER; 22018c2ecf20Sopenharmony_ci break; 22028c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_BITRATE: 22038c2ecf20Sopenharmony_ci ctx->params.bitrate = ctrl->val / 1000; 22048c2ecf20Sopenharmony_ci ctx->params.bitrate_changed = true; 22058c2ecf20Sopenharmony_ci break; 22068c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_GOP_SIZE: 22078c2ecf20Sopenharmony_ci ctx->params.gop_size = ctrl->val; 22088c2ecf20Sopenharmony_ci break; 22098c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: 22108c2ecf20Sopenharmony_ci ctx->params.h264_intra_qp = ctrl->val; 22118c2ecf20Sopenharmony_ci ctx->params.h264_intra_qp_changed = true; 22128c2ecf20Sopenharmony_ci break; 22138c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: 22148c2ecf20Sopenharmony_ci ctx->params.h264_inter_qp = ctrl->val; 22158c2ecf20Sopenharmony_ci break; 22168c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: 22178c2ecf20Sopenharmony_ci ctx->params.h264_min_qp = ctrl->val; 22188c2ecf20Sopenharmony_ci break; 22198c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: 22208c2ecf20Sopenharmony_ci ctx->params.h264_max_qp = ctrl->val; 22218c2ecf20Sopenharmony_ci break; 22228c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: 22238c2ecf20Sopenharmony_ci ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val; 22248c2ecf20Sopenharmony_ci break; 22258c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: 22268c2ecf20Sopenharmony_ci ctx->params.h264_slice_beta_offset_div2 = ctrl->val; 22278c2ecf20Sopenharmony_ci break; 22288c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: 22298c2ecf20Sopenharmony_ci ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; 22308c2ecf20Sopenharmony_ci break; 22318c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: 22328c2ecf20Sopenharmony_ci ctx->params.h264_constrained_intra_pred_flag = ctrl->val; 22338c2ecf20Sopenharmony_ci break; 22348c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: 22358c2ecf20Sopenharmony_ci ctx->params.frame_rc_enable = ctrl->val; 22368c2ecf20Sopenharmony_ci break; 22378c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: 22388c2ecf20Sopenharmony_ci ctx->params.mb_rc_enable = ctrl->val; 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: 22418c2ecf20Sopenharmony_ci ctx->params.h264_chroma_qp_index_offset = ctrl->val; 22428c2ecf20Sopenharmony_ci break; 22438c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_PROFILE: 22448c2ecf20Sopenharmony_ci /* TODO: switch between baseline and constrained baseline */ 22458c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_ENCODER) 22468c2ecf20Sopenharmony_ci ctx->params.h264_profile_idc = 66; 22478c2ecf20Sopenharmony_ci break; 22488c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_LEVEL: 22498c2ecf20Sopenharmony_ci /* nothing to do, this is set by the encoder */ 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: 22528c2ecf20Sopenharmony_ci ctx->params.mpeg4_intra_qp = ctrl->val; 22538c2ecf20Sopenharmony_ci break; 22548c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: 22558c2ecf20Sopenharmony_ci ctx->params.mpeg4_inter_qp = ctrl->val; 22568c2ecf20Sopenharmony_ci break; 22578c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: 22588c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: 22598c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: 22608c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: 22618c2ecf20Sopenharmony_ci /* nothing to do, these are fixed */ 22628c2ecf20Sopenharmony_ci break; 22638c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: 22648c2ecf20Sopenharmony_ci ctx->params.slice_mode = ctrl->val; 22658c2ecf20Sopenharmony_ci ctx->params.slice_mode_changed = true; 22668c2ecf20Sopenharmony_ci break; 22678c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: 22688c2ecf20Sopenharmony_ci ctx->params.slice_max_mb = ctrl->val; 22698c2ecf20Sopenharmony_ci ctx->params.slice_mode_changed = true; 22708c2ecf20Sopenharmony_ci break; 22718c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: 22728c2ecf20Sopenharmony_ci ctx->params.slice_max_bits = ctrl->val * 8; 22738c2ecf20Sopenharmony_ci ctx->params.slice_mode_changed = true; 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_HEADER_MODE: 22768c2ecf20Sopenharmony_ci break; 22778c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: 22788c2ecf20Sopenharmony_ci ctx->params.intra_refresh = ctrl->val; 22798c2ecf20Sopenharmony_ci ctx->params.intra_refresh_changed = true; 22808c2ecf20Sopenharmony_ci break; 22818c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: 22828c2ecf20Sopenharmony_ci ctx->params.force_ipicture = true; 22838c2ecf20Sopenharmony_ci break; 22848c2ecf20Sopenharmony_ci case V4L2_CID_JPEG_COMPRESSION_QUALITY: 22858c2ecf20Sopenharmony_ci coda_set_jpeg_compression_quality(ctx, ctrl->val); 22868c2ecf20Sopenharmony_ci break; 22878c2ecf20Sopenharmony_ci case V4L2_CID_JPEG_RESTART_INTERVAL: 22888c2ecf20Sopenharmony_ci ctx->params.jpeg_restart_interval = ctrl->val; 22898c2ecf20Sopenharmony_ci break; 22908c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_VBV_DELAY: 22918c2ecf20Sopenharmony_ci ctx->params.vbv_delay = ctrl->val; 22928c2ecf20Sopenharmony_ci break; 22938c2ecf20Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_VBV_SIZE: 22948c2ecf20Sopenharmony_ci ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); 22958c2ecf20Sopenharmony_ci break; 22968c2ecf20Sopenharmony_ci default: 22978c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n", 22988c2ecf20Sopenharmony_ci ctrl->id, ctrl->val); 22998c2ecf20Sopenharmony_ci return -EINVAL; 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci return 0; 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops coda_ctrl_ops = { 23068c2ecf20Sopenharmony_ci .s_ctrl = coda_s_ctrl, 23078c2ecf20Sopenharmony_ci}; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_cistatic void coda_encode_ctrls(struct coda_ctx *ctx) 23108c2ecf20Sopenharmony_ci{ 23118c2ecf20Sopenharmony_ci int max_gop_size = (ctx->dev->devtype->product == CODA_DX6) ? 60 : 99; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23148c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); 23158c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23168c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, max_gop_size, 1, 16); 23178c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23188c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25); 23198c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23208c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25); 23218c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product != CODA_960) { 23228c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23238c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12); 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23268c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51); 23278c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23288c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0); 23298c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23308c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); 23318c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23328c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, 23338c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 23348c2ecf20Sopenharmony_ci 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); 23358c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23368c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, 23378c2ecf20Sopenharmony_ci 0); 23388c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23398c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1); 23408c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23418c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, 0, 1, 1, 1); 23428c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23438c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); 23448c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23458c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_PROFILE, 23468c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0, 23478c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); 23488c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_HX4 || 23498c2ecf20Sopenharmony_ci ctx->dev->devtype->product == CODA_7541) { 23508c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23518c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LEVEL, 23528c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_LEVEL_3_1, 23538c2ecf20Sopenharmony_ci ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | 23548c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | 23558c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1)), 23568c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_LEVEL_3_1); 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_960) { 23598c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23608c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LEVEL, 23618c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_LEVEL_4_2, 23628c2ecf20Sopenharmony_ci ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | 23638c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | 23648c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | 23658c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | 23668c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | 23678c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | 23688c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | 23698c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), 23708c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_LEVEL_4_0); 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23738c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2); 23748c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23758c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2); 23768c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23778c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, 23788c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, 23798c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); 23808c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_HX4 || 23818c2ecf20Sopenharmony_ci ctx->dev->devtype->product == CODA_7541 || 23828c2ecf20Sopenharmony_ci ctx->dev->devtype->product == CODA_960) { 23838c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23848c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, 23858c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 23868c2ecf20Sopenharmony_ci ~(1 << V4L2_MPEG_VIDEO_MPEG4_LEVEL_5), 23878c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23908c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, 23918c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0, 23928c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); 23938c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23948c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); 23958c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 23968c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, 1, 0x3fffffff, 1, 23978c2ecf20Sopenharmony_ci 500); 23988c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, 23998c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_HEADER_MODE, 24008c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, 24018c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE), 24028c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); 24038c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24048c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 24058c2ecf20Sopenharmony_ci 1920 * 1088 / 256, 1, 0); 24068c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24078c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); 24088c2ecf20Sopenharmony_ci /* 24098c2ecf20Sopenharmony_ci * The maximum VBV size value is 0x7fffffff bits, 24108c2ecf20Sopenharmony_ci * one bit less than 262144 KiB 24118c2ecf20Sopenharmony_ci */ 24128c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24138c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); 24148c2ecf20Sopenharmony_ci} 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_cistatic void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24198c2ecf20Sopenharmony_ci V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50); 24208c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24218c2ecf20Sopenharmony_ci V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0); 24228c2ecf20Sopenharmony_ci} 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_cistatic void coda_decode_ctrls(struct coda_ctx *ctx) 24258c2ecf20Sopenharmony_ci{ 24268c2ecf20Sopenharmony_ci u8 max; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24298c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, 24308c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 24318c2ecf20Sopenharmony_ci ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | 24328c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | 24338c2ecf20Sopenharmony_ci (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), 24348c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); 24358c2ecf20Sopenharmony_ci if (ctx->h264_profile_ctrl) 24368c2ecf20Sopenharmony_ci ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_HX4 || 24398c2ecf20Sopenharmony_ci ctx->dev->devtype->product == CODA_7541) 24408c2ecf20Sopenharmony_ci max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; 24418c2ecf20Sopenharmony_ci else if (ctx->dev->devtype->product == CODA_960) 24428c2ecf20Sopenharmony_ci max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; 24438c2ecf20Sopenharmony_ci else 24448c2ecf20Sopenharmony_ci return; 24458c2ecf20Sopenharmony_ci ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24468c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); 24478c2ecf20Sopenharmony_ci if (ctx->h264_level_ctrl) 24488c2ecf20Sopenharmony_ci ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24518c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, 24528c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0, 24538c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH); 24548c2ecf20Sopenharmony_ci if (ctx->mpeg2_profile_ctrl) 24558c2ecf20Sopenharmony_ci ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24588c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, 24598c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0, 24608c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH); 24618c2ecf20Sopenharmony_ci if (ctx->mpeg2_level_ctrl) 24628c2ecf20Sopenharmony_ci ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24658c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, 24668c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, 24678c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY); 24688c2ecf20Sopenharmony_ci if (ctx->mpeg4_profile_ctrl) 24698c2ecf20Sopenharmony_ci ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, 24728c2ecf20Sopenharmony_ci &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, 24738c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, 24748c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); 24758c2ecf20Sopenharmony_ci if (ctx->mpeg4_level_ctrl) 24768c2ecf20Sopenharmony_ci ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 24778c2ecf20Sopenharmony_ci} 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_cistatic int coda_ctrls_setup(struct coda_ctx *ctx) 24808c2ecf20Sopenharmony_ci{ 24818c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&ctx->ctrls, 2); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24848c2ecf20Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, 0); 24858c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24868c2ecf20Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 24878c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_ENCODER) { 24888c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24898c2ecf20Sopenharmony_ci V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 24908c2ecf20Sopenharmony_ci 1, 1, 1, 1); 24918c2ecf20Sopenharmony_ci if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) 24928c2ecf20Sopenharmony_ci coda_jpeg_encode_ctrls(ctx); 24938c2ecf20Sopenharmony_ci else 24948c2ecf20Sopenharmony_ci coda_encode_ctrls(ctx); 24958c2ecf20Sopenharmony_ci } else { 24968c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, 24978c2ecf20Sopenharmony_ci V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 24988c2ecf20Sopenharmony_ci 1, 1, 1, 1); 24998c2ecf20Sopenharmony_ci if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) 25008c2ecf20Sopenharmony_ci coda_decode_ctrls(ctx); 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (ctx->ctrls.error) { 25048c2ecf20Sopenharmony_ci v4l2_err(&ctx->dev->v4l2_dev, 25058c2ecf20Sopenharmony_ci "control initialization error (%d)", 25068c2ecf20Sopenharmony_ci ctx->ctrls.error); 25078c2ecf20Sopenharmony_ci return -EINVAL; 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci return v4l2_ctrl_handler_setup(&ctx->ctrls); 25118c2ecf20Sopenharmony_ci} 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_cistatic int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) 25148c2ecf20Sopenharmony_ci{ 25158c2ecf20Sopenharmony_ci vq->drv_priv = ctx; 25168c2ecf20Sopenharmony_ci vq->ops = &coda_qops; 25178c2ecf20Sopenharmony_ci vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 25188c2ecf20Sopenharmony_ci vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 25198c2ecf20Sopenharmony_ci vq->lock = &ctx->dev->dev_mutex; 25208c2ecf20Sopenharmony_ci /* One way to indicate end-of-stream for coda is to set the 25218c2ecf20Sopenharmony_ci * bytesused == 0. However by default videobuf2 handles bytesused 25228c2ecf20Sopenharmony_ci * equal to 0 as a special case and changes its value to the size 25238c2ecf20Sopenharmony_ci * of the buffer. Set the allow_zero_bytesused flag, so 25248c2ecf20Sopenharmony_ci * that videobuf2 will keep the value of bytesused intact. 25258c2ecf20Sopenharmony_ci */ 25268c2ecf20Sopenharmony_ci vq->allow_zero_bytesused = 1; 25278c2ecf20Sopenharmony_ci /* 25288c2ecf20Sopenharmony_ci * We might be fine with no buffers on some of the queues, but that 25298c2ecf20Sopenharmony_ci * would need to be reflected in job_ready(). Currently we expect all 25308c2ecf20Sopenharmony_ci * queues to have at least one buffer queued. 25318c2ecf20Sopenharmony_ci */ 25328c2ecf20Sopenharmony_ci vq->min_buffers_needed = 1; 25338c2ecf20Sopenharmony_ci vq->dev = ctx->dev->dev; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci return vb2_queue_init(vq); 25368c2ecf20Sopenharmony_ci} 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ciint coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, 25398c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq) 25408c2ecf20Sopenharmony_ci{ 25418c2ecf20Sopenharmony_ci int ret; 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 25448c2ecf20Sopenharmony_ci src_vq->io_modes = VB2_DMABUF | VB2_MMAP; 25458c2ecf20Sopenharmony_ci src_vq->mem_ops = &vb2_dma_contig_memops; 25468c2ecf20Sopenharmony_ci 25478c2ecf20Sopenharmony_ci ret = coda_queue_init(priv, src_vq); 25488c2ecf20Sopenharmony_ci if (ret) 25498c2ecf20Sopenharmony_ci return ret; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 25528c2ecf20Sopenharmony_ci dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; 25538c2ecf20Sopenharmony_ci dst_vq->mem_ops = &vb2_dma_contig_memops; 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci return coda_queue_init(priv, dst_vq); 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ciint coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, 25598c2ecf20Sopenharmony_ci struct vb2_queue *dst_vq) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci int ret; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 25648c2ecf20Sopenharmony_ci src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR; 25658c2ecf20Sopenharmony_ci src_vq->mem_ops = &vb2_vmalloc_memops; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci ret = coda_queue_init(priv, src_vq); 25688c2ecf20Sopenharmony_ci if (ret) 25698c2ecf20Sopenharmony_ci return ret; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 25728c2ecf20Sopenharmony_ci dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; 25738c2ecf20Sopenharmony_ci dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; 25748c2ecf20Sopenharmony_ci dst_vq->mem_ops = &vb2_dma_contig_memops; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci return coda_queue_init(priv, dst_vq); 25778c2ecf20Sopenharmony_ci} 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci/* 25808c2ecf20Sopenharmony_ci * File operations 25818c2ecf20Sopenharmony_ci */ 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_cistatic int coda_open(struct file *file) 25848c2ecf20Sopenharmony_ci{ 25858c2ecf20Sopenharmony_ci struct video_device *vdev = video_devdata(file); 25868c2ecf20Sopenharmony_ci struct coda_dev *dev = video_get_drvdata(vdev); 25878c2ecf20Sopenharmony_ci struct coda_ctx *ctx; 25888c2ecf20Sopenharmony_ci unsigned int max = ~0; 25898c2ecf20Sopenharmony_ci char *name; 25908c2ecf20Sopenharmony_ci int ret; 25918c2ecf20Sopenharmony_ci int idx; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 25948c2ecf20Sopenharmony_ci if (!ctx) 25958c2ecf20Sopenharmony_ci return -ENOMEM; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) 25988c2ecf20Sopenharmony_ci max = CODADX6_MAX_INSTANCES - 1; 25998c2ecf20Sopenharmony_ci idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL); 26008c2ecf20Sopenharmony_ci if (idx < 0) { 26018c2ecf20Sopenharmony_ci ret = idx; 26028c2ecf20Sopenharmony_ci goto err_coda_max; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "context%d", idx); 26068c2ecf20Sopenharmony_ci if (!name) { 26078c2ecf20Sopenharmony_ci ret = -ENOMEM; 26088c2ecf20Sopenharmony_ci goto err_coda_name_init; 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); 26128c2ecf20Sopenharmony_ci kfree(name); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci ctx->cvd = to_coda_video_device(vdev); 26158c2ecf20Sopenharmony_ci ctx->inst_type = ctx->cvd->type; 26168c2ecf20Sopenharmony_ci ctx->ops = ctx->cvd->ops; 26178c2ecf20Sopenharmony_ci ctx->use_bit = !ctx->cvd->direct; 26188c2ecf20Sopenharmony_ci init_completion(&ctx->completion); 26198c2ecf20Sopenharmony_ci INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); 26208c2ecf20Sopenharmony_ci if (ctx->ops->seq_init_work) 26218c2ecf20Sopenharmony_ci INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work); 26228c2ecf20Sopenharmony_ci if (ctx->ops->seq_end_work) 26238c2ecf20Sopenharmony_ci INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); 26248c2ecf20Sopenharmony_ci v4l2_fh_init(&ctx->fh, video_devdata(file)); 26258c2ecf20Sopenharmony_ci file->private_data = &ctx->fh; 26268c2ecf20Sopenharmony_ci v4l2_fh_add(&ctx->fh); 26278c2ecf20Sopenharmony_ci ctx->dev = dev; 26288c2ecf20Sopenharmony_ci ctx->idx = idx; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "open instance (%p)\n", ctx); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 26338c2ecf20Sopenharmony_ci case CODA_960: 26348c2ecf20Sopenharmony_ci /* 26358c2ecf20Sopenharmony_ci * Enabling the BWB when decoding can hang the firmware with 26368c2ecf20Sopenharmony_ci * certain streams. The issue was tracked as ENGR00293425 by 26378c2ecf20Sopenharmony_ci * Freescale. As a workaround, disable BWB for all decoders. 26388c2ecf20Sopenharmony_ci * The enable_bwb module parameter allows to override this. 26398c2ecf20Sopenharmony_ci */ 26408c2ecf20Sopenharmony_ci if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) 26418c2ecf20Sopenharmony_ci ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; 26428c2ecf20Sopenharmony_ci fallthrough; 26438c2ecf20Sopenharmony_ci case CODA_HX4: 26448c2ecf20Sopenharmony_ci case CODA_7541: 26458c2ecf20Sopenharmony_ci ctx->reg_idx = 0; 26468c2ecf20Sopenharmony_ci break; 26478c2ecf20Sopenharmony_ci default: 26488c2ecf20Sopenharmony_ci ctx->reg_idx = idx; 26498c2ecf20Sopenharmony_ci } 26508c2ecf20Sopenharmony_ci if (ctx->dev->vdoa && !disable_vdoa) { 26518c2ecf20Sopenharmony_ci ctx->vdoa = vdoa_context_create(dev->vdoa); 26528c2ecf20Sopenharmony_ci if (!ctx->vdoa) 26538c2ecf20Sopenharmony_ci v4l2_warn(&dev->v4l2_dev, 26548c2ecf20Sopenharmony_ci "Failed to create vdoa context: not using vdoa"); 26558c2ecf20Sopenharmony_ci } 26568c2ecf20Sopenharmony_ci ctx->use_vdoa = false; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci /* Power up and upload firmware if necessary */ 26598c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev->dev); 26608c2ecf20Sopenharmony_ci if (ret < 0) { 26618c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); 26628c2ecf20Sopenharmony_ci goto err_pm_get; 26638c2ecf20Sopenharmony_ci } 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_per); 26668c2ecf20Sopenharmony_ci if (ret) 26678c2ecf20Sopenharmony_ci goto err_pm_get; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_ahb); 26708c2ecf20Sopenharmony_ci if (ret) 26718c2ecf20Sopenharmony_ci goto err_clk_ahb; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci set_default_params(ctx); 26748c2ecf20Sopenharmony_ci ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, 26758c2ecf20Sopenharmony_ci ctx->ops->queue_init); 26768c2ecf20Sopenharmony_ci if (IS_ERR(ctx->fh.m2m_ctx)) { 26778c2ecf20Sopenharmony_ci ret = PTR_ERR(ctx->fh.m2m_ctx); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n", 26808c2ecf20Sopenharmony_ci __func__, ret); 26818c2ecf20Sopenharmony_ci goto err_ctx_init; 26828c2ecf20Sopenharmony_ci } 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci ret = coda_ctrls_setup(ctx); 26858c2ecf20Sopenharmony_ci if (ret) { 26868c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n"); 26878c2ecf20Sopenharmony_ci goto err_ctrls_setup; 26888c2ecf20Sopenharmony_ci } 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci ctx->fh.ctrl_handler = &ctx->ctrls; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci mutex_init(&ctx->bitstream_mutex); 26938c2ecf20Sopenharmony_ci mutex_init(&ctx->buffer_mutex); 26948c2ecf20Sopenharmony_ci mutex_init(&ctx->wakeup_mutex); 26958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx->buffer_meta_list); 26968c2ecf20Sopenharmony_ci spin_lock_init(&ctx->buffer_meta_lock); 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci return 0; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_cierr_ctrls_setup: 27018c2ecf20Sopenharmony_ci v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 27028c2ecf20Sopenharmony_cierr_ctx_init: 27038c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 27048c2ecf20Sopenharmony_cierr_clk_ahb: 27058c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 27068c2ecf20Sopenharmony_cierr_pm_get: 27078c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev->dev); 27088c2ecf20Sopenharmony_ci v4l2_fh_del(&ctx->fh); 27098c2ecf20Sopenharmony_ci v4l2_fh_exit(&ctx->fh); 27108c2ecf20Sopenharmony_cierr_coda_name_init: 27118c2ecf20Sopenharmony_ci ida_free(&dev->ida, ctx->idx); 27128c2ecf20Sopenharmony_cierr_coda_max: 27138c2ecf20Sopenharmony_ci kfree(ctx); 27148c2ecf20Sopenharmony_ci return ret; 27158c2ecf20Sopenharmony_ci} 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_cistatic int coda_release(struct file *file) 27188c2ecf20Sopenharmony_ci{ 27198c2ecf20Sopenharmony_ci struct coda_dev *dev = video_drvdata(file); 27208c2ecf20Sopenharmony_ci struct coda_ctx *ctx = fh_to_ctx(file->private_data); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci coda_dbg(1, ctx, "release instance (%p)\n", ctx); 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) 27258c2ecf20Sopenharmony_ci coda_bit_stream_end_flag(ctx); 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci /* If this instance is running, call .job_abort and wait for it to end */ 27288c2ecf20Sopenharmony_ci v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if (ctx->vdoa) 27318c2ecf20Sopenharmony_ci vdoa_context_destroy(ctx->vdoa); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci /* In case the instance was not running, we still need to call SEQ_END */ 27348c2ecf20Sopenharmony_ci if (ctx->ops->seq_end_work) { 27358c2ecf20Sopenharmony_ci queue_work(dev->workqueue, &ctx->seq_end_work); 27368c2ecf20Sopenharmony_ci flush_work(&ctx->seq_end_work); 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (ctx->dev->devtype->product == CODA_DX6) 27408c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &ctx->workbuf); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&ctx->ctrls); 27438c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 27448c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 27458c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev->dev); 27468c2ecf20Sopenharmony_ci v4l2_fh_del(&ctx->fh); 27478c2ecf20Sopenharmony_ci v4l2_fh_exit(&ctx->fh); 27488c2ecf20Sopenharmony_ci ida_free(&dev->ida, ctx->idx); 27498c2ecf20Sopenharmony_ci if (ctx->ops->release) 27508c2ecf20Sopenharmony_ci ctx->ops->release(ctx); 27518c2ecf20Sopenharmony_ci debugfs_remove_recursive(ctx->debugfs_entry); 27528c2ecf20Sopenharmony_ci kfree(ctx); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci return 0; 27558c2ecf20Sopenharmony_ci} 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations coda_fops = { 27588c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 27598c2ecf20Sopenharmony_ci .open = coda_open, 27608c2ecf20Sopenharmony_ci .release = coda_release, 27618c2ecf20Sopenharmony_ci .poll = v4l2_m2m_fop_poll, 27628c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 27638c2ecf20Sopenharmony_ci .mmap = v4l2_m2m_fop_mmap, 27648c2ecf20Sopenharmony_ci}; 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_cistatic int coda_hw_init(struct coda_dev *dev) 27678c2ecf20Sopenharmony_ci{ 27688c2ecf20Sopenharmony_ci u32 data; 27698c2ecf20Sopenharmony_ci u16 *p; 27708c2ecf20Sopenharmony_ci int i, ret; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_per); 27738c2ecf20Sopenharmony_ci if (ret) 27748c2ecf20Sopenharmony_ci goto err_clk_per; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->clk_ahb); 27778c2ecf20Sopenharmony_ci if (ret) 27788c2ecf20Sopenharmony_ci goto err_clk_ahb; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci reset_control_reset(dev->rstc); 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci /* 27838c2ecf20Sopenharmony_ci * Copy the first CODA_ISRAM_SIZE in the internal SRAM. 27848c2ecf20Sopenharmony_ci * The 16-bit chars in the code buffer are in memory access 27858c2ecf20Sopenharmony_ci * order, re-sort them to CODA order for register download. 27868c2ecf20Sopenharmony_ci * Data in this SRAM survives a reboot. 27878c2ecf20Sopenharmony_ci */ 27888c2ecf20Sopenharmony_ci p = (u16 *)dev->codebuf.vaddr; 27898c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 27908c2ecf20Sopenharmony_ci for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { 27918c2ecf20Sopenharmony_ci data = CODA_DOWN_ADDRESS_SET(i) | 27928c2ecf20Sopenharmony_ci CODA_DOWN_DATA_SET(p[i ^ 1]); 27938c2ecf20Sopenharmony_ci coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci } else { 27968c2ecf20Sopenharmony_ci for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++) { 27978c2ecf20Sopenharmony_ci data = CODA_DOWN_ADDRESS_SET(i) | 27988c2ecf20Sopenharmony_ci CODA_DOWN_DATA_SET(p[round_down(i, 4) + 27998c2ecf20Sopenharmony_ci 3 - (i % 4)]); 28008c2ecf20Sopenharmony_ci coda_write(dev, data, CODA_REG_BIT_CODE_DOWN); 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci /* Clear registers */ 28058c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) 28068c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4); 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci /* Tell the BIT where to find everything it needs */ 28098c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960 || 28108c2ecf20Sopenharmony_ci dev->devtype->product == CODA_7541 || 28118c2ecf20Sopenharmony_ci dev->devtype->product == CODA_HX4) { 28128c2ecf20Sopenharmony_ci coda_write(dev, dev->tempbuf.paddr, 28138c2ecf20Sopenharmony_ci CODA_REG_BIT_TEMP_BUF_ADDR); 28148c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); 28158c2ecf20Sopenharmony_ci } else { 28168c2ecf20Sopenharmony_ci coda_write(dev, dev->workbuf.paddr, 28178c2ecf20Sopenharmony_ci CODA_REG_BIT_WORK_BUF_ADDR); 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_ci coda_write(dev, dev->codebuf.paddr, 28208c2ecf20Sopenharmony_ci CODA_REG_BIT_CODE_BUF_ADDR); 28218c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_CODE_RUN); 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci /* Set default values */ 28248c2ecf20Sopenharmony_ci switch (dev->devtype->product) { 28258c2ecf20Sopenharmony_ci case CODA_DX6: 28268c2ecf20Sopenharmony_ci coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, 28278c2ecf20Sopenharmony_ci CODA_REG_BIT_STREAM_CTRL); 28288c2ecf20Sopenharmony_ci break; 28298c2ecf20Sopenharmony_ci default: 28308c2ecf20Sopenharmony_ci coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, 28318c2ecf20Sopenharmony_ci CODA_REG_BIT_STREAM_CTRL); 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) 28348c2ecf20Sopenharmony_ci coda_write(dev, CODA9_FRAME_ENABLE_BWB, 28358c2ecf20Sopenharmony_ci CODA_REG_BIT_FRAME_MEM_CTRL); 28368c2ecf20Sopenharmony_ci else 28378c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci if (dev->devtype->product != CODA_DX6) 28408c2ecf20Sopenharmony_ci coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE); 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci coda_write(dev, CODA_INT_INTERRUPT_ENABLE, 28438c2ecf20Sopenharmony_ci CODA_REG_BIT_INT_ENABLE); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci /* Reset VPU and start processor */ 28468c2ecf20Sopenharmony_ci data = coda_read(dev, CODA_REG_BIT_CODE_RESET); 28478c2ecf20Sopenharmony_ci data |= CODA_REG_RESET_ENABLE; 28488c2ecf20Sopenharmony_ci coda_write(dev, data, CODA_REG_BIT_CODE_RESET); 28498c2ecf20Sopenharmony_ci udelay(10); 28508c2ecf20Sopenharmony_ci data &= ~CODA_REG_RESET_ENABLE; 28518c2ecf20Sopenharmony_ci coda_write(dev, data, CODA_REG_BIT_CODE_RESET); 28528c2ecf20Sopenharmony_ci coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 28558c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci return 0; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_cierr_clk_ahb: 28608c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_per); 28618c2ecf20Sopenharmony_cierr_clk_per: 28628c2ecf20Sopenharmony_ci return ret; 28638c2ecf20Sopenharmony_ci} 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_cistatic int coda_register_device(struct coda_dev *dev, int i) 28668c2ecf20Sopenharmony_ci{ 28678c2ecf20Sopenharmony_ci struct video_device *vfd = &dev->vfd[i]; 28688c2ecf20Sopenharmony_ci enum coda_inst_type type; 28698c2ecf20Sopenharmony_ci int ret; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci if (i >= dev->devtype->num_vdevs) 28728c2ecf20Sopenharmony_ci return -EINVAL; 28738c2ecf20Sopenharmony_ci type = dev->devtype->vdevs[i]->type; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); 28768c2ecf20Sopenharmony_ci vfd->fops = &coda_fops; 28778c2ecf20Sopenharmony_ci vfd->ioctl_ops = &coda_ioctl_ops; 28788c2ecf20Sopenharmony_ci vfd->release = video_device_release_empty, 28798c2ecf20Sopenharmony_ci vfd->lock = &dev->dev_mutex; 28808c2ecf20Sopenharmony_ci vfd->v4l2_dev = &dev->v4l2_dev; 28818c2ecf20Sopenharmony_ci vfd->vfl_dir = VFL_DIR_M2M; 28828c2ecf20Sopenharmony_ci vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; 28838c2ecf20Sopenharmony_ci video_set_drvdata(vfd, dev); 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci /* Not applicable, use the selection API instead */ 28868c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vfd, VIDIOC_CROPCAP); 28878c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); 28888c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); 28918c2ecf20Sopenharmony_ci if (!ret) 28928c2ecf20Sopenharmony_ci v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", 28938c2ecf20Sopenharmony_ci type == CODA_INST_ENCODER ? "encoder" : "decoder", 28948c2ecf20Sopenharmony_ci video_device_node_name(vfd)); 28958c2ecf20Sopenharmony_ci return ret; 28968c2ecf20Sopenharmony_ci} 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_cistatic void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf, 28998c2ecf20Sopenharmony_ci size_t size) 29008c2ecf20Sopenharmony_ci{ 29018c2ecf20Sopenharmony_ci u32 *src = (u32 *)buf; 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci /* Check if the firmware has a 16-byte Freescale header, skip it */ 29048c2ecf20Sopenharmony_ci if (buf[0] == 'M' && buf[1] == 'X') 29058c2ecf20Sopenharmony_ci src += 4; 29068c2ecf20Sopenharmony_ci /* 29078c2ecf20Sopenharmony_ci * Check whether the firmware is in native order or pre-reordered for 29088c2ecf20Sopenharmony_ci * memory access. The first instruction opcode always is 0xe40e. 29098c2ecf20Sopenharmony_ci */ 29108c2ecf20Sopenharmony_ci if (__le16_to_cpup((__le16 *)src) == 0xe40e) { 29118c2ecf20Sopenharmony_ci u32 *dst = dev->codebuf.vaddr; 29128c2ecf20Sopenharmony_ci int i; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci /* Firmware in native order, reorder while copying */ 29158c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 29168c2ecf20Sopenharmony_ci for (i = 0; i < (size - 16) / 4; i++) 29178c2ecf20Sopenharmony_ci dst[i] = (src[i] << 16) | (src[i] >> 16); 29188c2ecf20Sopenharmony_ci } else { 29198c2ecf20Sopenharmony_ci for (i = 0; i < (size - 16) / 4; i += 2) { 29208c2ecf20Sopenharmony_ci dst[i] = (src[i + 1] << 16) | (src[i + 1] >> 16); 29218c2ecf20Sopenharmony_ci dst[i + 1] = (src[i] << 16) | (src[i] >> 16); 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci } else { 29258c2ecf20Sopenharmony_ci /* Copy the already reordered firmware image */ 29268c2ecf20Sopenharmony_ci memcpy(dev->codebuf.vaddr, src, size); 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci} 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_cistatic void coda_fw_callback(const struct firmware *fw, void *context); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_cistatic int coda_firmware_request(struct coda_dev *dev) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci char *fw; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci if (dev->firmware >= ARRAY_SIZE(dev->devtype->firmware)) 29378c2ecf20Sopenharmony_ci return -EINVAL; 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci fw = dev->devtype->firmware[dev->firmware]; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw, 29428c2ecf20Sopenharmony_ci coda_product_name(dev->devtype->product)); 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev, 29458c2ecf20Sopenharmony_ci GFP_KERNEL, dev, coda_fw_callback); 29468c2ecf20Sopenharmony_ci} 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_cistatic void coda_fw_callback(const struct firmware *fw, void *context) 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci struct coda_dev *dev = context; 29518c2ecf20Sopenharmony_ci int i, ret; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci if (!fw) { 29548c2ecf20Sopenharmony_ci dev->firmware++; 29558c2ecf20Sopenharmony_ci ret = coda_firmware_request(dev); 29568c2ecf20Sopenharmony_ci if (ret < 0) { 29578c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); 29588c2ecf20Sopenharmony_ci goto put_pm; 29598c2ecf20Sopenharmony_ci } 29608c2ecf20Sopenharmony_ci return; 29618c2ecf20Sopenharmony_ci } 29628c2ecf20Sopenharmony_ci if (dev->firmware > 0) { 29638c2ecf20Sopenharmony_ci /* 29648c2ecf20Sopenharmony_ci * Since we can't suppress warnings for failed asynchronous 29658c2ecf20Sopenharmony_ci * firmware requests, report that the fallback firmware was 29668c2ecf20Sopenharmony_ci * found. 29678c2ecf20Sopenharmony_ci */ 29688c2ecf20Sopenharmony_ci dev_info(dev->dev, "Using fallback firmware %s\n", 29698c2ecf20Sopenharmony_ci dev->devtype->firmware[dev->firmware]); 29708c2ecf20Sopenharmony_ci } 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci /* allocate auxiliary per-device code buffer for the BIT processor */ 29738c2ecf20Sopenharmony_ci ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", 29748c2ecf20Sopenharmony_ci dev->debugfs_root); 29758c2ecf20Sopenharmony_ci if (ret < 0) 29768c2ecf20Sopenharmony_ci goto put_pm; 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci coda_copy_firmware(dev, fw->data, fw->size); 29798c2ecf20Sopenharmony_ci release_firmware(fw); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci ret = coda_hw_init(dev); 29828c2ecf20Sopenharmony_ci if (ret < 0) { 29838c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "HW initialization failed\n"); 29848c2ecf20Sopenharmony_ci goto put_pm; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci ret = coda_check_firmware(dev); 29888c2ecf20Sopenharmony_ci if (ret < 0) 29898c2ecf20Sopenharmony_ci goto put_pm; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops); 29928c2ecf20Sopenharmony_ci if (IS_ERR(dev->m2m_dev)) { 29938c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); 29948c2ecf20Sopenharmony_ci goto put_pm; 29958c2ecf20Sopenharmony_ci } 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci for (i = 0; i < dev->devtype->num_vdevs; i++) { 29988c2ecf20Sopenharmony_ci ret = coda_register_device(dev, i); 29998c2ecf20Sopenharmony_ci if (ret) { 30008c2ecf20Sopenharmony_ci v4l2_err(&dev->v4l2_dev, 30018c2ecf20Sopenharmony_ci "Failed to register %s video device: %d\n", 30028c2ecf20Sopenharmony_ci dev->devtype->vdevs[i]->name, ret); 30038c2ecf20Sopenharmony_ci goto rel_vfd; 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci } 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev->dev); 30088c2ecf20Sopenharmony_ci return; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_cirel_vfd: 30118c2ecf20Sopenharmony_ci while (--i >= 0) 30128c2ecf20Sopenharmony_ci video_unregister_device(&dev->vfd[i]); 30138c2ecf20Sopenharmony_ci v4l2_m2m_release(dev->m2m_dev); 30148c2ecf20Sopenharmony_ciput_pm: 30158c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev->dev); 30168c2ecf20Sopenharmony_ci} 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_cienum coda_platform { 30198c2ecf20Sopenharmony_ci CODA_IMX27, 30208c2ecf20Sopenharmony_ci CODA_IMX51, 30218c2ecf20Sopenharmony_ci CODA_IMX53, 30228c2ecf20Sopenharmony_ci CODA_IMX6Q, 30238c2ecf20Sopenharmony_ci CODA_IMX6DL, 30248c2ecf20Sopenharmony_ci}; 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_cistatic const struct coda_devtype coda_devdata[] = { 30278c2ecf20Sopenharmony_ci [CODA_IMX27] = { 30288c2ecf20Sopenharmony_ci .firmware = { 30298c2ecf20Sopenharmony_ci "vpu_fw_imx27_TO2.bin", 30308c2ecf20Sopenharmony_ci "vpu/vpu_fw_imx27_TO2.bin", 30318c2ecf20Sopenharmony_ci "v4l-codadx6-imx27.bin" 30328c2ecf20Sopenharmony_ci }, 30338c2ecf20Sopenharmony_ci .product = CODA_DX6, 30348c2ecf20Sopenharmony_ci .codecs = codadx6_codecs, 30358c2ecf20Sopenharmony_ci .num_codecs = ARRAY_SIZE(codadx6_codecs), 30368c2ecf20Sopenharmony_ci .vdevs = codadx6_video_devices, 30378c2ecf20Sopenharmony_ci .num_vdevs = ARRAY_SIZE(codadx6_video_devices), 30388c2ecf20Sopenharmony_ci .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, 30398c2ecf20Sopenharmony_ci .iram_size = 0xb000, 30408c2ecf20Sopenharmony_ci }, 30418c2ecf20Sopenharmony_ci [CODA_IMX51] = { 30428c2ecf20Sopenharmony_ci .firmware = { 30438c2ecf20Sopenharmony_ci "vpu_fw_imx51.bin", 30448c2ecf20Sopenharmony_ci "vpu/vpu_fw_imx51.bin", 30458c2ecf20Sopenharmony_ci "v4l-codahx4-imx51.bin" 30468c2ecf20Sopenharmony_ci }, 30478c2ecf20Sopenharmony_ci .product = CODA_HX4, 30488c2ecf20Sopenharmony_ci .codecs = codahx4_codecs, 30498c2ecf20Sopenharmony_ci .num_codecs = ARRAY_SIZE(codahx4_codecs), 30508c2ecf20Sopenharmony_ci .vdevs = codahx4_video_devices, 30518c2ecf20Sopenharmony_ci .num_vdevs = ARRAY_SIZE(codahx4_video_devices), 30528c2ecf20Sopenharmony_ci .workbuf_size = 128 * 1024, 30538c2ecf20Sopenharmony_ci .tempbuf_size = 304 * 1024, 30548c2ecf20Sopenharmony_ci .iram_size = 0x14000, 30558c2ecf20Sopenharmony_ci }, 30568c2ecf20Sopenharmony_ci [CODA_IMX53] = { 30578c2ecf20Sopenharmony_ci .firmware = { 30588c2ecf20Sopenharmony_ci "vpu_fw_imx53.bin", 30598c2ecf20Sopenharmony_ci "vpu/vpu_fw_imx53.bin", 30608c2ecf20Sopenharmony_ci "v4l-coda7541-imx53.bin" 30618c2ecf20Sopenharmony_ci }, 30628c2ecf20Sopenharmony_ci .product = CODA_7541, 30638c2ecf20Sopenharmony_ci .codecs = coda7_codecs, 30648c2ecf20Sopenharmony_ci .num_codecs = ARRAY_SIZE(coda7_codecs), 30658c2ecf20Sopenharmony_ci .vdevs = coda7_video_devices, 30668c2ecf20Sopenharmony_ci .num_vdevs = ARRAY_SIZE(coda7_video_devices), 30678c2ecf20Sopenharmony_ci .workbuf_size = 128 * 1024, 30688c2ecf20Sopenharmony_ci .tempbuf_size = 304 * 1024, 30698c2ecf20Sopenharmony_ci .iram_size = 0x14000, 30708c2ecf20Sopenharmony_ci }, 30718c2ecf20Sopenharmony_ci [CODA_IMX6Q] = { 30728c2ecf20Sopenharmony_ci .firmware = { 30738c2ecf20Sopenharmony_ci "vpu_fw_imx6q.bin", 30748c2ecf20Sopenharmony_ci "vpu/vpu_fw_imx6q.bin", 30758c2ecf20Sopenharmony_ci "v4l-coda960-imx6q.bin" 30768c2ecf20Sopenharmony_ci }, 30778c2ecf20Sopenharmony_ci .product = CODA_960, 30788c2ecf20Sopenharmony_ci .codecs = coda9_codecs, 30798c2ecf20Sopenharmony_ci .num_codecs = ARRAY_SIZE(coda9_codecs), 30808c2ecf20Sopenharmony_ci .vdevs = coda9_video_devices, 30818c2ecf20Sopenharmony_ci .num_vdevs = ARRAY_SIZE(coda9_video_devices), 30828c2ecf20Sopenharmony_ci .workbuf_size = 80 * 1024, 30838c2ecf20Sopenharmony_ci .tempbuf_size = 204 * 1024, 30848c2ecf20Sopenharmony_ci .iram_size = 0x21000, 30858c2ecf20Sopenharmony_ci }, 30868c2ecf20Sopenharmony_ci [CODA_IMX6DL] = { 30878c2ecf20Sopenharmony_ci .firmware = { 30888c2ecf20Sopenharmony_ci "vpu_fw_imx6d.bin", 30898c2ecf20Sopenharmony_ci "vpu/vpu_fw_imx6d.bin", 30908c2ecf20Sopenharmony_ci "v4l-coda960-imx6dl.bin" 30918c2ecf20Sopenharmony_ci }, 30928c2ecf20Sopenharmony_ci .product = CODA_960, 30938c2ecf20Sopenharmony_ci .codecs = coda9_codecs, 30948c2ecf20Sopenharmony_ci .num_codecs = ARRAY_SIZE(coda9_codecs), 30958c2ecf20Sopenharmony_ci .vdevs = coda9_video_devices, 30968c2ecf20Sopenharmony_ci .num_vdevs = ARRAY_SIZE(coda9_video_devices), 30978c2ecf20Sopenharmony_ci .workbuf_size = 80 * 1024, 30988c2ecf20Sopenharmony_ci .tempbuf_size = 204 * 1024, 30998c2ecf20Sopenharmony_ci .iram_size = 0x1f000, /* leave 4k for suspend code */ 31008c2ecf20Sopenharmony_ci }, 31018c2ecf20Sopenharmony_ci}; 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_cistatic const struct platform_device_id coda_platform_ids[] = { 31048c2ecf20Sopenharmony_ci { .name = "coda-imx27", .driver_data = CODA_IMX27 }, 31058c2ecf20Sopenharmony_ci { /* sentinel */ } 31068c2ecf20Sopenharmony_ci}; 31078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, coda_platform_ids); 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 31108c2ecf20Sopenharmony_cistatic const struct of_device_id coda_dt_ids[] = { 31118c2ecf20Sopenharmony_ci { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, 31128c2ecf20Sopenharmony_ci { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, 31138c2ecf20Sopenharmony_ci { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, 31148c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, 31158c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, 31168c2ecf20Sopenharmony_ci { /* sentinel */ } 31178c2ecf20Sopenharmony_ci}; 31188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, coda_dt_ids); 31198c2ecf20Sopenharmony_ci#endif 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_cistatic int coda_probe(struct platform_device *pdev) 31228c2ecf20Sopenharmony_ci{ 31238c2ecf20Sopenharmony_ci const struct of_device_id *of_id = 31248c2ecf20Sopenharmony_ci of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev); 31258c2ecf20Sopenharmony_ci const struct platform_device_id *pdev_id; 31268c2ecf20Sopenharmony_ci struct coda_platform_data *pdata = pdev->dev.platform_data; 31278c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 31288c2ecf20Sopenharmony_ci struct gen_pool *pool; 31298c2ecf20Sopenharmony_ci struct coda_dev *dev; 31308c2ecf20Sopenharmony_ci int ret, irq; 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 31338c2ecf20Sopenharmony_ci if (!dev) 31348c2ecf20Sopenharmony_ci return -ENOMEM; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci pdev_id = of_id ? of_id->data : platform_get_device_id(pdev); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci if (of_id) 31398c2ecf20Sopenharmony_ci dev->devtype = of_id->data; 31408c2ecf20Sopenharmony_ci else if (pdev_id) 31418c2ecf20Sopenharmony_ci dev->devtype = &coda_devdata[pdev_id->driver_data]; 31428c2ecf20Sopenharmony_ci else 31438c2ecf20Sopenharmony_ci return -EINVAL; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci dev->dev = &pdev->dev; 31468c2ecf20Sopenharmony_ci dev->clk_per = devm_clk_get(&pdev->dev, "per"); 31478c2ecf20Sopenharmony_ci if (IS_ERR(dev->clk_per)) { 31488c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get per clock\n"); 31498c2ecf20Sopenharmony_ci return PTR_ERR(dev->clk_per); 31508c2ecf20Sopenharmony_ci } 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 31538c2ecf20Sopenharmony_ci if (IS_ERR(dev->clk_ahb)) { 31548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get ahb clock\n"); 31558c2ecf20Sopenharmony_ci return PTR_ERR(dev->clk_ahb); 31568c2ecf20Sopenharmony_ci } 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci /* Get memory for physical registers */ 31598c2ecf20Sopenharmony_ci dev->regs_base = devm_platform_ioremap_resource(pdev, 0); 31608c2ecf20Sopenharmony_ci if (IS_ERR(dev->regs_base)) 31618c2ecf20Sopenharmony_ci return PTR_ERR(dev->regs_base); 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci /* IRQ */ 31648c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "bit"); 31658c2ecf20Sopenharmony_ci if (irq < 0) 31668c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 31678c2ecf20Sopenharmony_ci if (irq < 0) 31688c2ecf20Sopenharmony_ci return irq; 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, 31718c2ecf20Sopenharmony_ci dev_name(&pdev->dev), dev); 31728c2ecf20Sopenharmony_ci if (ret < 0) { 31738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request irq: %d\n", ret); 31748c2ecf20Sopenharmony_ci return ret; 31758c2ecf20Sopenharmony_ci } 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci /* JPEG IRQ */ 31788c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_960) { 31798c2ecf20Sopenharmony_ci irq = platform_get_irq_byname(pdev, "jpeg"); 31808c2ecf20Sopenharmony_ci if (irq < 0) 31818c2ecf20Sopenharmony_ci return irq; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 31848c2ecf20Sopenharmony_ci coda9_jpeg_irq_handler, 31858c2ecf20Sopenharmony_ci IRQF_ONESHOT, CODA_NAME " jpeg", 31868c2ecf20Sopenharmony_ci dev); 31878c2ecf20Sopenharmony_ci if (ret < 0) { 31888c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request jpeg irq\n"); 31898c2ecf20Sopenharmony_ci return ret; 31908c2ecf20Sopenharmony_ci } 31918c2ecf20Sopenharmony_ci } 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci dev->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, 31948c2ecf20Sopenharmony_ci NULL); 31958c2ecf20Sopenharmony_ci if (IS_ERR(dev->rstc)) { 31968c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->rstc); 31978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed get reset control: %d\n", ret); 31988c2ecf20Sopenharmony_ci return ret; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci /* Get IRAM pool from device tree or platform data */ 32028c2ecf20Sopenharmony_ci pool = of_gen_pool_get(np, "iram", 0); 32038c2ecf20Sopenharmony_ci if (!pool && pdata) 32048c2ecf20Sopenharmony_ci pool = gen_pool_get(pdata->iram_dev, NULL); 32058c2ecf20Sopenharmony_ci if (!pool) { 32068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "iram pool not available\n"); 32078c2ecf20Sopenharmony_ci return -ENOMEM; 32088c2ecf20Sopenharmony_ci } 32098c2ecf20Sopenharmony_ci dev->iram_pool = pool; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci /* Get vdoa_data if supported by the platform */ 32128c2ecf20Sopenharmony_ci dev->vdoa = coda_get_vdoa_data(); 32138c2ecf20Sopenharmony_ci if (PTR_ERR(dev->vdoa) == -EPROBE_DEFER) 32148c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 32178c2ecf20Sopenharmony_ci if (ret) 32188c2ecf20Sopenharmony_ci return ret; 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci mutex_init(&dev->dev_mutex); 32218c2ecf20Sopenharmony_ci mutex_init(&dev->coda_mutex); 32228c2ecf20Sopenharmony_ci ida_init(&dev->ida); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci dev->debugfs_root = debugfs_create_dir("coda", NULL); 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci /* allocate auxiliary per-device buffers for the BIT processor */ 32278c2ecf20Sopenharmony_ci if (dev->devtype->product == CODA_DX6) { 32288c2ecf20Sopenharmony_ci ret = coda_alloc_aux_buf(dev, &dev->workbuf, 32298c2ecf20Sopenharmony_ci dev->devtype->workbuf_size, "workbuf", 32308c2ecf20Sopenharmony_ci dev->debugfs_root); 32318c2ecf20Sopenharmony_ci if (ret < 0) 32328c2ecf20Sopenharmony_ci goto err_v4l2_register; 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci if (dev->devtype->tempbuf_size) { 32368c2ecf20Sopenharmony_ci ret = coda_alloc_aux_buf(dev, &dev->tempbuf, 32378c2ecf20Sopenharmony_ci dev->devtype->tempbuf_size, "tempbuf", 32388c2ecf20Sopenharmony_ci dev->debugfs_root); 32398c2ecf20Sopenharmony_ci if (ret < 0) 32408c2ecf20Sopenharmony_ci goto err_v4l2_register; 32418c2ecf20Sopenharmony_ci } 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci dev->iram.size = dev->devtype->iram_size; 32448c2ecf20Sopenharmony_ci dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size, 32458c2ecf20Sopenharmony_ci &dev->iram.paddr); 32468c2ecf20Sopenharmony_ci if (!dev->iram.vaddr) { 32478c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "unable to alloc iram\n"); 32488c2ecf20Sopenharmony_ci } else { 32498c2ecf20Sopenharmony_ci memset(dev->iram.vaddr, 0, dev->iram.size); 32508c2ecf20Sopenharmony_ci dev->iram.blob.data = dev->iram.vaddr; 32518c2ecf20Sopenharmony_ci dev->iram.blob.size = dev->iram.size; 32528c2ecf20Sopenharmony_ci dev->iram.dentry = debugfs_create_blob("iram", 0644, 32538c2ecf20Sopenharmony_ci dev->debugfs_root, 32548c2ecf20Sopenharmony_ci &dev->iram.blob); 32558c2ecf20Sopenharmony_ci } 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1); 32588c2ecf20Sopenharmony_ci if (!dev->workqueue) { 32598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to alloc workqueue\n"); 32608c2ecf20Sopenharmony_ci ret = -ENOMEM; 32618c2ecf20Sopenharmony_ci goto err_v4l2_register; 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci /* 32678c2ecf20Sopenharmony_ci * Start activated so we can directly call coda_hw_init in 32688c2ecf20Sopenharmony_ci * coda_fw_callback regardless of whether CONFIG_PM is 32698c2ecf20Sopenharmony_ci * enabled or whether the device is associated with a PM domain. 32708c2ecf20Sopenharmony_ci */ 32718c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 32728c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 32738c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci ret = coda_firmware_request(dev); 32768c2ecf20Sopenharmony_ci if (ret) 32778c2ecf20Sopenharmony_ci goto err_alloc_workqueue; 32788c2ecf20Sopenharmony_ci return 0; 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_cierr_alloc_workqueue: 32818c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 32828c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 32838c2ecf20Sopenharmony_ci destroy_workqueue(dev->workqueue); 32848c2ecf20Sopenharmony_cierr_v4l2_register: 32858c2ecf20Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 32868c2ecf20Sopenharmony_ci return ret; 32878c2ecf20Sopenharmony_ci} 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_cistatic int coda_remove(struct platform_device *pdev) 32908c2ecf20Sopenharmony_ci{ 32918c2ecf20Sopenharmony_ci struct coda_dev *dev = platform_get_drvdata(pdev); 32928c2ecf20Sopenharmony_ci int i; 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) { 32958c2ecf20Sopenharmony_ci if (video_get_drvdata(&dev->vfd[i])) 32968c2ecf20Sopenharmony_ci video_unregister_device(&dev->vfd[i]); 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci if (dev->m2m_dev) 32998c2ecf20Sopenharmony_ci v4l2_m2m_release(dev->m2m_dev); 33008c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 33018c2ecf20Sopenharmony_ci v4l2_device_unregister(&dev->v4l2_dev); 33028c2ecf20Sopenharmony_ci destroy_workqueue(dev->workqueue); 33038c2ecf20Sopenharmony_ci if (dev->iram.vaddr) 33048c2ecf20Sopenharmony_ci gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr, 33058c2ecf20Sopenharmony_ci dev->iram.size); 33068c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &dev->codebuf); 33078c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &dev->tempbuf); 33088c2ecf20Sopenharmony_ci coda_free_aux_buf(dev, &dev->workbuf); 33098c2ecf20Sopenharmony_ci debugfs_remove_recursive(dev->debugfs_root); 33108c2ecf20Sopenharmony_ci ida_destroy(&dev->ida); 33118c2ecf20Sopenharmony_ci return 0; 33128c2ecf20Sopenharmony_ci} 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 33158c2ecf20Sopenharmony_cistatic int coda_runtime_resume(struct device *dev) 33168c2ecf20Sopenharmony_ci{ 33178c2ecf20Sopenharmony_ci struct coda_dev *cdev = dev_get_drvdata(dev); 33188c2ecf20Sopenharmony_ci int ret = 0; 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci if (dev->pm_domain && cdev->codebuf.vaddr) { 33218c2ecf20Sopenharmony_ci ret = coda_hw_init(cdev); 33228c2ecf20Sopenharmony_ci if (ret) 33238c2ecf20Sopenharmony_ci v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n"); 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci return ret; 33278c2ecf20Sopenharmony_ci} 33288c2ecf20Sopenharmony_ci#endif 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_cistatic const struct dev_pm_ops coda_pm_ops = { 33318c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL) 33328c2ecf20Sopenharmony_ci}; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_cistatic struct platform_driver coda_driver = { 33358c2ecf20Sopenharmony_ci .probe = coda_probe, 33368c2ecf20Sopenharmony_ci .remove = coda_remove, 33378c2ecf20Sopenharmony_ci .driver = { 33388c2ecf20Sopenharmony_ci .name = CODA_NAME, 33398c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(coda_dt_ids), 33408c2ecf20Sopenharmony_ci .pm = &coda_pm_ops, 33418c2ecf20Sopenharmony_ci }, 33428c2ecf20Sopenharmony_ci .id_table = coda_platform_ids, 33438c2ecf20Sopenharmony_ci}; 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cimodule_platform_driver(coda_driver); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 33488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); 33498c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver"); 3350