mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-19 11:43:40 +00:00
3e52419ec0
When Gen3 support was first added to this R-Car VIN and CSI-2 driver the routing was centred around the CHSEL register which multiplexes the different parallel buses that sit between the CSI-2 receivers source side and the VIN dma engines. This was a bad design as the multiplexing do allow for only a few combinations and do not play nice with many video streams in the system. For example it's only possible for CSI-2 Virtual Channels 0 and 1 of any given CSI-2 receiver to be used together with the scaler. Later datasheets have expanded the documentation and it is now possible to improve on this design by allowing any Virtual Channel to be routed to any R-Car VIN instance, provided that there exists a parallel bus between them. This increases the flexibility as all Virtual Channels can now be used together with the scaler for example. The redesign is not however perfect. While the new design allows for many more routes, two constrains limit a small portion of routes that was possible in the old design but are no more. - It is no longer possible to route the same CSI-2 and VC to more then one VIN at a time. This was theoretically possible before if the specific SoC allowed for the same CSI-2 and VC to be routed to two different VIN capture groups. - It is no longer possible to simultaneously mix links from two CSI-2 IP blocks to the same VIN capture group. For example if VIN2 is capturing from CSI40 then VIN{0,1,3} must also capture from CSI40. While VIN{4,5,6,7} is still free to capture from any other CSI-2 IP in the system. Once all VIN{0,1,2,3} links to CSI40 are disabled that VIN capture group is free again to capture from any other CSI-2 IP it is connected to. At the core of the redesign is greater cooperator of the R-Car VIN and CSI-2 drivers in configuring the routing. The VIN driver is after this change only responsible to configure the full VIN capture groups parallel buses to be to a particular CSI-2 IP. While the configuration of which CSI-2 Virtual Channel is outputted on which of the R-Car CSI-2 IP output ports is handled by the CSI-2 driver. Before this change the CSI-2 Virtual Channel to output port was static in the CSI-2 driver and the different links only manipulated the VIN capture groups CHSEL register. With this change both the CHSEl register and the CSI-2 routing VCDT registers are modified for greater flexibility. This change touches both the R-Car VIN and R-Car CSI-2 drivers in the same commit as both drivers cooperate closely and one change without the other would more or less break video capture. Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> Tested-by: Jacopo Mondi <jacopo+renesas@jmondi.org> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> [hverkuil: fix two trivial checkpatch whitespace issues]
316 lines
7.9 KiB
C
316 lines
7.9 KiB
C
/* 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_mbus_config_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
|
|
*
|
|
* @master: VIN group master ID.
|
|
* @csi: CSI-2 receiver ID.
|
|
* @chsel: CHSEL register values that connects VIN group to CSI-2.
|
|
*
|
|
* .. 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.
|
|
*/
|
|
struct rvin_group_route {
|
|
unsigned int master;
|
|
enum rvin_csi_id csi;
|
|
unsigned int chsel;
|
|
};
|
|
|
|
/**
|
|
* 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
|