root/drivers/staging/media/sunxi/cedrus/cedrus.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Cedrus VPU driver
 *
 * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
 * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
 * Copyright (C) 2018 Bootlin
 *
 * Based on the vim2m driver, that is:
 *
 * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
 * Pawel Osciak, <pawel@osciak.com>
 * Marek Szyprowski, <m.szyprowski@samsung.com>
 */

#ifndef _CEDRUS_H_
#define _CEDRUS_H_

#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>

#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>

#define CEDRUS_NAME                     "cedrus"

#define CEDRUS_CAPABILITY_UNTILED       BIT(0)
#define CEDRUS_CAPABILITY_H265_DEC      BIT(1)
#define CEDRUS_CAPABILITY_H264_DEC      BIT(2)
#define CEDRUS_CAPABILITY_MPEG2_DEC     BIT(3)
#define CEDRUS_CAPABILITY_VP8_DEC       BIT(4)
#define CEDRUS_CAPABILITY_H265_10_DEC   BIT(5)

enum cedrus_irq_status {
        CEDRUS_IRQ_NONE,
        CEDRUS_IRQ_ERROR,
        CEDRUS_IRQ_OK,
};

enum cedrus_h264_pic_type {
        CEDRUS_H264_PIC_TYPE_FRAME      = 0,
        CEDRUS_H264_PIC_TYPE_FIELD,
        CEDRUS_H264_PIC_TYPE_MBAFF,
};

struct cedrus_control {
        struct v4l2_ctrl_config cfg;
        unsigned int            capabilities;
};

struct cedrus_h264_run {
        const struct v4l2_ctrl_h264_decode_params       *decode_params;
        const struct v4l2_ctrl_h264_pps                 *pps;
        const struct v4l2_ctrl_h264_scaling_matrix      *scaling_matrix;
        const struct v4l2_ctrl_h264_slice_params        *slice_params;
        const struct v4l2_ctrl_h264_sps                 *sps;
        const struct v4l2_ctrl_h264_pred_weights        *pred_weights;
};

struct cedrus_mpeg2_run {
        const struct v4l2_ctrl_mpeg2_sequence           *sequence;
        const struct v4l2_ctrl_mpeg2_picture            *picture;
        const struct v4l2_ctrl_mpeg2_quantisation       *quantisation;
};

struct cedrus_h265_run {
        const struct v4l2_ctrl_hevc_sps                 *sps;
        const struct v4l2_ctrl_hevc_pps                 *pps;
        const struct v4l2_ctrl_hevc_slice_params        *slice_params;
        const struct v4l2_ctrl_hevc_decode_params       *decode_params;
        const struct v4l2_ctrl_hevc_scaling_matrix      *scaling_matrix;
        const u32                                       *entry_points;
        u32                                             entry_points_count;
};

struct cedrus_vp8_run {
        const struct v4l2_ctrl_vp8_frame                *frame_params;
};

struct cedrus_run {
        struct vb2_v4l2_buffer  *src;
        struct vb2_v4l2_buffer  *dst;

        union {
                struct cedrus_h264_run  h264;
                struct cedrus_mpeg2_run mpeg2;
                struct cedrus_h265_run  h265;
                struct cedrus_vp8_run   vp8;
        };
};

struct cedrus_buffer {
        struct v4l2_m2m_buffer          m2m_buf;

        union {
                struct {
                        unsigned int                    position;
                        enum cedrus_h264_pic_type       pic_type;
                        void                            *mv_col_buf;
                        dma_addr_t                      mv_col_buf_dma;
                        ssize_t                         mv_col_buf_size;
                } h264;
                struct {
                        void            *mv_col_buf;
                        dma_addr_t      mv_col_buf_dma;
                        ssize_t         mv_col_buf_size;
                } h265;
        } codec;
};

struct cedrus_ctx {
        struct v4l2_fh                  fh;
        struct cedrus_dev               *dev;

        struct v4l2_pix_format          src_fmt;
        struct v4l2_pix_format          dst_fmt;
        struct cedrus_dec_ops           *current_codec;
        unsigned int                    bit_depth;

        struct v4l2_ctrl_handler        hdl;
        struct v4l2_ctrl                **ctrls;

        union {
                struct {
                        void            *pic_info_buf;
                        dma_addr_t      pic_info_buf_dma;
                        ssize_t         pic_info_buf_size;
                        void            *neighbor_info_buf;
                        dma_addr_t      neighbor_info_buf_dma;
                        void            *deblk_buf;
                        dma_addr_t      deblk_buf_dma;
                        ssize_t         deblk_buf_size;
                        void            *intra_pred_buf;
                        dma_addr_t      intra_pred_buf_dma;
                        ssize_t         intra_pred_buf_size;
                } h264;
                struct {
                        void            *neighbor_info_buf;
                        dma_addr_t      neighbor_info_buf_addr;
                        void            *entry_points_buf;
                        dma_addr_t      entry_points_buf_addr;
                } h265;
                struct {
                        unsigned int    last_frame_p_type;
                        unsigned int    last_filter_type;
                        unsigned int    last_sharpness_level;

                        u8              *entropy_probs_buf;
                        dma_addr_t      entropy_probs_buf_dma;
                } vp8;
        } codec;
};

static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file)
{
        return container_of(file_to_v4l2_fh(file), struct cedrus_ctx, fh);
}

struct cedrus_dec_ops {
        void (*irq_clear)(struct cedrus_ctx *ctx);
        void (*irq_disable)(struct cedrus_ctx *ctx);
        enum cedrus_irq_status (*irq_status)(struct cedrus_ctx *ctx);
        int (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run);
        int (*start)(struct cedrus_ctx *ctx);
        void (*stop)(struct cedrus_ctx *ctx);
        void (*trigger)(struct cedrus_ctx *ctx);
        unsigned int (*extra_cap_size)(struct cedrus_ctx *ctx,
                                       struct v4l2_pix_format *pix_fmt);
};

struct cedrus_variant {
        unsigned int    capabilities;
        unsigned int    mod_rate;
};

struct cedrus_dev {
        struct v4l2_device      v4l2_dev;
        struct video_device     vfd;
        struct media_device     mdev;
        struct media_pad        pad[2];
        struct platform_device  *pdev;
        struct device           *dev;
        struct v4l2_m2m_dev     *m2m_dev;

        /* Device file mutex */
        struct mutex            dev_mutex;

        void __iomem            *base;

        struct clk              *mod_clk;
        struct clk              *ahb_clk;
        struct clk              *ram_clk;

        struct reset_control    *rstc;

        unsigned int            capabilities;

        struct delayed_work     watchdog_work;
};

extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
extern struct cedrus_dec_ops cedrus_dec_ops_h264;
extern struct cedrus_dec_ops cedrus_dec_ops_h265;
extern struct cedrus_dec_ops cedrus_dec_ops_vp8;

static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
{
        writel(val, dev->base + reg);
}

static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
{
        return readl(dev->base + reg);
}

static inline u32 cedrus_wait_for(struct cedrus_dev *dev, u32 reg, u32 flag)
{
        u32 value;

        return readl_poll_timeout_atomic(dev->base + reg, value,
                        (value & flag) == 0, 10, 1000);
}

static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf,
                                         struct v4l2_pix_format *pix_fmt,
                                         unsigned int plane)
{
        dma_addr_t addr = vb2_dma_contig_plane_dma_addr(buf, 0);

        return addr + (pix_fmt ? (dma_addr_t)pix_fmt->bytesperline *
               pix_fmt->height * plane : 0);
}

static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx,
                                             struct vb2_buffer *buf,
                                             unsigned int plane)
{
        return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0;
}

static inline void cedrus_write_ref_buf_addr(struct cedrus_ctx *ctx,
                                             struct vb2_queue *q,
                                             u64 timestamp,
                                             u32 luma_reg,
                                             u32 chroma_reg)
{
        struct cedrus_dev *dev = ctx->dev;
        struct vb2_buffer *buf = vb2_find_buffer(q, timestamp);

        cedrus_write(dev, luma_reg, cedrus_dst_buf_addr(ctx, buf, 0));
        cedrus_write(dev, chroma_reg, cedrus_dst_buf_addr(ctx, buf, 1));
}

static inline struct cedrus_buffer *
vb2_v4l2_to_cedrus_buffer(const struct vb2_v4l2_buffer *p)
{
        return container_of(p, struct cedrus_buffer, m2m_buf.vb);
}

static inline struct cedrus_buffer *
vb2_to_cedrus_buffer(const struct vb2_buffer *p)
{
        return vb2_v4l2_to_cedrus_buffer(to_vb2_v4l2_buffer(p));
}

static inline bool
cedrus_is_capable(struct cedrus_ctx *ctx, unsigned int capabilities)
{
        return (ctx->dev->capabilities & capabilities) == capabilities;
}

void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);

#endif