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 接口中的一个缓冲区被填满,它将被标记为“DONE”并从活动缓冲区列表中删除。 然后可以被用户空间应用程序重新入队或出队。

    一旦最后一个缓冲区被填满,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 处理程序将视频缓冲区标记为 “done”,并将其从活动运行队列中删除。 同时,下一个视频缓冲区(如果存在)由 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: 具有下一个视频缓冲区的 desc-sg[0] 的 ddadr=,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。