1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
/* 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/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 8
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,
};
/**
* STOPPED - No operation in progress
* STARTING - Capture starting up
* RUNNING - Operation in progress have buffers
* STOPPING - Stopping operation
*/
enum rvin_dma_state {
STOPPED = 0,
STARTING,
RUNNING,
STOPPING,
};
/**
* 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
* @mbus_flags: media bus configuration flags
* @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;
unsigned int mbus_flags;
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
* @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;
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 @queue_buf, @buf_list, @sequence
* @state
* @queue_buf: 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
*
* @mbus_code: media bus format code
* @format: active V4L2 pixel format
*
* @crop: active cropping
* @compose: active composing
* @source: active size of the video source
* @std: active video standard of the video source
*/
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 vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM];
struct list_head buf_list;
unsigned int sequence;
enum rvin_dma_state state;
bool is_csi;
u32 mbus_code;
struct v4l2_pix_format format;
struct v4l2_rect crop;
struct v4l2_rect compose;
struct v4l2_rect source;
v4l2_std_id std;
};
#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
* @csi: array of pairs of fwnode and subdev pointers
* to all CSI-2 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];
struct {
struct fwnode_handle *fwnode;
struct v4l2_subdev *subdev;
} csi[RVIN_CSI_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(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);
#endif
|