linux/drivers/media/platform/marvell/mcam-core.c

// SPDX-License-Identifier: GPL-2.0
/*
 * The Marvell camera core.  This device appears in a number of settings,
 * so it needs platform-specific support outside of the core.
 *
 * Copyright 2011 Jonathan Corbet [email protected]
 * Copyright 2018 Lubomir Rintel <[email protected]>
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/videodev2.h>
#include <linux/pm_runtime.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>

#include "mcam-core.h"

#ifdef MCAM_MODE_VMALLOC
/*
 * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
 * we must have physically contiguous buffers to bring frames into.
 * These parameters control how many buffers we use, whether we
 * allocate them at load time (better chance of success, but nails down
 * memory) or when somebody tries to use the camera (riskier), and,
 * for load-time allocation, how big they should be.
 *
 * The controller can cycle through three buffers.  We could use
 * more by flipping pointers around, but it probably makes little
 * sense.
 */

static bool alloc_bufs_at_read;
module_param(alloc_bufs_at_read, bool, 0444);
MODULE_PARM_DESC();

static int n_dma_bufs =;
module_param(n_dma_bufs, uint, 0644);
MODULE_PARM_DESC();

static int dma_buf_size =;  /* Worst case */
module_param(dma_buf_size, uint, 0444);
MODULE_PARM_DESC();
#else /* MCAM_MODE_VMALLOC */
static const bool alloc_bufs_at_read;
static const int n_dma_bufs = 3;  /* Used by S/G_PARM */
#endif /* MCAM_MODE_VMALLOC */

static bool flip;
module_param(flip, bool, 0444);
MODULE_PARM_DESC();

static int buffer_mode =;
module_param(buffer_mode, int, 0444);
MODULE_PARM_DESC();

/*
 * Status flags.  Always manipulated with bit operations.
 */
#define CF_BUF0_VALID
#define CF_BUF1_VALID
#define CF_BUF2_VALID
#define CF_DMA_ACTIVE
#define CF_CONFIG_NEEDED
#define CF_SINGLE_BUFFER
#define CF_SG_RESTART
#define CF_FRAME_SOF0
#define CF_FRAME_SOF1
#define CF_FRAME_SOF2

#define sensor_call(cam, o, f, args...)

#define notifier_to_mcam(notifier)

static struct mcam_format_struct {} mcam_formats[] =;
#define N_MCAM_FMTS

static struct mcam_format_struct *mcam_find_format(u32 pixelformat)
{}

/*
 * The default format we use until somebody says otherwise.
 */
static const struct v4l2_pix_format mcam_def_pix_format =;

static const u32 mcam_def_mbus_code =;


/*
 * The two-word DMA descriptor format used by the Armada 610 and like.  There
 * Is a three-word format as well (set C1_DESC_3WORD) where the third
 * word is a pointer to the next descriptor, but we don't use it.  Two-word
 * descriptors have to be contiguous in memory.
 */
struct mcam_dma_desc {};

/*
 * Our buffer type for working with videobuf2.  Note that the vb2
 * developers have decreed that struct vb2_v4l2_buffer must be at the
 * beginning of this structure.
 */
struct mcam_vb_buffer {};

static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb)
{}

/*
 * Hand a completed buffer back to user space.
 */
static void mcam_buffer_done(struct mcam_camera *cam, int frame,
		struct vb2_v4l2_buffer *vbuf)
{}



/*
 * Debugging and related.
 */
#define cam_err(cam, fmt, arg...)
#define cam_warn(cam, fmt, arg...)
#define cam_dbg(cam, fmt, arg...)


/*
 * Flag manipulation helpers
 */
static void mcam_reset_buffers(struct mcam_camera *cam)
{}

static inline int mcam_needs_config(struct mcam_camera *cam)
{}

static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
{}

/* ------------------------------------------------------------------- */
/*
 * Make the controller start grabbing images.  Everything must
 * be set up before doing this.
 */
static void mcam_ctlr_start(struct mcam_camera *cam)
{}

static void mcam_ctlr_stop(struct mcam_camera *cam)
{}

static void mcam_enable_mipi(struct mcam_camera *mcam)
{}

static void mcam_disable_mipi(struct mcam_camera *mcam)
{}

static bool mcam_fmt_is_planar(__u32 pfmt)
{}

static void mcam_write_yuv_bases(struct mcam_camera *cam,
				 unsigned frame, dma_addr_t base)
{}

/* ------------------------------------------------------------------- */

#ifdef MCAM_MODE_VMALLOC
/*
 * Code specific to the vmalloc buffer mode.
 */

/*
 * Allocate in-kernel DMA buffers for vmalloc mode.
 */
static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
{}

static void mcam_free_dma_bufs(struct mcam_camera *cam)
{}


/*
 * Set up DMA buffers when operating in vmalloc mode
 */
static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
{}

/*
 * Copy data out to user space in the vmalloc case
 */
static void mcam_frame_work(struct work_struct *t)
{}


/*
 * Make sure our allocated buffers are up to the task.
 */
static int mcam_check_dma_buffers(struct mcam_camera *cam)
{}

static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
{}

#else /* MCAM_MODE_VMALLOC */

static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
{
	return 0;
}

static inline void mcam_free_dma_bufs(struct mcam_camera *cam)
{
	return;
}

static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
{
	return 0;
}



#endif /* MCAM_MODE_VMALLOC */


#ifdef MCAM_MODE_DMA_CONTIG
/* ---------------------------------------------------------------------- */
/*
 * DMA-contiguous code.
 */

/*
 * Set up a contiguous buffer for the given frame.  Here also is where
 * the underrun strategy is set: if there is no buffer available, reuse
 * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to
 * keep the interrupt handler from giving that buffer back to user
 * space.  In this way, we always have a buffer to DMA to and don't
 * have to try to play games stopping and restarting the controller.
 */
static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
{}

/*
 * Initial B_DMA_contig setup.
 */
static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
{}

/*
 * Frame completion handling.
 */
static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
{}

#endif /* MCAM_MODE_DMA_CONTIG */

#ifdef MCAM_MODE_DMA_SG
/* ---------------------------------------------------------------------- */
/*
 * Scatter/gather-specific code.
 */

/*
 * Set up the next buffer for S/G I/O; caller should be sure that
 * the controller is stopped and a buffer is available.
 */
static void mcam_sg_next_buffer(struct mcam_camera *cam)
{}

/*
 * Initial B_DMA_sg setup
 */
static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
{}


/*
 * Frame completion with S/G is trickier.  We can't muck with
 * a descriptor chain on the fly, since the controller buffers it
 * internally.  So we have to actually stop and restart; Marvell
 * says this is the way to do it.
 *
 * Of course, stopping is easier said than done; experience shows
 * that the controller can start a frame *after* C0_ENABLE has been
 * cleared.  So when running in S/G mode, the controller is "stopped"
 * on receipt of the start-of-frame interrupt.  That means we can
 * safely change the DMA descriptor array here and restart things
 * (assuming there's another buffer waiting to go).
 */
static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
{}


/*
 * Scatter/gather mode requires stopping the controller between
 * frames so we can put in a new DMA descriptor array.  If no new
 * buffer exists at frame completion, the controller is left stopped;
 * this function is charged with getting things going again.
 */
static void mcam_sg_restart(struct mcam_camera *cam)
{}

#else /* MCAM_MODE_DMA_SG */

static inline void mcam_sg_restart(struct mcam_camera *cam)
{
	return;
}

#endif /* MCAM_MODE_DMA_SG */

/* ---------------------------------------------------------------------- */
/*
 * Buffer-mode-independent controller code.
 */

/*
 * Image format setup
 */
static void mcam_ctlr_image(struct mcam_camera *cam)
{}


/*
 * Configure the controller for operation; caller holds the
 * device mutex.
 */
static int mcam_ctlr_configure(struct mcam_camera *cam)
{}

static void mcam_ctlr_irq_enable(struct mcam_camera *cam)
{}

static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
{}

/*
 * Stop the controller, and don't return until we're really sure that no
 * further DMA is going on.
 */
static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
{}

/*
 * Power up and down.
 */
static int mcam_ctlr_power_up(struct mcam_camera *cam)
{}

static void mcam_ctlr_power_down(struct mcam_camera *cam)
{}

/* ---------------------------------------------------------------------- */
/*
 * Master sensor clock.
 */
static int mclk_prepare(struct clk_hw *hw)
{}

static void mclk_unprepare(struct clk_hw *hw)
{}

static int mclk_enable(struct clk_hw *hw)
{}

static void mclk_disable(struct clk_hw *hw)
{}

static unsigned long mclk_recalc_rate(struct clk_hw *hw,
				unsigned long parent_rate)
{}

static const struct clk_ops mclk_ops =;

/* -------------------------------------------------------------------- */
/*
 * Communications with the sensor.
 */

static int __mcam_cam_reset(struct mcam_camera *cam)
{}

/*
 * We have found the sensor on the i2c.  Let's try to have a
 * conversation.
 */
static int mcam_cam_init(struct mcam_camera *cam)
{}

/*
 * Configure the sensor to match the parameters we have.  Caller should
 * hold s_mutex
 */
static int mcam_cam_set_flip(struct mcam_camera *cam)
{}


static int mcam_cam_configure(struct mcam_camera *cam)
{}

/*
 * Get everything ready, and start grabbing frames.
 */
static int mcam_read_setup(struct mcam_camera *cam)
{}

/* ----------------------------------------------------------------------- */
/*
 * Videobuf2 interface code.
 */

static int mcam_vb_queue_setup(struct vb2_queue *vq,
		unsigned int *nbufs,
		unsigned int *num_planes, unsigned int sizes[],
		struct device *alloc_devs[])
{}


static void mcam_vb_buf_queue(struct vb2_buffer *vb)
{}

static void mcam_vb_requeue_bufs(struct vb2_queue *vq,
				 enum vb2_buffer_state state)
{}

/*
 * These need to be called with the mutex held from vb2
 */
static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
{}

static void mcam_vb_stop_streaming(struct vb2_queue *vq)
{}


static const struct vb2_ops mcam_vb2_ops =;


#ifdef MCAM_MODE_DMA_SG
/*
 * Scatter/gather mode uses all of the above functions plus a
 * few extras to deal with DMA mapping.
 */
static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
{}

static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
{}

static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
{}


static const struct vb2_ops mcam_vb2_sg_ops =;

#endif /* MCAM_MODE_DMA_SG */

static int mcam_setup_vb2(struct mcam_camera *cam)
{}


/* ---------------------------------------------------------------------- */
/*
 * The long list of V4L2 ioctl() operations.
 */

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


static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
		void *priv, struct v4l2_fmtdesc *fmt)
{}

static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
		struct v4l2_format *fmt)
{}

static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
		struct v4l2_format *fmt)
{}

/*
 * Return our stored notion of how the camera is/should be configured.
 * The V4l2 spec wants us to be smarter, and actually get this from
 * the camera (and not mess with it at open time).  Someday.
 */
static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv,
		struct v4l2_format *f)
{}

/*
 * We only have one input - the sensor - so minimize the nonsense here.
 */
static int mcam_vidioc_enum_input(struct file *filp, void *priv,
		struct v4l2_input *input)
{}

static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
{}

static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
{}

/*
 * G/S_PARM.  Most of this is done by the sensor, but we are
 * the level which controls the number of read buffers.
 */
static int mcam_vidioc_g_parm(struct file *filp, void *priv,
		struct v4l2_streamparm *a)
{}

static int mcam_vidioc_s_parm(struct file *filp, void *priv,
		struct v4l2_streamparm *a)
{}

static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv,
		struct v4l2_frmsizeenum *sizes)
{}

static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv,
		struct v4l2_frmivalenum *interval)
{}

#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mcam_vidioc_g_register(struct file *file, void *priv,
		struct v4l2_dbg_register *reg)
{}

static int mcam_vidioc_s_register(struct file *file, void *priv,
		const struct v4l2_dbg_register *reg)
{}
#endif

static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops =;

/* ---------------------------------------------------------------------- */
/*
 * Our various file operations.
 */
static int mcam_v4l_open(struct file *filp)
{}


static int mcam_v4l_release(struct file *filp)
{}

static const struct v4l2_file_operations mcam_v4l_fops =;


/*
 * This template device holds all of those v4l2 methods; we
 * clone it for specific real devices.
 */
static const struct video_device mcam_v4l_template =;

/* ---------------------------------------------------------------------- */
/*
 * Interrupt handler stuff
 */
static void mcam_frame_complete(struct mcam_camera *cam, int frame)
{}


/*
 * The interrupt handler; this needs to be called from the
 * platform irq handler with the lock held.
 */
int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
{}
EXPORT_SYMBOL_GPL();

/* ---------------------------------------------------------------------- */
/*
 * Registration and such.
 */

static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
	struct v4l2_subdev *subdev, struct v4l2_async_connection *asd)
{}

static void mccic_notify_unbind(struct v4l2_async_notifier *notifier,
	struct v4l2_subdev *subdev, struct v4l2_async_connection *asd)
{}

static int mccic_notify_complete(struct v4l2_async_notifier *notifier)
{}

static const struct v4l2_async_notifier_operations mccic_notify_ops =;

int mccic_register(struct mcam_camera *cam)
{}
EXPORT_SYMBOL_GPL();

void mccic_shutdown(struct mcam_camera *cam)
{}
EXPORT_SYMBOL_GPL();

/*
 * Power management
 */
void mccic_suspend(struct mcam_camera *cam)
{}
EXPORT_SYMBOL_GPL();

int mccic_resume(struct mcam_camera *cam)
{}
EXPORT_SYMBOL_GPL();

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