162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ciPXA-Camera Host Driver
462306a36Sopenharmony_ci======================
562306a36Sopenharmony_ci
662306a36Sopenharmony_ciAuthor: Robert Jarzmik <robert.jarzmik@free.fr>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ciConstraints
962306a36Sopenharmony_ci-----------
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cia) Image size for YUV422P format
1262306a36Sopenharmony_ci   All YUV422P images are enforced to have width x height % 16 = 0.
1362306a36Sopenharmony_ci   This is due to DMA constraints, which transfers only planes of 8 byte
1462306a36Sopenharmony_ci   multiples.
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciGlobal video workflow
1862306a36Sopenharmony_ci---------------------
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cia) QCI stopped
2162306a36Sopenharmony_ci   Initially, the QCI interface is stopped.
2262306a36Sopenharmony_ci   When a buffer is queued, start_streaming is called and the QCI starts.
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cib) QCI started
2562306a36Sopenharmony_ci   More buffers can be queued while the QCI is started without halting the
2662306a36Sopenharmony_ci   capture.  The new buffers are "appended" at the tail of the DMA chain, and
2762306a36Sopenharmony_ci   smoothly captured one frame after the other.
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci   Once a buffer is filled in the QCI interface, it is marked as "DONE" and
3062306a36Sopenharmony_ci   removed from the active buffers list. It can be then requeud or dequeued by
3162306a36Sopenharmony_ci   userland application.
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci   Once the last buffer is filled in, the QCI interface stops.
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cic) Capture global finite state machine schema
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci.. code-block:: none
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	+----+                             +---+  +----+
4062306a36Sopenharmony_ci	| DQ |                             | Q |  | DQ |
4162306a36Sopenharmony_ci	|    v                             |   v  |    v
4262306a36Sopenharmony_ci	+-----------+                     +------------------------+
4362306a36Sopenharmony_ci	|   STOP    |                     | Wait for capture start |
4462306a36Sopenharmony_ci	+-----------+         Q           +------------------------+
4562306a36Sopenharmony_ci	+-> | QCI: stop | ------------------> | QCI: run               | <------------+
4662306a36Sopenharmony_ci	|   | DMA: stop |                     | DMA: stop              |              |
4762306a36Sopenharmony_ci	|   +-----------+             +-----> +------------------------+              |
4862306a36Sopenharmony_ci	|                            /                            |                   |
4962306a36Sopenharmony_ci	|                           /             +---+  +----+   |                   |
5062306a36Sopenharmony_ci	|capture list empty        /              | Q |  | DQ |   | QCI Irq EOF       |
5162306a36Sopenharmony_ci	|                         /               |   v  |    v   v                   |
5262306a36Sopenharmony_ci	|   +--------------------+             +----------------------+               |
5362306a36Sopenharmony_ci	|   | DMA hotlink missed |             |    Capture running   |               |
5462306a36Sopenharmony_ci	|   +--------------------+             +----------------------+               |
5562306a36Sopenharmony_ci	|   | QCI: run           |     +-----> | QCI: run             | <-+           |
5662306a36Sopenharmony_ci	|   | DMA: stop          |    /        | DMA: run             |   |           |
5762306a36Sopenharmony_ci	|   +--------------------+   /         +----------------------+   | Other     |
5862306a36Sopenharmony_ci	|     ^                     /DMA still            |               | channels  |
5962306a36Sopenharmony_ci	|     | capture list       /  running             | DMA Irq End   | not       |
6062306a36Sopenharmony_ci	|     | not empty         /                       |               | finished  |
6162306a36Sopenharmony_ci	|     |                  /                        v               | yet       |
6262306a36Sopenharmony_ci	|   +----------------------+           +----------------------+   |           |
6362306a36Sopenharmony_ci	|   |  Videobuf released   |           |  Channel completed   |   |           |
6462306a36Sopenharmony_ci	|   +----------------------+           +----------------------+   |           |
6562306a36Sopenharmony_ci	+-- | QCI: run             |           | QCI: run             | --+           |
6662306a36Sopenharmony_ci	| DMA: run             |           | DMA: run             |               |
6762306a36Sopenharmony_ci	+----------------------+           +----------------------+               |
6862306a36Sopenharmony_ci		^                      /           |                           |
6962306a36Sopenharmony_ci		|          no overrun /            | overrun                   |
7062306a36Sopenharmony_ci		|                    /             v                           |
7162306a36Sopenharmony_ci	+--------------------+         /   +----------------------+               |
7262306a36Sopenharmony_ci	|  Frame completed   |        /    |     Frame overran    |               |
7362306a36Sopenharmony_ci	+--------------------+ <-----+     +----------------------+ restart frame |
7462306a36Sopenharmony_ci	| QCI: run           |             | QCI: stop            | --------------+
7562306a36Sopenharmony_ci	| DMA: run           |             | DMA: stop            |
7662306a36Sopenharmony_ci	+--------------------+             +----------------------+
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	Legend: - each box is a FSM state
7962306a36Sopenharmony_ci		- each arrow is the condition to transition to another state
8062306a36Sopenharmony_ci		- an arrow with a comment is a mandatory transition (no condition)
8162306a36Sopenharmony_ci		- arrow "Q" means : a buffer was enqueued
8262306a36Sopenharmony_ci		- arrow "DQ" means : a buffer was dequeued
8362306a36Sopenharmony_ci		- "QCI: stop" means the QCI interface is not enabled
8462306a36Sopenharmony_ci		- "DMA: stop" means all 3 DMA channels are stopped
8562306a36Sopenharmony_ci		- "DMA: run" means at least 1 DMA channel is still running
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ciDMA usage
8862306a36Sopenharmony_ci---------
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cia) DMA flow
9162306a36Sopenharmony_ci     - first buffer queued for capture
9262306a36Sopenharmony_ci       Once a first buffer is queued for capture, the QCI is started, but data
9362306a36Sopenharmony_ci       transfer is not started. On "End Of Frame" interrupt, the irq handler
9462306a36Sopenharmony_ci       starts the DMA chain.
9562306a36Sopenharmony_ci     - capture of one videobuffer
9662306a36Sopenharmony_ci       The DMA chain starts transferring data into videobuffer RAM pages.
9762306a36Sopenharmony_ci       When all pages are transferred, the DMA irq is raised on "ENDINTR" status
9862306a36Sopenharmony_ci     - finishing one videobuffer
9962306a36Sopenharmony_ci       The DMA irq handler marks the videobuffer as "done", and removes it from
10062306a36Sopenharmony_ci       the active running queue
10162306a36Sopenharmony_ci       Meanwhile, the next videobuffer (if there is one), is transferred by DMA
10262306a36Sopenharmony_ci     - finishing the last videobuffer
10362306a36Sopenharmony_ci       On the DMA irq of the last videobuffer, the QCI is stopped.
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cib) DMA prepared buffer will have this structure
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci.. code-block:: none
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci     +------------+-----+---------------+-----------------+
11062306a36Sopenharmony_ci     | desc-sg[0] | ... | desc-sg[last] | finisher/linker |
11162306a36Sopenharmony_ci     +------------+-----+---------------+-----------------+
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ciThis structure is pointed by dma->sg_cpu.
11462306a36Sopenharmony_ciThe descriptors are used as follows:
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci- desc-sg[i]: i-th descriptor, transferring the i-th sg
11762306a36Sopenharmony_ci  element to the video buffer scatter gather
11862306a36Sopenharmony_ci- finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
11962306a36Sopenharmony_ci- linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciFor the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N],
12262306a36Sopenharmony_ci"f" stands for finisher and "l" for linker.
12362306a36Sopenharmony_ciA typical running chain is :
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci.. code-block:: none
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci         Videobuffer 1         Videobuffer 2
12862306a36Sopenharmony_ci     +---------+----+---+  +----+----+----+---+
12962306a36Sopenharmony_ci     | d0 | .. | dN | l |  | d0 | .. | dN | f |
13062306a36Sopenharmony_ci     +---------+----+-|-+  ^----+----+----+---+
13162306a36Sopenharmony_ci                      |    |
13262306a36Sopenharmony_ci                      +----+
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciAfter the chaining is finished, the chain looks like :
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci.. code-block:: none
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci         Videobuffer 1         Videobuffer 2         Videobuffer 3
13962306a36Sopenharmony_ci     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
14062306a36Sopenharmony_ci     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
14162306a36Sopenharmony_ci     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
14262306a36Sopenharmony_ci                      |    |                |    |
14362306a36Sopenharmony_ci                      +----+                +----+
14462306a36Sopenharmony_ci                                           new_link
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cic) DMA hot chaining timeslice issue
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciAs DMA chaining is done while DMA _is_ running, the linking may be done
14962306a36Sopenharmony_ciwhile the DMA jumps from one Videobuffer to another. On the schema, that
15062306a36Sopenharmony_ciwould be a problem if the following sequence is encountered :
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci- DMA chain is Videobuffer1 + Videobuffer2
15362306a36Sopenharmony_ci- pxa_videobuf_queue() is called to queue Videobuffer3
15462306a36Sopenharmony_ci- DMA controller finishes Videobuffer2, and DMA stops
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci.. code-block:: none
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci      =>
15962306a36Sopenharmony_ci         Videobuffer 1         Videobuffer 2
16062306a36Sopenharmony_ci     +---------+----+---+  +----+----+----+---+
16162306a36Sopenharmony_ci     | d0 | .. | dN | l |  | d0 | .. | dN | f |
16262306a36Sopenharmony_ci     +---------+----+-|-+  ^----+----+----+-^-+
16362306a36Sopenharmony_ci                      |    |                |
16462306a36Sopenharmony_ci                      +----+                +-- DMA DDADR loads DDADR_STOP
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci- pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is
16762306a36Sopenharmony_ci  replaced by a "linker" to Videobuffer3 (creation of new_link)
16862306a36Sopenharmony_ci- pxa_videobuf_queue() finishes
16962306a36Sopenharmony_ci- the DMA irq handler is called, which terminates Videobuffer2
17062306a36Sopenharmony_ci- Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!)
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci.. code-block:: none
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci         Videobuffer 1         Videobuffer 2         Videobuffer 3
17562306a36Sopenharmony_ci     +---------+----+---+  +----+----+----+---+  +----+----+----+---+
17662306a36Sopenharmony_ci     | d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
17762306a36Sopenharmony_ci     +---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
17862306a36Sopenharmony_ci                      |    |                |    |
17962306a36Sopenharmony_ci                      +----+                +----+
18062306a36Sopenharmony_ci                                           new_link
18162306a36Sopenharmony_ci                                          DMA DDADR still is DDADR_STOP
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci- pxa_camera_check_link_miss() is called
18462306a36Sopenharmony_ci  This checks if the DMA is finished and a buffer is still on the
18562306a36Sopenharmony_ci  pcdev->capture list. If that's the case, the capture will be restarted,
18662306a36Sopenharmony_ci  and Videobuffer3 is scheduled on DMA chain.
18762306a36Sopenharmony_ci- the DMA irq handler finishes
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci.. note::
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci     If DMA stops just after pxa_camera_check_link_miss() reads DDADR()
19262306a36Sopenharmony_ci     value, we have the guarantee that the DMA irq handler will be called back
19362306a36Sopenharmony_ci     when the DMA will finish the buffer, and pxa_camera_check_link_miss() will
19462306a36Sopenharmony_ci     be called again, to reschedule Videobuffer3.
195