2664 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI VPE mem2mem driver, based on the virtual v4l2-mem2mem example driver4 *5 * Copyright (c) 2013 Texas Instruments Inc.6 * David Griego, <dagriego@biglakesoftware.com>7 * Dale Farnsworth, <dale@farnsworth.org>8 * Archit Taneja, <archit@ti.com>9 *10 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.11 * Pawel Osciak, <pawel@osciak.com>12 * Marek Szyprowski, <m.szyprowski@samsung.com>13 *14 * Based on the virtual v4l2-mem2mem example device15 */16 17#include <linux/delay.h>18#include <linux/dma-mapping.h>19#include <linux/err.h>20#include <linux/fs.h>21#include <linux/interrupt.h>22#include <linux/io.h>23#include <linux/ioctl.h>24#include <linux/module.h>25#include <linux/of.h>26#include <linux/platform_device.h>27#include <linux/pm_runtime.h>28#include <linux/sched.h>29#include <linux/slab.h>30#include <linux/videodev2.h>31#include <linux/log2.h>32#include <linux/sizes.h>33 34#include <media/v4l2-common.h>35#include <media/v4l2-ctrls.h>36#include <media/v4l2-device.h>37#include <media/v4l2-event.h>38#include <media/v4l2-ioctl.h>39#include <media/v4l2-mem2mem.h>40#include <media/videobuf2-v4l2.h>41#include <media/videobuf2-dma-contig.h>42 43#include "vpdma.h"44#include "vpdma_priv.h"45#include "vpe_regs.h"46#include "sc.h"47#include "csc.h"48 49#define VPE_MODULE_NAME "vpe"50 51/* minimum and maximum frame sizes */52#define MIN_W 3253#define MIN_H 3254#define MAX_W 204855#define MAX_H 204856 57/* required alignments */58#define S_ALIGN 0 /* multiple of 1 */59#define H_ALIGN 1 /* multiple of 2 */60 61/* flags that indicate a format can be used for capture/output */62#define VPE_FMT_TYPE_CAPTURE (1 << 0)63#define VPE_FMT_TYPE_OUTPUT (1 << 1)64 65/* used as plane indices */66#define VPE_MAX_PLANES 267#define VPE_LUMA 068#define VPE_CHROMA 169 70/* per m2m context info */71#define VPE_MAX_SRC_BUFS 3 /* need 3 src fields to de-interlace */72 73#define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */74 75/*76 * each VPE context can need up to 3 config descriptors, 7 input descriptors,77 * 3 output descriptors, and 10 control descriptors78 */79#define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \80 13 * VPDMA_CFD_CTD_DESC_SIZE)81 82#define vpe_dbg(vpedev, fmt, arg...) \83 dev_dbg((vpedev)->v4l2_dev.dev, fmt, ##arg)84#define vpe_err(vpedev, fmt, arg...) \85 dev_err((vpedev)->v4l2_dev.dev, fmt, ##arg)86 87struct vpe_us_coeffs {88 unsigned short anchor_fid0_c0;89 unsigned short anchor_fid0_c1;90 unsigned short anchor_fid0_c2;91 unsigned short anchor_fid0_c3;92 unsigned short interp_fid0_c0;93 unsigned short interp_fid0_c1;94 unsigned short interp_fid0_c2;95 unsigned short interp_fid0_c3;96 unsigned short anchor_fid1_c0;97 unsigned short anchor_fid1_c1;98 unsigned short anchor_fid1_c2;99 unsigned short anchor_fid1_c3;100 unsigned short interp_fid1_c0;101 unsigned short interp_fid1_c1;102 unsigned short interp_fid1_c2;103 unsigned short interp_fid1_c3;104};105 106/*107 * Default upsampler coefficients108 */109static const struct vpe_us_coeffs us_coeffs[] = {110 {111 /* Coefficients for progressive input */112 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,113 0x00C8, 0x0348, 0x0018, 0x3FD8, 0x3FB8, 0x0378, 0x00E8, 0x3FE8,114 },115 {116 /* Coefficients for Top Field Interlaced input */117 0x0051, 0x03D5, 0x3FE3, 0x3FF7, 0x3FB5, 0x02E9, 0x018F, 0x3FD3,118 /* Coefficients for Bottom Field Interlaced input */119 0x016B, 0x0247, 0x00B1, 0x3F9D, 0x3FCF, 0x03DB, 0x005D, 0x3FF9,120 },121};122 123/*124 * the following registers are for configuring some of the parameters of the125 * motion and edge detection blocks inside DEI, these generally remain the same,126 * these could be passed later via userspace if some one needs to tweak these.127 */128struct vpe_dei_regs {129 unsigned long mdt_spacial_freq_thr_reg; /* VPE_DEI_REG2 */130 unsigned long edi_config_reg; /* VPE_DEI_REG3 */131 unsigned long edi_lut_reg0; /* VPE_DEI_REG4 */132 unsigned long edi_lut_reg1; /* VPE_DEI_REG5 */133 unsigned long edi_lut_reg2; /* VPE_DEI_REG6 */134 unsigned long edi_lut_reg3; /* VPE_DEI_REG7 */135};136 137/*138 * default expert DEI register values, unlikely to be modified.139 */140static const struct vpe_dei_regs dei_regs = {141 .mdt_spacial_freq_thr_reg = 0x020C0804u,142 .edi_config_reg = 0x0118100Cu,143 .edi_lut_reg0 = 0x08040200u,144 .edi_lut_reg1 = 0x1010100Cu,145 .edi_lut_reg2 = 0x10101010u,146 .edi_lut_reg3 = 0x10101010u,147};148 149/*150 * The port_data structure contains per-port data.151 */152struct vpe_port_data {153 enum vpdma_channel channel; /* VPDMA channel */154 u8 vb_index; /* input frame f, f-1, f-2 index */155 u8 vb_part; /* plane index for co-panar formats */156};157 158/*159 * Define indices into the port_data tables160 */161#define VPE_PORT_LUMA1_IN 0162#define VPE_PORT_CHROMA1_IN 1163#define VPE_PORT_LUMA2_IN 2164#define VPE_PORT_CHROMA2_IN 3165#define VPE_PORT_LUMA3_IN 4166#define VPE_PORT_CHROMA3_IN 5167#define VPE_PORT_MV_IN 6168#define VPE_PORT_MV_OUT 7169#define VPE_PORT_LUMA_OUT 8170#define VPE_PORT_CHROMA_OUT 9171#define VPE_PORT_RGB_OUT 10172 173static const struct vpe_port_data port_data[11] = {174 [VPE_PORT_LUMA1_IN] = {175 .channel = VPE_CHAN_LUMA1_IN,176 .vb_index = 0,177 .vb_part = VPE_LUMA,178 },179 [VPE_PORT_CHROMA1_IN] = {180 .channel = VPE_CHAN_CHROMA1_IN,181 .vb_index = 0,182 .vb_part = VPE_CHROMA,183 },184 [VPE_PORT_LUMA2_IN] = {185 .channel = VPE_CHAN_LUMA2_IN,186 .vb_index = 1,187 .vb_part = VPE_LUMA,188 },189 [VPE_PORT_CHROMA2_IN] = {190 .channel = VPE_CHAN_CHROMA2_IN,191 .vb_index = 1,192 .vb_part = VPE_CHROMA,193 },194 [VPE_PORT_LUMA3_IN] = {195 .channel = VPE_CHAN_LUMA3_IN,196 .vb_index = 2,197 .vb_part = VPE_LUMA,198 },199 [VPE_PORT_CHROMA3_IN] = {200 .channel = VPE_CHAN_CHROMA3_IN,201 .vb_index = 2,202 .vb_part = VPE_CHROMA,203 },204 [VPE_PORT_MV_IN] = {205 .channel = VPE_CHAN_MV_IN,206 },207 [VPE_PORT_MV_OUT] = {208 .channel = VPE_CHAN_MV_OUT,209 },210 [VPE_PORT_LUMA_OUT] = {211 .channel = VPE_CHAN_LUMA_OUT,212 .vb_part = VPE_LUMA,213 },214 [VPE_PORT_CHROMA_OUT] = {215 .channel = VPE_CHAN_CHROMA_OUT,216 .vb_part = VPE_CHROMA,217 },218 [VPE_PORT_RGB_OUT] = {219 .channel = VPE_CHAN_RGB_OUT,220 .vb_part = VPE_LUMA,221 },222};223 224 225/* driver info for each of the supported video formats */226struct vpe_fmt {227 u32 fourcc; /* standard format identifier */228 u8 types; /* CAPTURE and/or OUTPUT */229 u8 coplanar; /* set for unpacked Luma and Chroma */230 /* vpdma format info for each plane */231 struct vpdma_data_format const *vpdma_fmt[VPE_MAX_PLANES];232};233 234static struct vpe_fmt vpe_formats[] = {235 {236 .fourcc = V4L2_PIX_FMT_NV16,237 .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,238 .coplanar = 1,239 .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y444],240 &vpdma_yuv_fmts[VPDMA_DATA_FMT_C444],241 },242 },243 {244 .fourcc = V4L2_PIX_FMT_NV12,245 .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,246 .coplanar = 1,247 .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],248 &vpdma_yuv_fmts[VPDMA_DATA_FMT_C420],249 },250 },251 {252 .fourcc = V4L2_PIX_FMT_NV21,253 .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,254 .coplanar = 1,255 .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],256 &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420],257 },258 },259 {260 .fourcc = V4L2_PIX_FMT_YUYV,261 .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,262 .coplanar = 0,263 .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422],264 },265 },266 {267 .fourcc = V4L2_PIX_FMT_UYVY,268 .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,269 .coplanar = 0,270 .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],271 },272 },273 {274 .fourcc = V4L2_PIX_FMT_RGB24,275 .types = VPE_FMT_TYPE_CAPTURE,276 .coplanar = 0,277 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24],278 },279 },280 {281 .fourcc = V4L2_PIX_FMT_RGB32,282 .types = VPE_FMT_TYPE_CAPTURE,283 .coplanar = 0,284 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32],285 },286 },287 {288 .fourcc = V4L2_PIX_FMT_BGR24,289 .types = VPE_FMT_TYPE_CAPTURE,290 .coplanar = 0,291 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24],292 },293 },294 {295 .fourcc = V4L2_PIX_FMT_BGR32,296 .types = VPE_FMT_TYPE_CAPTURE,297 .coplanar = 0,298 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32],299 },300 },301 {302 .fourcc = V4L2_PIX_FMT_RGB565,303 .types = VPE_FMT_TYPE_CAPTURE,304 .coplanar = 0,305 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB565],306 },307 },308 {309 .fourcc = V4L2_PIX_FMT_RGB555,310 .types = VPE_FMT_TYPE_CAPTURE,311 .coplanar = 0,312 .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGBA16_5551],313 },314 },315};316 317/*318 * per-queue, driver-specific private data.319 * there is one source queue and one destination queue for each m2m context.320 */321struct vpe_q_data {322 /* current v4l2 format info */323 struct v4l2_format format;324 unsigned int flags;325 struct v4l2_rect c_rect; /* crop/compose rectangle */326 struct vpe_fmt *fmt; /* format info */327};328 329/* vpe_q_data flag bits */330#define Q_DATA_FRAME_1D BIT(0)331#define Q_DATA_MODE_TILED BIT(1)332#define Q_DATA_INTERLACED_ALTERNATE BIT(2)333#define Q_DATA_INTERLACED_SEQ_TB BIT(3)334#define Q_DATA_INTERLACED_SEQ_BT BIT(4)335 336#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \337 Q_DATA_INTERLACED_SEQ_BT)338 339#define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \340 Q_DATA_INTERLACED_SEQ_TB | \341 Q_DATA_INTERLACED_SEQ_BT)342 343enum {344 Q_DATA_SRC = 0,345 Q_DATA_DST = 1,346};347 348/* find our format description corresponding to the passed v4l2_format */349static struct vpe_fmt *__find_format(u32 fourcc)350{351 struct vpe_fmt *fmt;352 unsigned int k;353 354 for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) {355 fmt = &vpe_formats[k];356 if (fmt->fourcc == fourcc)357 return fmt;358 }359 360 return NULL;361}362 363static struct vpe_fmt *find_format(struct v4l2_format *f)364{365 return __find_format(f->fmt.pix.pixelformat);366}367 368/*369 * there is one vpe_dev structure in the driver, it is shared by370 * all instances.371 */372struct vpe_dev {373 struct v4l2_device v4l2_dev;374 struct video_device vfd;375 struct v4l2_m2m_dev *m2m_dev;376 377 atomic_t num_instances; /* count of driver instances */378 dma_addr_t loaded_mmrs; /* shadow mmrs in device */379 struct mutex dev_mutex;380 spinlock_t lock;381 382 int irq;383 void __iomem *base;384 struct resource *res;385 386 struct vpdma_data vpdma_data;387 struct vpdma_data *vpdma; /* vpdma data handle */388 struct sc_data *sc; /* scaler data handle */389 struct csc_data *csc; /* csc data handle */390};391 392/*393 * There is one vpe_ctx structure for each m2m context.394 */395struct vpe_ctx {396 struct v4l2_fh fh;397 struct vpe_dev *dev;398 struct v4l2_ctrl_handler hdl;399 400 unsigned int field; /* current field */401 unsigned int sequence; /* current frame/field seq */402 unsigned int aborting; /* abort after next irq */403 404 unsigned int bufs_per_job; /* input buffers per batch */405 unsigned int bufs_completed; /* bufs done in this batch */406 407 struct vpe_q_data q_data[2]; /* src & dst queue data */408 struct vb2_v4l2_buffer *src_vbs[VPE_MAX_SRC_BUFS];409 struct vb2_v4l2_buffer *dst_vb;410 411 dma_addr_t mv_buf_dma[2]; /* dma addrs of motion vector in/out bufs */412 void *mv_buf[2]; /* virtual addrs of motion vector bufs */413 size_t mv_buf_size; /* current motion vector buffer size */414 struct vpdma_buf mmr_adb; /* shadow reg addr/data block */415 struct vpdma_buf sc_coeff_h; /* h coeff buffer */416 struct vpdma_buf sc_coeff_v; /* v coeff buffer */417 struct vpdma_desc_list desc_list; /* DMA descriptor list */418 419 bool deinterlacing; /* using de-interlacer */420 bool load_mmrs; /* have new shadow reg values */421 422 unsigned int src_mv_buf_selector;423};424 425 426/*427 * M2M devices get 2 queues.428 * Return the queue given the type.429 */430static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,431 enum v4l2_buf_type type)432{433 switch (type) {434 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:435 case V4L2_BUF_TYPE_VIDEO_OUTPUT:436 return &ctx->q_data[Q_DATA_SRC];437 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:438 case V4L2_BUF_TYPE_VIDEO_CAPTURE:439 return &ctx->q_data[Q_DATA_DST];440 default:441 return NULL;442 }443 return NULL;444}445 446static u32 read_reg(struct vpe_dev *dev, int offset)447{448 return ioread32(dev->base + offset);449}450 451static void write_reg(struct vpe_dev *dev, int offset, u32 value)452{453 iowrite32(value, dev->base + offset);454}455 456/* register field read/write helpers */457static int get_field(u32 value, u32 mask, int shift)458{459 return (value & (mask << shift)) >> shift;460}461 462static int read_field_reg(struct vpe_dev *dev, int offset, u32 mask, int shift)463{464 return get_field(read_reg(dev, offset), mask, shift);465}466 467static void write_field(u32 *valp, u32 field, u32 mask, int shift)468{469 u32 val = *valp;470 471 val &= ~(mask << shift);472 val |= (field & mask) << shift;473 *valp = val;474}475 476static void write_field_reg(struct vpe_dev *dev, int offset, u32 field,477 u32 mask, int shift)478{479 u32 val = read_reg(dev, offset);480 481 write_field(&val, field, mask, shift);482 483 write_reg(dev, offset, val);484}485 486/*487 * DMA address/data block for the shadow registers488 */489struct vpe_mmr_adb {490 struct vpdma_adb_hdr out_fmt_hdr;491 u32 out_fmt_reg[1];492 u32 out_fmt_pad[3];493 struct vpdma_adb_hdr us1_hdr;494 u32 us1_regs[8];495 struct vpdma_adb_hdr us2_hdr;496 u32 us2_regs[8];497 struct vpdma_adb_hdr us3_hdr;498 u32 us3_regs[8];499 struct vpdma_adb_hdr dei_hdr;500 u32 dei_regs[8];501 struct vpdma_adb_hdr sc_hdr0;502 u32 sc_regs0[7];503 u32 sc_pad0[1];504 struct vpdma_adb_hdr sc_hdr8;505 u32 sc_regs8[6];506 u32 sc_pad8[2];507 struct vpdma_adb_hdr sc_hdr17;508 u32 sc_regs17[9];509 u32 sc_pad17[3];510 struct vpdma_adb_hdr csc_hdr;511 u32 csc_regs[6];512 u32 csc_pad[2];513};514 515#define GET_OFFSET_TOP(ctx, obj, reg) \516 ((obj)->res->start - ctx->dev->res->start + reg)517 518#define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a) \519 VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a)520/*521 * Set the headers for all of the address/data block structures.522 */523static void init_adb_hdrs(struct vpe_ctx *ctx)524{525 VPE_SET_MMR_ADB_HDR(ctx, out_fmt_hdr, out_fmt_reg, VPE_CLK_FORMAT_SELECT);526 VPE_SET_MMR_ADB_HDR(ctx, us1_hdr, us1_regs, VPE_US1_R0);527 VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0);528 VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0);529 VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE);530 VPE_SET_MMR_ADB_HDR(ctx, sc_hdr0, sc_regs0,531 GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC0));532 VPE_SET_MMR_ADB_HDR(ctx, sc_hdr8, sc_regs8,533 GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC8));534 VPE_SET_MMR_ADB_HDR(ctx, sc_hdr17, sc_regs17,535 GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC17));536 VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs,537 GET_OFFSET_TOP(ctx, ctx->dev->csc, CSC_CSC00));538};539 540/*541 * Allocate or re-allocate the motion vector DMA buffers542 * There are two buffers, one for input and one for output.543 * However, the roles are reversed after each field is processed.544 * In other words, after each field is processed, the previous545 * output (dst) MV buffer becomes the new input (src) MV buffer.546 */547static int realloc_mv_buffers(struct vpe_ctx *ctx, size_t size)548{549 struct device *dev = ctx->dev->v4l2_dev.dev;550 551 if (ctx->mv_buf_size == size)552 return 0;553 554 if (ctx->mv_buf[0])555 dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[0],556 ctx->mv_buf_dma[0]);557 558 if (ctx->mv_buf[1])559 dma_free_coherent(dev, ctx->mv_buf_size, ctx->mv_buf[1],560 ctx->mv_buf_dma[1]);561 562 if (size == 0)563 return 0;564 565 ctx->mv_buf[0] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[0],566 GFP_KERNEL);567 if (!ctx->mv_buf[0]) {568 vpe_err(ctx->dev, "failed to allocate motion vector buffer\n");569 return -ENOMEM;570 }571 572 ctx->mv_buf[1] = dma_alloc_coherent(dev, size, &ctx->mv_buf_dma[1],573 GFP_KERNEL);574 if (!ctx->mv_buf[1]) {575 vpe_err(ctx->dev, "failed to allocate motion vector buffer\n");576 dma_free_coherent(dev, size, ctx->mv_buf[0],577 ctx->mv_buf_dma[0]);578 579 return -ENOMEM;580 }581 582 ctx->mv_buf_size = size;583 ctx->src_mv_buf_selector = 0;584 585 return 0;586}587 588static void free_mv_buffers(struct vpe_ctx *ctx)589{590 realloc_mv_buffers(ctx, 0);591}592 593/*594 * While de-interlacing, we keep the two most recent input buffers595 * around. This function frees those two buffers when we have596 * finished processing the current stream.597 */598static void free_vbs(struct vpe_ctx *ctx)599{600 struct vpe_dev *dev = ctx->dev;601 unsigned long flags;602 603 if (ctx->src_vbs[2] == NULL)604 return;605 606 spin_lock_irqsave(&dev->lock, flags);607 if (ctx->src_vbs[2]) {608 v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE);609 if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2]))610 v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE);611 ctx->src_vbs[2] = NULL;612 ctx->src_vbs[1] = NULL;613 }614 spin_unlock_irqrestore(&dev->lock, flags);615}616 617/*618 * Enable or disable the VPE clocks619 */620static void vpe_set_clock_enable(struct vpe_dev *dev, bool on)621{622 u32 val = 0;623 624 if (on)625 val = VPE_DATA_PATH_CLK_ENABLE | VPE_VPEDMA_CLK_ENABLE;626 write_reg(dev, VPE_CLK_ENABLE, val);627}628 629static void vpe_top_reset(struct vpe_dev *dev)630{631 632 write_field_reg(dev, VPE_CLK_RESET, 1, VPE_DATA_PATH_CLK_RESET_MASK,633 VPE_DATA_PATH_CLK_RESET_SHIFT);634 635 usleep_range(100, 150);636 637 write_field_reg(dev, VPE_CLK_RESET, 0, VPE_DATA_PATH_CLK_RESET_MASK,638 VPE_DATA_PATH_CLK_RESET_SHIFT);639}640 641static void vpe_top_vpdma_reset(struct vpe_dev *dev)642{643 write_field_reg(dev, VPE_CLK_RESET, 1, VPE_VPDMA_CLK_RESET_MASK,644 VPE_VPDMA_CLK_RESET_SHIFT);645 646 usleep_range(100, 150);647 648 write_field_reg(dev, VPE_CLK_RESET, 0, VPE_VPDMA_CLK_RESET_MASK,649 VPE_VPDMA_CLK_RESET_SHIFT);650}651 652/*653 * Load the correct of upsampler coefficients into the shadow MMRs654 */655static void set_us_coefficients(struct vpe_ctx *ctx)656{657 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;658 struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];659 u32 *us1_reg = &mmr_adb->us1_regs[0];660 u32 *us2_reg = &mmr_adb->us2_regs[0];661 u32 *us3_reg = &mmr_adb->us3_regs[0];662 const unsigned short *cp, *end_cp;663 664 cp = &us_coeffs[0].anchor_fid0_c0;665 666 if (s_q_data->flags & Q_IS_INTERLACED) /* interlaced */667 cp += sizeof(us_coeffs[0]) / sizeof(*cp);668 669 end_cp = cp + sizeof(us_coeffs[0]) / sizeof(*cp);670 671 while (cp < end_cp) {672 write_field(us1_reg, *cp++, VPE_US_C0_MASK, VPE_US_C0_SHIFT);673 write_field(us1_reg, *cp++, VPE_US_C1_MASK, VPE_US_C1_SHIFT);674 *us2_reg++ = *us1_reg;675 *us3_reg++ = *us1_reg++;676 }677 ctx->load_mmrs = true;678}679 680/*681 * Set the upsampler config mode and the VPDMA line mode in the shadow MMRs.682 */683static void set_cfg_modes(struct vpe_ctx *ctx)684{685 struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt;686 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;687 u32 *us1_reg0 = &mmr_adb->us1_regs[0];688 u32 *us2_reg0 = &mmr_adb->us2_regs[0];689 u32 *us3_reg0 = &mmr_adb->us3_regs[0];690 int cfg_mode = 1;691 692 /*693 * Cfg Mode 0: YUV420 source, enable upsampler, DEI is de-interlacing.694 * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing.695 */696 697 if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||698 fmt->fourcc == V4L2_PIX_FMT_NV21)699 cfg_mode = 0;700 701 write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);702 write_field(us2_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);703 write_field(us3_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);704 705 ctx->load_mmrs = true;706}707 708static void set_line_modes(struct vpe_ctx *ctx)709{710 struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt;711 int line_mode = 1;712 713 if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||714 fmt->fourcc == V4L2_PIX_FMT_NV21)715 line_mode = 0; /* double lines to line buffer */716 717 /* regs for now */718 vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA1_IN);719 vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA2_IN);720 vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA3_IN);721 722 /* frame start for input luma */723 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,724 VPE_CHAN_LUMA1_IN);725 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,726 VPE_CHAN_LUMA2_IN);727 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,728 VPE_CHAN_LUMA3_IN);729 730 /* frame start for input chroma */731 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,732 VPE_CHAN_CHROMA1_IN);733 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,734 VPE_CHAN_CHROMA2_IN);735 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,736 VPE_CHAN_CHROMA3_IN);737 738 /* frame start for MV in client */739 vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE,740 VPE_CHAN_MV_IN);741}742 743/*744 * Set the shadow registers that are modified when the source745 * format changes.746 */747static void set_src_registers(struct vpe_ctx *ctx)748{749 set_us_coefficients(ctx);750}751 752/*753 * Set the shadow registers that are modified when the destination754 * format changes.755 */756static void set_dst_registers(struct vpe_ctx *ctx)757{758 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;759 struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt;760 const struct v4l2_format_info *finfo;761 u32 val = 0;762 763 finfo = v4l2_format_info(fmt->fourcc);764 if (v4l2_is_format_rgb(finfo)) {765 val |= VPE_RGB_OUT_SELECT;766 vpdma_set_bg_color(ctx->dev->vpdma,767 (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff);768 } else if (fmt->fourcc == V4L2_PIX_FMT_NV16)769 val |= VPE_COLOR_SEPARATE_422;770 771 /*772 * the source of CHR_DS and CSC is always the scaler, irrespective of773 * whether it's used or not774 */775 val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER;776 777 if (fmt->fourcc != V4L2_PIX_FMT_NV12 &&778 fmt->fourcc != V4L2_PIX_FMT_NV21)779 val |= VPE_DS_BYPASS;780 781 mmr_adb->out_fmt_reg[0] = val;782 783 ctx->load_mmrs = true;784}785 786/*787 * Set the de-interlacer shadow register values788 */789static void set_dei_regs(struct vpe_ctx *ctx)790{791 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;792 struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];793 unsigned int src_h = s_q_data->c_rect.height;794 unsigned int src_w = s_q_data->c_rect.width;795 u32 *dei_mmr0 = &mmr_adb->dei_regs[0];796 bool deinterlace = true;797 u32 val = 0;798 799 /*800 * according to TRM, we should set DEI in progressive bypass mode when801 * the input content is progressive, however, DEI is bypassed correctly802 * for both progressive and interlace content in interlace bypass mode.803 * It has been recommended not to use progressive bypass mode.804 */805 if (!(s_q_data->flags & Q_IS_INTERLACED) || !ctx->deinterlacing) {806 deinterlace = false;807 val = VPE_DEI_INTERLACE_BYPASS;808 }809 810 src_h = deinterlace ? src_h * 2 : src_h;811 812 val |= (src_h << VPE_DEI_HEIGHT_SHIFT) |813 (src_w << VPE_DEI_WIDTH_SHIFT) |814 VPE_DEI_FIELD_FLUSH;815 816 *dei_mmr0 = val;817 818 ctx->load_mmrs = true;819}820 821static void set_dei_shadow_registers(struct vpe_ctx *ctx)822{823 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;824 u32 *dei_mmr = &mmr_adb->dei_regs[0];825 const struct vpe_dei_regs *cur = &dei_regs;826 827 dei_mmr[2] = cur->mdt_spacial_freq_thr_reg;828 dei_mmr[3] = cur->edi_config_reg;829 dei_mmr[4] = cur->edi_lut_reg0;830 dei_mmr[5] = cur->edi_lut_reg1;831 dei_mmr[6] = cur->edi_lut_reg2;832 dei_mmr[7] = cur->edi_lut_reg3;833 834 ctx->load_mmrs = true;835}836 837static void config_edi_input_mode(struct vpe_ctx *ctx, int mode)838{839 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;840 u32 *edi_config_reg = &mmr_adb->dei_regs[3];841 842 if (mode & 0x2)843 write_field(edi_config_reg, 1, 1, 2); /* EDI_ENABLE_3D */844 845 if (mode & 0x3)846 write_field(edi_config_reg, 1, 1, 3); /* EDI_CHROMA_3D */847 848 write_field(edi_config_reg, mode, VPE_EDI_INP_MODE_MASK,849 VPE_EDI_INP_MODE_SHIFT);850 851 ctx->load_mmrs = true;852}853 854/*855 * Set the shadow registers whose values are modified when either the856 * source or destination format is changed.857 */858static int set_srcdst_params(struct vpe_ctx *ctx)859{860 struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];861 struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];862 struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;863 unsigned int src_w = s_q_data->c_rect.width;864 unsigned int src_h = s_q_data->c_rect.height;865 unsigned int dst_w = d_q_data->c_rect.width;866 unsigned int dst_h = d_q_data->c_rect.height;867 struct v4l2_pix_format_mplane *spix;868 size_t mv_buf_size;869 int ret;870 871 ctx->sequence = 0;872 ctx->field = V4L2_FIELD_TOP;873 spix = &s_q_data->format.fmt.pix_mp;874 875 if ((s_q_data->flags & Q_IS_INTERLACED) &&876 !(d_q_data->flags & Q_IS_INTERLACED)) {877 int bytes_per_line;878 const struct vpdma_data_format *mv =879 &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];880 881 /*882 * we make sure that the source image has a 16 byte aligned883 * stride, we need to do the same for the motion vector buffer884 * by aligning it's stride to the next 16 byte boundary. this885 * extra space will not be used by the de-interlacer, but will886 * ensure that vpdma operates correctly887 */888 bytes_per_line = ALIGN((spix->width * mv->depth) >> 3,889 VPDMA_STRIDE_ALIGN);890 mv_buf_size = bytes_per_line * spix->height;891 892 ctx->deinterlacing = true;893 src_h <<= 1;894 } else {895 ctx->deinterlacing = false;896 mv_buf_size = 0;897 }898 899 free_vbs(ctx);900 ctx->src_vbs[2] = ctx->src_vbs[1] = ctx->src_vbs[0] = NULL;901 902 ret = realloc_mv_buffers(ctx, mv_buf_size);903 if (ret)904 return ret;905 906 set_cfg_modes(ctx);907 set_dei_regs(ctx);908 909 csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0],910 &s_q_data->format, &d_q_data->format);911 912 sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w);913 sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h);914 915 sc_config_scaler(ctx->dev->sc, &mmr_adb->sc_regs0[0],916 &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0],917 src_w, src_h, dst_w, dst_h);918 919 return 0;920}921 922/*923 * mem2mem callbacks924 */925 926/*927 * job_ready() - check whether an instance is ready to be scheduled to run928 */929static int job_ready(void *priv)930{931 struct vpe_ctx *ctx = priv;932 933 /*934 * This check is needed as this might be called directly from driver935 * When called by m2m framework, this will always satisfy, but when936 * called from vpe_irq, this might fail. (src stream with zero buffers)937 */938 if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) <= 0 ||939 v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) <= 0)940 return 0;941 942 return 1;943}944 945static void job_abort(void *priv)946{947 struct vpe_ctx *ctx = priv;948 949 /* Will cancel the transaction in the next interrupt handler */950 ctx->aborting = 1;951}952 953static void vpe_dump_regs(struct vpe_dev *dev)954{955#define DUMPREG(r) vpe_dbg(dev, "%-35s %08x\n", #r, read_reg(dev, VPE_##r))956 957 vpe_dbg(dev, "VPE Registers:\n");958 959 DUMPREG(PID);960 DUMPREG(SYSCONFIG);961 DUMPREG(INT0_STATUS0_RAW);962 DUMPREG(INT0_STATUS0);963 DUMPREG(INT0_ENABLE0);964 DUMPREG(INT0_STATUS1_RAW);965 DUMPREG(INT0_STATUS1);966 DUMPREG(INT0_ENABLE1);967 DUMPREG(CLK_ENABLE);968 DUMPREG(CLK_RESET);969 DUMPREG(CLK_FORMAT_SELECT);970 DUMPREG(CLK_RANGE_MAP);971 DUMPREG(US1_R0);972 DUMPREG(US1_R1);973 DUMPREG(US1_R2);974 DUMPREG(US1_R3);975 DUMPREG(US1_R4);976 DUMPREG(US1_R5);977 DUMPREG(US1_R6);978 DUMPREG(US1_R7);979 DUMPREG(US2_R0);980 DUMPREG(US2_R1);981 DUMPREG(US2_R2);982 DUMPREG(US2_R3);983 DUMPREG(US2_R4);984 DUMPREG(US2_R5);985 DUMPREG(US2_R6);986 DUMPREG(US2_R7);987 DUMPREG(US3_R0);988 DUMPREG(US3_R1);989 DUMPREG(US3_R2);990 DUMPREG(US3_R3);991 DUMPREG(US3_R4);992 DUMPREG(US3_R5);993 DUMPREG(US3_R6);994 DUMPREG(US3_R7);995 DUMPREG(DEI_FRAME_SIZE);996 DUMPREG(MDT_BYPASS);997 DUMPREG(MDT_SF_THRESHOLD);998 DUMPREG(EDI_CONFIG);999 DUMPREG(DEI_EDI_LUT_R0);1000 DUMPREG(DEI_EDI_LUT_R1);1001 DUMPREG(DEI_EDI_LUT_R2);1002 DUMPREG(DEI_EDI_LUT_R3);1003 DUMPREG(DEI_FMD_WINDOW_R0);1004 DUMPREG(DEI_FMD_WINDOW_R1);1005 DUMPREG(DEI_FMD_CONTROL_R0);1006 DUMPREG(DEI_FMD_CONTROL_R1);1007 DUMPREG(DEI_FMD_STATUS_R0);1008 DUMPREG(DEI_FMD_STATUS_R1);1009 DUMPREG(DEI_FMD_STATUS_R2);1010#undef DUMPREG1011 1012 sc_dump_regs(dev->sc);1013 csc_dump_regs(dev->csc);1014}1015 1016static void add_out_dtd(struct vpe_ctx *ctx, int port)1017{1018 struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];1019 const struct vpe_port_data *p_data = &port_data[port];1020 struct vb2_buffer *vb = &ctx->dst_vb->vb2_buf;1021 struct vpe_fmt *fmt = q_data->fmt;1022 const struct vpdma_data_format *vpdma_fmt;1023 int mv_buf_selector = !ctx->src_mv_buf_selector;1024 struct v4l2_pix_format_mplane *pix;1025 dma_addr_t dma_addr;1026 u32 flags = 0;1027 u32 offset = 0;1028 u32 stride;1029 1030 if (port == VPE_PORT_MV_OUT) {1031 vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];1032 dma_addr = ctx->mv_buf_dma[mv_buf_selector];1033 q_data = &ctx->q_data[Q_DATA_SRC];1034 pix = &q_data->format.fmt.pix_mp;1035 stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3,1036 VPDMA_STRIDE_ALIGN);1037 } else {1038 /* to incorporate interleaved formats */1039 int plane = fmt->coplanar ? p_data->vb_part : 0;1040 1041 pix = &q_data->format.fmt.pix_mp;1042 vpdma_fmt = fmt->vpdma_fmt[plane];1043 /*1044 * If we are using a single plane buffer and1045 * we need to set a separate vpdma chroma channel.1046 */1047 if (pix->num_planes == 1 && plane) {1048 dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);1049 /* Compute required offset */1050 offset = pix->plane_fmt[0].bytesperline * pix->height;1051 } else {1052 dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);1053 /* Use address as is, no offset */1054 offset = 0;1055 }1056 if (!dma_addr) {1057 vpe_err(ctx->dev,1058 "acquiring output buffer(%d) dma_addr failed\n",1059 port);1060 return;1061 }1062 /* Apply the offset */1063 dma_addr += offset;1064 stride = pix->plane_fmt[VPE_LUMA].bytesperline;1065 }1066 1067 if (q_data->flags & Q_DATA_FRAME_1D)1068 flags |= VPDMA_DATA_FRAME_1D;1069 if (q_data->flags & Q_DATA_MODE_TILED)1070 flags |= VPDMA_DATA_MODE_TILED;1071 1072 vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1,1073 MAX_W, MAX_H);1074 1075 vpdma_add_out_dtd(&ctx->desc_list, pix->width,1076 stride, &q_data->c_rect,1077 vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1,1078 MAX_OUT_HEIGHT_REG1, p_data->channel, flags);1079}1080 1081static void add_in_dtd(struct vpe_ctx *ctx, int port)1082{1083 struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];1084 const struct vpe_port_data *p_data = &port_data[port];1085 struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf;1086 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);1087 struct vpe_fmt *fmt = q_data->fmt;1088 struct v4l2_pix_format_mplane *pix;1089 const struct vpdma_data_format *vpdma_fmt;1090 int mv_buf_selector = ctx->src_mv_buf_selector;1091 int field = vbuf->field == V4L2_FIELD_BOTTOM;1092 int frame_width, frame_height;1093 dma_addr_t dma_addr;1094 u32 flags = 0;1095 u32 offset = 0;1096 u32 stride;1097 1098 pix = &q_data->format.fmt.pix_mp;1099 if (port == VPE_PORT_MV_IN) {1100 vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];1101 dma_addr = ctx->mv_buf_dma[mv_buf_selector];1102 stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3,1103 VPDMA_STRIDE_ALIGN);1104 } else {1105 /* to incorporate interleaved formats */1106 int plane = fmt->coplanar ? p_data->vb_part : 0;1107 1108 vpdma_fmt = fmt->vpdma_fmt[plane];1109 /*1110 * If we are using a single plane buffer and1111 * we need to set a separate vpdma chroma channel.1112 */1113 if (pix->num_planes == 1 && plane) {1114 dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);1115 /* Compute required offset */1116 offset = pix->plane_fmt[0].bytesperline * pix->height;1117 } else {1118 dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);1119 /* Use address as is, no offset */1120 offset = 0;1121 }1122 if (!dma_addr) {1123 vpe_err(ctx->dev,1124 "acquiring output buffer(%d) dma_addr failed\n",1125 port);1126 return;1127 }1128 /* Apply the offset */1129 dma_addr += offset;1130 stride = pix->plane_fmt[VPE_LUMA].bytesperline;1131 1132 /*1133 * field used in VPDMA desc = 0 (top) / 1 (bottom)1134 * Use top or bottom field from same vb alternately1135 * For each de-interlacing operation, f,f-1,f-2 should be one1136 * of TBT or BTB1137 */1138 if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB ||1139 q_data->flags & Q_DATA_INTERLACED_SEQ_BT) {1140 /* Select initial value based on format */1141 if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT)1142 field = 1;1143 else1144 field = 0;1145 1146 /* Toggle for each vb_index and each operation */1147 field = (field + p_data->vb_index + ctx->sequence) % 2;1148 1149 if (field) {1150 int height = pix->height / 2;1151 int bpp;1152 1153 if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||1154 fmt->fourcc == V4L2_PIX_FMT_NV21)1155 bpp = 1;1156 else1157 bpp = vpdma_fmt->depth >> 3;1158 1159 if (plane)1160 height /= 2;1161 1162 dma_addr += pix->width * height * bpp;1163 }1164 }1165 }1166 1167 if (q_data->flags & Q_DATA_FRAME_1D)1168 flags |= VPDMA_DATA_FRAME_1D;1169 if (q_data->flags & Q_DATA_MODE_TILED)1170 flags |= VPDMA_DATA_MODE_TILED;1171 1172 frame_width = q_data->c_rect.width;1173 frame_height = q_data->c_rect.height;1174 1175 if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 ||1176 fmt->fourcc == V4L2_PIX_FMT_NV21))1177 frame_height /= 2;1178 1179 vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride,1180 &q_data->c_rect, vpdma_fmt, dma_addr,1181 p_data->channel, field, flags, frame_width,1182 frame_height, 0, 0);1183}1184 1185/*1186 * Enable the expected IRQ sources1187 */1188static void enable_irqs(struct vpe_ctx *ctx)1189{1190 write_reg(ctx->dev, VPE_INT0_ENABLE0_SET, VPE_INT0_LIST0_COMPLETE);1191 write_reg(ctx->dev, VPE_INT0_ENABLE1_SET, VPE_DEI_ERROR_INT |1192 VPE_DS1_UV_ERROR_INT);1193 1194 vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, true);1195}1196 1197static void disable_irqs(struct vpe_ctx *ctx)1198{1199 write_reg(ctx->dev, VPE_INT0_ENABLE0_CLR, 0xffffffff);1200 write_reg(ctx->dev, VPE_INT0_ENABLE1_CLR, 0xffffffff);1201 1202 vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, false);1203}1204 1205/* device_run() - prepares and starts the device1206 *1207 * This function is only called when both the source and destination1208 * buffers are in place.1209 */1210static void device_run(void *priv)1211{1212 struct vpe_ctx *ctx = priv;1213 struct sc_data *sc = ctx->dev->sc;1214 struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];1215 struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];1216 const struct v4l2_format_info *d_finfo;1217 1218 d_finfo = v4l2_format_info(d_q_data->fmt->fourcc);1219 1220 if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX &&1221 ctx->sequence % 2 == 0) {1222 /* When using SEQ_XX type buffers, each buffer has two fields1223 * each buffer has two fields (top & bottom)1224 * Removing one buffer is actually getting two fields1225 * Alternate between two operations:-1226 * Even : consume one field but DO NOT REMOVE from queue1227 * Odd : consume other field and REMOVE from queue1228 */1229 ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);1230 WARN_ON(ctx->src_vbs[0] == NULL);1231 } else {1232 ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);1233 WARN_ON(ctx->src_vbs[0] == NULL);1234 }1235 1236 ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);1237 WARN_ON(ctx->dst_vb == NULL);1238 1239 if (ctx->deinterlacing) {1240 1241 if (ctx->src_vbs[2] == NULL) {1242 ctx->src_vbs[2] = ctx->src_vbs[0];1243 WARN_ON(ctx->src_vbs[2] == NULL);1244 ctx->src_vbs[1] = ctx->src_vbs[0];1245 WARN_ON(ctx->src_vbs[1] == NULL);1246 }1247 1248 /*1249 * we have output the first 2 frames through line average, we1250 * now switch to EDI de-interlacer1251 */1252 if (ctx->sequence == 2)1253 config_edi_input_mode(ctx, 0x3); /* EDI (Y + UV) */1254 }1255 1256 /* config descriptors */1257 if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) {1258 vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb);1259 vpdma_add_cfd_adb(&ctx->desc_list, CFD_MMR_CLIENT, &ctx->mmr_adb);1260 1261 set_line_modes(ctx);1262 1263 ctx->dev->loaded_mmrs = ctx->mmr_adb.dma_addr;1264 ctx->load_mmrs = false;1265 }1266 1267 if (sc->loaded_coeff_h != ctx->sc_coeff_h.dma_addr ||1268 sc->load_coeff_h) {1269 vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_h);1270 vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT,1271 &ctx->sc_coeff_h, 0);1272 1273 sc->loaded_coeff_h = ctx->sc_coeff_h.dma_addr;1274 sc->load_coeff_h = false;1275 }1276 1277 if (sc->loaded_coeff_v != ctx->sc_coeff_v.dma_addr ||1278 sc->load_coeff_v) {1279 vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_v);1280 vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT,1281 &ctx->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4);1282 1283 sc->loaded_coeff_v = ctx->sc_coeff_v.dma_addr;1284 sc->load_coeff_v = false;1285 }1286 1287 /* output data descriptors */1288 if (ctx->deinterlacing)1289 add_out_dtd(ctx, VPE_PORT_MV_OUT);1290 1291 if (v4l2_is_format_rgb(d_finfo)) {1292 add_out_dtd(ctx, VPE_PORT_RGB_OUT);1293 } else {1294 add_out_dtd(ctx, VPE_PORT_LUMA_OUT);1295 if (d_q_data->fmt->coplanar)1296 add_out_dtd(ctx, VPE_PORT_CHROMA_OUT);1297 }1298 1299 /* input data descriptors */1300 if (ctx->deinterlacing) {1301 add_in_dtd(ctx, VPE_PORT_LUMA3_IN);1302 add_in_dtd(ctx, VPE_PORT_CHROMA3_IN);1303 1304 add_in_dtd(ctx, VPE_PORT_LUMA2_IN);1305 add_in_dtd(ctx, VPE_PORT_CHROMA2_IN);1306 }1307 1308 add_in_dtd(ctx, VPE_PORT_LUMA1_IN);1309 add_in_dtd(ctx, VPE_PORT_CHROMA1_IN);1310 1311 if (ctx->deinterlacing)1312 add_in_dtd(ctx, VPE_PORT_MV_IN);1313 1314 /* sync on channel control descriptors for input ports */1315 vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA1_IN);1316 vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA1_IN);1317 1318 if (ctx->deinterlacing) {1319 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1320 VPE_CHAN_LUMA2_IN);1321 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1322 VPE_CHAN_CHROMA2_IN);1323 1324 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1325 VPE_CHAN_LUMA3_IN);1326 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1327 VPE_CHAN_CHROMA3_IN);1328 1329 vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_IN);1330 }1331 1332 /* sync on channel control descriptors for output ports */1333 if (v4l2_is_format_rgb(d_finfo)) {1334 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1335 VPE_CHAN_RGB_OUT);1336 } else {1337 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1338 VPE_CHAN_LUMA_OUT);1339 if (d_q_data->fmt->coplanar)1340 vpdma_add_sync_on_channel_ctd(&ctx->desc_list,1341 VPE_CHAN_CHROMA_OUT);1342 }1343 1344 if (ctx->deinterlacing)1345 vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT);1346 1347 enable_irqs(ctx);1348 1349 vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->desc_list.buf);1350 vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list, 0);1351}1352 1353static void dei_error(struct vpe_ctx *ctx)1354{1355 dev_warn(ctx->dev->v4l2_dev.dev,1356 "received DEI error interrupt\n");1357}1358 1359static void ds1_uv_error(struct vpe_ctx *ctx)1360{1361 dev_warn(ctx->dev->v4l2_dev.dev,1362 "received downsampler error interrupt\n");1363}1364 1365static irqreturn_t vpe_irq(int irq_vpe, void *data)1366{1367 struct vpe_dev *dev = (struct vpe_dev *)data;1368 struct vpe_ctx *ctx;1369 struct vpe_q_data *d_q_data;1370 struct vb2_v4l2_buffer *s_vb, *d_vb;1371 unsigned long flags;1372 u32 irqst0, irqst1;1373 bool list_complete = false;1374 1375 irqst0 = read_reg(dev, VPE_INT0_STATUS0);1376 if (irqst0) {1377 write_reg(dev, VPE_INT0_STATUS0_CLR, irqst0);1378 vpe_dbg(dev, "INT0_STATUS0 = 0x%08x\n", irqst0);1379 }1380 1381 irqst1 = read_reg(dev, VPE_INT0_STATUS1);1382 if (irqst1) {1383 write_reg(dev, VPE_INT0_STATUS1_CLR, irqst1);1384 vpe_dbg(dev, "INT0_STATUS1 = 0x%08x\n", irqst1);1385 }1386 1387 ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);1388 if (!ctx) {1389 vpe_err(dev, "instance released before end of transaction\n");1390 goto handled;1391 }1392 1393 if (irqst1) {1394 if (irqst1 & VPE_DEI_ERROR_INT) {1395 irqst1 &= ~VPE_DEI_ERROR_INT;1396 dei_error(ctx);1397 }1398 if (irqst1 & VPE_DS1_UV_ERROR_INT) {1399 irqst1 &= ~VPE_DS1_UV_ERROR_INT;1400 ds1_uv_error(ctx);1401 }1402 }1403 1404 if (irqst0) {1405 if (irqst0 & VPE_INT0_LIST0_COMPLETE)1406 vpdma_clear_list_stat(ctx->dev->vpdma, 0, 0);1407 1408 irqst0 &= ~(VPE_INT0_LIST0_COMPLETE);1409 list_complete = true;1410 }1411 1412 if (irqst0 | irqst1) {1413 dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n",1414 irqst0, irqst1);1415 }1416 1417 /*1418 * Setup next operation only when list complete IRQ occurs1419 * otherwise, skip the following code1420 */1421 if (!list_complete)1422 goto handled;1423 1424 disable_irqs(ctx);1425 1426 vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);1427 vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);1428 vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);1429 vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);1430 1431 vpdma_reset_desc_list(&ctx->desc_list);1432 1433 /* the previous dst mv buffer becomes the next src mv buffer */1434 ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector;1435 1436 s_vb = ctx->src_vbs[0];1437 d_vb = ctx->dst_vb;1438 1439 d_vb->flags = s_vb->flags;1440 d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp;1441 1442 if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE)1443 d_vb->timecode = s_vb->timecode;1444 1445 d_vb->sequence = ctx->sequence;1446 s_vb->sequence = ctx->sequence;1447 1448 d_q_data = &ctx->q_data[Q_DATA_DST];1449 if (d_q_data->flags & Q_IS_INTERLACED) {1450 d_vb->field = ctx->field;1451 if (ctx->field == V4L2_FIELD_BOTTOM) {1452 ctx->sequence++;1453 ctx->field = V4L2_FIELD_TOP;1454 } else {1455 WARN_ON(ctx->field != V4L2_FIELD_TOP);1456 ctx->field = V4L2_FIELD_BOTTOM;1457 }1458 } else {1459 d_vb->field = V4L2_FIELD_NONE;1460 ctx->sequence++;1461 }1462 1463 if (ctx->deinterlacing) {1464 /*1465 * Allow source buffer to be dequeued only if it won't be used1466 * in the next iteration. All vbs are initialized to first1467 * buffer and we are shifting buffers every iteration, for the1468 * first two iterations, no buffer will be dequeued.1469 * This ensures that driver will keep (n-2)th (n-1)th and (n)th1470 * field when deinterlacing is enabled1471 */1472 if (ctx->src_vbs[2] != ctx->src_vbs[1])1473 s_vb = ctx->src_vbs[2];1474 else1475 s_vb = NULL;1476 }1477 1478 spin_lock_irqsave(&dev->lock, flags);1479 1480 if (s_vb)1481 v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE);1482 1483 v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_DONE);1484 1485 spin_unlock_irqrestore(&dev->lock, flags);1486 1487 if (ctx->deinterlacing) {1488 ctx->src_vbs[2] = ctx->src_vbs[1];1489 ctx->src_vbs[1] = ctx->src_vbs[0];1490 }1491 1492 /*1493 * Since the vb2_buf_done has already been called fir therse1494 * buffer we can now NULL them out so that we won't try1495 * to clean out stray pointer later on.1496 */1497 ctx->src_vbs[0] = NULL;1498 ctx->dst_vb = NULL;1499 1500 if (ctx->aborting)1501 goto finished;1502 1503 ctx->bufs_completed++;1504 if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) {1505 device_run(ctx);1506 goto handled;1507 }1508 1509finished:1510 vpe_dbg(ctx->dev, "finishing transaction\n");1511 ctx->bufs_completed = 0;1512 v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);1513handled:1514 return IRQ_HANDLED;1515}1516 1517/*1518 * video ioctls1519 */1520static int vpe_querycap(struct file *file, void *priv,1521 struct v4l2_capability *cap)1522{1523 strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver));1524 strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card));1525 snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",1526 VPE_MODULE_NAME);1527 return 0;1528}1529 1530static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type)1531{1532 int i, index;1533 struct vpe_fmt *fmt = NULL;1534 1535 index = 0;1536 for (i = 0; i < ARRAY_SIZE(vpe_formats); ++i) {1537 if (vpe_formats[i].types & type) {1538 if (index == f->index) {1539 fmt = &vpe_formats[i];1540 break;1541 }1542 index++;1543 }1544 }1545 1546 if (!fmt)1547 return -EINVAL;1548 1549 f->pixelformat = fmt->fourcc;1550 return 0;1551}1552 1553static int vpe_enum_fmt(struct file *file, void *priv,1554 struct v4l2_fmtdesc *f)1555{1556 if (V4L2_TYPE_IS_OUTPUT(f->type))1557 return __enum_fmt(f, VPE_FMT_TYPE_OUTPUT);1558 1559 return __enum_fmt(f, VPE_FMT_TYPE_CAPTURE);1560}1561 1562static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f)1563{1564 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;1565 struct vpe_ctx *ctx = file->private_data;1566 struct vb2_queue *vq;1567 struct vpe_q_data *q_data;1568 1569 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);1570 if (!vq)1571 return -EINVAL;1572 1573 q_data = get_q_data(ctx, f->type);1574 if (!q_data)1575 return -EINVAL;1576 1577 *f = q_data->format;1578 1579 if (V4L2_TYPE_IS_CAPTURE(f->type)) {1580 struct vpe_q_data *s_q_data;1581 struct v4l2_pix_format_mplane *spix;1582 1583 /* get colorimetry from the source queue */1584 s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);1585 spix = &s_q_data->format.fmt.pix_mp;1586 1587 pix->colorspace = spix->colorspace;1588 pix->xfer_func = spix->xfer_func;1589 pix->ycbcr_enc = spix->ycbcr_enc;1590 pix->quantization = spix->quantization;1591 }1592 1593 return 0;1594}1595 1596static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,1597 struct vpe_fmt *fmt, int type)1598{1599 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;1600 struct v4l2_plane_pix_format *plane_fmt;1601 unsigned int w_align;1602 int i, depth, depth_bytes, height;1603 unsigned int stride = 0;1604 const struct v4l2_format_info *finfo;1605 1606 if (!fmt || !(fmt->types & type)) {1607 vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n",1608 pix->pixelformat);1609 fmt = __find_format(V4L2_PIX_FMT_YUYV);1610 }1611 1612 if (pix->field != V4L2_FIELD_NONE &&1613 pix->field != V4L2_FIELD_ALTERNATE &&1614 pix->field != V4L2_FIELD_SEQ_TB &&1615 pix->field != V4L2_FIELD_SEQ_BT)1616 pix->field = V4L2_FIELD_NONE;1617 1618 depth = fmt->vpdma_fmt[VPE_LUMA]->depth;1619 1620 /*1621 * the line stride should 16 byte aligned for VPDMA to work, based on1622 * the bytes per pixel, figure out how much the width should be aligned1623 * to make sure line stride is 16 byte aligned1624 */1625 depth_bytes = depth >> 3;1626 1627 if (depth_bytes == 3) {1628 /*1629 * if bpp is 3(as in some RGB formats), the pixel width doesn't1630 * really help in ensuring line stride is 16 byte aligned1631 */1632 w_align = 4;1633 } else {1634 /*1635 * for the remainder bpp(4, 2 and 1), the pixel width alignment1636 * can ensure a line stride alignment of 16 bytes. For example,1637 * if bpp is 2, then the line stride can be 16 byte aligned if1638 * the width is 8 byte aligned1639 */1640 1641 /*1642 * HACK: using order_base_2() here causes lots of asm output1643 * errors with smatch, on i386:1644 * ./arch/x86/include/asm/bitops.h:457:22:1645 * warning: asm output is not an lvalue1646 * Perhaps some gcc optimization is doing the wrong thing1647 * there.1648 * Let's get rid of them by doing the calculus on two steps1649 */1650 w_align = roundup_pow_of_two(VPDMA_DESC_ALIGN / depth_bytes);1651 w_align = ilog2(w_align);1652 }1653 1654 v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align,1655 &pix->height, MIN_H, MAX_H, H_ALIGN,1656 S_ALIGN);1657 1658 if (!pix->num_planes || pix->num_planes > 2)1659 pix->num_planes = fmt->coplanar ? 2 : 1;1660 else if (pix->num_planes > 1 && !fmt->coplanar)1661 pix->num_planes = 1;1662 1663 pix->pixelformat = fmt->fourcc;1664 finfo = v4l2_format_info(fmt->fourcc);1665 1666 /*1667 * For the actual image parameters, we need to consider the field1668 * height of the image for SEQ_XX buffers.1669 */1670 if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT)1671 height = pix->height / 2;1672 else1673 height = pix->height;1674 1675 if (!pix->colorspace) {1676 if (v4l2_is_format_rgb(finfo)) {1677 pix->colorspace = V4L2_COLORSPACE_SRGB;1678 } else {1679 if (height > 1280) /* HD */1680 pix->colorspace = V4L2_COLORSPACE_REC709;1681 else /* SD */1682 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;1683 }1684 }1685 1686 for (i = 0; i < pix->num_planes; i++) {1687 plane_fmt = &pix->plane_fmt[i];1688 depth = fmt->vpdma_fmt[i]->depth;1689 1690 stride = (pix->width * fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;1691 if (stride > plane_fmt->bytesperline)1692 plane_fmt->bytesperline = stride;1693 1694 plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline,1695 stride,1696 VPDMA_MAX_STRIDE);1697 1698 plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline,1699 VPDMA_STRIDE_ALIGN);1700 1701 if (i == VPE_LUMA) {1702 plane_fmt->sizeimage = pix->height *1703 plane_fmt->bytesperline;1704 1705 if (pix->num_planes == 1 && fmt->coplanar)1706 plane_fmt->sizeimage += pix->height *1707 plane_fmt->bytesperline *1708 fmt->vpdma_fmt[VPE_CHROMA]->depth >> 3;1709 1710 } else { /* i == VIP_CHROMA */1711 plane_fmt->sizeimage = (pix->height *1712 plane_fmt->bytesperline *1713 depth) >> 3;1714 }1715 }1716 1717 return 0;1718}1719 1720static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f)1721{1722 struct vpe_ctx *ctx = file->private_data;1723 struct vpe_fmt *fmt = find_format(f);1724 1725 if (V4L2_TYPE_IS_OUTPUT(f->type))1726 return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_OUTPUT);1727 else1728 return __vpe_try_fmt(ctx, f, fmt, VPE_FMT_TYPE_CAPTURE);1729}1730 1731static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)1732{1733 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;1734 struct v4l2_pix_format_mplane *qpix;1735 struct vpe_q_data *q_data;1736 struct vb2_queue *vq;1737 1738 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);1739 if (!vq)1740 return -EINVAL;1741 1742 if (vb2_is_busy(vq)) {1743 vpe_err(ctx->dev, "queue busy\n");1744 return -EBUSY;1745 }1746 1747 q_data = get_q_data(ctx, f->type);1748 if (!q_data)1749 return -EINVAL;1750 1751 qpix = &q_data->format.fmt.pix_mp;1752 q_data->fmt = find_format(f);1753 q_data->format = *f;1754 1755 q_data->c_rect.left = 0;1756 q_data->c_rect.top = 0;1757 q_data->c_rect.width = pix->width;1758 q_data->c_rect.height = pix->height;1759 1760 if (qpix->field == V4L2_FIELD_ALTERNATE)1761 q_data->flags |= Q_DATA_INTERLACED_ALTERNATE;1762 else if (qpix->field == V4L2_FIELD_SEQ_TB)1763 q_data->flags |= Q_DATA_INTERLACED_SEQ_TB;1764 else if (qpix->field == V4L2_FIELD_SEQ_BT)1765 q_data->flags |= Q_DATA_INTERLACED_SEQ_BT;1766 else1767 q_data->flags &= ~Q_IS_INTERLACED;1768 1769 /* the crop height is halved for the case of SEQ_XX buffers */1770 if (q_data->flags & Q_IS_SEQ_XX)1771 q_data->c_rect.height /= 2;1772 1773 vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d",1774 f->type, pix->width, pix->height, pix->pixelformat,1775 pix->plane_fmt[0].bytesperline);1776 if (pix->num_planes == 2)1777 vpe_dbg(ctx->dev, " bpl_uv %d\n",1778 pix->plane_fmt[1].bytesperline);1779 1780 return 0;1781}1782 1783static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)1784{1785 int ret;1786 struct vpe_ctx *ctx = file->private_data;1787 1788 ret = vpe_try_fmt(file, priv, f);1789 if (ret)1790 return ret;1791 1792 ret = __vpe_s_fmt(ctx, f);1793 if (ret)1794 return ret;1795 1796 if (V4L2_TYPE_IS_OUTPUT(f->type))1797 set_src_registers(ctx);1798 else1799 set_dst_registers(ctx);1800 1801 return set_srcdst_params(ctx);1802}1803 1804static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)1805{1806 struct vpe_q_data *q_data;1807 struct v4l2_pix_format_mplane *pix;1808 int height;1809 1810 if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&1811 (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))1812 return -EINVAL;1813 1814 q_data = get_q_data(ctx, s->type);1815 if (!q_data)1816 return -EINVAL;1817 1818 pix = &q_data->format.fmt.pix_mp;1819 1820 switch (s->target) {1821 case V4L2_SEL_TGT_COMPOSE:1822 /*1823 * COMPOSE target is only valid for capture buffer type, return1824 * error for output buffer type1825 */1826 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)1827 return -EINVAL;1828 break;1829 case V4L2_SEL_TGT_CROP:1830 /*1831 * CROP target is only valid for output buffer type, return1832 * error for capture buffer type1833 */1834 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1835 return -EINVAL;1836 break;1837 /*1838 * bound and default crop/compose targets are invalid targets to1839 * try/set1840 */1841 default:1842 return -EINVAL;1843 }1844 1845 /*1846 * For SEQ_XX buffers, crop height should be less than the height of1847 * the field height, not the buffer height1848 */1849 if (q_data->flags & Q_IS_SEQ_XX)1850 height = pix->height / 2;1851 else1852 height = pix->height;1853 1854 if (s->r.top < 0 || s->r.left < 0) {1855 vpe_err(ctx->dev, "negative values for top and left\n");1856 s->r.top = s->r.left = 0;1857 }1858 1859 v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1,1860 &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN);1861 1862 /* adjust left/top if cropping rectangle is out of bounds */1863 if (s->r.left + s->r.width > pix->width)1864 s->r.left = pix->width - s->r.width;1865 if (s->r.top + s->r.height > pix->height)1866 s->r.top = pix->height - s->r.height;1867 1868 return 0;1869}1870 1871static int vpe_g_selection(struct file *file, void *fh,1872 struct v4l2_selection *s)1873{1874 struct vpe_ctx *ctx = file->private_data;1875 struct vpe_q_data *q_data;1876 struct v4l2_pix_format_mplane *pix;1877 bool use_c_rect = false;1878 1879 if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&1880 (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))1881 return -EINVAL;1882 1883 q_data = get_q_data(ctx, s->type);1884 if (!q_data)1885 return -EINVAL;1886 1887 pix = &q_data->format.fmt.pix_mp;1888 1889 switch (s->target) {1890 case V4L2_SEL_TGT_COMPOSE_DEFAULT:1891 case V4L2_SEL_TGT_COMPOSE_BOUNDS:1892 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)1893 return -EINVAL;1894 break;1895 case V4L2_SEL_TGT_CROP_BOUNDS:1896 case V4L2_SEL_TGT_CROP_DEFAULT:1897 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1898 return -EINVAL;1899 break;1900 case V4L2_SEL_TGT_COMPOSE:1901 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)1902 return -EINVAL;1903 use_c_rect = true;1904 break;1905 case V4L2_SEL_TGT_CROP:1906 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)1907 return -EINVAL;1908 use_c_rect = true;1909 break;1910 default:1911 return -EINVAL;1912 }1913 1914 if (use_c_rect) {1915 /*1916 * for CROP/COMPOSE target type, return c_rect params from the1917 * respective buffer type1918 */1919 s->r = q_data->c_rect;1920 } else {1921 /*1922 * for DEFAULT/BOUNDS target type, return width and height from1923 * S_FMT of the respective buffer type1924 */1925 s->r.left = 0;1926 s->r.top = 0;1927 s->r.width = pix->width;1928 s->r.height = pix->height;1929 }1930 1931 return 0;1932}1933 1934 1935static int vpe_s_selection(struct file *file, void *fh,1936 struct v4l2_selection *s)1937{1938 struct vpe_ctx *ctx = file->private_data;1939 struct vpe_q_data *q_data;1940 struct v4l2_selection sel = *s;1941 int ret;1942 1943 ret = __vpe_try_selection(ctx, &sel);1944 if (ret)1945 return ret;1946 1947 q_data = get_q_data(ctx, sel.type);1948 if (!q_data)1949 return -EINVAL;1950 1951 if ((q_data->c_rect.left == sel.r.left) &&1952 (q_data->c_rect.top == sel.r.top) &&1953 (q_data->c_rect.width == sel.r.width) &&1954 (q_data->c_rect.height == sel.r.height)) {1955 vpe_dbg(ctx->dev,1956 "requested crop/compose values are already set\n");1957 return 0;1958 }1959 1960 q_data->c_rect = sel.r;1961 1962 return set_srcdst_params(ctx);1963}1964 1965/*1966 * defines number of buffers/frames a context can process with VPE before1967 * switching to a different context. default value is 1 buffer per context1968 */1969#define V4L2_CID_VPE_BUFS_PER_JOB (V4L2_CID_USER_TI_VPE_BASE + 0)1970 1971static int vpe_s_ctrl(struct v4l2_ctrl *ctrl)1972{1973 struct vpe_ctx *ctx =1974 container_of(ctrl->handler, struct vpe_ctx, hdl);1975 1976 switch (ctrl->id) {1977 case V4L2_CID_VPE_BUFS_PER_JOB:1978 ctx->bufs_per_job = ctrl->val;1979 break;1980 1981 default:1982 vpe_err(ctx->dev, "Invalid control\n");1983 return -EINVAL;1984 }1985 1986 return 0;1987}1988 1989static const struct v4l2_ctrl_ops vpe_ctrl_ops = {1990 .s_ctrl = vpe_s_ctrl,1991};1992 1993static const struct v4l2_ioctl_ops vpe_ioctl_ops = {1994 .vidioc_querycap = vpe_querycap,1995 1996 .vidioc_enum_fmt_vid_cap = vpe_enum_fmt,1997 .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt,1998 .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt,1999 .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt,2000 2001 .vidioc_enum_fmt_vid_out = vpe_enum_fmt,2002 .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt,2003 .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt,2004 .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt,2005 2006 .vidioc_g_selection = vpe_g_selection,2007 .vidioc_s_selection = vpe_s_selection,2008 2009 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,2010 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,2011 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,2012 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,2013 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,2014 .vidioc_streamon = v4l2_m2m_ioctl_streamon,2015 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,2016 2017 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,2018 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,2019};2020 2021/*2022 * Queue operations2023 */2024static int vpe_queue_setup(struct vb2_queue *vq,2025 unsigned int *nbuffers, unsigned int *nplanes,2026 unsigned int sizes[], struct device *alloc_devs[])2027{2028 int i;2029 struct vpe_ctx *ctx = vb2_get_drv_priv(vq);2030 struct vpe_q_data *q_data;2031 struct v4l2_pix_format_mplane *pix;2032 2033 q_data = get_q_data(ctx, vq->type);2034 if (!q_data)2035 return -EINVAL;2036 2037 pix = &q_data->format.fmt.pix_mp;2038 *nplanes = pix->num_planes;2039 2040 for (i = 0; i < *nplanes; i++)2041 sizes[i] = pix->plane_fmt[i].sizeimage;2042 2043 vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers,2044 sizes[VPE_LUMA]);2045 if (*nplanes == 2)2046 vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]);2047 2048 return 0;2049}2050 2051static int vpe_buf_prepare(struct vb2_buffer *vb)2052{2053 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);2054 struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);2055 struct vpe_q_data *q_data;2056 struct v4l2_pix_format_mplane *pix;2057 int i;2058 2059 vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type);2060 2061 q_data = get_q_data(ctx, vb->vb2_queue->type);2062 if (!q_data)2063 return -EINVAL;2064 2065 pix = &q_data->format.fmt.pix_mp;2066 2067 if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {2068 if (!(q_data->flags & Q_IS_INTERLACED)) {2069 vbuf->field = V4L2_FIELD_NONE;2070 } else {2071 if (vbuf->field != V4L2_FIELD_TOP &&2072 vbuf->field != V4L2_FIELD_BOTTOM &&2073 vbuf->field != V4L2_FIELD_SEQ_TB &&2074 vbuf->field != V4L2_FIELD_SEQ_BT)2075 return -EINVAL;2076 }2077 }2078 2079 for (i = 0; i < pix->num_planes; i++) {2080 if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) {2081 vpe_err(ctx->dev,2082 "data will not fit into plane (%lu < %lu)\n",2083 vb2_plane_size(vb, i),2084 (long)pix->plane_fmt[i].sizeimage);2085 return -EINVAL;2086 }2087 }2088 2089 for (i = 0; i < pix->num_planes; i++)2090 vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage);2091 2092 return 0;2093}2094 2095static void vpe_buf_queue(struct vb2_buffer *vb)2096{2097 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);2098 struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);2099 2100 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);2101}2102 2103static int check_srcdst_sizes(struct vpe_ctx *ctx)2104{2105 struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];2106 struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];2107 unsigned int src_w = s_q_data->c_rect.width;2108 unsigned int src_h = s_q_data->c_rect.height;2109 unsigned int dst_w = d_q_data->c_rect.width;2110 unsigned int dst_h = d_q_data->c_rect.height;2111 2112 if (src_w == dst_w && src_h == dst_h)2113 return 0;2114 2115 if (src_h <= SC_MAX_PIXEL_HEIGHT &&2116 src_w <= SC_MAX_PIXEL_WIDTH &&2117 dst_h <= SC_MAX_PIXEL_HEIGHT &&2118 dst_w <= SC_MAX_PIXEL_WIDTH)2119 return 0;2120 2121 return -1;2122}2123 2124static void vpe_return_all_buffers(struct vpe_ctx *ctx, struct vb2_queue *q,2125 enum vb2_buffer_state state)2126{2127 struct vb2_v4l2_buffer *vb;2128 unsigned long flags;2129 2130 for (;;) {2131 if (V4L2_TYPE_IS_OUTPUT(q->type))2132 vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);2133 else2134 vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);2135 if (!vb)2136 break;2137 spin_lock_irqsave(&ctx->dev->lock, flags);2138 v4l2_m2m_buf_done(vb, state);2139 spin_unlock_irqrestore(&ctx->dev->lock, flags);2140 }2141 2142 /*2143 * Cleanup the in-transit vb2 buffers that have been2144 * removed from their respective queue already but for2145 * which procecessing has not been completed yet.2146 */2147 if (V4L2_TYPE_IS_OUTPUT(q->type)) {2148 spin_lock_irqsave(&ctx->dev->lock, flags);2149 2150 if (ctx->src_vbs[2])2151 v4l2_m2m_buf_done(ctx->src_vbs[2], state);2152 2153 if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2]))2154 v4l2_m2m_buf_done(ctx->src_vbs[1], state);2155 2156 if (ctx->src_vbs[0] &&2157 (ctx->src_vbs[0] != ctx->src_vbs[1]) &&2158 (ctx->src_vbs[0] != ctx->src_vbs[2]))2159 v4l2_m2m_buf_done(ctx->src_vbs[0], state);2160 2161 ctx->src_vbs[2] = NULL;2162 ctx->src_vbs[1] = NULL;2163 ctx->src_vbs[0] = NULL;2164 2165 spin_unlock_irqrestore(&ctx->dev->lock, flags);2166 } else {2167 if (ctx->dst_vb) {2168 spin_lock_irqsave(&ctx->dev->lock, flags);2169 2170 v4l2_m2m_buf_done(ctx->dst_vb, state);2171 ctx->dst_vb = NULL;2172 spin_unlock_irqrestore(&ctx->dev->lock, flags);2173 }2174 }2175}2176 2177static int vpe_start_streaming(struct vb2_queue *q, unsigned int count)2178{2179 struct vpe_ctx *ctx = vb2_get_drv_priv(q);2180 2181 /* Check any of the size exceed maximum scaling sizes */2182 if (check_srcdst_sizes(ctx)) {2183 vpe_err(ctx->dev,2184 "Conversion setup failed, check source and destination parameters\n"2185 );2186 vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_QUEUED);2187 return -EINVAL;2188 }2189 2190 if (ctx->deinterlacing)2191 config_edi_input_mode(ctx, 0x0);2192 2193 if (ctx->sequence != 0)2194 set_srcdst_params(ctx);2195 2196 return 0;2197}2198 2199static void vpe_stop_streaming(struct vb2_queue *q)2200{2201 struct vpe_ctx *ctx = vb2_get_drv_priv(q);2202 2203 vpe_dump_regs(ctx->dev);2204 vpdma_dump_regs(ctx->dev->vpdma);2205 2206 vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_ERROR);2207}2208 2209static const struct vb2_ops vpe_qops = {2210 .queue_setup = vpe_queue_setup,2211 .buf_prepare = vpe_buf_prepare,2212 .buf_queue = vpe_buf_queue,2213 .wait_prepare = vb2_ops_wait_prepare,2214 .wait_finish = vb2_ops_wait_finish,2215 .start_streaming = vpe_start_streaming,2216 .stop_streaming = vpe_stop_streaming,2217};2218 2219static int queue_init(void *priv, struct vb2_queue *src_vq,2220 struct vb2_queue *dst_vq)2221{2222 struct vpe_ctx *ctx = priv;2223 struct vpe_dev *dev = ctx->dev;2224 int ret;2225 2226 memset(src_vq, 0, sizeof(*src_vq));2227 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;2228 src_vq->io_modes = VB2_MMAP | VB2_DMABUF;2229 src_vq->drv_priv = ctx;2230 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);2231 src_vq->ops = &vpe_qops;2232 src_vq->mem_ops = &vb2_dma_contig_memops;2233 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;2234 src_vq->lock = &dev->dev_mutex;2235 src_vq->dev = dev->v4l2_dev.dev;2236 2237 ret = vb2_queue_init(src_vq);2238 if (ret)2239 return ret;2240 2241 memset(dst_vq, 0, sizeof(*dst_vq));2242 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;2243 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;2244 dst_vq->drv_priv = ctx;2245 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);2246 dst_vq->ops = &vpe_qops;2247 dst_vq->mem_ops = &vb2_dma_contig_memops;2248 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;2249 dst_vq->lock = &dev->dev_mutex;2250 dst_vq->dev = dev->v4l2_dev.dev;2251 2252 return vb2_queue_init(dst_vq);2253}2254 2255static const struct v4l2_ctrl_config vpe_bufs_per_job = {2256 .ops = &vpe_ctrl_ops,2257 .id = V4L2_CID_VPE_BUFS_PER_JOB,2258 .name = "Buffers Per Transaction",2259 .type = V4L2_CTRL_TYPE_INTEGER,2260 .def = VPE_DEF_BUFS_PER_JOB,2261 .min = 1,2262 .max = VIDEO_MAX_FRAME,2263 .step = 1,2264};2265 2266/*2267 * File operations2268 */2269static int vpe_open(struct file *file)2270{2271 struct vpe_dev *dev = video_drvdata(file);2272 struct vpe_q_data *s_q_data;2273 struct v4l2_ctrl_handler *hdl;2274 struct vpe_ctx *ctx;2275 struct v4l2_pix_format_mplane *pix;2276 int ret;2277 2278 vpe_dbg(dev, "vpe_open\n");2279 2280 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);2281 if (!ctx)2282 return -ENOMEM;2283 2284 ctx->dev = dev;2285 2286 if (mutex_lock_interruptible(&dev->dev_mutex)) {2287 ret = -ERESTARTSYS;2288 goto free_ctx;2289 }2290 2291 ret = vpdma_create_desc_list(&ctx->desc_list, VPE_DESC_LIST_SIZE,2292 VPDMA_LIST_TYPE_NORMAL);2293 if (ret != 0)2294 goto unlock;2295 2296 ret = vpdma_alloc_desc_buf(&ctx->mmr_adb, sizeof(struct vpe_mmr_adb));2297 if (ret != 0)2298 goto free_desc_list;2299 2300 ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_h, SC_COEF_SRAM_SIZE);2301 if (ret != 0)2302 goto free_mmr_adb;2303 2304 ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_v, SC_COEF_SRAM_SIZE);2305 if (ret != 0)2306 goto free_sc_h;2307 2308 init_adb_hdrs(ctx);2309 2310 v4l2_fh_init(&ctx->fh, video_devdata(file));2311 file->private_data = ctx;2312 2313 hdl = &ctx->hdl;2314 v4l2_ctrl_handler_init(hdl, 1);2315 v4l2_ctrl_new_custom(hdl, &vpe_bufs_per_job, NULL);2316 if (hdl->error) {2317 ret = hdl->error;2318 goto exit_fh;2319 }2320 ctx->fh.ctrl_handler = hdl;2321 v4l2_ctrl_handler_setup(hdl);2322 2323 s_q_data = &ctx->q_data[Q_DATA_SRC];2324 pix = &s_q_data->format.fmt.pix_mp;2325 s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV);2326 pix->pixelformat = s_q_data->fmt->fourcc;2327 s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;2328 pix->width = 1920;2329 pix->height = 1080;2330 pix->num_planes = 1;2331 pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width *2332 s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;2333 pix->plane_fmt[VPE_LUMA].sizeimage =2334 pix->plane_fmt[VPE_LUMA].bytesperline *2335 pix->height;2336 pix->colorspace = V4L2_COLORSPACE_REC709;2337 pix->xfer_func = V4L2_XFER_FUNC_DEFAULT;2338 pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;2339 pix->quantization = V4L2_QUANTIZATION_DEFAULT;2340 pix->field = V4L2_FIELD_NONE;2341 s_q_data->c_rect.left = 0;2342 s_q_data->c_rect.top = 0;2343 s_q_data->c_rect.width = pix->width;2344 s_q_data->c_rect.height = pix->height;2345 s_q_data->flags = 0;2346 2347 ctx->q_data[Q_DATA_DST] = *s_q_data;2348 ctx->q_data[Q_DATA_DST].format.type =2349 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;2350 2351 set_dei_shadow_registers(ctx);2352 set_src_registers(ctx);2353 set_dst_registers(ctx);2354 ret = set_srcdst_params(ctx);2355 if (ret)2356 goto exit_fh;2357 2358 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);2359 2360 if (IS_ERR(ctx->fh.m2m_ctx)) {2361 ret = PTR_ERR(ctx->fh.m2m_ctx);2362 goto exit_fh;2363 }2364 2365 v4l2_fh_add(&ctx->fh);2366 2367 /*2368 * for now, just report the creation of the first instance, we can later2369 * optimize the driver to enable or disable clocks when the first2370 * instance is created or the last instance released2371 */2372 if (atomic_inc_return(&dev->num_instances) == 1)2373 vpe_dbg(dev, "first instance created\n");2374 2375 ctx->bufs_per_job = VPE_DEF_BUFS_PER_JOB;2376 2377 ctx->load_mmrs = true;2378 2379 vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n",2380 ctx, ctx->fh.m2m_ctx);2381 2382 mutex_unlock(&dev->dev_mutex);2383 2384 return 0;2385exit_fh:2386 v4l2_ctrl_handler_free(hdl);2387 v4l2_fh_exit(&ctx->fh);2388 vpdma_free_desc_buf(&ctx->sc_coeff_v);2389free_sc_h:2390 vpdma_free_desc_buf(&ctx->sc_coeff_h);2391free_mmr_adb:2392 vpdma_free_desc_buf(&ctx->mmr_adb);2393free_desc_list:2394 vpdma_free_desc_list(&ctx->desc_list);2395unlock:2396 mutex_unlock(&dev->dev_mutex);2397free_ctx:2398 kfree(ctx);2399 return ret;2400}2401 2402static int vpe_release(struct file *file)2403{2404 struct vpe_dev *dev = video_drvdata(file);2405 struct vpe_ctx *ctx = file->private_data;2406 2407 vpe_dbg(dev, "releasing instance %p\n", ctx);2408 2409 mutex_lock(&dev->dev_mutex);2410 free_mv_buffers(ctx);2411 2412 vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);2413 vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);2414 vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);2415 vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);2416 2417 vpdma_free_desc_list(&ctx->desc_list);2418 vpdma_free_desc_buf(&ctx->mmr_adb);2419 2420 vpdma_free_desc_buf(&ctx->sc_coeff_v);2421 vpdma_free_desc_buf(&ctx->sc_coeff_h);2422 2423 v4l2_fh_del(&ctx->fh);2424 v4l2_fh_exit(&ctx->fh);2425 v4l2_ctrl_handler_free(&ctx->hdl);2426 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);2427 2428 kfree(ctx);2429 2430 /*2431 * for now, just report the release of the last instance, we can later2432 * optimize the driver to enable or disable clocks when the first2433 * instance is created or the last instance released2434 */2435 if (atomic_dec_return(&dev->num_instances) == 0)2436 vpe_dbg(dev, "last instance released\n");2437 2438 mutex_unlock(&dev->dev_mutex);2439 2440 return 0;2441}2442 2443static const struct v4l2_file_operations vpe_fops = {2444 .owner = THIS_MODULE,2445 .open = vpe_open,2446 .release = vpe_release,2447 .poll = v4l2_m2m_fop_poll,2448 .unlocked_ioctl = video_ioctl2,2449 .mmap = v4l2_m2m_fop_mmap,2450};2451 2452static const struct video_device vpe_videodev = {2453 .name = VPE_MODULE_NAME,2454 .fops = &vpe_fops,2455 .ioctl_ops = &vpe_ioctl_ops,2456 .minor = -1,2457 .release = video_device_release_empty,2458 .vfl_dir = VFL_DIR_M2M,2459 .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,2460};2461 2462static const struct v4l2_m2m_ops m2m_ops = {2463 .device_run = device_run,2464 .job_ready = job_ready,2465 .job_abort = job_abort,2466};2467 2468static int vpe_runtime_get(struct platform_device *pdev)2469{2470 int r;2471 2472 dev_dbg(&pdev->dev, "vpe_runtime_get\n");2473 2474 r = pm_runtime_resume_and_get(&pdev->dev);2475 WARN_ON(r < 0);2476 return r;2477}2478 2479static void vpe_runtime_put(struct platform_device *pdev)2480{2481 2482 int r;2483 2484 dev_dbg(&pdev->dev, "vpe_runtime_put\n");2485 2486 r = pm_runtime_put_sync(&pdev->dev);2487 WARN_ON(r < 0 && r != -ENOSYS);2488}2489 2490static void vpe_fw_cb(struct platform_device *pdev)2491{2492 struct vpe_dev *dev = platform_get_drvdata(pdev);2493 struct video_device *vfd;2494 int ret;2495 2496 vfd = &dev->vfd;2497 *vfd = vpe_videodev;2498 vfd->lock = &dev->dev_mutex;2499 vfd->v4l2_dev = &dev->v4l2_dev;2500 2501 ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);2502 if (ret) {2503 vpe_err(dev, "Failed to register video device\n");2504 2505 vpe_set_clock_enable(dev, 0);2506 vpe_runtime_put(pdev);2507 pm_runtime_disable(&pdev->dev);2508 v4l2_m2m_release(dev->m2m_dev);2509 v4l2_device_unregister(&dev->v4l2_dev);2510 2511 return;2512 }2513 2514 video_set_drvdata(vfd, dev);2515 dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",2516 vfd->num);2517}2518 2519static int vpe_probe(struct platform_device *pdev)2520{2521 struct vpe_dev *dev;2522 int ret, irq, func;2523 2524 ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));2525 if (ret) {2526 dev_err(&pdev->dev,2527 "32-bit consistent DMA enable failed\n");2528 return ret;2529 }2530 2531 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);2532 if (!dev)2533 return -ENOMEM;2534 2535 spin_lock_init(&dev->lock);2536 2537 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);2538 if (ret)2539 return ret;2540 2541 atomic_set(&dev->num_instances, 0);2542 mutex_init(&dev->dev_mutex);2543 2544 dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,2545 "vpe_top");2546 if (!dev->res) {2547 dev_err(&pdev->dev, "missing 'vpe_top' resources data\n");2548 return -ENODEV;2549 }2550 2551 /*2552 * HACK: we get resource info from device tree in the form of a list of2553 * VPE sub blocks, the driver currently uses only the base of vpe_top2554 * for register access, the driver should be changed later to access2555 * registers based on the sub block base addresses2556 */2557 dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K);2558 if (!dev->base) {2559 ret = -ENOMEM;2560 goto v4l2_dev_unreg;2561 }2562 2563 irq = platform_get_irq(pdev, 0);2564 ret = devm_request_irq(&pdev->dev, irq, vpe_irq, 0, VPE_MODULE_NAME,2565 dev);2566 if (ret)2567 goto v4l2_dev_unreg;2568 2569 platform_set_drvdata(pdev, dev);2570 2571 dev->m2m_dev = v4l2_m2m_init(&m2m_ops);2572 if (IS_ERR(dev->m2m_dev)) {2573 vpe_err(dev, "Failed to init mem2mem device\n");2574 ret = PTR_ERR(dev->m2m_dev);2575 goto v4l2_dev_unreg;2576 }2577 2578 pm_runtime_enable(&pdev->dev);2579 2580 ret = vpe_runtime_get(pdev);2581 if (ret < 0)2582 goto rel_m2m;2583 2584 /* Perform clk enable followed by reset */2585 vpe_set_clock_enable(dev, 1);2586 2587 vpe_top_reset(dev);2588 2589 func = read_field_reg(dev, VPE_PID, VPE_PID_FUNC_MASK,2590 VPE_PID_FUNC_SHIFT);2591 vpe_dbg(dev, "VPE PID function %x\n", func);2592 2593 vpe_top_vpdma_reset(dev);2594 2595 dev->sc = sc_create(pdev, "sc");2596 if (IS_ERR(dev->sc)) {2597 ret = PTR_ERR(dev->sc);2598 goto runtime_put;2599 }2600 2601 dev->csc = csc_create(pdev, "csc");2602 if (IS_ERR(dev->csc)) {2603 ret = PTR_ERR(dev->csc);2604 goto runtime_put;2605 }2606 2607 dev->vpdma = &dev->vpdma_data;2608 ret = vpdma_create(pdev, dev->vpdma, vpe_fw_cb);2609 if (ret)2610 goto runtime_put;2611 2612 return 0;2613 2614runtime_put:2615 vpe_runtime_put(pdev);2616rel_m2m:2617 pm_runtime_disable(&pdev->dev);2618 v4l2_m2m_release(dev->m2m_dev);2619v4l2_dev_unreg:2620 v4l2_device_unregister(&dev->v4l2_dev);2621 2622 return ret;2623}2624 2625static void vpe_remove(struct platform_device *pdev)2626{2627 struct vpe_dev *dev = platform_get_drvdata(pdev);2628 2629 v4l2_info(&dev->v4l2_dev, "Removing " VPE_MODULE_NAME);2630 2631 v4l2_m2m_release(dev->m2m_dev);2632 video_unregister_device(&dev->vfd);2633 v4l2_device_unregister(&dev->v4l2_dev);2634 2635 vpe_set_clock_enable(dev, 0);2636 vpe_runtime_put(pdev);2637 pm_runtime_disable(&pdev->dev);2638}2639 2640#if defined(CONFIG_OF)2641static const struct of_device_id vpe_of_match[] = {2642 {2643 .compatible = "ti,dra7-vpe",2644 },2645 {},2646};2647MODULE_DEVICE_TABLE(of, vpe_of_match);2648#endif2649 2650static struct platform_driver vpe_pdrv = {2651 .probe = vpe_probe,2652 .remove_new = vpe_remove,2653 .driver = {2654 .name = VPE_MODULE_NAME,2655 .of_match_table = of_match_ptr(vpe_of_match),2656 },2657};2658 2659module_platform_driver(vpe_pdrv);2660 2661MODULE_DESCRIPTION("TI VPE driver");2662MODULE_AUTHOR("Dale Farnsworth, <dale@farnsworth.org>");2663MODULE_LICENSE("GPL");2664