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