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
|
Theory of Operations
====================
There are three separate drivers within the V4L2 framework that are interesting
to Tegra-based platforms. They are as follows:
Image Sensor driver
===================
This driver communicates only with the image sensor hardware (typically via
I2C transactions), and is intentionally PLATFORM-AGNOSTIC. Existing image
sensor drivers can be found in drivers/media/video. For example, the ov9740
driver communicates with the Omnivision OV9740 image sensor with built-in ISP.
Some of the things that this driver is responsible for are:
Setting up the proper output format of the image sensor,
Setting up image output extents
Setting up capture and crop regions
Camera Host driver
==================
This driver communicates only with the camera controller on a given platform,
and is intentionally IMAGE-SENSOR-AGNOSTIC. Existing camera host drivers
can be found in drivers/media/video, of which tegra_v4l2_camera.c is the
example that is interesting to us. This camera host driver knows how to
program the CSI/VI block on Tegra2 and Tegra3 platforms.
Some of the things that this driver is responsible for are:
Setting up the proper input format (image frame data flowing from the image
sensor to the camera host),
Setting up the proper output format (image frame data flowing from the
camera host to system memory),
Programming the DMA destination to receive the image frame data,
Starting and stopping the reception of image frame data.
Videobuf driver
===============
This driver is responsible for the allocation and deallocation of buffers that
are used to hold image frame data. Different camera hosts have different
DMA requirements, which makes it necessary to allow for different methods of
buffer allocation. For example, the Tegra2 and Tegra3 camera host cannot
DMA via a scatter-gather list, so the image frame buffers must be physically
contiguous. The videobuf-dma-contig.c videobuf driver can be found in
drivers/media/video, and contains a videobuf implementation that allocates
physically contiguous regions. One can also have a videobuf driver that
uses a different allocator like nvmap.
The nvhost driver and Syncpts
=============================
The camera host driver (tegra_v4l2_camera) has a dependency on the nvhost
driver/subsystem in order to make use of syncpts. In other words, the camera
host driver is a client of nvhost.
A syncpt is essentially an incrementing hardware counter that triggers an
interrupt when a certain number (or threshold) is reached. The interrupt,
however, is hidden from clients of nvhost. Instead, asynchronous completion
notification is done via calling an nvhost routine that goes to sleep, and
wakes up upon completion.
Tegra has a number of syncpts that serve various purposes. The two syncpts
that are used by the camera host driver are the VI and CSI syncpts. Other
syncpts are used in display, etc.
A syncpt increments when a certain hardware condition is met.
The public operations available for a syncpt are:
nvhost_syncpt_read_ext(syncpt_id) - Read the current syncpt counter value.
nvhost_syncpt_wait_timeout_ext(syncpt_id, threshold, timeout) - Go to sleep
until the syncpt value reaches the threshold, or until the timeout
expires.
nvhost_syncpt_cpu_incr_ext(syncpt_id) - Manually increment a syncpt.
Syncpts are used in the camera host driver in order to signify the completion
of an operation. The typical usage case can be illustrated by summarizing
the steps that the camera host driver takes in capturing a single frame
(this is called one-shot mode, where we program up each frame transfer
separately):
0) At the very start, read the current syncpt values and remember them. See
tegra_camera_activate() -> tegra_camera_save_syncpts(), where we read
the current values and store them in pcdev->syncpt_csi and pcdev->syncpt_vi.
1) Program the camera host registers to prepare to receive frames from the
image sensor using the proper input format. Note that we are at this
point NOT telling the camera host to DMA a frame. That comes later. See
tegra_camera_capture_setup(), where we do a whole bunch of magical
register writes depending on our input format, output format, image extents,
etc.
2) Increment our remembered copies of the current syncpt values according to
how many syncpt increments we are expecting for the given operation we
want to perform. For capturing a single frame, we are expecting a single
increment on the CSI syncpt when the reception of the frame is complete, and
a single increment on the VI syncpt when the DMA of the frame is complete.
See tegra_camera_capture_start(), where we increment pcdev->syncpt_csi
and pcdev->syncpt_vi.
3) Program the DMA destination registers, and toggle the bit in
TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND to do the DMA on the next available
frame. See tegra_camera_capture_start() for this.
4) Call nvhost_syncpt_wait_timeout_ext() to wait on the CSI syncpt threshold.
Remember that we incremented our local syncpt values in step 2. Those
new values become the threshold to wait for. See
tegra_camera_capture_start().
5) When the frame finishes its transfer from the image sensor to the camera
host, the CSI syncpt hardware counter will be incremented by hardware.
Since the hardware syncpt value will now match the threshold, our call to
nvhost_syncpt_wait_timeout_ext() in step 4 wakes up.
6) We now tell the camera host to get ready for the DMA to complete. We do
this by writing again to TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND. See
tegra_camera_capture_stop().
7) When the camera host finishes its DMA, we expect the hardware to increment
the VI syncpt. Therefore, we call nvhost_syncpt_wait_timeout_ext() on
the VI syncpt with our new threshold that we got by the incrementing in
step 2. See tegra_camera_capture_stop().
8) When the camera host finally finishes its DMA, the VI syncpt hardware
counter increments. Since our VI syncpt threshold is met, the call to
nvhost_syncpt_wait_timeout_ext() wakes up, and we are done. See
tegra_camera_capture_stop().
9) To capture the next frame, go back to step 2. The tegra_v4l2_camera driver
calls tegra_camera_capture_setup at the beginning, and then a worker thread
repeatedly calls tegra_camera_capture_start() and
tegra_camera_capture_stop(). See tegra_camera_work() ->
tegra_camera_capture_frame().
Note for VIP: Only a single syncpt is used for the VIP path. We use the
continuous VIP VSYNC syncpt to determine the completion of a frame transfer.
In addition, to start and finish the capture of a frame, the
VI_CAMERA_CONTROL register is used. See tegra_camera_capture_start() and
tegra_camera_capture_stop() to see how that register is used for the VIP path.
Essentially, steps 4, 5, and 6 are eliminated, and instead of writing to
TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND or TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
we write to VI_CAMERA_CONTROL to achieve the same purpose for VIP.
VIP versus CSI
==============
VI_VI_CORE_CONTROL bits 26:24 (INPUT_TO_CORE_EXT) should be set to 0
(use INPUT_TO_CORE).
VI_VI_INPUT_CONTROL bit 1 (VIP_INPUT_ENABLE) should be set to 1 (ENABLED),
bit 26:25 (SYNC_FORMAT) should be set to 1 (ITU656), and bit 27 (FIELD_DETECT)
should be set to 1 (ENABLED).
VI_H_DOWNSCALE_CONTROL bit 0 (INPUT_H_SIZE_SEL) should be set to 0 (VIP),
and bits 3:2 (INPUT_H_SIZE_SEL_EXT) should be set to 0 (USE INPUT_H_SIZE_SEL).
Rather than placing the image width and height into VI_CSI_PPA_H_ACTIVE and
VI_CSI_PPA_V_ACTIVE, respectively (or the CSI B counterparts), use
VI_VIP_H_ACTIVE and VI_VIP_V_ACTIVE bits 31:16. Bits 15:0 of VI_VIP_H_ACTIVE
and VI_VIP_V_ACTIVE are the number of clock cycles to wait after receiving
HSYNC or VSYNC before starting. This can be used to adjust the vertical and
horizontal back porches.
VI_PIN_INPUT_ENABLE should be set to 0x00006fff, which enables input pins
VHS, VVS, and VD11..VD0.
VI_PIN_INVERSION bits 1 and 2 can be used to invert input pins VHS and VVS,
respectively.
VI_CONT_SYNCPT_VIP_VSYNC bit 8 (enable VIP_VSYNC) should be set to 1, and
bits 7:0 should hold the index of the syncpt to be used. When this syncpt
is enabled, the syncpt specified by the index will increment by 1 every
time a VSYNC occurs. We use this syncpt to signal frame completion.
VI_CAMERA_CONTROL bit 0 should be set to 1 to start capturing. Writing a 0
to this bit is ignored, so to stop capturing, write 1 to bit 2.
|