summaryrefslogtreecommitdiff
path: root/Documentation/media/v4l-drivers/pxa_camera.rst
blob: e4fbca755e1aa42f7b52c018d5377a080c43ba23 (plain) (blame)
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
.. SPDX-License-Identifier: GPL-2.0

PXA-Camera Host Driver
======================

Author: Robert Jarzmik <robert.jarzmik@free.fr>

Constraints
-----------

a) Image size for YUV422P format
   All YUV422P images are enforced to have width x height % 16 = 0.
   This is due to DMA constraints, which transfers only planes of 8 byte
   multiples.


Global video workflow
---------------------

a) QCI stopped
   Initialy, the QCI interface is stopped.
   When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts.

b) QCI started
   More buffers can be queued while the QCI is started without halting the
   capture.  The new buffers are "appended" at the tail of the DMA chain, and
   smoothly captured one frame after the other.

   Once a buffer is filled in the QCI interface, it is marked as "DONE" and
   removed from the active buffers list. It can be then requeud or dequeued by
   userland application.

   Once the last buffer is filled in, the QCI interface stops.

c) Capture global finite state machine schema

.. code-block:: none

	+----+                             +---+  +----+
	| DQ |                             | Q |  | DQ |
	|    v                             |   v  |    v
	+-----------+                     +------------------------+
	|   STOP    |                     | Wait for capture start |
	+-----------+         Q           +------------------------+
	+-> | QCI: stop | ------------------> | QCI: run               | <------------+
	|   | DMA: stop |                     | DMA: stop              |              |
	|   +-----------+             +-----> +------------------------+              |
	|                            /                            |                   |
	|                           /             +---+  +----+   |                   |
	|capture list empty        /              | Q |  | DQ |   | QCI Irq EOF       |
	|                         /               |   v  |    v   v                   |
	|   +--------------------+             +----------------------+               |
	|   | DMA hotlink missed |             |    Capture running   |               |
	|   +--------------------+             +----------------------+               |
	|   | QCI: run           |     +-----> | QCI: run             | <-+           |
	|   | DMA: stop          |    /        | DMA: run             |   |           |
	|   +--------------------+   /         +----------------------+   | Other     |
	|     ^                     /DMA still            |               | channels  |
	|     | capture list       /  running             | DMA Irq End   | not       |
	|     | not empty         /                       |               | finished  |
	|     |                  /                        v               | yet       |
	|   +----------------------+           +----------------------+   |           |
	|   |  Videobuf released   |           |  Channel completed   |   |           |
	|   +----------------------+           +----------------------+   |           |
	+-- | QCI: run             |           | QCI: run             | --+           |
	| DMA: run             |           | DMA: run             |               |
	+----------------------+           +----------------------+               |
		^                      /           |                           |
		|          no overrun /            | overrun                   |
		|                    /             v                           |
	+--------------------+         /   +----------------------+               |
	|  Frame completed   |        /    |     Frame overran    |               |
	+--------------------+ <-----+     +----------------------+ restart frame |
	| QCI: run           |             | QCI: stop            | --------------+
	| DMA: run           |             | DMA: stop            |
	+--------------------+             +----------------------+

	Legend: - each box is a FSM state
		- each arrow is the condition to transition to another state
		- an arrow with a comment is a mandatory transition (no condition)
		- arrow "Q" means : a buffer was enqueued
		- arrow "DQ" means : a buffer was dequeued
		- "QCI: stop" means the QCI interface is not enabled
		- "DMA: stop" means all 3 DMA channels are stopped
		- "DMA: run" means at least 1 DMA channel is still running

DMA usage
---------

a) DMA flow
     - first buffer queued for capture
       Once a first buffer is queued for capture, the QCI is started, but data
       transfer is not started. On "End Of Frame" interrupt, the irq handler
       starts the DMA chain.
     - capture of one videobuffer
       The DMA chain starts transferring data into videobuffer RAM pages.
       When all pages are transferred, the DMA irq is raised on "ENDINTR" status
     - finishing one videobuffer
       The DMA irq handler marks the videobuffer as "done", and removes it from
       the active running queue
       Meanwhile, the next videobuffer (if there is one), is transferred by DMA
     - finishing the last videobuffer
       On the DMA irq of the last videobuffer, the QCI is stopped.

b) DMA prepared buffer will have this structure

.. code-block:: none

     +------------+-----+---------------+-----------------+
     | desc-sg[0] | ... | desc-sg[last] | finisher/linker |
     +------------+-----+---------------+-----------------+

This structure is pointed by dma->sg_cpu.
The descriptors are used as follows:

- desc-sg[i]: i-th descriptor, transferring the i-th sg
  element to the video buffer scatter gather
- finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
- linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0

For the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N],
"f" stands for finisher and "l" for linker.
A typical running chain is :

.. code-block:: none

         Videobuffer 1         Videobuffer 2
     +---------+----+---+  +----+----+----+---+
     | d0 | .. | dN | l |  | d0 | .. | dN | f |
     +---------+----+-|-+  ^----+----+----+---+
                      |    |
                      +----+

After the chaining is finished, the chain looks like :

.. code-block:: none

         Videobuffer 1         Videobuffer 2         Videobuffer 3
     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
                      |    |                |    |
                      +----+                +----+
                                           new_link

c) DMA hot chaining timeslice issue

As DMA chaining is done while DMA _is_ running, the linking may be done
while the DMA jumps from one Videobuffer to another. On the schema, that
would be a problem if the following sequence is encountered :

- DMA chain is Videobuffer1 + Videobuffer2
- pxa_videobuf_queue() is called to queue Videobuffer3
- DMA controller finishes Videobuffer2, and DMA stops

.. code-block:: none

      =>
         Videobuffer 1         Videobuffer 2
     +---------+----+---+  +----+----+----+---+
     | d0 | .. | dN | l |  | d0 | .. | dN | f |
     +---------+----+-|-+  ^----+----+----+-^-+
                      |    |                |
                      +----+                +-- DMA DDADR loads DDADR_STOP

- pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is
  replaced by a "linker" to Videobuffer3 (creation of new_link)
- pxa_videobuf_queue() finishes
- the DMA irq handler is called, which terminates Videobuffer2
- Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!)

.. code-block:: none

         Videobuffer 1         Videobuffer 2         Videobuffer 3
     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
                      |    |                |    |
                      +----+                +----+
                                           new_link
                                          DMA DDADR still is DDADR_STOP

- pxa_camera_check_link_miss() is called
  This checks if the DMA is finished and a buffer is still on the
  pcdev->capture list. If that's the case, the capture will be restarted,
  and Videobuffer3 is scheduled on DMA chain.
- the DMA irq handler finishes

.. note::

     If DMA stops just after pxa_camera_check_link_miss() reads DDADR()
     value, we have the guarantee that the DMA irq handler will be called back
     when the DMA will finish the buffer, and pxa_camera_check_link_miss() will
     be called again, to reschedule Videobuffer3.