blob: 6c06320174a2ed96cc5d7817101a19130f11901c [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Driver for Renesas R-Car VIN
*
* Copyright (C) 2016 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
*
* Based on the soc-camera rcar_vin driver
*/
#ifndef __RCAR_VIN__
#define __RCAR_VIN__
#include <linux/kref.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <media/videobuf2-v4l2.h>
/* Number of HW buffers */
#define HW_BUFFER_NUM 3
/* Address alignment mask for HW buffers */
#define HW_BUFFER_MASK 0x7f
/* Max number on VIN instances that can be in a system */
#define RCAR_VIN_NUM 32
struct rvin_group;
enum model_id {
RCAR_H1,
RCAR_M1,
RCAR_GEN2,
RCAR_GEN3,
};
enum rvin_csi_id {
RVIN_CSI20,
RVIN_CSI21,
RVIN_CSI40,
RVIN_CSI41,
RVIN_CSI_MAX,
};
enum rvin_isp_id {
RVIN_ISP0,
RVIN_ISP1,
RVIN_ISP2,
RVIN_ISP4,
RVIN_ISP_MAX,
};
#define RVIN_REMOTES_MAX \
(((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \
RVIN_CSI_MAX : RVIN_ISP_MAX)
/**
* enum rvin_dma_state - DMA states
* @STOPPED: No operation in progress
* @STARTING: Capture starting up
* @RUNNING: Operation in progress have buffers
* @STOPPING: Stopping operation
* @SUSPENDED: Capture is suspended
*/
enum rvin_dma_state {
STOPPED = 0,
STARTING,
RUNNING,
STOPPING,
SUSPENDED,
};
/**
* enum rvin_buffer_type
*
* Describes how a buffer is given to the hardware. To be able
* to capture SEQ_TB/BT it's needed to capture to the same vb2
* buffer twice so the type of buffer needs to be kept.
*
* @FULL: One capture fills the whole vb2 buffer
* @HALF_TOP: One capture fills the top half of the vb2 buffer
* @HALF_BOTTOM: One capture fills the bottom half of the vb2 buffer
*/
enum rvin_buffer_type {
FULL,
HALF_TOP,
HALF_BOTTOM,
};
/**
* struct rvin_video_format - Data format stored in memory
* @fourcc: Pixelformat
* @bpp: Bytes per pixel
*/
struct rvin_video_format {
u32 fourcc;
u8 bpp;
};
/**
* struct rvin_parallel_entity - Parallel video input endpoint descriptor
* @asd: sub-device descriptor for async framework
* @subdev: subdevice matched using async framework
* @mbus_type: media bus type
* @bus: media bus parallel configuration
* @source_pad: source pad of remote subdevice
* @sink_pad: sink pad of remote subdevice
*
*/
struct rvin_parallel_entity {
struct v4l2_async_subdev *asd;
struct v4l2_subdev *subdev;
enum v4l2_mbus_type mbus_type;
struct v4l2_fwnode_bus_parallel bus;
unsigned int source_pad;
unsigned int sink_pad;
};
/**
* struct rvin_group_route - describes a route from a channel of a
* CSI-2 receiver to a VIN
*
* @csi: CSI-2 receiver ID.
* @channel: Output channel of the CSI-2 receiver.
* @vin: VIN ID.
* @mask: Bitmask of the different CHSEL register values that
* allow for a route from @csi + @chan to @vin.
*
* .. note::
* Each R-Car CSI-2 receiver has four output channels facing the VIN
* devices, each channel can carry one CSI-2 Virtual Channel (VC).
* There is no correlation between channel number and CSI-2 VC. It's
* up to the CSI-2 receiver driver to configure which VC is output
* on which channel, the VIN devices only care about output channels.
*
* There are in some cases multiple CHSEL register settings which would
* allow for the same route from @csi + @channel to @vin. For example
* on R-Car H3 both the CHSEL values 0 and 3 allow for a route from
* CSI40/VC0 to VIN0. All possible CHSEL values for a route need to be
* recorded as a bitmask in @mask, in this example bit 0 and 3 should
* be set.
*/
struct rvin_group_route {
enum rvin_csi_id csi;
unsigned int channel;
unsigned int vin;
unsigned int mask;
};
/**
* struct rvin_info - Information about the particular VIN implementation
* @model: VIN model
* @use_mc: use media controller instead of controlling subdevice
* @use_isp: the VIN is connected to the ISP and not to the CSI-2
* @nv12: support outputing NV12 pixel format
* @max_width: max input width the VIN supports
* @max_height: max input height the VIN supports
* @routes: list of possible routes from the CSI-2 recivers to
* all VINs. The list mush be NULL terminated.
*/
struct rvin_info {
enum model_id model;
bool use_mc;
bool use_isp;
bool nv12;
unsigned int max_width;
unsigned int max_height;
const struct rvin_group_route *routes;
};
/**
* struct rvin_dev - Renesas VIN device structure
* @dev: (OF) device
* @base: device I/O register space remapped to virtual memory
* @info: info about VIN instance
*
* @vdev: V4L2 video device associated with VIN
* @v4l2_dev: V4L2 device
* @ctrl_handler: V4L2 control handler
* @notifier: V4L2 asynchronous subdevs notifier
*
* @parallel: parallel input subdevice descriptor
*
* @group: Gen3 CSI group
* @id: Gen3 group id for this VIN
* @pad: media pad for the video device entity
*
* @lock: protects @queue
* @queue: vb2 buffers queue
* @scratch: cpu address for scratch buffer
* @scratch_phys: physical address of the scratch buffer
*
* @qlock: protects @buf_hw, @buf_list, @sequence and @state
* @buf_hw: Keeps track of buffers given to HW slot
* @buf_list: list of queued buffers
* @sequence: V4L2 buffers sequence number
* @state: keeps track of operation state
*
* @is_csi: flag to mark the VIN as using a CSI-2 subdevice
* @chsel: Cached value of the current CSI-2 channel selection
*
* @mbus_code: media bus format code
* @format: active V4L2 pixel format
*
* @crop: active cropping
* @compose: active composing
* @src_rect: active size of the video source
* @std: active video standard of the video source
*
* @alpha: Alpha component to fill in for supported pixel formats
*/
struct rvin_dev {
struct device *dev;
void __iomem *base;
const struct rvin_info *info;
struct video_device vdev;
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_async_notifier notifier;
struct rvin_parallel_entity parallel;
struct rvin_group *group;
unsigned int id;
struct media_pad pad;
struct mutex lock;
struct vb2_queue queue;
void *scratch;
dma_addr_t scratch_phys;
spinlock_t qlock;
struct {
struct vb2_v4l2_buffer *buffer;
enum rvin_buffer_type type;
dma_addr_t phys;
} buf_hw[HW_BUFFER_NUM];
struct list_head buf_list;
unsigned int sequence;
enum rvin_dma_state state;
bool is_csi;
unsigned int chsel;
u32 mbus_code;
struct v4l2_pix_format format;
struct v4l2_rect crop;
struct v4l2_rect compose;
struct v4l2_rect src_rect;
v4l2_std_id std;
unsigned int alpha;
};
#define vin_to_source(vin) ((vin)->parallel.subdev)
/* Debug */
#define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg)
#define vin_info(d, fmt, arg...) dev_info(d->dev, fmt, ##arg)
#define vin_warn(d, fmt, arg...) dev_warn(d->dev, fmt, ##arg)
#define vin_err(d, fmt, arg...) dev_err(d->dev, fmt, ##arg)
/**
* struct rvin_group - VIN CSI2 group information
* @refcount: number of VIN instances using the group
*
* @mdev: media device which represents the group
*
* @lock: protects the count, notifier, vin and csi members
* @count: number of enabled VIN instances found in DT
* @notifier: group notifier for CSI-2 async subdevices
* @vin: VIN instances which are part of the group
* @link_setup: Callback to create all links for the media graph
* @remotes: array of pairs of fwnode and subdev pointers
* to all remote subdevices.
*/
struct rvin_group {
struct kref refcount;
struct media_device mdev;
struct mutex lock;
unsigned int count;
struct v4l2_async_notifier notifier;
struct rvin_dev *vin[RCAR_VIN_NUM];
int (*link_setup)(struct rvin_dev *vin);
struct {
struct v4l2_async_subdev *asd;
struct v4l2_subdev *subdev;
} remotes[RVIN_REMOTES_MAX];
};
int rvin_dma_register(struct rvin_dev *vin, int irq);
void rvin_dma_unregister(struct rvin_dev *vin);
int rvin_v4l2_register(struct rvin_dev *vin);
void rvin_v4l2_unregister(struct rvin_dev *vin);
const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
u32 pixelformat);
/* Cropping, composing and scaling */
void rvin_crop_scale_comp(struct rvin_dev *vin);
int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel);
void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha);
int rvin_start_streaming(struct rvin_dev *vin);
void rvin_stop_streaming(struct rvin_dev *vin);
#endif