Documentation/driver-api/media/drivers/pxa_camera.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

PXA-Camera Host Driver

PXA camera의 QCI capture FSM, DMA descriptor chain, hot-link race와 복구 보장을 설명하는 전문 번역입니다.

Source pathDocumentation/driver-api/media/drivers/pxa_camera.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

pxa_camera.rst:1-194

PXA-Camera host driver는 QCI의 frame boundary와 세 DMA channel의 descriptor chain을 함께 관리합니다. 실행 중인 chain의 tail을 바꾸는 race는 `DDADR_STOP`과 capture list를 검사해 복구하며, 검사 직후 발생하는 정지도 다음 DMA IRQ에서 다시 확인합니다.

문서 구성
원문 줄내용
1-16YUV422P DMA alignment 제약
17-86Global capture workflow와 FSM
87-120DMA lifecycle과 descriptor 구조
121-145Videobuffer chain append
146-170Hot-link timeslice race
171-194`pxa_camera_check_link_miss()` 복구

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 PXA-Camera Host Driver
4 ======================
5
6 Author: Robert Jarzmik <[email protected]>
7
8 Constraints
9 -----------
10
11 a) Image size for YUV422P format
12 All YUV422P images are enforced to have width x height % 16 = 0.
13 This is due to DMA constraints, which transfers only planes of 8 byte
14 multiples.
15
16
17 Global video workflow
18 ---------------------
19
20 a) QCI stopped
21 Initially, the QCI interface is stopped.
22 When a buffer is queued, start_streaming is called and the QCI starts.
23
24 b) QCI started
25 More buffers can be queued while the QCI is started without halting the
26 capture. The new buffers are "appended" at the tail of the DMA chain, and
27 smoothly captured one frame after the other.
28
29 Once a buffer is filled in the QCI interface, it is marked as "DONE" and
30 removed from the active buffers list. It can be then requeud or dequeued by
31 userland application.
32
33 Once the last buffer is filled in, the QCI interface stops.
34
35 c) Capture global finite state machine schema
36
37 .. code-block:: none
38
39 +----+ +---+ +----+
40 | DQ | | Q | | DQ |
41 | v | v | v
42 +-----------+ +------------------------+
43 | STOP | | Wait for capture start |
44 +-----------+ Q +------------------------+
45 +-> | QCI: stop | ------------------> | QCI: run | <------------+
46 | | DMA: stop | | DMA: stop | |
47 | +-----------+ +-----> +------------------------+ |
48 | / | |
49 | / +---+ +----+ | |
50 |capture list empty / | Q | | DQ | | QCI Irq EOF |
51 | / | v | v v |
52 | +--------------------+ +----------------------+ |
53 | | DMA hotlink missed | | Capture running | |
54 | +--------------------+ +----------------------+ |
55 | | QCI: run | +-----> | QCI: run | <-+ |
56 | | DMA: stop | / | DMA: run | | |
57 | +--------------------+ / +----------------------+ | Other |
58 | ^ /DMA still | | channels |
59 | | capture list / running | DMA Irq End | not |
60 | | not empty / | | finished |
61 | | / v | yet |
62 | +----------------------+ +----------------------+ | |
63 | | Videobuf released | | Channel completed | | |
64 | +----------------------+ +----------------------+ | |
65 +-- | QCI: run | | QCI: run | --+ |
66 | DMA: run | | DMA: run | |
67 +----------------------+ +----------------------+ |
68 ^ / | |
69 | no overrun / | overrun |
70 | / v |
71 +--------------------+ / +----------------------+ |
72 | Frame completed | / | Frame overran | |
73 +--------------------+ <-----+ +----------------------+ restart frame |
74 | QCI: run | | QCI: stop | --------------+
75 | DMA: run | | DMA: stop |
76 +--------------------+ +----------------------+
77
78 Legend: - each box is a FSM state
79 - each arrow is the condition to transition to another state
80 - an arrow with a comment is a mandatory transition (no condition)
81 - arrow "Q" means : a buffer was enqueued
82 - arrow "DQ" means : a buffer was dequeued
83 - "QCI: stop" means the QCI interface is not enabled
84 - "DMA: stop" means all 3 DMA channels are stopped
85 - "DMA: run" means at least 1 DMA channel is still running
86
87 DMA usage
88 ---------
89
90 a) DMA flow
91 - first buffer queued for capture
92 Once a first buffer is queued for capture, the QCI is started, but data
93 transfer is not started. On "End Of Frame" interrupt, the irq handler
94 starts the DMA chain.
95 - capture of one videobuffer
96 The DMA chain starts transferring data into videobuffer RAM pages.
97 When all pages are transferred, the DMA irq is raised on "ENDINTR" status
98 - finishing one videobuffer
99 The DMA irq handler marks the videobuffer as "done", and removes it from
100 the active running queue
101 Meanwhile, the next videobuffer (if there is one), is transferred by DMA
102 - finishing the last videobuffer
103 On the DMA irq of the last videobuffer, the QCI is stopped.
104
105 b) DMA prepared buffer will have this structure
106
107 .. code-block:: none
108
109 +------------+-----+---------------+-----------------+
110 | desc-sg[0] | ... | desc-sg[last] | finisher/linker |
111 +------------+-----+---------------+-----------------+
112
113 This structure is pointed by dma->sg_cpu.
114 The descriptors are used as follows:
115
116 - desc-sg[i]: i-th descriptor, transferring the i-th sg
117 element to the video buffer scatter gather
118 - finisher: has ddadr=DADDR_STOP, dcmd=ENDIRQEN
119 - linker: has ddadr= desc-sg[0] of next video buffer, dcmd=0
120
121 For the next schema, let's assume d0=desc-sg[0] .. dN=desc-sg[N],
122 "f" stands for finisher and "l" for linker.
123 A typical running chain is :
124
125 .. code-block:: none
126
127 Videobuffer 1 Videobuffer 2
128 +---------+----+---+ +----+----+----+---+
129 | d0 | .. | dN | l | | d0 | .. | dN | f |
130 +---------+----+-|-+ ^----+----+----+---+
131 | |
132 +----+
133
134 After the chaining is finished, the chain looks like :
135
136 .. code-block:: none
137
138 Videobuffer 1 Videobuffer 2 Videobuffer 3
139 +---------+----+---+ +----+----+----+---+ +----+----+----+---+
140 | d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
141 +---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
142 | | | |
143 +----+ +----+
144 new_link
145
146 c) DMA hot chaining timeslice issue
147
148 As DMA chaining is done while DMA _is_ running, the linking may be done
149 while the DMA jumps from one Videobuffer to another. On the schema, that
150 would be a problem if the following sequence is encountered :
151
152 - DMA chain is Videobuffer1 + Videobuffer2
153 - pxa_videobuf_queue() is called to queue Videobuffer3
154 - DMA controller finishes Videobuffer2, and DMA stops
155
156 .. code-block:: none
157
158 =>
159 Videobuffer 1 Videobuffer 2
160 +---------+----+---+ +----+----+----+---+
161 | d0 | .. | dN | l | | d0 | .. | dN | f |
162 +---------+----+-|-+ ^----+----+----+-^-+
163 | | |
164 +----+ +-- DMA DDADR loads DDADR_STOP
165
166 - pxa_dma_add_tail_buf() is called, the Videobuffer2 "finisher" is
167 replaced by a "linker" to Videobuffer3 (creation of new_link)
168 - pxa_videobuf_queue() finishes
169 - the DMA irq handler is called, which terminates Videobuffer2
170 - Videobuffer3 capture is not scheduled on DMA chain (as it stopped !!!)
171
172 .. code-block:: none
173
174 Videobuffer 1 Videobuffer 2 Videobuffer 3
175 +---------+----+---+ +----+----+----+---+ +----+----+----+---+
176 | d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
177 +---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
178 | | | |
179 +----+ +----+
180 new_link
181 DMA DDADR still is DDADR_STOP
182
183 - pxa_camera_check_link_miss() is called
184 This checks if the DMA is finished and a buffer is still on the
185 pcdev->capture list. If that's the case, the capture will be restarted,
186 and Videobuffer3 is scheduled on DMA chain.
187 - the DMA irq handler finishes
188
189 .. note::
190
191 If DMA stops just after pxa_camera_check_link_miss() reads DDADR()
192 value, we have the guarantee that the DMA irq handler will be called back
193 when the DMA will finish the buffer, and pxa_camera_check_link_miss() will
194 be called again, to reschedule Videobuffer3.
195

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

YUV422P image 제약

1-16

Robert Jarzmik이 작성한 이 `GPL-2.0` 문서는 PXA-Camera host driver를 설명합니다. `YUV422P` 형식의 모든 image는 `width × height % 16 = 0`을 만족해야 합니다.

이 제약은 DMA가 8-byte 배수 크기의 plane만 전송할 수 있기 때문에 생깁니다. 따라서 format negotiation과 buffer 준비 단계에서 image geometry가 이 조건을 만족해야 합니다.

YUV422P capture 제약
항목조건
Pixel format`YUV422P`
Image geometry`width × height % 16 = 0`
DMA plane granularity8-byte multiples
적용 시점Format 설정과 capture buffer 준비

.. SPDX-License-Identifier: GPL-2.0

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

Author: Robert Jarzmik <[email protected]>

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.

전체 video capture 흐름

17-34

초기에는 QCI interface가 정지해 있습니다. 첫 buffer가 queue되면 `start_streaming`이 호출되고 QCI가 시작됩니다.

QCI가 동작 중일 때도 capture를 멈추지 않고 buffer를 더 queue할 수 있습니다. 새 buffer는 DMA chain의 tail에 append되어 frame이 차례로 부드럽게 capture됩니다.

QCI가 buffer 하나를 채우면 해당 buffer를 `DONE`으로 표시하고 active buffer list에서 제거합니다. 이후 userspace application은 그 buffer를 다시 queue하거나 dequeue할 수 있습니다. 마지막 buffer까지 채우면 QCI interface가 멈춥니다.

Global capture workflow
QCI stoppedFirst buffer queuedstart_streamingQCI started
QCI runningAppend new buffer at DMA tailCapture frames in order
Buffer filledMark DONERemove from active listUserspace requeue or dequeue
Last buffer filledQCI stopped

첫 queue가 QCI를 시작하고 마지막 완료가 QCI를 정지시킵니다.

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

a) QCI stopped
   Initially, the QCI interface is stopped.
   When a buffer is queued, start_streaming is called and 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.

Capture finite-state machine

35-86

원문의 FSM에서 각 box는 state, 각 arrow는 다른 state로 이동하는 condition입니다. 설명이 붙은 arrow는 별도 조건 없이 반드시 일어나는 전이입니다. `Q`는 buffer enqueue, `DQ`는 buffer dequeue를 뜻합니다.

`QCI: stop`은 QCI interface가 disable된 상태이고, `DMA: stop`은 세 DMA channel이 모두 정지한 상태입니다. `DMA: run`은 최소 한 channel이 아직 동작 중임을 뜻합니다.

STOP에서 `Q`가 발생하면 QCI는 동작하지만 DMA는 EOF를 기다리는 `Wait for capture start`로 갑니다. QCI EOF interrupt가 오면 DMA를 시작해 `Capture running`으로 전이합니다. Channel 완료가 이어지며 모든 channel이 끝나면 frame 완료 또는 overrun을 판정합니다.

Overrun이면 QCI와 DMA를 멈추고 frame을 restart합니다. Capture list가 비면 STOP으로 돌아갑니다. DMA hot-link를 놓친 경우 QCI는 계속 동작하지만 DMA가 멈춘 `DMA hotlink missed` 상태가 되며, 남은 buffer가 있으면 capture를 재시작합니다.

FSM state와 engine 상태
StateQCIDMA주요 진입/이탈
STOPstopstop`Q` → Wait for capture start
Wait for capture startrunstopQCI IRQ EOF → Capture running
Capture runningrunrunDMA IRQ End → Channel completed
Channel completedrunrun다른 channel 대기 또는 frame 판정
Frame completedrunrunNo overrun → Videobuf released
Frame overranstopstopRestart frame
Videobuf releasedrunrunList empty → STOP
DMA hotlink missedrunstopList not empty → restart capture

원문의 Q/DQ self-transition과 mandatory transition 의미를 상태별로 정리했습니다.

주요 FSM 실행 경로
STOPQWait for capture startQCI IRQ EOFCapture running
Capture runningDMA IRQ EndChannel completedAll channels finishedFrame completed
Frame completedVideobuf releasedCapture list emptySTOP
Channel completedOverrunFrame overranRestart frameWait for capture start
Videobuf releasedDMA still stopped with buffers pendingDMA hotlink missedRestart capture

정상 frame 완료와 overrun/hot-link miss 복구 경로를 분리했습니다.

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 capture 흐름

87-104

첫 capture buffer가 queue되면 QCI는 시작되지만 data transfer는 즉시 시작되지 않습니다. `End Of Frame` interrupt에서 IRQ handler가 DMA chain을 시작합니다.

DMA chain은 videobuffer의 RAM page로 data를 전송합니다. 모든 page 전송이 끝나면 DMA가 `ENDINTR` status로 IRQ를 발생시킵니다.

DMA IRQ handler는 videobuffer를 `done`으로 표시하고 active running queue에서 제거합니다. 다음 videobuffer가 있으면 DMA가 동시에 이어서 전송하며, 마지막 videobuffer의 DMA IRQ에서는 QCI를 정지합니다.

DMA buffer lifecycle
First buffer queuedStart QCIWait for End Of Frame
QCI EOF IRQStart DMA chainTransfer RAM pages
All pages transferredDMA ENDINTR IRQMark buffer doneRemove from active queue
Next buffer existsDMA continues with next videobuffer
Last videobuffer IRQStop QCI

QCI EOF에서 DMA를 시작하고 마지막 DMA 완료에서 QCI를 멈춥니다.

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.

DMA prepared buffer 구조

105-120

준비된 DMA buffer는 여러 `desc-sg[]` descriptor와 마지막 `finisher` 또는 `linker`로 구성되며 `dma->sg_cpu`가 이 구조를 가리킵니다.

`desc-sg[i]`는 video buffer scatter-gather의 i번째 element를 전송하는 i번째 descriptor입니다. `finisher`는 `ddadr=DADDR_STOP`, `dcmd=ENDIRQEN`으로 chain을 끝내고 interrupt를 요청합니다. `linker`는 `ddadr`가 다음 video buffer의 `desc-sg[0]`을 가리키며 `dcmd=0`입니다.

DMA descriptor 의미
요소`ddadr``dcmd`역할
`desc-sg[i]`다음 descriptorSG transfer commandi번째 SG element 전송
`finisher``DADDR_STOP``ENDIRQEN`현재 chain 종료와 IRQ
`linker`다음 buffer의 `desc-sg[0]``0`다음 videobuffer로 연결

Prepared DMA buffer layout
dma->sg_cpudesc-sg[0]...desc-sg[last]finisher or linker

`dma->sg_cpu`가 첫 descriptor를 가리키며 마지막 slot은 finisher 또는 linker입니다.

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

Videobuffer DMA chain 연결

121-145

아래 표기에서 `d0`부터 `dN`은 각 buffer의 `desc-sg[0]`부터 `desc-sg[N]`, `f`는 finisher, `l`은 linker를 뜻합니다.

두 buffer의 일반적인 running chain에서 Videobuffer 1의 마지막 `l`은 Videobuffer 2의 `d0`을 가리키고, Videobuffer 2는 `f`로 끝납니다.

Videobuffer 3을 append하면 Videobuffer 2의 마지막 요소가 `f`에서 `l`로 바뀌어 Videobuffer 3의 `d0`을 가리키는 `new_link`가 됩니다. 새 tail인 Videobuffer 3은 `f`로 끝납니다.

두 videobuffer running chain
Videobuffer 1: d0 ... dNlVideobuffer 2: d0 ... dNf

첫 buffer는 linker로 다음 buffer에 연결되고 tail만 finisher를 갖습니다.

세 번째 buffer append 후
Videobuffer 1: d0 ... dNlVideobuffer 2: d0 ... dNlVideobuffer 3: d0 ... dNf
Videobuffer 2 old finisherReplace with linkernew_link to Videobuffer 3 d0

기존 tail의 finisher를 linker로 교체한 `new_link`가 새 tail을 연결합니다.

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