blob: 2810ebe9b5f75c3bb918ea5e7f6868c03d95b773 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* V4L2 Capture ISI subdev for i.MX8QXP/QM platform
*
* ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
* used to process image from camera sensor to memory or DC
* Copyright 2019-2020 NXP
*/
#ifndef __MXC_ISI_CORE_H__
#define __MXC_ISI_CORE_H__
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
struct clk_bulk_data;
struct dentry;
struct device;
struct media_intf_devnode;
struct regmap;
struct v4l2_m2m_dev;
/* Pipeline pads */
#define MXC_ISI_PIPE_PAD_SINK 0
#define MXC_ISI_PIPE_PAD_SOURCE 1
#define MXC_ISI_PIPE_PADS_NUM 2
#define MXC_ISI_MIN_WIDTH 1U
#define MXC_ISI_MIN_HEIGHT 1U
#define MXC_ISI_MAX_WIDTH_UNCHAINED 2048U
#define MXC_ISI_MAX_WIDTH_CHAINED 4096U
#define MXC_ISI_MAX_HEIGHT 8191U
#define MXC_ISI_DEF_WIDTH 1920U
#define MXC_ISI_DEF_HEIGHT 1080U
#define MXC_ISI_DEF_MBUS_CODE_SINK MEDIA_BUS_FMT_UYVY8_1X16
#define MXC_ISI_DEF_MBUS_CODE_SOURCE MEDIA_BUS_FMT_YUV8_1X24
#define MXC_ISI_DEF_PIXEL_FORMAT V4L2_PIX_FMT_YUYV
#define MXC_ISI_DEF_COLOR_SPACE V4L2_COLORSPACE_SRGB
#define MXC_ISI_DEF_YCBCR_ENC V4L2_YCBCR_ENC_601
#define MXC_ISI_DEF_QUANTIZATION V4L2_QUANTIZATION_LIM_RANGE
#define MXC_ISI_DEF_XFER_FUNC V4L2_XFER_FUNC_SRGB
#define MXC_ISI_DRIVER_NAME "mxc-isi"
#define MXC_ISI_CAPTURE "mxc-isi-cap"
#define MXC_ISI_M2M "mxc-isi-m2m"
#define MXC_MAX_PLANES 3
struct mxc_isi_dev;
struct mxc_isi_m2m_ctx;
enum mxc_isi_buf_id {
MXC_ISI_BUF1 = 0x0,
MXC_ISI_BUF2,
};
enum mxc_isi_encoding {
MXC_ISI_ENC_RAW,
MXC_ISI_ENC_RGB,
MXC_ISI_ENC_YUV,
};
enum mxc_isi_input_id {
/* Inputs from the crossbar switch range from 0 to 15 */
MXC_ISI_INPUT_MEM = 16,
};
enum mxc_isi_video_type {
MXC_ISI_VIDEO_CAP = BIT(0),
MXC_ISI_VIDEO_M2M_OUT = BIT(1),
MXC_ISI_VIDEO_M2M_CAP = BIT(2),
};
struct mxc_isi_format_info {
u32 mbus_code;
u32 fourcc;
enum mxc_isi_video_type type;
u32 isi_in_format;
u32 isi_out_format;
u8 mem_planes;
u8 color_planes;
u8 depth[MXC_MAX_PLANES];
u8 hsub;
u8 vsub;
enum mxc_isi_encoding encoding;
};
struct mxc_isi_bus_format_info {
u32 mbus_code;
u32 output;
u32 pads;
enum mxc_isi_encoding encoding;
};
struct mxc_isi_buffer {
struct vb2_v4l2_buffer v4l2_buf;
struct list_head list;
dma_addr_t dma_addrs[3];
enum mxc_isi_buf_id id;
bool discard;
};
struct mxc_isi_reg {
u32 offset;
u32 mask;
};
struct mxc_isi_ier_reg {
/* Overflow Y/U/V trigger enable*/
struct mxc_isi_reg oflw_y_buf_en;
struct mxc_isi_reg oflw_u_buf_en;
struct mxc_isi_reg oflw_v_buf_en;
/* Excess overflow Y/U/V trigger enable*/
struct mxc_isi_reg excs_oflw_y_buf_en;
struct mxc_isi_reg excs_oflw_u_buf_en;
struct mxc_isi_reg excs_oflw_v_buf_en;
/* Panic Y/U/V trigger enable*/
struct mxc_isi_reg panic_y_buf_en;
struct mxc_isi_reg panic_v_buf_en;
struct mxc_isi_reg panic_u_buf_en;
};
struct mxc_isi_panic_thd {
u32 mask;
u32 offset;
u32 threshold;
};
struct mxc_isi_set_thd {
struct mxc_isi_panic_thd panic_set_thd_y;
struct mxc_isi_panic_thd panic_set_thd_u;
struct mxc_isi_panic_thd panic_set_thd_v;
};
struct mxc_gasket_ops {
void (*enable)(struct mxc_isi_dev *isi,
const struct v4l2_mbus_frame_desc *fd,
const struct v4l2_mbus_framefmt *fmt,
const unsigned int port);
void (*disable)(struct mxc_isi_dev *isi, const unsigned int port);
};
enum model {
MXC_ISI_IMX8MN,
MXC_ISI_IMX8MP,
MXC_ISI_IMX93,
};
struct mxc_isi_plat_data {
enum model model;
unsigned int num_ports;
unsigned int num_channels;
unsigned int reg_offset;
const struct mxc_isi_ier_reg *ier_reg;
const struct mxc_isi_set_thd *set_thd;
const struct mxc_gasket_ops *gasket_ops;
const struct clk_bulk_data *clks;
unsigned int num_clks;
bool buf_active_reverse;
bool has_36bit_dma;
};
struct mxc_isi_dma_buffer {
size_t size;
void *addr;
dma_addr_t dma;
};
struct mxc_isi_input {
unsigned int enable_count;
};
struct mxc_isi_crossbar {
struct mxc_isi_dev *isi;
unsigned int num_sinks;
unsigned int num_sources;
struct mxc_isi_input *inputs;
struct v4l2_subdev sd;
struct media_pad *pads;
};
struct mxc_isi_video {
struct mxc_isi_pipe *pipe;
struct video_device vdev;
struct media_pad pad;
/* Protects is_streaming, and the vdev and vb2_q operations */
struct mutex lock;
bool is_streaming;
struct v4l2_pix_format_mplane pix;
const struct mxc_isi_format_info *fmtinfo;
struct {
struct v4l2_ctrl_handler handler;
unsigned int alpha;
bool hflip;
bool vflip;
} ctrls;
struct vb2_queue vb2_q;
struct mxc_isi_buffer buf_discard[3];
struct list_head out_pending;
struct list_head out_active;
struct list_head out_discard;
u32 frame_count;
/* Protects out_pending, out_active, out_discard and frame_count */
spinlock_t buf_lock;
struct mxc_isi_dma_buffer discard_buffer[MXC_MAX_PLANES];
};
typedef void(*mxc_isi_pipe_irq_t)(struct mxc_isi_pipe *, u32);
struct mxc_isi_pipe {
struct mxc_isi_dev *isi;
u32 id;
void __iomem *regs;
struct media_pipeline pipe;
struct v4l2_subdev sd;
struct media_pad pads[MXC_ISI_PIPE_PADS_NUM];
struct mxc_isi_video video;
/*
* Protects use_count, irq_handler, res_available, res_acquired,
* chained_res, and the CHNL_CTRL register.
*/
struct mutex lock;
unsigned int use_count;
mxc_isi_pipe_irq_t irq_handler;
#define MXC_ISI_CHANNEL_RES_LINE_BUF BIT(0)
#define MXC_ISI_CHANNEL_RES_OUTPUT_BUF BIT(1)
u8 available_res;
u8 acquired_res;
u8 chained_res;
bool chained;
};
struct mxc_isi_m2m {
struct mxc_isi_dev *isi;
struct mxc_isi_pipe *pipe;
struct media_pad pad;
struct video_device vdev;
struct media_intf_devnode *intf;
struct v4l2_m2m_dev *m2m_dev;
/* Protects last_ctx, usage_count and chained_count */
struct mutex lock;
struct mxc_isi_m2m_ctx *last_ctx;
int usage_count;
int chained_count;
};
struct mxc_isi_dev {
struct device *dev;
const struct mxc_isi_plat_data *pdata;
void __iomem *regs;
struct clk_bulk_data *clks;
struct regmap *gasket;
struct mxc_isi_crossbar crossbar;
struct mxc_isi_pipe *pipes;
struct mxc_isi_m2m m2m;
struct media_device media_dev;
struct v4l2_device v4l2_dev;
struct v4l2_async_notifier notifier;
struct dentry *debugfs_root;
};
extern const struct mxc_gasket_ops mxc_imx8_gasket_ops;
extern const struct mxc_gasket_ops mxc_imx93_gasket_ops;
int mxc_isi_crossbar_init(struct mxc_isi_dev *isi);
void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar);
int mxc_isi_crossbar_register(struct mxc_isi_crossbar *xbar);
void mxc_isi_crossbar_unregister(struct mxc_isi_crossbar *xbar);
const struct mxc_isi_bus_format_info *
mxc_isi_bus_format_by_code(u32 code, unsigned int pad);
const struct mxc_isi_bus_format_info *
mxc_isi_bus_format_by_index(unsigned int index, unsigned int pad);
const struct mxc_isi_format_info *
mxc_isi_format_by_fourcc(u32 fourcc, enum mxc_isi_video_type type);
const struct mxc_isi_format_info *
mxc_isi_format_enum(unsigned int index, enum mxc_isi_video_type type);
const struct mxc_isi_format_info *
mxc_isi_format_try(struct mxc_isi_pipe *pipe, struct v4l2_pix_format_mplane *pix,
enum mxc_isi_video_type type);
int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id);
void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe);
int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
mxc_isi_pipe_irq_t irq_handler);
void mxc_isi_pipe_release(struct mxc_isi_pipe *pipe);
int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe);
void mxc_isi_pipe_disable(struct mxc_isi_pipe *pipe);
int mxc_isi_video_register(struct mxc_isi_pipe *pipe,
struct v4l2_device *v4l2_dev);
void mxc_isi_video_unregister(struct mxc_isi_pipe *pipe);
void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe);
int mxc_isi_video_resume(struct mxc_isi_pipe *pipe);
int mxc_isi_video_queue_setup(const struct v4l2_pix_format_mplane *format,
const struct mxc_isi_format_info *info,
unsigned int *num_buffers,
unsigned int *num_planes, unsigned int sizes[]);
void mxc_isi_video_buffer_init(struct vb2_buffer *vb2, dma_addr_t dma_addrs[3],
const struct mxc_isi_format_info *info,
const struct v4l2_pix_format_mplane *pix);
int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2,
const struct mxc_isi_format_info *info,
const struct v4l2_pix_format_mplane *pix);
#ifdef CONFIG_VIDEO_IMX8_ISI_M2M
int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev);
int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi);
#else
static inline int mxc_isi_m2m_register(struct mxc_isi_dev *isi,
struct v4l2_device *v4l2_dev)
{
return 0;
}
static inline int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
{
return 0;
}
#endif
int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe,
mxc_isi_pipe_irq_t irq_handler, bool bypass);
void mxc_isi_channel_release(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_get(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_put(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe);
int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass);
void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_config(struct mxc_isi_pipe *pipe,
enum mxc_isi_input_id input,
const struct v4l2_area *in_size,
const struct v4l2_area *scale,
const struct v4l2_rect *crop,
enum mxc_isi_encoding in_encoding,
enum mxc_isi_encoding out_encoding);
void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe,
const struct mxc_isi_format_info *info,
const struct v4l2_pix_format_mplane *format);
void mxc_isi_channel_set_output_format(struct mxc_isi_pipe *pipe,
const struct mxc_isi_format_info *info,
struct v4l2_pix_format_mplane *format);
void mxc_isi_channel_m2m_start(struct mxc_isi_pipe *pipe);
void mxc_isi_channel_set_alpha(struct mxc_isi_pipe *pipe, u8 alpha);
void mxc_isi_channel_set_flip(struct mxc_isi_pipe *pipe, bool hflip, bool vflip);
void mxc_isi_channel_set_inbuf(struct mxc_isi_pipe *pipe, dma_addr_t dma_addr);
void mxc_isi_channel_set_outbuf(struct mxc_isi_pipe *pipe,
const dma_addr_t dma_addrs[3],
enum mxc_isi_buf_id buf_id);
u32 mxc_isi_channel_irq_status(struct mxc_isi_pipe *pipe, bool clear);
void mxc_isi_channel_irq_clear(struct mxc_isi_pipe *pipe);
#if IS_ENABLED(CONFIG_DEBUG_FS)
void mxc_isi_debug_init(struct mxc_isi_dev *isi);
void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi);
#else
static inline void mxc_isi_debug_init(struct mxc_isi_dev *isi)
{
}
static inline void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi)
{
}
#endif
#endif /* __MXC_ISI_CORE_H__ */