linux/drivers/media/platform/broadcom/bcm2835-unicam.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * BCM283x / BCM271x Unicam Capture Driver
 *
 * Copyright (C) 2017-2020 - Raspberry Pi (Trading) Ltd.
 * Copyright (C) 2024 - Ideas on Board
 *
 * Dave Stevenson <[email protected]>
 *
 * Based on TI am437x driver by
 *   Benoit Parrot <[email protected]>
 *   Lad, Prabhakar <[email protected]>
 *
 * and TI CAL camera interface driver by
 *    Benoit Parrot <[email protected]>
 *
 *
 * There are two camera drivers in the kernel for BCM283x - this one and
 * bcm2835-camera (currently in staging).
 *
 * This driver directly controls the Unicam peripheral - there is no
 * involvement with the VideoCore firmware. Unicam receives CSI-2 or CCP2 data
 * and writes it into SDRAM. The only potential processing options are to
 * repack Bayer data into an alternate format, and applying windowing. The
 * repacking does not shift the data, so can repack V4L2_PIX_FMT_Sxxxx10P to
 * V4L2_PIX_FMT_Sxxxx10, or V4L2_PIX_FMT_Sxxxx12P to V4L2_PIX_FMT_Sxxxx12, but
 * not generically up to V4L2_PIX_FMT_Sxxxx16. Support for windowing may be
 * added later.
 *
 * It should be possible to connect this driver to any sensor with a suitable
 * output interface and V4L2 subdevice driver.
 */

#include <linux/clk.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/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>

#include <media/mipi-csi2.h>
#include <media/v4l2-async.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-dma-contig.h>

#include "bcm2835-unicam-regs.h"

#define UNICAM_MODULE_NAME

/*
 * Unicam must request a minimum of 250Mhz from the VPU clock.
 * Otherwise the input FIFOs overrun and cause image corruption.
 */
#define UNICAM_MIN_VPU_CLOCK_RATE

/* Unicam has an internal DMA alignment constraint of 16 bytes for each line. */
#define UNICAM_DMA_BPL_ALIGNMENT

/*
 * The image stride is stored in a 16 bit register, and needs to be aligned to
 * the DMA constraint. As the ISP in the same SoC has a 32 bytes alignment
 * constraint on its input, set the image stride alignment to 32 bytes here as
 * well to avoid incompatible configurations.
 */
#define UNICAM_IMAGE_BPL_ALIGNMENT
#define UNICAM_IMAGE_MAX_BPL

/*
 * Max width is therefore determined by the max stride divided by the number of
 * bits per pixel. Take 32bpp as a worst case. No imposed limit on the height,
 * so adopt a square image for want of anything better.
 */
#define UNICAM_IMAGE_MIN_WIDTH
#define UNICAM_IMAGE_MIN_HEIGHT
#define UNICAM_IMAGE_MAX_WIDTH
#define UNICAM_IMAGE_MAX_HEIGHT

/*
 * There's no intrinsic limits on the width and height for embedded data. Use
 * the same maximum values as for the image, to avoid overflows in the image
 * size computation.
 */
#define UNICAM_META_MIN_WIDTH
#define UNICAM_META_MIN_HEIGHT
#define UNICAM_META_MAX_WIDTH
#define UNICAM_META_MAX_HEIGHT

/*
 * Size of the dummy buffer. Can be any size really, but the DMA
 * allocation works in units of page sizes.
 */
#define UNICAM_DUMMY_BUF_SIZE

enum unicam_pad {};

enum unicam_node_type {};

/*
 * struct unicam_format_info - Unicam media bus format information
 * @fourcc: V4L2 pixel format FCC identifier. 0 if n/a.
 * @unpacked_fourcc: V4L2 pixel format FCC identifier if the data is expanded
 * out to 16bpp. 0 if n/a.
 * @code: V4L2 media bus format code.
 * @depth: Bits per pixel as delivered from the source.
 * @csi_dt: CSI data type.
 * @unpack: PUM value when unpacking to @unpacked_fourcc
 */
struct unicam_format_info {};

struct unicam_buffer {};

static inline struct unicam_buffer *to_unicam_buffer(struct vb2_buffer *vb)
{}

struct unicam_node {};

struct unicam_device {};

static inline struct unicam_device *
notifier_to_unicam_device(struct v4l2_async_notifier *notifier)
{}

static inline struct unicam_device *
sd_to_unicam_device(struct v4l2_subdev *sd)
{}

static void unicam_release(struct kref *kref)
{}

static struct unicam_device *unicam_get(struct unicam_device *unicam)
{}

static void unicam_put(struct unicam_device *unicam)
{}

/* -----------------------------------------------------------------------------
 * Misc helper functions
 */

static inline bool unicam_sd_pad_is_source(u32 pad)
{}

static inline bool is_metadata_node(struct unicam_node *node)
{}

static inline bool is_image_node(struct unicam_node *node)
{}

/* -----------------------------------------------------------------------------
 * Format data table and helper functions
 */

static const struct v4l2_mbus_framefmt unicam_default_image_format =;

static const struct v4l2_mbus_framefmt unicam_default_meta_format =;

static const struct unicam_format_info unicam_image_formats[] =;

static const struct unicam_format_info unicam_meta_formats[] =;

/* Format setup functions */
static const struct unicam_format_info *
unicam_find_format_by_code(u32 code, u32 pad)
{}

static const struct unicam_format_info *
unicam_find_format_by_fourcc(u32 fourcc, u32 pad)
{}

static void unicam_calc_image_size_bpl(struct unicam_device *unicam,
				       const struct unicam_format_info *fmtinfo,
				       struct v4l2_pix_format *pix)
{}

static void unicam_calc_meta_size_bpl(struct unicam_device *unicam,
				      const struct unicam_format_info *fmtinfo,
				      struct v4l2_meta_format *meta)
{}

/* -----------------------------------------------------------------------------
 * Hardware handling
 */

static inline void unicam_clk_write(struct unicam_device *unicam, u32 val)
{}

static inline u32 unicam_reg_read(struct unicam_device *unicam, u32 offset)
{}

static inline void unicam_reg_write(struct unicam_device *unicam, u32 offset, u32 val)
{}

static inline int unicam_get_field(u32 value, u32 mask)
{}

static inline void unicam_set_field(u32 *valp, u32 field, u32 mask)
{}

static inline void unicam_reg_write_field(struct unicam_device *unicam, u32 offset,
					  u32 field, u32 mask)
{}

static void unicam_wr_dma_addr(struct unicam_node *node,
			       struct unicam_buffer *buf)
{}

static unsigned int unicam_get_lines_done(struct unicam_device *unicam)
{}

static void unicam_schedule_next_buffer(struct unicam_node *node)
{}

static void unicam_schedule_dummy_buffer(struct unicam_node *node)
{}

static void unicam_process_buffer_complete(struct unicam_node *node,
					   unsigned int sequence)
{}

static void unicam_queue_event_sof(struct unicam_device *unicam)
{}

static irqreturn_t unicam_isr(int irq, void *dev)
{}

static void unicam_set_packing_config(struct unicam_device *unicam,
				      const struct unicam_format_info *fmtinfo)
{}

static void unicam_cfg_image_id(struct unicam_device *unicam, u8 vc, u8 dt)
{}

static void unicam_enable_ed(struct unicam_device *unicam)
{}

static int unicam_get_image_vc_dt(struct unicam_device *unicam,
				  struct v4l2_subdev_state *state,
				  u8 *vc, u8 *dt)
{}

static void unicam_start_rx(struct unicam_device *unicam,
			    struct v4l2_subdev_state *state)
{}

static void unicam_start_metadata(struct unicam_device *unicam)
{}

static void unicam_disable(struct unicam_device *unicam)
{}

/* -----------------------------------------------------------------------------
 * V4L2 subdev operations
 */

static int __unicam_subdev_set_routing(struct v4l2_subdev *sd,
				       struct v4l2_subdev_state *state,
				       struct v4l2_subdev_krouting *routing)
{}

static int unicam_subdev_init_state(struct v4l2_subdev *sd,
				    struct v4l2_subdev_state *state)
{}

static int unicam_subdev_enum_mbus_code(struct v4l2_subdev *sd,
					struct v4l2_subdev_state *state,
					struct v4l2_subdev_mbus_code_enum *code)
{}

static int unicam_subdev_enum_frame_size(struct v4l2_subdev *sd,
					 struct v4l2_subdev_state *state,
					 struct v4l2_subdev_frame_size_enum *fse)
{}

static int unicam_subdev_set_format(struct v4l2_subdev *sd,
				    struct v4l2_subdev_state *state,
				    struct v4l2_subdev_format *format)
{}

static int unicam_subdev_set_routing(struct v4l2_subdev *sd,
				     struct v4l2_subdev_state *state,
				     enum v4l2_subdev_format_whence which,
				     struct v4l2_subdev_krouting *routing)
{}

static int unicam_sd_enable_streams(struct v4l2_subdev *sd,
				    struct v4l2_subdev_state *state, u32 pad,
				    u64 streams_mask)
{}

static int unicam_sd_disable_streams(struct v4l2_subdev *sd,
				     struct v4l2_subdev_state *state, u32 pad,
				     u64 streams_mask)
{}

static const struct v4l2_subdev_pad_ops unicam_subdev_pad_ops =;

static const struct v4l2_subdev_ops unicam_subdev_ops =;

static const struct v4l2_subdev_internal_ops unicam_subdev_internal_ops =;

static const struct media_entity_operations unicam_subdev_media_ops =;

static int unicam_subdev_init(struct unicam_device *unicam)
{}

static void unicam_subdev_cleanup(struct unicam_device *unicam)
{}

/* -----------------------------------------------------------------------------
 * Videobuf2 queue operations
 */

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

static int unicam_buffer_prepare(struct vb2_buffer *vb)
{}

static void unicam_return_buffers(struct unicam_node *node,
				  enum vb2_buffer_state state)
{}

static int unicam_num_data_lanes(struct unicam_device *unicam)
{}

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

static void unicam_stop_streaming(struct vb2_queue *vq)
{}

static void unicam_buffer_queue(struct vb2_buffer *vb)
{}

static const struct vb2_ops unicam_video_qops =;

/* -----------------------------------------------------------------------------
 *  V4L2 video device operations
 */

static int unicam_querycap(struct file *file, void *priv,
			   struct v4l2_capability *cap)
{}

static int unicam_enum_fmt_vid(struct file *file, void  *priv,
			       struct v4l2_fmtdesc *f)
{}

static int unicam_g_fmt_vid(struct file *file, void *priv,
			    struct v4l2_format *f)
{}

static void __unicam_try_fmt_vid(struct unicam_node *node,
				 struct v4l2_pix_format *pix)
{}

static int unicam_try_fmt_vid(struct file *file, void *priv,
			      struct v4l2_format *f)
{}

static int unicam_s_fmt_vid(struct file *file, void *priv,
			    struct v4l2_format *f)
{}

static int unicam_enum_fmt_meta(struct file *file, void *priv,
				struct v4l2_fmtdesc *f)
{}

static int unicam_g_fmt_meta(struct file *file, void *priv,
			     struct v4l2_format *f)
{}

static const struct unicam_format_info *
__unicam_try_fmt_meta(struct unicam_node *node, struct v4l2_meta_format *meta)
{}

static int unicam_try_fmt_meta(struct file *file, void *priv,
			       struct v4l2_format *f)
{}

static int unicam_s_fmt_meta(struct file *file, void *priv,
			     struct v4l2_format *f)
{}

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

static int unicam_log_status(struct file *file, void *fh)
{}

static int unicam_subscribe_event(struct v4l2_fh *fh,
				  const struct v4l2_event_subscription *sub)
{}

static const struct v4l2_ioctl_ops unicam_ioctl_ops =;

/* unicam capture driver file operations */
static const struct v4l2_file_operations unicam_fops =;

static int unicam_video_link_validate(struct media_link *link)
{}

static const struct media_entity_operations unicam_video_media_ops =;

static void unicam_node_release(struct video_device *vdev)
{}

static void unicam_set_default_format(struct unicam_node *node)
{}

static int unicam_register_node(struct unicam_device *unicam,
				enum unicam_node_type type)
{}

static void unicam_unregister_nodes(struct unicam_device *unicam)
{}

/* -----------------------------------------------------------------------------
 * Power management
 */

static int unicam_runtime_resume(struct device *dev)
{}

static int unicam_runtime_suspend(struct device *dev)
{}

static const struct dev_pm_ops unicam_pm_ops =;

/* -----------------------------------------------------------------------------
 * V4L2 async notifier
 */

static int unicam_async_bound(struct v4l2_async_notifier *notifier,
			      struct v4l2_subdev *subdev,
			      struct v4l2_async_connection *asc)
{}

static int unicam_async_complete(struct v4l2_async_notifier *notifier)
{}

static const struct v4l2_async_notifier_operations unicam_async_ops =;

static int unicam_async_nf_init(struct unicam_device *unicam)
{}

/* -----------------------------------------------------------------------------
 * Probe & remove
 */

static int unicam_media_init(struct unicam_device *unicam)
{}

static int unicam_probe(struct platform_device *pdev)
{}

static void unicam_remove(struct platform_device *pdev)
{}

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

static struct platform_driver unicam_driver =;

module_platform_driver();

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