9.1.6. PXA 摄像头主机驱动

作者:Robert Jarzmik <robert.jarzmik@free.fr>

9.1.6.1. 约束

  1. YUV422P 格式的图像尺寸 所有 YUV422P 图像都被强制要求宽度 x 高度 % 16 = 0。这是由于 DMA 约束,它只传输 8 字节倍数的平面。

9.1.6.2. 全局视频工作流程

  1. QCI 已停止 最初,QCI 接口是停止的。当一个缓冲区被排队时,调用 start_streaming,并且 QCI 启动。

  2. QCI 已启动 当 QCI 启动时,可以排队更多缓冲区,而无需停止捕获。新的缓冲区被“附加”到 DMA 链的末尾,并一个接一个地平稳捕获帧。

    一旦 QCI 接口中的缓冲区被填满,它将被标记为“完成”并从活动缓冲区列表中删除。然后它可以被用户空间应用程序重新排队或出队。

    一旦最后一个缓冲区被填满,QCI 接口就会停止。

  3. 捕获全局有限状态机模式

+----+                             +---+  +----+
| 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

9.1.6.3. DMA 使用

  1. DMA 流
    • 排队用于捕获的第一个缓冲区 一旦第一个缓冲区被排队用于捕获,QCI 就会启动,但数据传输不会启动。在“帧结束”中断时,irq 处理程序启动 DMA 链。

    • 捕获一个视频缓冲区 DMA 链开始将数据传输到视频缓冲区 RAM 页。当所有页面都传输完毕后,DMA irq 会在“ENDINTR”状态下被触发

    • 完成一个视频缓冲区 DMA irq 处理程序将视频缓冲区标记为“完成”,并将其从活动运行队列中删除。同时,下一个视频缓冲区(如果有)会通过 DMA 传输

    • 完成最后一个视频缓冲区 在最后一个视频缓冲区的 DMA irq 上,QCI 停止。

  2. DMA 准备好的缓冲区将具有以下结构

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

此结构由 dma->sg_cpu 指向。描述符的使用方式如下

  • desc-sg[i]:第 i 个描述符,将第 i 个 sg 元素传输到视频缓冲区散列收集

  • finisher:具有 ddadr=DADDR_STOP,dcmd=ENDIRQEN

  • linker:具有 ddadr=下一个视频缓冲区的 desc-sg[0],dcmd=0

对于下一个模式,我们假设 d0=desc-sg[0] .. dN=desc-sg[N],“f”代表 finisher,“l”代表 linker。一个典型的运行链是

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

链接完成后,链看起来像

    Videobuffer 1         Videobuffer 2         Videobuffer 3
+---------+----+---+  +----+----+----+---+  +----+----+----+---+
| d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
+---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
                 |    |                |    |
                 +----+                +----+
                                      new_link
  1. DMA 热链接时间片问题

由于 DMA 链接是在 DMA _正在_ 运行时完成的,因此链接可能在 DMA 从一个视频缓冲区跳到另一个视频缓冲区时完成。在模式上,如果遇到以下序列,这将是一个问题

  • DMA 链是 VideoBuffer1 + VideoBuffer2

  • 调用 pxa_videobuf_queue() 来排队 VideoBuffer3

  • DMA 控制器完成 VideoBuffer2,DMA 停止

 =>
    Videobuffer 1         Videobuffer 2
+---------+----+---+  +----+----+----+---+
| d0 | .. | dN | l |  | d0 | .. | dN | f |
+---------+----+-|-+  ^----+----+----+-^-+
                 |    |                |
                 +----+                +-- DMA DDADR loads DDADR_STOP
  • 调用 pxa_dma_add_tail_buf(),VideoBuffer2 的“finisher”被替换为到 VideoBuffer3 的“linker”(创建 new_link)

  • pxa_videobuf_queue() 完成

  • 调用 DMA irq 处理程序,它终止 VideoBuffer2

  • VideoBuffer3 捕获未在 DMA 链上调度(因为它已停止!!!)

    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() 这会检查 DMA 是否已完成,并且缓冲区仍在 pcdev->capture 列表中。如果是这种情况,捕获将重新启动,并且 VideoBuffer3 将在 DMA 链上调度。

  • DMA irq 处理程序完成

注意

如果 DMA 在 pxa_camera_check_link_miss() 读取 DDADR() 值后立即停止,我们保证当 DMA 完成缓冲区时,将再次调用 DMA irq 处理程序,并且将再次调用 pxa_camera_check_link_miss(),以重新调度 VideoBuffer3。