linux/drivers/media/platform/nxp/imx7-media-csi.c

// SPDX-License-Identifier: GPL-2.0
/*
 * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC
 *
 * Copyright (c) 2019 Linaro Ltd
 */

#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/math.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/timekeeping.h>
#include <linux/types.h>

#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-async.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-v4l2.h>

#define IMX7_CSI_PAD_SINK
#define IMX7_CSI_PAD_SRC
#define IMX7_CSI_PADS_NUM

/* csi control reg 1 */
#define BIT_SWAP16_EN
#define BIT_EXT_VSYNC
#define BIT_EOF_INT_EN
#define BIT_PRP_IF_EN
#define BIT_CCIR_MODE
#define BIT_COF_INT_EN
#define BIT_SF_OR_INTEN
#define BIT_RF_OR_INTEN
#define BIT_SFF_DMA_DONE_INTEN
#define BIT_STATFF_INTEN
#define BIT_FB2_DMA_DONE_INTEN
#define BIT_FB1_DMA_DONE_INTEN
#define BIT_RXFF_INTEN
#define BIT_SOF_POL
#define BIT_SOF_INTEN
#define BIT_MCLKDIV(n)
#define BIT_MCLKDIV_MASK
#define BIT_HSYNC_POL
#define BIT_CCIR_EN
#define BIT_MCLKEN
#define BIT_FCC
#define BIT_PACK_DIR
#define BIT_CLR_STATFIFO
#define BIT_CLR_RXFIFO
#define BIT_GCLK_MODE
#define BIT_INV_DATA
#define BIT_INV_PCLK
#define BIT_REDGE
#define BIT_PIXEL_BIT

/* control reg 2 */
#define BIT_DMA_BURST_TYPE_RFF_INCR4
#define BIT_DMA_BURST_TYPE_RFF_INCR8
#define BIT_DMA_BURST_TYPE_RFF_INCR16
#define BIT_DMA_BURST_TYPE_RFF_MASK

/* control reg 3 */
#define BIT_FRMCNT(n)
#define BIT_FRMCNT_MASK
#define BIT_FRMCNT_RST
#define BIT_DMA_REFLASH_RFF
#define BIT_DMA_REFLASH_SFF
#define BIT_DMA_REQ_EN_RFF
#define BIT_DMA_REQ_EN_SFF
#define BIT_STATFF_LEVEL(n)
#define BIT_STATFF_LEVEL_MASK
#define BIT_HRESP_ERR_EN
#define BIT_RXFF_LEVEL(n)
#define BIT_RXFF_LEVEL_MASK
#define BIT_TWO_8BIT_SENSOR
#define BIT_ZERO_PACK_EN
#define BIT_ECC_INT_EN
#define BIT_ECC_AUTO_EN

/* csi status reg */
#define BIT_ADDR_CH_ERR_INT
#define BIT_FIELD0_INT
#define BIT_FIELD1_INT
#define BIT_SFF_OR_INT
#define BIT_RFF_OR_INT
#define BIT_DMA_TSF_DONE_SFF
#define BIT_STATFF_INT
#define BIT_DMA_TSF_DONE_FB2
#define BIT_DMA_TSF_DONE_FB1
#define BIT_RXFF_INT
#define BIT_EOF_INT
#define BIT_SOF_INT
#define BIT_F2_INT
#define BIT_F1_INT
#define BIT_COF_INT
#define BIT_HRESP_ERR_INT
#define BIT_ECC_INT
#define BIT_DRDY

/* csi image parameter reg */
#define BIT_IMAGE_WIDTH(n)
#define BIT_IMAGE_HEIGHT(n)

/* csi control reg 18 */
#define BIT_CSI_HW_ENABLE
#define BIT_MIPI_DATA_FORMAT_RAW8
#define BIT_MIPI_DATA_FORMAT_RAW10
#define BIT_MIPI_DATA_FORMAT_RAW12
#define BIT_MIPI_DATA_FORMAT_RAW14
#define BIT_MIPI_DATA_FORMAT_YUV422_8B
#define BIT_MIPI_DATA_FORMAT_MASK
#define BIT_DATA_FROM_MIPI
#define BIT_MIPI_YU_SWAP
#define BIT_MIPI_DOUBLE_CMPNT
#define BIT_MASK_OPTION_FIRST_FRAME
#define BIT_MASK_OPTION_CSI_EN
#define BIT_MASK_OPTION_SECOND_FRAME
#define BIT_MASK_OPTION_ON_DATA
#define BIT_BASEADDR_CHG_ERR_EN
#define BIT_BASEADDR_SWITCH_SEL
#define BIT_BASEADDR_SWITCH_EN
#define BIT_PARALLEL24_EN
#define BIT_DEINTERLACE_EN
#define BIT_TVDECODER_IN_EN
#define BIT_NTSC_EN

#define CSI_MCLK_VF
#define CSI_MCLK_ENC
#define CSI_MCLK_RAW
#define CSI_MCLK_I2C

#define CSI_CSICR1
#define CSI_CSICR2
#define CSI_CSICR3
#define CSI_STATFIFO
#define CSI_CSIRXFIFO
#define CSI_CSIRXCNT
#define CSI_CSISR

#define CSI_CSIDBG
#define CSI_CSIDMASA_STATFIFO
#define CSI_CSIDMATS_STATFIFO
#define CSI_CSIDMASA_FB1
#define CSI_CSIDMASA_FB2
#define CSI_CSIFBUF_PARA
#define CSI_CSIIMAG_PARA

#define CSI_CSICR18
#define CSI_CSICR19

#define IMX7_CSI_VIDEO_NAME
/* In bytes, per queue */
#define IMX7_CSI_VIDEO_MEM_LIMIT
#define IMX7_CSI_VIDEO_EOF_TIMEOUT

#define IMX7_CSI_DEF_MBUS_CODE
#define IMX7_CSI_DEF_PIX_FORMAT
#define IMX7_CSI_DEF_PIX_WIDTH
#define IMX7_CSI_DEF_PIX_HEIGHT

enum imx_csi_model {};

struct imx7_csi_pixfmt {};

struct imx7_csi_vb2_buffer {};

static inline struct imx7_csi_vb2_buffer *
to_imx7_csi_vb2_buffer(struct vb2_buffer *vb)
{}

struct imx7_csi_dma_buf {};

struct imx7_csi {};

static struct imx7_csi *
imx7_csi_notifier_to_dev(struct v4l2_async_notifier *n)
{}

/* -----------------------------------------------------------------------------
 * Hardware Configuration
 */

static u32 imx7_csi_reg_read(struct imx7_csi *csi, unsigned int offset)
{}

static void imx7_csi_reg_write(struct imx7_csi *csi, unsigned int value,
			       unsigned int offset)
{}

static u32 imx7_csi_irq_clear(struct imx7_csi *csi)
{}

static void imx7_csi_init_default(struct imx7_csi *csi)
{}

static void imx7_csi_hw_enable_irq(struct imx7_csi *csi)
{}

static void imx7_csi_hw_disable_irq(struct imx7_csi *csi)
{}

static void imx7_csi_hw_enable(struct imx7_csi *csi)
{}

static void imx7_csi_hw_disable(struct imx7_csi *csi)
{}

static void imx7_csi_dma_reflash(struct imx7_csi *csi)
{}

static void imx7_csi_rx_fifo_clear(struct imx7_csi *csi)
{}

static void imx7_csi_dmareq_rff_enable(struct imx7_csi *csi)
{}

static void imx7_csi_dmareq_rff_disable(struct imx7_csi *csi)
{}

static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t dma_addr,
				int buf_num)
{}

static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi);

static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
{}

static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
					 enum vb2_buffer_state return_status)
{}

static void imx7_csi_free_dma_buf(struct imx7_csi *csi,
				  struct imx7_csi_dma_buf *buf)
{}

static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi,
				  struct imx7_csi_dma_buf *buf, int size)
{}

static int imx7_csi_dma_setup(struct imx7_csi *csi)
{}

static void imx7_csi_dma_cleanup(struct imx7_csi *csi,
				 enum vb2_buffer_state return_status)
{}

static void imx7_csi_dma_stop(struct imx7_csi *csi)
{}

static void imx7_csi_configure(struct imx7_csi *csi,
			       struct v4l2_subdev_state *sd_state)
{}

static int imx7_csi_init(struct imx7_csi *csi,
			 struct v4l2_subdev_state *sd_state)
{}

static void imx7_csi_deinit(struct imx7_csi *csi,
			    enum vb2_buffer_state return_status)
{}

static void imx7_csi_baseaddr_switch_on_second_frame(struct imx7_csi *csi)
{}

static void imx7_csi_enable(struct imx7_csi *csi)
{}

static void imx7_csi_disable(struct imx7_csi *csi)
{}

/* -----------------------------------------------------------------------------
 * Interrupt Handling
 */

static void imx7_csi_error_recovery(struct imx7_csi *csi)
{}

static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
{}

static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
{}

/* -----------------------------------------------------------------------------
 * Format Helpers
 */

#define IMX_BUS_FMTS(fmt...)

/*
 * List of supported pixel formats for the subdevs. Keep V4L2_PIX_FMT_UYVY and
 * MEDIA_BUS_FMT_UYVY8_2X8 first to match IMX7_CSI_DEF_PIX_FORMAT and
 * IMX7_CSI_DEF_MBUS_CODE.
 *
 * TODO: Restrict the supported formats list based on the SoC integration.
 *
 * The CSI bridge can be configured to sample pixel components from the Rx queue
 * in single (8bpp) or double (16bpp) component modes. Image format variants
 * with different sample sizes (ie YUYV_2X8 vs YUYV_1X16) determine the pixel
 * components sampling size per each clock cycle and their packing mode (see
 * imx7_csi_configure() for details).
 *
 * As the CSI bridge can be interfaced with different IP blocks depending on the
 * SoC model it is integrated on, the Rx queue sampling size should match the
 * size of the samples transferred by the transmitting IP block. To avoid
 * misconfigurations of the capture pipeline, the enumeration of the supported
 * formats should be restricted to match the pixel source transmitting mode.
 *
 * Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2
 * receiver which operates in dual pixel sampling mode. The CSI bridge should
 * only expose the 1X16 formats variant which instructs it to operate in dual
 * pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7,
 * which supports both serial and parallel input, it should expose both
 * variants.
 *
 * This currently only applies to YUYV formats, but other formats might need to
 * be handled in the same way.
 */
static const struct imx7_csi_pixfmt pixel_formats[] =;

/*
 * Search in the pixel_formats[] array for an entry with the given fourcc
 * return it.
 */
static const struct imx7_csi_pixfmt *imx7_csi_find_pixel_format(u32 fourcc)
{}

/*
 * Search in the pixel_formats[] array for an entry with the given media
 * bus code and return it.
 */
static const struct imx7_csi_pixfmt *imx7_csi_find_mbus_format(u32 code)
{}

/*
 * Enumerate entries in the pixel_formats[] array that match the
 * requested search criteria. Return the media-bus code that matches
 * the search criteria at the requested match index.
 *
 * @code: The returned media-bus code that matches the search criteria at
 *        the requested match index.
 * @index: The requested match index.
 */
static int imx7_csi_enum_mbus_formats(u32 *code, u32 index)
{}

/* -----------------------------------------------------------------------------
 * Video Capture Device - IOCTLs
 */

static int imx7_csi_video_querycap(struct file *file, void *fh,
				   struct v4l2_capability *cap)
{}

static int imx7_csi_video_enum_fmt_vid_cap(struct file *file, void *fh,
					   struct v4l2_fmtdesc *f)
{}

static int imx7_csi_video_enum_framesizes(struct file *file, void *fh,
					  struct v4l2_frmsizeenum *fsize)
{}

static int imx7_csi_video_g_fmt_vid_cap(struct file *file, void *fh,
					struct v4l2_format *f)
{}

static const struct imx7_csi_pixfmt *
__imx7_csi_video_try_fmt(struct v4l2_pix_format *pixfmt,
			 struct v4l2_rect *compose)
{}

static int imx7_csi_video_try_fmt_vid_cap(struct file *file, void *fh,
					  struct v4l2_format *f)
{}

static int imx7_csi_video_s_fmt_vid_cap(struct file *file, void *fh,
					struct v4l2_format *f)
{}

static int imx7_csi_video_g_selection(struct file *file, void *fh,
				      struct v4l2_selection *s)
{}

static const struct v4l2_ioctl_ops imx7_csi_video_ioctl_ops =;

/* -----------------------------------------------------------------------------
 * Video Capture Device - Queue Operations
 */

static int imx7_csi_video_queue_setup(struct vb2_queue *vq,
				      unsigned int *nbuffers,
				      unsigned int *nplanes,
				      unsigned int sizes[],
				      struct device *alloc_devs[])
{}

static int imx7_csi_video_buf_init(struct vb2_buffer *vb)
{}

static int imx7_csi_video_buf_prepare(struct vb2_buffer *vb)
{}

static bool imx7_csi_fast_track_buffer(struct imx7_csi *csi,
				       struct imx7_csi_vb2_buffer *buf)
{}

static void imx7_csi_video_buf_queue(struct vb2_buffer *vb)
{}

static int imx7_csi_video_validate_fmt(struct imx7_csi *csi)
{}

static int imx7_csi_video_start_streaming(struct vb2_queue *vq,
					  unsigned int count)
{}

static void imx7_csi_video_stop_streaming(struct vb2_queue *vq)
{}

static const struct vb2_ops imx7_csi_video_qops =;

/* -----------------------------------------------------------------------------
 * Video Capture Device - File Operations
 */

static int imx7_csi_video_open(struct file *file)
{}

static int imx7_csi_video_release(struct file *file)
{}

static const struct v4l2_file_operations imx7_csi_video_fops =;

/* -----------------------------------------------------------------------------
 * Video Capture Device - Init & Cleanup
 */

static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi)
{}

static void imx7_csi_video_init_format(struct imx7_csi *csi)
{}

static int imx7_csi_video_register(struct imx7_csi *csi)
{}

static void imx7_csi_video_unregister(struct imx7_csi *csi)
{}

static int imx7_csi_video_init(struct imx7_csi *csi)
{}

/* -----------------------------------------------------------------------------
 * V4L2 Subdev Operations
 */

static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
{}

static int imx7_csi_init_state(struct v4l2_subdev *sd,
			       struct v4l2_subdev_state *sd_state)
{}

static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
				   struct v4l2_subdev_state *sd_state,
				   struct v4l2_subdev_mbus_code_enum *code)
{}

/*
 * Default the colorspace in tryfmt to SRGB if set to an unsupported
 * colorspace or not initialized. Then set the remaining colorimetry
 * parameters based on the colorspace if they are uninitialized.
 *
 * tryfmt->code must be set on entry.
 */
static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt)
{}

static void imx7_csi_try_fmt(struct v4l2_subdev *sd,
			     struct v4l2_subdev_state *sd_state,
			     struct v4l2_subdev_format *sdformat,
			     const struct imx7_csi_pixfmt **cc)
{}

static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
			    struct v4l2_subdev_state *sd_state,
			    struct v4l2_subdev_format *sdformat)
{}

static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
				      struct media_link *link,
				      struct v4l2_subdev_format *source_fmt,
				      struct v4l2_subdev_format *sink_fmt)
{}

static int imx7_csi_registered(struct v4l2_subdev *sd)
{}

static void imx7_csi_unregistered(struct v4l2_subdev *sd)
{}

static const struct v4l2_subdev_video_ops imx7_csi_video_ops =;

static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops =;

static const struct v4l2_subdev_ops imx7_csi_subdev_ops =;

static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops =;

/* -----------------------------------------------------------------------------
 * Media Entity Operations
 */

static const struct media_entity_operations imx7_csi_entity_ops =;

/* -----------------------------------------------------------------------------
 * Probe & Remove
 */

static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier,
				 struct v4l2_subdev *sd,
				 struct v4l2_async_connection *asd)
{}

static int imx7_csi_notify_complete(struct v4l2_async_notifier *notifier)
{}

static const struct v4l2_async_notifier_operations imx7_csi_notify_ops =;

static int imx7_csi_async_register(struct imx7_csi *csi)
{}

static void imx7_csi_media_cleanup(struct imx7_csi *csi)
{}

static const struct media_device_ops imx7_csi_media_ops =;

static int imx7_csi_media_dev_init(struct imx7_csi *csi)
{}

static int imx7_csi_media_init(struct imx7_csi *csi)
{}

static int imx7_csi_probe(struct platform_device *pdev)
{}

static void imx7_csi_remove(struct platform_device *pdev)
{}

static const struct of_device_id imx7_csi_of_match[] =;
MODULE_DEVICE_TABLE(of, imx7_csi_of_match);

static struct platform_driver imx7_csi_driver =;
module_platform_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();
MODULE_ALIAS();