// SPDX-License-Identifier: GPL-2.0-only /* * ispvideo.c * * TI OMAP3 ISP - Generic video node * * Copyright (C) 2009-2010 Nokia Corporation * * Contacts: Laurent Pinchart <[email protected]> * Sakari Ailus <[email protected]> */ #include <linux/clk.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <media/v4l2-dev.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-mc.h> #include <media/videobuf2-dma-contig.h> #include "ispvideo.h" #include "isp.h" /* ----------------------------------------------------------------------------- * Helper functions */ /* * NOTE: When adding new media bus codes, always remember to add * corresponding in-memory formats to the table below!!! */ static struct isp_format_info formats[] = …; const struct isp_format_info *omap3isp_video_format_info(u32 code) { … } /* * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format * @video: ISP video instance * @mbus: v4l2_mbus_framefmt format (input) * @pix: v4l2_pix_format format (output) * * Fill the output pix structure with information from the input mbus format. * The bytesperline and sizeimage fields are computed from the requested bytes * per line value in the pix format and information from the video instance. * * Return the number of padding bytes at end of line. */ static unsigned int isp_video_mbus_to_pix(const struct isp_video *video, const struct v4l2_mbus_framefmt *mbus, struct v4l2_pix_format *pix) { … } static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mbus) { … } static struct v4l2_subdev * isp_video_remote_subdev(struct isp_video *video, u32 *pad) { … } /* Return a pointer to the ISP video instance at the far end of the pipeline. */ static int isp_video_get_graph_data(struct isp_video *video, struct isp_pipeline *pipe) { … } static int __isp_video_get_format(struct isp_video *video, struct v4l2_format *format) { … } static int isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) { … } /* ----------------------------------------------------------------------------- * Video queue operations */ static int isp_video_queue_setup(struct vb2_queue *queue, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], struct device *alloc_devs[]) { … } static int isp_video_buffer_prepare(struct vb2_buffer *buf) { … } /* * isp_video_buffer_queue - Add buffer to streaming queue * @buf: Video buffer * * In memory-to-memory mode, start streaming on the pipeline if buffers are * queued on both the input and the output, if the pipeline isn't already busy. * If the pipeline is busy, it will be restarted in the output module interrupt * handler. */ static void isp_video_buffer_queue(struct vb2_buffer *buf) { … } /* * omap3isp_video_return_buffers - Return all queued buffers to videobuf2 * @video: ISP video object * @state: new state for the returned buffers * * Return all buffers queued on the video node to videobuf2 in the given state. * The buffer state should be VB2_BUF_STATE_QUEUED if called due to an error * when starting the stream, or VB2_BUF_STATE_ERROR otherwise. * * The function must be called with the video irqlock held. */ static void omap3isp_video_return_buffers(struct isp_video *video, enum vb2_buffer_state state) { … } static int isp_video_start_streaming(struct vb2_queue *queue, unsigned int count) { … } static const struct vb2_ops isp_video_queue_ops = …; /* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object * * Remove the current video buffer from the DMA queue and fill its timestamp and * field count before handing it back to videobuf2. * * For capture video nodes the buffer state is set to VB2_BUF_STATE_DONE if no * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise. * For video output nodes the buffer state is always set to VB2_BUF_STATE_DONE. * * The DMA queue is expected to contain at least one buffer. * * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is * empty. */ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) { … } /* * omap3isp_video_cancel_stream - Cancel stream on a video node * @video: ISP video object * * Cancelling a stream returns all buffers queued on the video node to videobuf2 * in the erroneous state and makes sure no new buffer can be queued. */ void omap3isp_video_cancel_stream(struct isp_video *video) { … } /* * omap3isp_video_resume - Perform resume operation on the buffers * @video: ISP video object * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise * * This function is intended to be used on suspend/resume scenario. It * requests video queue layer to discard buffers marked as DONE if it's in * continuous mode and requests ISP modules to queue again the ACTIVE buffer * if there's any. */ void omap3isp_video_resume(struct isp_video *video, int continuous) { … } /* ----------------------------------------------------------------------------- * V4L2 ioctls */ static int isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { … } static int isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) { … } static int isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) { … } static int isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format) { … } static int isp_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel) { … } static int isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) { … } static int isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { … } static int isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) { … } static int isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) { … } static int isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { … } static int isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) { … } static int isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { … } static int isp_video_check_external_subdevs(struct isp_video *video, struct isp_pipeline *pipe) { … } /* * Stream management * * Every ISP pipeline has a single input and a single output. The input can be * either a sensor or a video node. The output is always a video node. * * As every pipeline has an output video node, the ISP video objects at the * pipeline output stores the pipeline state. It tracks the streaming state of * both the input and output, as well as the availability of buffers. * * In sensor-to-memory mode, frames are always available at the pipeline input. * Starting the sensor usually requires I2C transfers and must be done in * interruptible context. The pipeline is started and stopped synchronously * to the stream on/off commands. All modules in the pipeline will get their * subdev set stream handler called. The module at the end of the pipeline must * delay starting the hardware until buffers are available at its output. * * In memory-to-memory mode, starting/stopping the stream requires * synchronization between the input and output. ISP modules can't be stopped * in the middle of a frame, and at least some of the modules seem to become * busy as soon as they're started, even if they don't receive a frame start * event. For that reason frames need to be processed in single-shot mode. The * driver needs to wait until a frame is completely processed and written to * memory before restarting the pipeline for the next frame. Pipelined * processing might be possible but requires more testing. * * Stream start must be delayed until buffers are available at both the input * and output. The pipeline must be started in the vb2 queue callback with * the buffers queue spinlock held. The modules subdev set stream operation must * not sleep. */ static int isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { … } static int isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { … } static int isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input) { … } static int isp_video_g_input(struct file *file, void *fh, unsigned int *input) { … } static int isp_video_s_input(struct file *file, void *fh, unsigned int input) { … } static const struct v4l2_ioctl_ops isp_video_ioctl_ops = …; /* ----------------------------------------------------------------------------- * V4L2 file operations */ static int isp_video_open(struct file *file) { … } static int isp_video_release(struct file *file) { … } static __poll_t isp_video_poll(struct file *file, poll_table *wait) { … } static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) { … } static const struct v4l2_file_operations isp_video_fops = …; /* ----------------------------------------------------------------------------- * ISP video core */ static const struct isp_video_operations isp_video_dummy_ops = …; int omap3isp_video_init(struct isp_video *video, const char *name) { … } void omap3isp_video_cleanup(struct isp_video *video) { … } int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) { … } void omap3isp_video_unregister(struct isp_video *video) { … }