<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://yangchao315.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://yangchao315.github.io/" rel="alternate" type="text/html" /><updated>2026-03-27T10:30:51+00:00</updated><id>https://yangchao315.github.io/feed.xml</id><title type="html">Shamrock</title><subtitle>我的随笔</subtitle><entry><title type="html">Linux DRM 驱动中的 Atomic Commit 机制详解</title><link href="https://yangchao315.github.io/DRM-Atomic-Commit/" rel="alternate" type="text/html" title="Linux DRM 驱动中的 Atomic Commit 机制详解" /><published>2026-03-27T00:00:00+00:00</published><updated>2026-03-27T00:00:00+00:00</updated><id>https://yangchao315.github.io/DRM-Atomic-Commit</id><content type="html" xml:base="https://yangchao315.github.io/DRM-Atomic-Commit/"><![CDATA[<!-- more -->
<ul>
  <li><a href="#linux-drm-驱动中的-atomic-commit-机制详解">Linux DRM 驱动中的 Atomic Commit 机制详解</a>
    <ul>
      <li><a href="#1-背景与动机">1. 背景与动机</a></li>
      <li><a href="#2-核心数据结构">2. 核心数据结构</a>
        <ul>
          <li><a href="#21-drm_atomic_state">2.1 drm_atomic_state</a></li>
          <li><a href="#22-各对象的-state-结构">2.2 各对象的 state 结构</a></li>
        </ul>
      </li>
      <li><a href="#3-atomic-commit-流程">3. Atomic Commit 流程</a>
        <ul>
          <li><a href="#31-用户空间接口">3.1 用户空间接口</a></li>
          <li><a href="#32-内核处理流程">3.2 内核处理流程</a></li>
          <li><a href="#33-check-阶段">3.3 check 阶段</a></li>
          <li><a href="#34-commit-阶段">3.4 commit 阶段</a></li>
        </ul>
      </li>
      <li><a href="#4-驱动实现要点">4. 驱动实现要点</a>
        <ul>
          <li><a href="#41-atomic_check-回调">4.1 atomic_check 回调</a></li>
          <li><a href="#42-atomic_commit_tail-回调">4.2 atomic_commit_tail 回调</a></li>
        </ul>
      </li>
      <li><a href="#5-异步提交与-commit_work">5. 异步提交与 commit_work</a></li>
      <li><a href="#6-与旧版-legacy-接口的对比">6. 与旧版 legacy 接口的对比</a></li>
      <li><a href="#7-常见问题排查">7. 常见问题排查</a></li>
    </ul>
  </li>
</ul>

<h1 id="linux-drm-驱动中的-atomic-commit-机制详解">Linux DRM 驱动中的 Atomic Commit 机制详解</h1>

<p>DRM（Direct Rendering Manager）子系统从 Linux 4.2 起引入了 atomic modeset 机制，用于原子地更新显示硬件状态，避免中间状态的撕裂（tearing）和不一致。本文深入分析 atomic commit 的设计思路、核心数据结构以及驱动实现方式。</p>

<h2 id="1-背景与动机">1. 背景与动机</h2>

<p>传统的 legacy KMS 接口（<code class="language-plaintext highlighter-rouge">drmModeSetCrtc</code>、<code class="language-plaintext highlighter-rouge">drmModePageFlip</code> 等）每次只能更新单一对象（CRTC/Plane/Connector），多个对象的协同更新无法保证原子性，容易产生以下问题：</p>

<ul>
  <li>屏幕闪烁（中间帧显示了不完整的配置）</li>
  <li>多 CRTC 同步困难（多屏场景）</li>
  <li>驱动内部难以做硬件校验（check 与 commit 分离不清晰）</li>
</ul>

<p>Atomic modeset 将一次显示更新封装为一个”事务”：先 check，再 commit，要么全部成功，要么回滚到原有状态。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>用户空间                 内核 DRM 核心               驱动
   |                         |                        |
   |  DRM_IOCTL_MODE_ATOMIC  |                        |
   |------------------------&gt;|                        |
   |                         |  atomic_check()        |
   |                         |-----------------------&gt;|
   |                         |  &lt;------ ok/err -------|
   |                         |  atomic_commit()       |
   |                         |-----------------------&gt;|
   |                         |  &lt;------ done ---------|
   |&lt;------------------------|                        |
</code></pre></div></div>

<h2 id="2-核心数据结构">2. 核心数据结构</h2>

<h3 id="21-drm_atomic_state">2.1 drm_atomic_state</h3>

<p><code class="language-plaintext highlighter-rouge">drm_atomic_state</code> 是整个事务的容器，记录了本次 commit 涉及的所有对象（CRTC、Plane、Connector）的新旧状态。</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* include/drm/drm_atomic.h */</span>
<span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">kref</span> <span class="n">ref</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span>

    <span class="n">bool</span> <span class="n">allow_modeset</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">legacy_cursor_update</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">async_update</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">duplicated</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">__drm_planes_state</span>   <span class="o">*</span><span class="n">planes</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">__drm_crtcs_state</span>    <span class="o">*</span><span class="n">crtcs</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">__drm_connectors_state</span> <span class="o">*</span><span class="n">connectors</span><span class="p">;</span>

    <span class="kt">int</span> <span class="n">num_connector</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_modeset_acquire_ctx</span> <span class="o">*</span><span class="n">acquire_ctx</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="o">*</span><span class="n">fake_commit</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">work_struct</span> <span class="n">commit_work</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>每个条目同时保存旧 state 指针（<code class="language-plaintext highlighter-rouge">old_state</code>）和新 state 指针（<code class="language-plaintext highlighter-rouge">new_state</code>），便于在 check 失败时恢复。</p>

<h3 id="22-各对象的-state-结构">2.2 各对象的 state 结构</h3>

<p>DRM 中三类可更新对象各自有对应的 state 结构：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* CRTC state */</span>
<span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">enable</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">active</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">planes_changed</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">mode_changed</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">active_changed</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">connectors_changed</span> <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">drm_display_mode</span> <span class="n">mode</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_display_mode</span> <span class="n">adjusted_mode</span><span class="p">;</span>

    <span class="n">u32</span> <span class="n">plane_mask</span><span class="p">;</span>
    <span class="n">u32</span> <span class="n">connector_mask</span><span class="p">;</span>
    <span class="n">u32</span> <span class="n">encoder_mask</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="o">*</span><span class="n">commit</span><span class="p">;</span>
    <span class="cm">/* ... */</span>
<span class="p">};</span>

<span class="cm">/* Plane state */</span>
<span class="k">struct</span> <span class="n">drm_plane_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_plane</span> <span class="o">*</span><span class="n">plane</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_framebuffer</span> <span class="o">*</span><span class="n">fb</span><span class="p">;</span>

    <span class="cm">/* 源矩形（Q16.16 定点数，像素坐标）*/</span>
    <span class="kt">uint32_t</span> <span class="n">src_x</span><span class="p">,</span> <span class="n">src_y</span><span class="p">,</span> <span class="n">src_w</span><span class="p">,</span> <span class="n">src_h</span><span class="p">;</span>
    <span class="cm">/* 目标矩形（整数，屏幕坐标）*/</span>
    <span class="kt">int32_t</span> <span class="n">crtc_x</span><span class="p">,</span> <span class="n">crtc_y</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">crtc_w</span><span class="p">,</span> <span class="n">crtc_h</span><span class="p">;</span>

    <span class="cm">/* rotation / z-order / alpha */</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">rotation</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">zpos</span><span class="p">;</span>
    <span class="n">u16</span> <span class="n">alpha</span><span class="p">;</span>
    <span class="cm">/* ... */</span>
<span class="p">};</span>
</code></pre></div></div>

<p>驱动可以通过继承这些结构扩展私有字段：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">meson_plane_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_plane_state</span> <span class="n">base</span><span class="p">;</span> <span class="cm">/* 必须放第一位 */</span>
    <span class="cm">/* 驱动私有字段 */</span>
    <span class="n">bool</span> <span class="n">premult_alpha</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<h2 id="3-atomic-commit-流程">3. Atomic Commit 流程</h2>

<h3 id="31-用户空间接口">3.1 用户空间接口</h3>

<p>用户空间通过 <code class="language-plaintext highlighter-rouge">DRM_IOCTL_MODE_ATOMIC</code> ioctl 发起请求，传入若干 <code class="language-plaintext highlighter-rouge">(object_id, property_id, value)</code> 三元组，由内核统一解析并映射到各对象的 state 字段。</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* libdrm 调用示例 */</span>
<span class="n">drmModeAtomicReqPtr</span> <span class="n">req</span> <span class="o">=</span> <span class="n">drmModeAtomicAlloc</span><span class="p">();</span>
<span class="n">drmModeAtomicAddProperty</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">plane_id</span><span class="p">,</span> <span class="n">prop_fb_id</span><span class="p">,</span>   <span class="n">fb_id</span><span class="p">);</span>
<span class="n">drmModeAtomicAddProperty</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">plane_id</span><span class="p">,</span> <span class="n">prop_crtc_id</span><span class="p">,</span> <span class="n">crtc_id</span><span class="p">);</span>
<span class="n">drmModeAtomicAddProperty</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">plane_id</span><span class="p">,</span> <span class="n">prop_src_w</span><span class="p">,</span>   <span class="n">width</span> <span class="o">&lt;&lt;</span> <span class="mi">16</span><span class="p">);</span>
<span class="n">drmModeAtomicAddProperty</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">plane_id</span><span class="p">,</span> <span class="n">prop_crtc_w</span><span class="p">,</span>  <span class="n">width</span><span class="p">);</span>

<span class="kt">uint32_t</span> <span class="n">flags</span> <span class="o">=</span> <span class="n">DRM_MODE_ATOMIC_ALLOW_MODESET</span><span class="p">;</span>
<span class="n">drmModeAtomicCommit</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">req</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">drmModeAtomicFree</span><span class="p">(</span><span class="n">req</span><span class="p">);</span>
</code></pre></div></div>

<p>常用 flags：</p>

<table>
  <thead>
    <tr>
      <th>Flag</th>
      <th>含义</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_TEST_ONLY</code></td>
      <td>只做 check，不实际提交</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_NONBLOCK</code></td>
      <td>非阻塞提交（异步）</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_ALLOW_MODESET</code></td>
      <td>允许 modeset（改分辨率/时序）</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_PAGE_FLIP_EVENT</code></td>
      <td>提交完成后发送 page-flip 事件</td>
    </tr>
  </tbody>
</table>

<h3 id="32-内核处理流程">3.2 内核处理流程</h3>

<p>ioctl 入口为 <code class="language-plaintext highlighter-rouge">drm_mode_atomic_ioctl()</code>，主要步骤如下：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>drm_mode_atomic_ioctl()
  └── drm_atomic_helper_commit()
        ├── drm_atomic_helper_prepare_planes()   // 分配/pin framebuffer
        ├── drm_atomic_helper_check()            // 驱动 check 回调
        │     ├── drm_atomic_helper_check_modeset()
        │     └── drm_atomic_helper_check_planes()
        └── drm_atomic_helper_commit_tail()      // 实际硬件更新
              ├── drm_atomic_helper_commit_modeset_disables()
              ├── drm_atomic_helper_commit_planes()
              ├── drm_atomic_helper_commit_modeset_enables()
              └── drm_atomic_helper_wait_for_flip_done()
</code></pre></div></div>

<h3 id="33-check-阶段">3.3 check 阶段</h3>

<p>check 阶段不修改任何硬件寄存器，只做合法性验证：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* drivers/gpu/drm/drm_atomic_helper.c */</span>
<span class="kt">int</span> <span class="nf">drm_atomic_helper_check</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span>
                             <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">ret</span><span class="p">;</span>

    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_check_modeset</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">mode_config</span><span class="p">.</span><span class="n">normalize_zpos</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_normalize_zpos</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_check_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ret</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span><span class="p">)</span>
        <span class="n">state</span><span class="o">-&gt;</span><span class="n">async_update</span> <span class="o">=</span> <span class="o">!</span><span class="n">drm_atomic_helper_async_check</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>

    <span class="n">drm_self_refresh_helper_alter_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>驱动在 <code class="language-plaintext highlighter-rouge">atomic_check</code> 回调中对私有约束（带宽、格式、缩放比例等）做额外校验，返回非零值即触发回滚。</p>

<h3 id="34-commit-阶段">3.4 commit 阶段</h3>

<p>commit 阶段负责将新 state 写入硬件，分为三步：</p>

<ol>
  <li><strong>disable</strong> 不再使用的编码器/CRTC</li>
  <li><strong>update planes</strong>（调用 <code class="language-plaintext highlighter-rouge">plane-&gt;helper_private-&gt;atomic_update</code>）</li>
  <li><strong>enable</strong> 新启用的编码器/CRTC</li>
</ol>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">drm_atomic_helper_commit_planes</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span>
                                     <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">old_state</span><span class="p">,</span>
                                     <span class="kt">uint32_t</span> <span class="n">flags</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="o">*</span><span class="n">old_crtc_state</span><span class="p">,</span> <span class="o">*</span><span class="n">new_crtc_state</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_plane</span> <span class="o">*</span><span class="n">plane</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_plane_state</span> <span class="o">*</span><span class="n">old_plane_state</span><span class="p">,</span> <span class="o">*</span><span class="n">new_plane_state</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>

    <span class="cm">/* 调用每个 CRTC 的 begin 回调 */</span>
    <span class="n">for_each_oldnew_crtc_in_state</span><span class="p">(</span><span class="n">old_state</span><span class="p">,</span> <span class="n">crtc</span><span class="p">,</span>
                                  <span class="n">old_crtc_state</span><span class="p">,</span> <span class="n">new_crtc_state</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">funcs</span> <span class="o">=</span> <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">helper_private</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_begin</span><span class="p">)</span>
            <span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_begin</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="cm">/* 遍历所有 plane，调用 atomic_update 或 atomic_disable */</span>
    <span class="n">for_each_oldnew_plane_in_state</span><span class="p">(</span><span class="n">old_state</span><span class="p">,</span> <span class="n">plane</span><span class="p">,</span>
                                   <span class="n">old_plane_state</span><span class="p">,</span> <span class="n">new_plane_state</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">funcs</span> <span class="o">=</span> <span class="n">plane</span><span class="o">-&gt;</span><span class="n">helper_private</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">drm_atomic_plane_disabling</span><span class="p">(</span><span class="n">old_plane_state</span><span class="p">,</span> <span class="n">new_plane_state</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_disable</span><span class="p">(</span><span class="n">plane</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
            <span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_update</span><span class="p">(</span><span class="n">plane</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="cm">/* 调用每个 CRTC 的 flush 回调，触发硬件生效 */</span>
    <span class="n">for_each_oldnew_crtc_in_state</span><span class="p">(</span><span class="n">old_state</span><span class="p">,</span> <span class="n">crtc</span><span class="p">,</span>
                                  <span class="n">old_crtc_state</span><span class="p">,</span> <span class="n">new_crtc_state</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">funcs</span> <span class="o">=</span> <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">helper_private</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_flush</span><span class="p">)</span>
            <span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_flush</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="4-驱动实现要点">4. 驱动实现要点</h2>

<h3 id="41-atomic_check-回调">4.1 atomic_check 回调</h3>

<p>驱动需要在 <code class="language-plaintext highlighter-rouge">drm_plane_helper_funcs.atomic_check</code> 或 <code class="language-plaintext highlighter-rouge">drm_crtc_helper_funcs.atomic_check</code> 中检查私有约束：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">int</span> <span class="nf">my_plane_atomic_check</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_plane</span> <span class="o">*</span><span class="n">plane</span><span class="p">,</span>
                                  <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_plane_state</span> <span class="o">*</span><span class="n">new_state</span> <span class="o">=</span>
        <span class="n">drm_atomic_get_new_plane_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">plane</span><span class="p">);</span>

    <span class="cm">/* 示例：检查格式支持 */</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">switch</span> <span class="p">(</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">format</span><span class="o">-&gt;</span><span class="n">format</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">case</span> <span class="n">DRM_FORMAT_XRGB8888</span><span class="p">:</span>
        <span class="k">case</span> <span class="n">DRM_FORMAT_ARGB8888</span><span class="p">:</span>
        <span class="k">case</span> <span class="n">DRM_FORMAT_NV12</span><span class="p">:</span>
            <span class="k">break</span><span class="p">;</span>
        <span class="nl">default:</span>
            <span class="n">DRM_DEBUG_ATOMIC</span><span class="p">(</span><span class="s">"unsupported format %p4cc</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
                             <span class="o">&amp;</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">format</span><span class="o">-&gt;</span><span class="n">format</span><span class="p">);</span>
            <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="cm">/* 示例：检查缩放比例上限（最大 8x 缩放）*/</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_w</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">src_w</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">u32</span> <span class="n">src_w</span> <span class="o">=</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">src_w</span> <span class="o">&gt;&gt;</span> <span class="mi">16</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">src_w</span> <span class="o">/</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_w</span> <span class="o">&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">DRM_DEBUG_ATOMIC</span><span class="p">(</span><span class="s">"downscale ratio too large</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
            <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="42-atomic_commit_tail-回调">4.2 atomic_commit_tail 回调</h3>

<p>驱动可重写 <code class="language-plaintext highlighter-rouge">drm_mode_config_helper_funcs.atomic_commit_tail</code> 来控制 commit 顺序，例如在 VBlank 期间刷新寄存器：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">my_atomic_commit_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">old_state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span> <span class="o">=</span> <span class="n">old_state</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">;</span>

    <span class="cm">/* 先关掉旧的 encoder/CRTC */</span>
    <span class="n">drm_atomic_helper_commit_modeset_disables</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>

    <span class="cm">/* 更新所有 plane */</span>
    <span class="n">drm_atomic_helper_commit_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">,</span>
                                    <span class="n">DRM_PLANE_COMMIT_ACTIVE_ONLY</span><span class="p">);</span>

    <span class="cm">/* 开启新的 encoder/CRTC */</span>
    <span class="n">drm_atomic_helper_commit_modeset_enables</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>

    <span class="cm">/* 等待下一个 VBlank，确保帧完整显示 */</span>
    <span class="n">drm_atomic_helper_wait_for_flip_done</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>

    <span class="cm">/* 释放旧 framebuffer */</span>
    <span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">drm_mode_config_helper_funcs</span> <span class="n">my_mode_config_helpers</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">atomic_commit_tail</span> <span class="o">=</span> <span class="n">my_atomic_commit_tail</span><span class="p">,</span>
<span class="p">};</span>
</code></pre></div></div>

<h2 id="5-异步提交与-commit_work">5. 异步提交与 commit_work</h2>

<p>当用户空间传入 <code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_NONBLOCK</code> 时，实际硬件操作会推迟到工作队列中执行：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* drm_atomic_helper.c */</span>
<span class="kt">int</span> <span class="nf">drm_atomic_helper_commit</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span>
                              <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span>
                              <span class="n">bool</span> <span class="n">nonblock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* ... check ... */</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">nonblock</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">drm_atomic_helper_setup_commit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">nonblock</span><span class="p">);</span>

    <span class="cm">/* 同步路径：直接调用 commit_tail */</span>
    <span class="n">drm_atomic_helper_commit_tail</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>异步路径通过 <code class="language-plaintext highlighter-rouge">drm_crtc_commit</code> 对象和 completion 机制保证顺序：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">kref</span> <span class="n">ref</span><span class="p">;</span>

    <span class="cm">/* flip_done：plane 更新完成（可以释放旧 fb）*/</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">flip_done</span><span class="p">;</span>

    <span class="cm">/* hw_done：硬件配置完成（可以开始下一次 commit）*/</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">hw_done</span><span class="p">;</span>

    <span class="cm">/* cleanup_done：cleanup_planes 完成（可以销毁 state）*/</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">cleanup_done</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">list_head</span> <span class="n">commit_entry</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_pending_vblank_event</span> <span class="o">*</span><span class="n">event</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">abort_completion</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>多个连续的非阻塞 commit 之间通过等待前一个 <code class="language-plaintext highlighter-rouge">hw_done</code> 来串行化硬件写入，避免乱序。</p>

<h2 id="6-与旧版-legacy-接口的对比">6. 与旧版 legacy 接口的对比</h2>

<table>
  <thead>
    <tr>
      <th>维度</th>
      <th>Legacy KMS</th>
      <th>Atomic Modeset</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>更新粒度</td>
      <td>单对象（CRTC 或 Plane）</td>
      <td>事务（多对象同时更新）</td>
    </tr>
    <tr>
      <td>check/commit 分离</td>
      <td>否（隐式，易出错）</td>
      <td>是（显式两阶段）</td>
    </tr>
    <tr>
      <td>失败回滚</td>
      <td>需驱动自行处理</td>
      <td>框架保证 state 回滚</td>
    </tr>
    <tr>
      <td>异步支持</td>
      <td>仅 page-flip</td>
      <td>全部操作均可异步</td>
    </tr>
    <tr>
      <td>驱动复杂度</td>
      <td>较低</td>
      <td>较高，但可复用 helper</td>
    </tr>
    <tr>
      <td>多屏同步</td>
      <td>困难</td>
      <td>原生支持（同一 state）</td>
    </tr>
  </tbody>
</table>

<p>目前新驱动均应优先实现 atomic 接口；legacy 接口由 DRM 核心通过兼容层自动适配旧版用户空间程序。</p>

<h2 id="7-常见问题排查">7. 常见问题排查</h2>

<p><strong>1. atomic_check 返回 -EINVAL 但日志无明显报错</strong></p>

<p>启用 DRM 调试日志后重现：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>0x3f <span class="o">&gt;</span> /sys/module/drm/parameters/debug
dmesg | <span class="nb">grep</span> <span class="nt">-i</span> atomic
</code></pre></div></div>

<p><strong>2. 页面撕裂（tearing）仍然存在</strong></p>

<p>检查驱动的 <code class="language-plaintext highlighter-rouge">atomic_flush</code> 回调是否正确等待 VBlank，确认 hardware double buffering（寄存器 shadow）逻辑是否在 VBlank 中断中触发 latch：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">irqreturn_t</span> <span class="nf">my_vblank_irq_handler</span><span class="p">(</span><span class="kt">int</span> <span class="n">irq</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">my_drm_private</span> <span class="o">*</span><span class="n">priv</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>

    <span class="cm">/* 触发硬件寄存器影子寄存器生效 */</span>
    <span class="n">writel</span><span class="p">(</span><span class="n">BIT</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">priv</span><span class="o">-&gt;</span><span class="n">regs</span> <span class="o">+</span> <span class="n">REG_UPDATE_LATCH</span><span class="p">);</span>

    <span class="n">drm_crtc_handle_vblank</span><span class="p">(</span><span class="o">&amp;</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">crtc</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">IRQ_HANDLED</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>3. 非阻塞 commit 之后旧 framebuffer 被提前释放</strong></p>

<p>确认驱动调用了 <code class="language-plaintext highlighter-rouge">drm_atomic_helper_cleanup_planes()</code>，且在 <code class="language-plaintext highlighter-rouge">flip_done</code> completion 之后再执行清理：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* 正确做法：等待 flip_done 再 cleanup */</span>
<span class="n">drm_atomic_helper_wait_for_flip_done</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
<span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
</code></pre></div></div>

<hr />
<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DRM" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">K230 SDK 编译流程分析：目录结构、Makefile 入口与 Buildroot 集成</title><link href="https://yangchao315.github.io/K230-SDK-Build-Analysis/" rel="alternate" type="text/html" title="K230 SDK 编译流程分析：目录结构、Makefile 入口与 Buildroot 集成" /><published>2026-03-27T00:00:00+00:00</published><updated>2026-03-27T00:00:00+00:00</updated><id>https://yangchao315.github.io/K230-SDK-Build-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/K230-SDK-Build-Analysis/"><![CDATA[<p>K230 是嘉楠科技基于玄铁 C908 双核的 RISC-V AI 视觉 SoC。本文分析 K230 SDK 的编译流程，覆盖目录布局、Makefile 入口、Buildroot 集成方式以及最终输出产物。</p>

<!-- more -->

<ul>
  <li><a href="#sdk-目录结构">SDK 目录结构</a></li>
  <li><a href="#makefile-入口分析">Makefile 入口分析</a></li>
  <li><a href="#buildroot-集成方式">Buildroot 集成方式</a>
    <ul>
      <li><a href="#br2_external-机制">BR2_EXTERNAL 机制</a></li>
      <li><a href="#自定义-package-示例">自定义 package 示例</a></li>
    </ul>
  </li>
  <li><a href="#编译输出产物">编译输出产物</a></li>
  <li><a href="#常用编译命令">常用编译命令</a></li>
</ul>

<hr />

<h2 id="sdk-目录结构">SDK 目录结构</h2>

<p>K230 SDK 顶层目录布局如下：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>k230_sdk/
├── Makefile                  # 顶层入口，核心编译驱动
├── configs/                  # defconfig（如 k230_evb_defconfig）
├── board/                    # 板级配置文件、设备树、启动脚本
│   └── k230/
│       ├── env.env           # U-Boot 环境变量
│       └── genimage.cfg      # 镜像打包配置
├── buildroot-ext/            # BR2_EXTERNAL 扩展目录
│   ├── Config.in             # 顶层 Kconfig 入口
│   ├── external.mk           # 顶层 make 入口
│   ├── package/              # 自定义 package（AI 库、驱动、应用）
│   └── configs/              # Buildroot defconfig
├── src/
│   ├── little/               # 小核（Linux + Buildroot）
│   │   └── buildroot/        # Buildroot 源码（submodule）
│   ├── big/                  # 大核（RT-Thread 或裸机）
│   │   └── rtsmart/          # RT-Smart 源码
│   └── uboot/                # U-Boot 源码
├── tools/                    # 镜像打包、烧录工具
└── output/                   # 编译产物目录
    ├── images/               # 最终镜像
    └── build/                # 中间产物
</code></pre></div></div>

<p>K230 采用双核异构架构：小核运行 Linux（Buildroot 构建），大核运行 RT-Smart（实时操作系统），两者通过共享内存 + mailbox 通信。</p>

<hr />

<h2 id="makefile-入口分析">Makefile 入口分析</h2>

<p>顶层 <code class="language-plaintext highlighter-rouge">Makefile</code> 的核心逻辑如下：</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 加载 defconfig，确定 ARCH、CROSS_COMPILE 等变量
</span><span class="k">include</span><span class="sx"> $(BR2_CONFIG)</span>

<span class="c"># 小核编译：调用 Buildroot
</span><span class="nl">little</span><span class="o">:</span>
	<span class="nv">$(MAKE)</span> <span class="nt">-C</span> src/little/buildroot <span class="se">\</span>
		<span class="nv">BR2_EXTERNAL</span><span class="o">=</span><span class="nv">$(SDK_ROOT)</span>/buildroot-ext <span class="se">\</span>
		<span class="nv">O</span><span class="o">=</span><span class="nv">$(OUTPUT)</span>/little <span class="se">\</span>
		<span class="nv">$(LITTLE_DEFCONFIG)</span>
	<span class="nv">$(MAKE)</span> <span class="nt">-C</span> src/little/buildroot <span class="se">\</span>
		<span class="nv">O</span><span class="o">=</span><span class="nv">$(OUTPUT)</span>/little

<span class="c"># 大核编译：调用 RT-Smart
</span><span class="nl">big</span><span class="o">:</span>
	<span class="nv">$(MAKE)</span> <span class="nt">-C</span> src/big/rtsmart <span class="se">\</span>
		<span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(RISCV_BIG_CROSS)</span> <span class="se">\</span>
		<span class="nv">O</span><span class="o">=</span><span class="nv">$(OUTPUT)</span>/big

<span class="c"># U-Boot 编译
</span><span class="nl">uboot</span><span class="o">:</span>
	<span class="nv">$(MAKE)</span> <span class="nt">-C</span> src/uboot <span class="se">\</span>
		<span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(RISCV_CROSS)</span> <span class="se">\</span>
		k230_evb_defconfig
	<span class="nv">$(MAKE)</span> <span class="nt">-C</span> src/uboot <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(RISCV_CROSS)</span>

<span class="c"># 打包镜像
</span><span class="nl">image</span><span class="o">:</span> <span class="nf">little big uboot</span>
	python3 tools/gen_image.py <span class="se">\</span>
		<span class="nt">--config</span> board/k230/genimage.cfg <span class="se">\</span>
		<span class="nt">--output</span> output/images/sysimage-sdcard.img
</code></pre></div></div>

<p>编译顺序：<code class="language-plaintext highlighter-rouge">uboot</code> → <code class="language-plaintext highlighter-rouge">big</code>（RT-Smart）→ <code class="language-plaintext highlighter-rouge">little</code>（Buildroot/Linux）→ <code class="language-plaintext highlighter-rouge">image</code>（打包）。</p>

<p>顶层 <code class="language-plaintext highlighter-rouge">make</code> 不加参数时默认执行 <code class="language-plaintext highlighter-rouge">all</code>，等价于完整编译并打包。可单独执行 <code class="language-plaintext highlighter-rouge">make little</code> 仅编译小核部分。</p>

<hr />

<h2 id="buildroot-集成方式">Buildroot 集成方式</h2>

<h3 id="br2_external-机制">BR2_EXTERNAL 机制</h3>

<p>K230 SDK 通过 Buildroot 的 <code class="language-plaintext highlighter-rouge">BR2_EXTERNAL</code> 机制将 SDK 特有 package 和配置注入 Buildroot，而不修改 Buildroot 主线源码。</p>

<p><code class="language-plaintext highlighter-rouge">BR2_EXTERNAL</code> 目录须包含以下固定文件：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>buildroot-ext/
├── Config.in        # 必须：声明 source "$BR2_EXTERNAL_K230_PATH/package/.../Config.in"
├── external.mk      # 必须：include 所有自定义 package 的 .mk 文件
└── external.desc    # 必须：描述此 BR2_EXTERNAL 的 name 和 desc
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">external.desc</code> 示例：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>name: K230
desc: Canaan K230 SDK external tree
</code></pre></div></div>

<p>Buildroot 在调用时通过 <code class="language-plaintext highlighter-rouge">O=</code> 指定独立输出目录，源码树与产物分离，支持多配置并存。</p>

<h3 id="自定义-package-示例">自定义 package 示例</h3>

<p>以 K230 AI 推理库 <code class="language-plaintext highlighter-rouge">k230_nncase_runtime</code> 为例，package 目录结构：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>buildroot-ext/package/k230_nncase_runtime/
├── Config.in
└── k230_nncase_runtime.mk
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Config.in</code>：</p>

<pre><code class="language-kconfig">config BR2_PACKAGE_K230_NNCASE_RUNTIME
	bool "k230_nncase_runtime"
	help
	  nncase runtime library for K230 KPU inference.
</code></pre>

<p><code class="language-plaintext highlighter-rouge">k230_nncase_runtime.mk</code>：</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">K230_NNCASE_RUNTIME_VERSION</span> <span class="o">=</span> 1.0.0
<span class="nv">K230_NNCASE_RUNTIME_SITE</span> <span class="o">=</span> <span class="nv">$(SDK_ROOT)</span>/src/little/nncase
<span class="nv">K230_NNCASE_RUNTIME_SITE_METHOD</span> <span class="o">=</span> <span class="nb">local</span>

<span class="err">define</span> <span class="err">K230_NNCASE_RUNTIME_BUILD_CMDS</span>
	<span class="err">$(MAKE)</span> <span class="err">-C</span> <span class="err">$(@D)</span> <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(TARGET_CROSS)</span>
<span class="err">endef</span>

<span class="err">define</span> <span class="err">K230_NNCASE_RUNTIME_INSTALL_TARGET_CMDS</span>
	<span class="err">$(INSTALL)</span> <span class="err">-D</span> <span class="err">-m</span> <span class="err">0755</span> <span class="err">$(@D)/libnncase.so</span> <span class="err">$(TARGET_DIR)/usr/lib/</span>
<span class="err">endef</span>

<span class="err">$(eval</span> <span class="err">$(generic-package))</span>
</code></pre></div></div>

<hr />

<h2 id="编译输出产物">编译输出产物</h2>

<p>完整编译后，<code class="language-plaintext highlighter-rouge">output/images/</code> 目录包含：</p>

<table>
  <thead>
    <tr>
      <th>文件</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sysimage-sdcard.img</code></td>
      <td>SD 卡完整镜像（含分区表、U-Boot、内核、rootfs）</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">u-boot.bin</code></td>
      <td>U-Boot 二进制</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Image</code> / <code class="language-plaintext highlighter-rouge">Image.gz</code></td>
      <td>Linux 内核镜像</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230-evb.dtb</code></td>
      <td>设备树 blob</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">rootfs.ext4</code></td>
      <td>小核 Linux rootfs（ext4）</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">rtsmart.img</code></td>
      <td>大核 RT-Smart 镜像</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">env.bin</code></td>
      <td>U-Boot 环境变量二进制</td>
    </tr>
  </tbody>
</table>

<p><code class="language-plaintext highlighter-rouge">sysimage-sdcard.img</code> 的分区布局（典型配置）：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Offset 0       : MBR 分区表
Partition 1    : U-Boot（raw，不格式化）
Partition 2    : U-Boot env
Partition 3    : Linux 内核 + DTB（FAT32）
Partition 4    : rootfs（ext4）
</code></pre></div></div>

<hr />

<h2 id="常用编译命令">常用编译命令</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 完整编译（首次或 clean 后）</span>
make <span class="nv">CONF</span><span class="o">=</span>k230_evb_defconfig

<span class="c"># 仅编译小核（Linux + Buildroot）</span>
make little

<span class="c"># 仅重新打包镜像（不重编代码）</span>
make image

<span class="c"># 单独重编某个 Buildroot package</span>
make <span class="nt">-C</span> src/little/buildroot <span class="nv">O</span><span class="o">=</span><span class="si">$(</span><span class="nb">pwd</span><span class="si">)</span>/output/little k230_nncase_runtime-rebuild

<span class="c"># 清理输出</span>
make clean

<span class="c"># 烧录 SD 卡镜像（Linux 主机）</span>
<span class="nb">sudo dd </span><span class="k">if</span><span class="o">=</span>output/images/sysimage-sdcard.img <span class="nv">of</span><span class="o">=</span>/dev/sdX <span class="nv">bs</span><span class="o">=</span>4M <span class="nv">status</span><span class="o">=</span>progress
</code></pre></div></div>

<hr />
<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="K230" /><summary type="html"><![CDATA[K230 是嘉楠科技基于玄铁 C908 双核的 RISC-V AI 视觉 SoC。本文分析 K230 SDK 的编译流程，覆盖目录布局、Makefile 入口、Buildroot 集成方式以及最终输出产物。]]></summary></entry><entry><title type="html">K230 SDK 编译流程深度分析</title><link href="https://yangchao315.github.io/K230-SDK-Compile-Flow-Analysis/" rel="alternate" type="text/html" title="K230 SDK 编译流程深度分析" /><published>2026-03-26T00:00:00+00:00</published><updated>2026-03-26T00:00:00+00:00</updated><id>https://yangchao315.github.io/K230-SDK-Compile-Flow-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/K230-SDK-Compile-Flow-Analysis/"><![CDATA[<!-- more -->
<ul>
  <li><a href="#k230-sdk-编译流程深度分析">K230 SDK 编译流程深度分析</a>
    <ul>
      <li><a href="#1-编译命令入口分析">1. 编译命令入口分析</a></li>
      <li><a href="#2-配置加载机制">2. 配置加载机制</a></li>
      <li><a href="#3-完整编译流程">3. 完整编译流程</a></li>
      <li><a href="#4-各组件编译详解">4. 各组件编译详解</a></li>
      <li><a href="#5-镜像生成流程">5. 镜像生成流程</a></li>
      <li><a href="#6-编译产物分析">6. 编译产物分析</a></li>
      <li><a href="#7-关键配置变量">7. 关键配置变量</a></li>
      <li><a href="#8-k230-sdk-配置对比分析">8. K230 SDK 配置对比分析</a>
        <ul>
          <li><a href="#81-dongshanpi-配置">8.1 DongshanPI 配置</a></li>
          <li><a href="#82-各配置对比表">8.2 各配置对比表</a></li>
          <li><a href="#83-关键差异分析">8.3 关键差异分析</a></li>
          <li><a href="#84-如何选择配置">8.4 如何选择配置</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h1 id="k230-sdk-编译流程深度分析">K230 SDK 编译流程深度分析</h1>

<p>本文深入分析 <code class="language-plaintext highlighter-rouge">make CONF=k230_canmv_dongshanpi_defconfig</code> 命令的完整编译流程，揭示 K230 SDK 的构建机制。</p>

<h2 id="1-编译命令入口分析">1. 编译命令入口分析</h2>

<h3 id="11-命令解析">1.1 命令解析</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 29-33 行
</span><span class="k">ifeq</span> <span class="nv">($(origin CONF), "command line")</span>
    <span class="err">$(shell</span> <span class="err">echo</span> <span class="nv">CONF</span><span class="o">=</span><span class="nv">$(CONF)</span><span class="o">&gt;</span>.last_conf<span class="p">;</span><span class="nb">cp </span>configs/<span class="nv">$(CONF)</span> .config<span class="o">)</span>
<span class="k">else</span>
    <span class="err">$(shell</span> <span class="err">[</span> <span class="err">-f</span> <span class="err">.last_conf</span> <span class="err">]</span> <span class="err">||</span> <span class="err">(</span> <span class="err">echo</span> <span class="nv">CONF</span><span class="o">=</span>k230_evb_defconfig&gt;.last_conf<span class="p">;</span> <span class="nb">cp </span>configs/k230_evb_defconfig .config <span class="o">)</span> <span class="o">)</span>
<span class="k">endif</span>

<span class="k">include</span><span class="sx"> .last_conf</span>
<span class="k">export </span><span class="nv">BUILD_DIR</span> <span class="o">:=</span> <span class="nv">$(K230_SDK_ROOT)</span>/output/<span class="nv">$(CONF)</span>
</code></pre></div></div>

<p><strong>执行流程</strong>：</p>
<ol>
  <li>读取 <code class="language-plaintext highlighter-rouge">CONF</code> 参数 <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></li>
  <li>写入 <code class="language-plaintext highlighter-rouge">.last_conf</code> 文件记录配置名</li>
  <li>复制 <code class="language-plaintext highlighter-rouge">configs/k230_canmv_dongshanpi_defconfig</code> 到 <code class="language-plaintext highlighter-rouge">.config</code></li>
  <li>设置输出目录 <code class="language-plaintext highlighter-rouge">output/k230_canmv_dongshanpi_defconfig/</code></li>
</ol>

<h3 id="12-构建目标选择">1.2 构建目标选择</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 79-85 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">all</span>
<span class="k">ifeq</span> <span class="nv">($(CONFIG_SUPPORT_RTSMART)$(CONFIG_SUPPORT_LINUX),yy)</span>
    <span class="nl">all .DEFAULT</span><span class="o">:</span> <span class="nf">check_src prepare_memory linux mpp cdk-kernel cdk-kernel-install cdk-user cdk-user-install rt-smart-apps rt-smart-kernel big-core-opensbi little-core-opensbi buildroot uboot build-image</span>
<span class="err">else</span> <span class="k">ifeq</span> <span class="nv">($(CONFIG_SUPPORT_RTSMART),y)</span>
    <span class="nl">all .DEFAULT</span><span class="o">:</span> <span class="nf">check_src prepare_memory mpp rt-smart-apps rt-smart-kernel big-core-opensbi uboot build-image</span>
<span class="err">else</span> <span class="k">ifeq</span> <span class="nv">($(CONFIG_SUPPORT_LINUX),y)</span>
    <span class="nl">all .DEFAULT</span><span class="o">:</span> <span class="nf">check_src prepare_memory linux little-core-opensbi buildroot uboot build-image</span>
<span class="k">endif</span>
</code></pre></div></div>

<p>对于 <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code>，同时启用了 RT-Smart 和 Linux，因此执行完整构建流程。</p>

<h2 id="2-配置加载机制">2. 配置加载机制</h2>

<h3 id="21-配置文件解析">2.1 配置文件解析</h3>

<p><code class="language-plaintext highlighter-rouge">parse.mak</code> 负责解析 <code class="language-plaintext highlighter-rouge">.config</code>：</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># parse.mak 第 1-5 行
</span><span class="k">ifeq</span> <span class="nv">($(wildcard .config), .config)</span>
    <span class="k">include</span><span class="sx"> .config</span>
<span class="k">else</span>
    <span class="k">include</span><span class="sx"> $(DEFCONFIG)</span>
<span class="k">endif</span>
</code></pre></div></div>

<h3 id="22-工具链配置转换">2.2 工具链配置转换</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># parse.mak 第 20-26 行
</span><span class="k">export </span><span class="nv">RTT_CC</span>     <span class="o">:=</span> gcc
<span class="k">export </span><span class="nv">RTT_CC_PREFIX</span>   <span class="o">:=</span> <span class="nv">$(CONFIG_TOOLCHAIN_PREFIX_RTT)</span>
<span class="k">export </span><span class="nv">RTT_EXEC_PATH</span>   <span class="o">:=</span> <span class="nv">$(CONFIG_TOOLCHAIN_PATH_RTT)</span>

<span class="k">export </span><span class="nv">LINUX_CC</span>   <span class="o">:=</span> gcc
<span class="k">export </span><span class="nv">LINUX_CC_PREFIX</span>   <span class="o">:=</span> <span class="nv">$(CONFIG_TOOLCHAIN_PREFIX_LINUX)</span>
<span class="k">export </span><span class="nv">LINUX_EXEC_PATH</span>  <span class="o">:=</span> <span class="nv">$(CONFIG_TOOLCHAIN_PATH_LINUX)</span>
</code></pre></div></div>

<h3 id="23-组件-defconfig-推导">2.3 组件 defconfig 推导</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># parse.mak 第 51-54 行
</span><span class="nv">LINUX_KERNEL_DEFCONFIG</span>   <span class="o">=</span> <span class="nv">$(CONFIG_LINUX_DEFCONFIG)</span>_defconfig
<span class="nv">UBOOT_DEFCONFIG</span>          <span class="o">=</span> <span class="nv">$(CONFIG_UBOOT_DEFCONFIG)</span>_defconfig
<span class="nv">BUILDROOT_DEFCONFIG</span>      <span class="o">=</span> <span class="nv">$(CONFIG_BUILDROOT_DEFCONFIG)</span>_defconfig
</code></pre></div></div>

<p>对于 <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code>：</p>
<ul>
  <li>Linux kernel defconfig: <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></li>
  <li>U-Boot defconfig: <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></li>
  <li>Buildroot defconfig: <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></li>
</ul>

<h2 id="3-完整编译流程">3. 完整编译流程</h2>

<h3 id="31-构建顺序图">3.1 构建顺序图</h3>

<pre><code class="language-mermaid">graph TD
    A[check_src] --&gt; B[prepare_memory]
    B --&gt; C[linux]
    B --&gt; D[mpp]
    B --&gt; E[cdk-kernel]
    E --&gt; F[cdk-kernel-install]
    F --&gt; G[cdk-user]
    G --&gt; H[cdk-user-install]
    C --&gt; I[rt-smart-apps]
    C --&gt; J[rt-smart-kernel]
    D --&gt; I
    I --&gt; K[big-core-opensbi]
    C --&gt; L[little-core-opensbi]
    C --&gt; M[buildroot]
    C --&gt; N[uboot]
    K --&gt; O[build-image]
    L --&gt; O
    M --&gt; O
    N --&gt; O
    H --&gt; O
</code></pre>

<h3 id="32-依赖检查">3.2 依赖检查</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 172-175 行
</span><span class="nl">check_src</span><span class="o">:</span><span class="nf">check_toolchain</span>
    <span class="err">@if</span> <span class="err">[</span> <span class="err">!</span> <span class="err">-f</span> <span class="err">src/.src_fetched</span> <span class="err">];then</span> <span class="err">\</span>
    <span class="nl">echo "Please run command</span><span class="o">:</span> <span class="nf">make prepare_sourcecode";exit 1; </span>\
<span class="nf">    fi;</span>

<span class="nl">check_toolchain</span><span class="o">:</span>
    <span class="err">@if</span> <span class="err">[</span> <span class="err">!</span> <span class="err">-f</span> <span class="err">$(CONFIG_TOOLCHAIN_PATH_LINUX)/$(CONFIG_TOOLCHAIN_PREFIX_LINUX)gcc</span> <span class="err">]</span> <span class="err">||</span> <span class="err">\</span>
         <span class="err">[</span> <span class="err">!</span> <span class="err">-f</span> <span class="err">$(CONFIG_TOOLCHAIN_PATH_RTT)/$(CONFIG_TOOLCHAIN_PREFIX_RTT)gcc</span> <span class="err">];</span> <span class="err">then</span> <span class="err">\</span>
        <span class="nl">echo "please run command</span><span class="o">:</span> <span class="nf">make prepare_toolchain"; exit 1; </span>\
<span class="nf">    fi;</span>
</code></pre></div></div>

<p>编译前需要确保：</p>
<ol>
  <li>工具链已准备 (<code class="language-plaintext highlighter-rouge">make prepare_toolchain</code>)</li>
  <li>源码已获取 (<code class="language-plaintext highlighter-rouge">make prepare_sourcecode</code>)</li>
</ol>

<h3 id="33-prepare_memory-阶段">3.3 prepare_memory 阶段</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 198-209 行
</span><span class="nl">prepare_memory</span><span class="o">:</span> <span class="nf">defconfig .config tools/menuconfig_to_code.sh parse.mak</span>
    <span class="err">@echo</span> <span class="s2">"prepare memory"</span>
    <span class="err">@mkdir</span> <span class="err">-p</span> <span class="err">include/generated/</span> <span class="err">include/config/;</span>
    <span class="err">@./tools/kconfig/conf</span> <span class="err">--silentoldconfig</span> <span class="err">--olddefconfig</span> <span class="err">$(KCONFIG_CFG)</span>
    <span class="err">@cp</span> <span class="err">include/generated/autoconf.h</span> <span class="err">src/little/uboot/board/canaan/common/sdk_autoconf.h</span>
    <span class="err">@cp</span> <span class="err">include/generated/autoconf.h</span> <span class="err">src/big/mpp/include/comm/k_autoconf_comm.h</span>
    <span class="err">@rm</span> <span class="err">-rf</span> <span class="err">include;</span>
    <span class="err">@./tools/menuconfig_to_code.sh</span>
</code></pre></div></div>

<p>生成内核配置头文件并分发给各组件：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">include/generated/autoconf.h</code> → U-Boot 和 MPP 的 <code class="language-plaintext highlighter-rouge">sdk_autoconf.h</code></li>
</ul>

<h2 id="4-各组件编译详解">4. 各组件编译详解</h2>

<h3 id="41-linux-内核编译">4.1 Linux 内核编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 412-421 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">linux</span>
<span class="nl">linux</span><span class="o">:</span> <span class="nf">check_src defconfig prepare_memory linux-config linux-build</span>

<span class="nl">linux-config</span><span class="o">:</span>
    <span class="err">cd</span> <span class="err">$(LINUX_SRC_PATH);</span> <span class="err">\</span>
    <span class="err">make</span> <span class="nv">ARCH</span><span class="o">=</span>riscv <span class="nv">$(LINUX_KERNEL_DEFCONFIG)</span> <span class="nv">O</span><span class="o">=</span><span class="nv">$(LINUX_BUILD_DIR)</span> <span class="se">\</span>
    <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(LINUX_EXEC_PATH)</span>/<span class="nv">$(LINUX_CC_PREFIX)</span> <span class="nv">ARCH</span><span class="o">=</span>riscv

<span class="nl">linux-build</span><span class="o">:</span>
    <span class="err">cd</span> <span class="err">$(LINUX_SRC_PATH);</span> <span class="err">\</span>
    <span class="err">make</span> <span class="err">-j16</span> <span class="nv">O</span><span class="o">=</span><span class="nv">$(LINUX_BUILD_DIR)</span> <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(LINUX_EXEC_PATH)</span>/<span class="nv">$(LINUX_CC_PREFIX)</span> <span class="nv">ARCH</span><span class="o">=</span>riscv
    <span class="err">make</span> <span class="err">modules_install</span> <span class="nv">INSTALL_MOD_PATH</span><span class="o">=</span><span class="nv">$(LINUX_BUILD_DIR)</span>/rootfs/ <span class="se">\</span>
    <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(LINUX_EXEC_PATH)</span>/<span class="nv">$(LINUX_CC_PREFIX)</span> <span class="nv">ARCH</span><span class="o">=</span>riscv
</code></pre></div></div>

<p><strong>编译参数</strong>：</p>
<ul>
  <li>ARCH: riscv</li>
  <li>CROSS_COMPILE: <code class="language-plaintext highlighter-rouge">riscv64-unknown-linux-gnu-</code></li>
  <li>输出目录: <code class="language-plaintext highlighter-rouge">output/k230_canmv_dongshanpi_defconfig/little/linux/</code></li>
</ul>

<h3 id="42-rt-smart-内核编译">4.2 RT-Smart 内核编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 368-378 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">rt-smart-kernel</span>
<span class="nl">rt-smart-kernel</span><span class="o">:</span> <span class="nf">defconfig prepare_memory check_src</span>
    <span class="err">@</span><span class="k">export </span><span class="nv">RTT_CC</span><span class="o">=</span><span class="nv">$(RTT_CC)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">export </span><span class="nv">RTT_CC_PREFIX</span><span class="o">=</span><span class="nv">$(RTT_CC_PREFIX)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">export </span><span class="nv">RTT_EXEC_PATH</span><span class="o">=</span><span class="nv">$(RTT_EXEC_PATH)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">cd</span> <span class="err">$</span><span class="o">(</span>RT-SMART_SRC_PATH<span class="o">)</span>/kernel/bsp/maix3<span class="p">;</span> <span class="se">\</span>
    <span class="nb">rm</span> <span class="nt">-f</span> rtthread.elf<span class="p">;</span> <span class="se">\</span>
    scons <span class="nt">-j16</span>
    <span class="err">mkdir</span> <span class="err">-p</span> <span class="err">$(RTT_SDK_BUILD_DIR);</span> <span class="err">\</span>
    <span class="err">cp</span> <span class="err">rtthread.bin</span> <span class="err">rtthread.elf</span> <span class="err">$(RTT_SDK_BUILD_DIR)/;</span>
</code></pre></div></div>

<p><strong>编译方式</strong>：使用 scons 构建系统</p>

<h3 id="43-mpp-多媒体处理组件-编译">4.3 MPP (多媒体处理组件) 编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 266-267 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">mpp</span>
<span class="nl">mpp</span><span class="o">:</span> <span class="nf">mpp-kernel mpp-apps $(MPP_MIDDLEWARE)</span>

<span class="nl">mpp-kernel</span><span class="o">:</span>
    <span class="k">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$(RTT_EXEC_PATH)</span>:<span class="nv">$(PATH)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">export </span><span class="nv">RTSMART_SRC_DIR</span><span class="o">=</span><span class="nv">$(K230_SDK_ROOT)</span>/<span class="err">$</span><span class="o">(</span>RT-SMART_SRC_PATH<span class="o">)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">cd</span> <span class="nv">$(MPP_SRC_PATH)</span><span class="p">;</span> make <span class="nt">-C</span> kernel

<span class="nl">mpp-apps</span><span class="o">:</span>
    <span class="k">export </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$(RTT_EXEC_PATH)</span>:<span class="nv">$(PATH)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">cd</span> <span class="nv">$(MPP_SRC_DIR)</span><span class="p">;</span> make <span class="nt">-C</span> userapps/src
    <span class="err">make</span> <span class="err">-C</span> <span class="err">userapps/sample</span>
</code></pre></div></div>

<h3 id="44-buildroot-编译">4.4 Buildroot 编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 475-480 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">buildroot</span>
<span class="nl">buildroot</span><span class="o">:</span> <span class="nf">defconfig prepare_memory check_src</span>
    <span class="nl">@export PATH=$(LINUX_EXEC_PATH)</span><span class="o">:</span><span class="nf">$(PATH); </span>\
<span class="nf">    cd $(BUILDROOT-EXT_SRC_PATH); </span>\
<span class="nf">    make CONF=$(BUILDROOT_DEFCONFIG) BRW_BUILD_DIR=$(BUILDROOT_BUILD_DIR) </span>\
<span class="nf">    BR2_TOOLCHAIN_EXTERNAL_PATH=$(LINUX_EXEC_PATH)/../ </span>\
<span class="nf">    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=$(LINUX_CC_PREFIX)</span>
</code></pre></div></div>

<h3 id="45-u-boot-编译">4.5 U-Boot 编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Makefile 第 510-515 行
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">uboot</span>
<span class="nl">uboot</span><span class="o">:</span> <span class="nf">defconfig prepare_memory check_src</span>
    <span class="nl">@export PATH=$(LINUX_EXEC_PATH)</span><span class="o">:</span><span class="nf">$(PATH);export CROSS_COMPILE=$(LINUX_CC_PREFIX);export ARCH=riscv; </span>\
<span class="nf">    cd $(UBOOT_SRC_PATH); </span>\
<span class="nf">    make $(UBOOT_DEFCONFIG) O=$(UBOOT_BUILD_DIR)</span>
    <span class="err">make</span> <span class="err">-C</span> <span class="err">$(UBOOT_BUILD_DIR)</span>
</code></pre></div></div>

<h3 id="46-opensbi-编译">4.6 OpenSBI 编译</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># 大核 OpenSBI
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">big-core-opensbi</span>
<span class="nl">big-core-opensbi</span><span class="o">:</span> <span class="nf">rt-smart-kernel</span>
    <span class="err">@mkdir</span> <span class="err">-p</span> <span class="err">$(BIG_OPENSBI_BUILD_DIR);</span> <span class="err">\</span>
    <span class="err">cp</span> <span class="err">$(RT-SMART_SRC_PATH)/kernel/bsp/maix3/rtthread.bin</span> <span class="err">$(OPENSBI_SRC_PATH)/;</span> <span class="err">\</span>
    <span class="err">cd</span> <span class="err">$(OPENSBI_SRC_PATH);</span> <span class="err">\</span>
    <span class="k">export </span><span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(LINUX_EXEC_PATH)</span>/<span class="nv">$(LINUX_CC_PREFIX)</span><span class="p">;</span> <span class="se">\</span>
    <span class="nb">export </span><span class="nv">PLATFORM</span><span class="o">=</span>kendryte/fpgac908<span class="p">;</span> <span class="se">\</span>
    make <span class="nv">FW_FDT_PATH</span><span class="o">=</span>hw.dtb <span class="nv">FW_PAYLOAD_PATH</span><span class="o">=</span>rtthread.bin <span class="se">\</span>
    <span class="nv">O</span><span class="o">=</span><span class="nv">$(BIG_OPENSBI_BUILD_DIR)</span> <span class="nv">OPENSBI_QUIET</span><span class="o">=</span>1

<span class="c"># 小核 OpenSBI
</span><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">little-core-opensbi</span>
<span class="nl">little-core-opensbi</span><span class="o">:</span> <span class="nf">linux</span>
    <span class="err">@mkdir</span> <span class="err">-p</span> <span class="err">$(LITTLE_OPENSBI_BUILD_DIR);</span> <span class="err">\</span>
    <span class="err">cd</span> <span class="err">$(OPENSBI_SRC_PATH);</span> <span class="err">\</span>
    <span class="err">make</span> <span class="nv">CROSS_COMPILE</span><span class="o">=</span><span class="nv">$(LINUX_EXEC_PATH)</span>/<span class="nv">$(LINUX_CC_PREFIX)</span> <span class="se">\</span>
    <span class="nv">PLATFORM</span><span class="o">=</span>generic <span class="nv">FW_PAYLOAD_PATH</span><span class="o">=</span><span class="nv">$(LINUX_BUILD_DIR)</span>/arch/riscv/boot/Image <span class="se">\</span>
    <span class="nv">O</span><span class="o">=</span><span class="nv">$(LITTLE_OPENSBI_BUILD_DIR)</span> <span class="nv">K230_LITTLE_CORE</span><span class="o">=</span>1 <span class="nv">OPENSBI_QUIET</span><span class="o">=</span>1
</code></pre></div></div>

<h2 id="5-镜像生成流程">5. 镜像生成流程</h2>

<h3 id="51-最终构建目标">5.1 最终构建目标</h3>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">.PHONY</span><span class="o">:</span> <span class="nf">build-image</span>
<span class="nl">build-image</span><span class="o">:</span>
    <span class="err">@set</span> <span class="err">-e;</span> <span class="err">\</span>
    <span class="err">echo</span> <span class="s2">"build SDK images"</span>
</code></pre></div></div>

<h3 id="52-镜像生成脚本">5.2 镜像生成脚本</h3>

<p>镜像生成使用 <code class="language-plaintext highlighter-rouge">gen_image.sh</code> 脚本：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># board/common/gen_image_script/gen_image.sh</span>
1. copy_file_to_images    <span class="c"># 复制文件到输出目录</span>
2. gen_version             <span class="c"># 生成版本信息</span>
3. add_dev_firmware        <span class="c"># 添加设备固件</span>
4. gen_linux_bin           <span class="c"># 生成 Linux 镜像 (Image + DTB)</span>
5. gen_final_ext2          <span class="c"># 生成根文件系统</span>
6. gen_rtt_bin             <span class="c"># 生成 RT-Smart 镜像</span>
7. gen_uboot_bin           <span class="c"># 生成 U-Boot</span>
8. gen_env_bin             <span class="c"># 生成环境变量</span>
9. copy_app                <span class="c"># 复制应用程序</span>
10. gen_image              <span class="c"># 使用 genimage 生成最终镜像</span>
</code></pre></div></div>

<h3 id="53-分区配置文件">5.3 分区配置文件</h3>

<p>镜像分区定义在 <code class="language-plaintext highlighter-rouge">board/common/gen_image_cfg/genimage-sdcard.cfg</code>：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──────────┬─────────┬────────────────┬────────────────────┐
│ Offset   │ Size    │ Partition      │ Description        │
├──────────┼─────────┼────────────────┼────────────────────│
│ 1MB      │ 512KB   │ uboot_spl_1   │ SPL 1st copy       │
│ 1.5MB    │ 512KB   │ uboot_spl_2   │ SPL 2nd copy       │
│ 2MB      │ 1.5MB   │ uboot         │ U-Boot             │
│ 3.5MB    │ 128KB   │ uboot_env     │ U-Boot 环境变量     │
│ 10MB     │ 20MB    │ rtt           │ RT-Smart 系统       │
│ 30MB     │ 50MB    │ linux         │ Linux 内核+DTB      │
│ 80MB     │ -       │ rootfs        │ 根文件系统 (ext4)   │
│ 128MB    │ 32MB    │ fat32appfs    │ App 分区 (vfat)    │
└──────────┴─────────┴────────────────┴────────────────────┘
</code></pre></div></div>

<h2 id="6-编译产物分析">6. 编译产物分析</h2>

<h3 id="61-输出目录结构">6.1 输出目录结构</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>output/k230_canmv_dongshanpi_defconfig/
├── big/                           # 大核组件
│   ├── mpp/                      # MPP 编译产物
│   │   ├── kernel/               # MPP 内核模块
│   │   └── userapps/             # MPP 用户应用
│   └── rt-smart/                 # RT-Smart 编译产物
│       ├── rtthread.bin
│       └── rtthread.elf
├── common/                        # 公共组件
│   ├── big-opensbi/              # 大核 OpenSBI
│   │   └── fw_payload.bin
│   ├── little-opensbi/           # 小核 OpenSBI
│   │   └── fw_payload.bin
│   └── cdk/                      # CDK 编译产物
├── little/                        # 小核组件
│   ├── linux/                    # Linux 内核
│   │   ├── vmlinux
│   │   ├── arch/riscv/boot/Image
│   │   └── modules/
│   ├── buildroot-ext/           # Buildroot 产物
│   │   └── images/
│   │       └── rootfs.ext4
│   └── uboot/                    # U-Boot 编译产物
└── images/                       # 最终镜像
    ├── big-core/                 # 大核镜像
    │   ├── rtt_system.bin
    │   └── fastboot_app.elf
    ├── little-core/              # 小核镜像
    │   ├── linux_system.bin      # Linux + DTB
    │   ├── rootfs.ext4
    │   └── uboot/
    ├── sysimage-sdcard.img       # 可烧录镜像
    └── sysimage-sdcard.img.gz    # 压缩镜像
</code></pre></div></div>

<h3 id="62-关键产物说明">6.2 关键产物说明</h3>

<table>
  <thead>
    <tr>
      <th>文件</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">rtthread.bin</code></td>
      <td>RT-Smart 内核镜像</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fw_payload.bin</code></td>
      <td>OpenSBI 固件 (含 payload)</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Image</code></td>
      <td>Linux 内核镜像</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*.dts</code></td>
      <td>设备树二进制</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">linux_system.bin</code></td>
      <td>Linux 内核 + DTB 合并镜像</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">rootfs.ext4</code></td>
      <td>Buildroot 根文件系统</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sysimage-sdcard.img</code></td>
      <td>最终可烧录镜像</td>
    </tr>
  </tbody>
</table>

<h2 id="7-关键配置变量">7. 关键配置变量</h2>

<h3 id="71-编译目录变量">7.1 编译目录变量</h3>

<table>
  <thead>
    <tr>
      <th>变量</th>
      <th>路径</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">output/k230_canmv_dongshanpi_defconfig/</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">MPP_BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">$(BUILD_DIR)/big/mpp</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">RTT_SDK_BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">$(BUILD_DIR)/big/rt-smart</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">LINUX_BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">$(BUILD_DIR)/little/linux</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">BUILDROOT_BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">$(BUILD_DIR)/little/buildroot-ext</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">UBOOT_BUILD_DIR</code></td>
      <td><code class="language-plaintext highlighter-rouge">$(BUILD_DIR)/little/uboot</code></td>
    </tr>
  </tbody>
</table>

<h3 id="72-工具链变量">7.2 工具链变量</h3>

<table>
  <thead>
    <tr>
      <th>组件</th>
      <th>工具链前缀</th>
      <th>路径</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>RT-Smart</td>
      <td><code class="language-plaintext highlighter-rouge">riscv64-unknown-linux-musl-</code></td>
      <td><code class="language-plaintext highlighter-rouge">/opt/toolchain/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin</code></td>
    </tr>
    <tr>
      <td>Linux</td>
      <td><code class="language-plaintext highlighter-rouge">riscv64-unknown-linux-gnu-</code></td>
      <td><code class="language-plaintext highlighter-rouge">/opt/toolchain/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.6.0/bin</code></td>
    </tr>
  </tbody>
</table>

<h3 id="73-编译参数">7.3 编译参数</h3>

<table>
  <thead>
    <tr>
      <th>参数</th>
      <th>值</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>并行编译</td>
      <td><code class="language-plaintext highlighter-rouge">-j16</code></td>
    </tr>
    <tr>
      <td>架构</td>
      <td><code class="language-plaintext highlighter-rouge">riscv</code></td>
    </tr>
    <tr>
      <td>调试级别</td>
      <td><code class="language-plaintext highlighter-rouge">0</code> (Release)</td>
    </tr>
  </tbody>
</table>

<h2 id="8-k230-sdk-配置对比分析">8. K230 SDK 配置对比分析</h2>

<h3 id="81-dongshanpi-配置">8.1 DongshanPI 配置</h3>

<p>当前 <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code> 是<strong>唯一</strong>针对 DongshanPI (东山PI) 的配置：</p>

<table>
  <thead>
    <tr>
      <th>配置项</th>
      <th>DongshanPI 值</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>板级</td>
      <td><code class="language-plaintext highlighter-rouge">CONFIG_BOARD_K230_CANMV_DONGSHANPI=y</code></td>
    </tr>
    <tr>
      <td>U-Boot</td>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi</code></td>
    </tr>
    <tr>
      <td>Linux</td>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi</code></td>
    </tr>
    <tr>
      <td>DTB</td>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi</code></td>
    </tr>
    <tr>
      <td>总内存</td>
      <td>1GB (0x40000000)</td>
    </tr>
    <tr>
      <td>RT-Smart 内存</td>
      <td>126MB (0x07E00000)</td>
    </tr>
    <tr>
      <td>Linux 内存</td>
      <td>128MB (0x08000000)</td>
    </tr>
    <tr>
      <td>MMZ 内存</td>
      <td>252MB (0x0FC00000)</td>
    </tr>
    <tr>
      <td>存储</td>
      <td>SD/eMMC</td>
    </tr>
    <tr>
      <td>WiFi</td>
      <td>RTL8188FU</td>
    </tr>
    <tr>
      <td>双核</td>
      <td>Linux + RT-Smart</td>
    </tr>
  </tbody>
</table>

<h3 id="82-各配置对比表">8.2 各配置对比表</h3>

<table>
  <thead>
    <tr>
      <th>配置文件</th>
      <th>板级</th>
      <th>总内存</th>
      <th>Linux</th>
      <th>RT-Smart</th>
      <th>存储</th>
      <th>WiFi</th>
      <th>用途</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_evb_defconfig</code></td>
      <td>EVB</td>
      <td>512MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC/SPI NAND</td>
      <td>AP6212A</td>
      <td>EVB 开发板</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_defconfig</code></td>
      <td>CanMV</td>
      <td>512MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>AP6212A</td>
      <td>CanMV-K230</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_v2_defconfig</code></td>
      <td>CanMV V2</td>
      <td>512MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>-</td>
      <td>CanMV-K230 V2</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_v3_defconfig</code></td>
      <td>CanMV V3</td>
      <td>512MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>-</td>
      <td>CanMV-K230 V3</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></td>
      <td>DongshanPI</td>
      <td><strong>1GB</strong></td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>RTL8188FU</td>
      <td><strong>东山PI</strong></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_only_linux_defconfig</code></td>
      <td>CanMV</td>
      <td>512MB</td>
      <td>✅</td>
      <td>❌</td>
      <td>SD/eMMC</td>
      <td>AP6212A</td>
      <td>仅 Linux</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_only_rtt_defconfig</code></td>
      <td>CanMV</td>
      <td>256MB</td>
      <td>❌</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>-</td>
      <td>仅 RT-Smart</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230d_defconfig</code></td>
      <td>K230D</td>
      <td>512MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SPI NOR/NAND/eMMC</td>
      <td>-</td>
      <td>K230D 芯片</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230d_canmv_defconfig</code></td>
      <td>K230D CanMV</td>
      <td>128MB</td>
      <td>✅</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>-</td>
      <td>K230D CanMV</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">BPI-CanMV-K230D-Zero_defconfig</code></td>
      <td>BPI K230D</td>
      <td>128MB</td>
      <td>❌</td>
      <td>✅</td>
      <td>SD/eMMC</td>
      <td>-</td>
      <td>香蕉派 K230D Zero</td>
    </tr>
  </tbody>
</table>

<h3 id="83-关键差异分析">8.3 关键差异分析</h3>

<h4 id="内存差异">内存差异</h4>

<table>
  <thead>
    <tr>
      <th>配置</th>
      <th>总内存</th>
      <th>Linux 内存</th>
      <th>RT-Smart 内存</th>
      <th>MMZ</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code></td>
      <td><strong>1GB</strong></td>
      <td>128MB</td>
      <td>126MB</td>
      <td>252MB</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230_canmv_defconfig</code></td>
      <td>512MB</td>
      <td>128MB</td>
      <td>126MB</td>
      <td>252MB</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230d_defconfig</code></td>
      <td>-</td>
      <td>72MB</td>
      <td>20MB</td>
      <td>30MB</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">k230d_canmv_defconfig</code></td>
      <td>128MB</td>
      <td>48MB</td>
      <td>34MB</td>
      <td>43MB</td>
    </tr>
  </tbody>
</table>

<p><strong>DongshanPI 配置特点</strong>：</p>
<ul>
  <li>总内存翻倍 (1GB vs 512MB)</li>
  <li>使用 RTL8188FU WiFi 模块 (其他多使用 AP6212A)</li>
  <li>内存布局包含完整的 MMZ 区域供多媒体和 AI 使用</li>
</ul>

<h4 id="系统配置差异">系统配置差异</h4>

<table>
  <thead>
    <tr>
      <th>配置</th>
      <th>Linux</th>
      <th>RT-Smart</th>
      <th>特性</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_defconfig</code> (默认)</td>
      <td>✅</td>
      <td>✅</td>
      <td>双核完整</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_only_linux</code></td>
      <td>✅</td>
      <td>❌</td>
      <td>仅 Linux</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">_only_rtt</code></td>
      <td>❌</td>
      <td>✅</td>
      <td>仅 RT-Smart</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">BPI-xxx</code></td>
      <td>❌</td>
      <td>✅</td>
      <td>仅 RT-Smart (香蕉派)</td>
    </tr>
  </tbody>
</table>

<h3 id="84-如何选择配置">8.4 如何选择配置</h3>

<ul>
  <li><strong>DongshanPI (东山PI)</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_dongshanpi_defconfig</code> ✅</li>
  <li><strong>CanMV-K230 标准版</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_defconfig</code></li>
  <li><strong>CanMV-K230 V2</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_v2_defconfig</code></li>
  <li><strong>CanMV-K230 V3</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_v3_defconfig</code></li>
  <li><strong>K230 EVB 开发板</strong>: <code class="language-plaintext highlighter-rouge">k230_evb_defconfig</code></li>
  <li><strong>K230D 芯片</strong>: <code class="language-plaintext highlighter-rouge">k230d_defconfig</code> 或 <code class="language-plaintext highlighter-rouge">k230d_canmv_defconfig</code></li>
  <li><strong>仅运行 Linux</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_only_linux_defconfig</code></li>
  <li><strong>仅运行 RT-Smart</strong>: <code class="language-plaintext highlighter-rouge">k230_canmv_only_rtt_defconfig</code></li>
</ul>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="K230" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">ARMv8 系统启动流程深度解析：BL0~BL33、TEE、SMMU 与异常等级</title><link href="https://yangchao315.github.io/ARMv8-Boot-Flow-BL0-BL33-TEE/" rel="alternate" type="text/html" title="ARMv8 系统启动流程深度解析：BL0~BL33、TEE、SMMU 与异常等级" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/ARMv8-Boot-Flow-BL0-BL33-TEE</id><content type="html" xml:base="https://yangchao315.github.io/ARMv8-Boot-Flow-BL0-BL33-TEE/"><![CDATA[<p>ARMv8 平台的启动流程涉及多个引导阶段（BL0~BL33）、安全世界（TrustZone/TEE）、DDR 初始化、MMU/SMMU 配置、中断控制器初始化以及最终跳转到 Linux Kernel。本文从硬件上电复位出发，逐阶段剖析每个 BL 阶段的功能、异常等级切换、TEE 启动机制，并给出 Mermaid 流程图辅助理解。</p>

<!-- more -->

<ul>
  <li><a href="#一armv8-异常等级与安全状态">一、ARMv8 异常等级与安全状态</a>
    <ul>
      <li><a href="#11-exception-level-划分">1.1 Exception Level 划分</a></li>
      <li><a href="#12-安全状态与-trustzone">1.2 安全状态与 TrustZone</a></li>
    </ul>
  </li>
  <li><a href="#二整体启动流程总览">二、整体启动流程总览</a></li>
  <li><a href="#三bl0片上-rom-启动">三、BL0：片上 ROM 启动</a>
    <ul>
      <li><a href="#31-硬件复位与-cpu-状态">3.1 硬件复位与 CPU 状态</a></li>
      <li><a href="#32-bl0-完成的工作">3.2 BL0 完成的工作</a></li>
    </ul>
  </li>
  <li><a href="#四bl1ap-trusted-rom--第一阶段-bootloader">四、BL1：AP Trusted ROM / 第一阶段 Bootloader</a>
    <ul>
      <li><a href="#41-运行环境">4.1 运行环境</a></li>
      <li><a href="#42-主要功能">4.2 主要功能</a></li>
    </ul>
  </li>
  <li><a href="#五bl2trusted-boot-firmware">五、BL2：Trusted Boot Firmware</a>
    <ul>
      <li><a href="#51-ddr-初始化">5.1 DDR 初始化</a></li>
      <li><a href="#52-安全外设初始化">5.2 安全外设初始化</a></li>
      <li><a href="#53-加载后续镜像">5.3 加载后续镜像</a></li>
    </ul>
  </li>
  <li><a href="#六bl31el3-runtime-firmwareatf">六、BL31：EL3 Runtime Firmware（ATF）</a>
    <ul>
      <li><a href="#61-el3-永驻服务">6.1 EL3 永驻服务</a></li>
      <li><a href="#62-gic-中断初始化">6.2 GIC 中断初始化</a></li>
      <li><a href="#63-psci-电源管理">6.3 PSCI 电源管理</a></li>
      <li><a href="#64-smc-调用处理">6.4 SMC 调用处理</a></li>
    </ul>
  </li>
  <li><a href="#七bl32secure-el1-tee-os">七、BL32：Secure EL1 TEE OS</a>
    <ul>
      <li><a href="#71-tee-启动流程">7.1 TEE 启动流程</a></li>
      <li><a href="#72-smmu-安全配置">7.2 SMMU 安全配置</a></li>
      <li><a href="#73-安全内存隔离">7.3 安全内存隔离</a></li>
    </ul>
  </li>
  <li><a href="#八bl33non-secure-bootloaderu-boot--uefi">八、BL33：Non-Secure Bootloader（U-Boot / UEFI）</a>
    <ul>
      <li><a href="#81-mmu-初始化">8.1 MMU 初始化</a></li>
      <li><a href="#82-外设驱动初始化">8.2 外设驱动初始化</a></li>
      <li><a href="#83-kernel-image-加载与跳转">8.3 Kernel Image 加载与跳转</a></li>
    </ul>
  </li>
  <li><a href="#九linux-kernel-早期启动">九、Linux Kernel 早期启动</a>
    <ul>
      <li><a href="#91-heads-汇编阶段">9.1 head.S 汇编阶段</a></li>
      <li><a href="#92-mmu-与页表建立">9.2 MMU 与页表建立</a></li>
      <li><a href="#93-中断控制器与-gic-初始化">9.3 中断控制器与 GIC 初始化</a></li>
    </ul>
  </li>
  <li><a href="#十虚拟化hypervisor-与-guest-os">十、虚拟化：Hypervisor 与 Guest OS</a>
    <ul>
      <li><a href="#101-el2-hypervisor-启动">10.1 EL2 Hypervisor 启动</a></li>
      <li><a href="#102-smmu-虚拟化stage-2-translation">10.2 SMMU 虚拟化（Stage-2 Translation）</a></li>
    </ul>
  </li>
  <li><a href="#十一完整启动时序图">十一、完整启动时序图</a></li>
</ul>

<hr />

<h2 id="一armv8-异常等级与安全状态">一、ARMv8 异常等级与安全状态</h2>

<h3 id="11-exception-level-划分">1.1 Exception Level 划分</h3>

<p>ARMv8-A 定义了 4 个异常等级（Exception Level, EL），权限从低到高：</p>

<table>
  <thead>
    <tr>
      <th>等级</th>
      <th>典型软件</th>
      <th>特权</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>EL0</td>
      <td>用户态应用 / TEE TA</td>
      <td>最低</td>
    </tr>
    <tr>
      <td>EL1</td>
      <td>Linux Kernel / TEE OS (S-EL1)</td>
      <td>内核级</td>
    </tr>
    <tr>
      <td>EL2</td>
      <td>Hypervisor (KVM/Xen)</td>
      <td>虚拟化</td>
    </tr>
    <tr>
      <td>EL3</td>
      <td>Secure Monitor (ATF BL31)</td>
      <td>最高，控制安全/非安全切换</td>
    </tr>
  </tbody>
</table>

<pre><code class="language-mermaid">graph LR
    EL0["EL0\nApp / TA"] --&gt;|异常上升| EL1["EL1\nKernel / TEE OS"]
    EL1 --&gt;|异常上升| EL2["EL2\nHypervisor"]
    EL2 --&gt;|SMC/异常| EL3["EL3\nSecure Monitor\n(ATF BL31)"]
    EL3 --&gt;|切换SCR_EL3.NS| SW["Secure World\nS-EL1 TEE"]
    EL3 --&gt;|切换SCR_EL3.NS=1| NW["Non-Secure World\nEL1/EL2/EL0"]
    style EL3 fill:#c0392b,color:#fff
    style SW fill:#8e44ad,color:#fff
    style NW fill:#2980b9,color:#fff
</code></pre>

<h3 id="12-安全状态与-trustzone">1.2 安全状态与 TrustZone</h3>

<p>ARM TrustZone 将处理器划分为<strong>安全世界（Secure World）</strong>和<strong>普通世界（Normal World）</strong>。<code class="language-plaintext highlighter-rouge">SCR_EL3.NS</code> 位控制当前世界：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">NS=0</code>：安全世界，访问所有内存/外设</li>
  <li><code class="language-plaintext highlighter-rouge">NS=1</code>：普通世界，被 TrustZone 保护区域不可访问</li>
</ul>

<p>EL3（Secure Monitor）是唯一能够在两个世界之间切换的等级，通过 <code class="language-plaintext highlighter-rouge">SMC</code>（Secure Monitor Call）指令触发。</p>

<hr />

<h2 id="二整体启动流程总览">二、整体启动流程总览</h2>

<pre><code class="language-mermaid">flowchart TD
    RESET([上电复位\nCPU Reset Vector]) --&gt; BL0
    BL0["BL0\n片上 ROM\nEL3 Secure\n- CPU 最小初始化\n- 验证 BL1/BL2\n- 加载到 SRAM"] --&gt; BL1
    BL1["BL1\nAP Trusted ROM\nEL3 Secure\n- 时钟/PLL 初始化\n- Flash/eMMC 驱动\n- 加载 BL2"] --&gt; BL2
    BL2["BL2\nTrusted Boot Firmware\nEL1 Secure\n- DDR 初始化训练\n- TZASC/TZC400 配置\n- 加载 BL31/BL32/BL33"] --&gt; BL31
    BL2 --&gt; BL32
    BL2 --&gt; BL33_img["BL33 镜像\n加载到 DRAM"]
    BL31["BL31\nEL3 Runtime\n- GIC 初始化\n- PSCI\n- SMC 处理\n- 永驻 EL3"] --&gt; BL32
    BL32["BL32\nTEE OS (OP-TEE)\nS-EL1\n- Secure Heap\n- SMMU 安全配置\n- TA 管理"] --&gt; BL33
    BL33["BL33\nU-Boot / UEFI\nEL2/EL1 Non-Secure\n- MMU 开启\n- 外设驱动\n- 加载 Kernel\n- 设备树传递"] --&gt; KERNEL
    KERNEL["Linux Kernel\nEL1 Non-Secure\n- head.S 汇编\n- 页表重建\n- GIC 驱动\n- SMMU 驱动\n- 子系统初始化"] --&gt; USERSPACE
    USERSPACE([用户空间\nEL0])

    style RESET fill:#27ae60,color:#fff
    style BL0 fill:#e74c3c,color:#fff
    style BL1 fill:#e67e22,color:#fff
    style BL2 fill:#f39c12,color:#fff
    style BL31 fill:#c0392b,color:#fff
    style BL32 fill:#8e44ad,color:#fff
    style BL33 fill:#2980b9,color:#fff
    style KERNEL fill:#16a085,color:#fff
    style USERSPACE fill:#27ae60,color:#fff
</code></pre>

<hr />

<h2 id="三bl0片上-rom-启动">三、BL0：片上 ROM 启动</h2>

<h3 id="31-硬件复位与-cpu-状态">3.1 硬件复位与 CPU 状态</h3>

<p>CPU 上电或复位后，PC 跳转到固定的复位向量（Reset Vector），通常为片上 ROM 起始地址（如 <code class="language-plaintext highlighter-rouge">0x00000000</code> 或 <code class="language-plaintext highlighter-rouge">0xFFFF0000</code>）。此时处于：</p>
<ul>
  <li><strong>EL3</strong>，<strong>安全世界</strong></li>
  <li>AArch64 或 AArch32（由 <code class="language-plaintext highlighter-rouge">RES1</code> 引脚/熔丝决定）</li>
  <li>寄存器处于 UNKNOWN 状态，需要软件初始化</li>
</ul>

<h3 id="32-bl0-完成的工作">3.2 BL0 完成的工作</h3>

<pre><code class="language-mermaid">flowchart LR
    A[CPU 复位 EL3] --&gt; B[栈指针 SP_EL3 初始化]
    B --&gt; C[CPU 内部寄存器清零\nSCTLR_EL3 关闭 MMU/Cache]
    C --&gt; D[安全配置寄存器\nSCR_EL3 初始化]
    D --&gt; E[片上 SRAM 可用性检测]
    E --&gt; F[存储接口初始化\neMMC/SPI NOR BootROM驱动]
    F --&gt; G[镜像签名验证\nHASH/RSA 公钥]
    G --&gt; H{验证通过?}
    H -- Yes --&gt; I[加载 BL1/BL2 到 SRAM]
    H -- No --&gt; J[进入恢复模式\nUSB/UART下载]
    I --&gt; K[跳转 BL1/BL2\nATF Entry Point]
</code></pre>

<p>关键寄存器初始化：</p>
<pre><code class="language-asm">/* 关闭 MMU，禁用 I/D Cache，进入已知状态 */
msr     SCTLR_EL3, xzr
isb

/* 配置安全状态：EL3 为 AArch64，允许访问安全内存 */
mov     x0, #(SCR_RES1_BITS | SCR_RW_BIT)
msr     SCR_EL3, x0

/* 设置异常向量表 */
adr     x0, bl0_vector_table
msr     VBAR_EL3, x0
isb
</code></pre>

<hr />

<h2 id="四bl1ap-trusted-rom--第一阶段-bootloader">四、BL1：AP Trusted ROM / 第一阶段 Bootloader</h2>

<h3 id="41-运行环境">4.1 运行环境</h3>

<ul>
  <li><strong>异常等级</strong>：EL3，安全世界</li>
  <li><strong>运行介质</strong>：片上 SRAM（DDR 尚未初始化）</li>
  <li><strong>入口</strong>：ATF 标准入口 <code class="language-plaintext highlighter-rouge">bl1_entrypoint</code></li>
</ul>

<h3 id="42-主要功能">4.2 主要功能</h3>

<table>
  <thead>
    <tr>
      <th>功能</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>CPU 架构初始化</td>
      <td>开启指令缓存（I-Cache），设置 CPACR/CPTR</td>
    </tr>
    <tr>
      <td>PLL/时钟初始化</td>
      <td>配置主 PLL，提升 CPU 频率至工作频率</td>
    </tr>
    <tr>
      <td>UART 初始化</td>
      <td>早期调试串口输出</td>
    </tr>
    <tr>
      <td>存储控制器初始化</td>
      <td>eMMC/UFS/SPI NOR 控制器基本配置</td>
    </tr>
    <tr>
      <td>BL2 镜像加载</td>
      <td>从存储介质加载 BL2 到 SRAM/IRAM</td>
    </tr>
    <tr>
      <td>镜像认证</td>
      <td>使用 TBB（Trusted Board Boot）验证 BL2 签名</td>
    </tr>
    <tr>
      <td>跳转 BL2</td>
      <td>通过 <code class="language-plaintext highlighter-rouge">bl1_run_next_image()</code> 跳转到 BL2 EL1</td>
    </tr>
  </tbody>
</table>

<p>BL1 → BL2 的异常等级切换（EL3 → EL1 Secure）：</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* ATF bl1_main.c 简化逻辑 */</span>
<span class="kt">void</span> <span class="nf">bl1_main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* 加载 BL2 镜像描述 */</span>
    <span class="n">image_info_t</span> <span class="n">bl2_image</span> <span class="o">=</span> <span class="n">load_image</span><span class="p">(</span><span class="n">BL2_ID</span><span class="p">);</span>

    <span class="cm">/* 构造 BL2 入口参数：在 EL1 Secure 运行 */</span>
    <span class="n">entry_point_info_t</span> <span class="n">ep</span> <span class="o">=</span> <span class="p">{</span>
        <span class="p">.</span><span class="n">pc</span>    <span class="o">=</span> <span class="n">bl2_image</span><span class="p">.</span><span class="n">image_base</span><span class="p">,</span>
        <span class="p">.</span><span class="n">spsr</span>  <span class="o">=</span> <span class="n">SPSR_64</span><span class="p">(</span><span class="n">MODE_EL1</span><span class="p">,</span> <span class="n">MODE_SP_ELX</span><span class="p">,</span> <span class="n">DISABLE_ALL_EXCEPTIONS</span><span class="p">),</span>
        <span class="cm">/* NS bit = 0 → Secure EL1 */</span>
    <span class="p">};</span>

    <span class="cm">/* ERET 到 EL1S */</span>
    <span class="n">bl1_run_next_image</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ep</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="五bl2trusted-boot-firmware">五、BL2：Trusted Boot Firmware</h2>

<p>BL2 在 <strong>Secure EL1</strong> 运行，是启动链中功能最复杂的阶段，核心职责是初始化 DDR 并加载后续所有镜像。</p>

<h3 id="51-ddr-初始化">5.1 DDR 初始化</h3>

<p>DDR 初始化是 BL2 最关键的硬件工作，分为以下步骤：</p>

<pre><code class="language-mermaid">flowchart TD
    A[BL2 开始 DDR 初始化] --&gt; B[DDR PHY 复位\n配置 PLL/时钟]
    B --&gt; C[ZQ 校准\nODT/驱动强度]
    C --&gt; D[发送 MRS 命令\n配置 MR0-MR6]
    D --&gt; E[Write Leveling\n时序对齐]
    E --&gt; F[Read/Write DQ Training\nDLL 锁相]
    F --&gt; G[内存颗粒 BIST 测试]
    G --&gt; H{测试通过?}
    H -- Yes --&gt; I[DDR 控制器 DRAM Map 配置\n地址映射/交织]
    H -- No --&gt; J[尝试降速/换配置\n失败则 Panic]
    I --&gt; K[ECC 初始化\n全内存清零]
    K --&gt; L[DDR 可用\n迁移运行环境到 DRAM]
</code></pre>

<h3 id="52-安全外设初始化">5.2 安全外设初始化</h3>

<p>BL2 配置 TrustZone 内存/外设保护控制器，防止普通世界访问安全资源：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* TZC-400 配置示例（保护安全内存区域）*/</span>
<span class="n">tzc400_init</span><span class="p">(</span><span class="n">TZC_BASE</span><span class="p">);</span>
<span class="cm">/* 区域0：默认拒绝所有访问 */</span>
<span class="n">tzc400_configure_region0</span><span class="p">(</span><span class="n">TZC_REGION_S_NONE</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="cm">/* 区域1：安全 TEE 内存，仅 Secure 可访问 */</span>
<span class="n">tzc400_configure_region</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span>
    <span class="n">TEE_DRAM_BASE</span><span class="p">,</span> <span class="n">TEE_DRAM_BASE</span> <span class="o">+</span> <span class="n">TEE_DRAM_SIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span>
    <span class="n">TZC_REGION_S_RDWR</span><span class="p">,</span>   <span class="cm">/* Secure RW */</span>
    <span class="mi">0</span><span class="p">);</span>                   <span class="cm">/* Non-Secure 拒绝 */</span>
<span class="cm">/* 区域2：共享内存，Normal World 只读 */</span>
<span class="n">tzc400_configure_region</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">SHARED_MEM_BASE</span><span class="p">,</span> <span class="n">SHARED_MEM_BASE</span> <span class="o">+</span> <span class="n">SHARED_MEM_SIZE</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span>
    <span class="n">TZC_REGION_S_RDWR</span><span class="p">,</span>
    <span class="n">TZC_REGION_ACCESS_RDONLY</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="n">tzc400_set_action</span><span class="p">(</span><span class="n">TZC_ACTION_ERR</span><span class="p">);</span> <span class="cm">/* 违规触发总线错误 */</span>
</code></pre></div></div>

<h3 id="53-加载后续镜像">5.3 加载后续镜像</h3>

<p>BL2 依次加载 BL31（EL3 Runtime）、BL32（TEE OS）、BL33（U-Boot）并验证签名，然后通过 <code class="language-plaintext highlighter-rouge">bl2_run_next_image</code> 跳转到 BL31：</p>

<pre><code class="language-mermaid">sequenceDiagram
    participant BL2
    participant Storage as eMMC/Flash
    participant DRAM

    BL2-&gt;&gt;Storage: 读取 FIP 镜像包
    Storage--&gt;&gt;BL2: FIP (BL31+BL32+BL33+证书)
    BL2-&gt;&gt;BL2: 验证 FIP 签名链 (TBB)
    BL2-&gt;&gt;DRAM: 加载 BL31 → BL31_BASE
    BL2-&gt;&gt;DRAM: 加载 BL32 → BL32_BASE (Secure DRAM)
    BL2-&gt;&gt;DRAM: 加载 BL33 → BL33_BASE (NS DRAM)
    BL2-&gt;&gt;BL2: 构造 BL31 入口参数\n(bl31_params: BL32/BL33 ep_info)
    BL2-&gt;&gt;BL2: ERET → EL3 跳转 BL31
</code></pre>

<hr />

<h2 id="六bl31el3-runtime-firmwareatf">六、BL31：EL3 Runtime Firmware（ATF）</h2>

<p>BL31 是<strong>永驻 EL3</strong> 的运行时固件，负责提供 EL3 级安全服务。系统运行期间，BL31 始终驻留在安全内存中，通过 <code class="language-plaintext highlighter-rouge">SMC</code> 接口对外提供服务。</p>

<h3 id="61-el3-永驻服务">6.1 EL3 永驻服务</h3>

<pre><code class="language-mermaid">graph TB
    subgraph EL3["EL3 BL31 (永驻)"]
        PSCI["PSCI\n电源管理服务\nCPU_ON/OFF\nSYSTEM_SUSPEND"]
        SMC_HANDLER["SMC 分发器\nSMC Handler"]
        SDEI["SDEI\n软件授权异常接口"]
        TZ_MGMT["TrustZone 世界切换\n安全/普通世界管理"]
        GIC_EL3["GIC EL3 部分配置\nFIQ 路由到 EL3"]
    end
    NORMAL["Normal World\nEL1/EL0"] --&gt;|SMC 指令| SMC_HANDLER
    SECURE["Secure World\nS-EL1 TEE"] --&gt;|SMC 指令| SMC_HANDLER
    SMC_HANDLER --&gt; PSCI
    SMC_HANDLER --&gt; SDEI
    SMC_HANDLER --&gt; TZ_MGMT
    TZ_MGMT --&gt;|ERET NS=1| NORMAL
    TZ_MGMT --&gt;|ERET NS=0| SECURE
</code></pre>

<h3 id="62-gic-中断初始化">6.2 GIC 中断初始化</h3>

<p>ARMv8 系统通常使用 GICv3/v4 中断控制器。BL31 完成 Distributor 和 Re-Distributor 的基础初始化：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* GICv3 初始化 (gicv3_driver_init) */</span>
<span class="kt">void</span> <span class="nf">gicv3_distif_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* 禁用 Distributor */</span>
    <span class="n">gicd_write_ctlr</span><span class="p">(</span><span class="n">gicd_base</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>

    <span class="cm">/* 配置所有 SPI 为不触发（默认禁用）*/</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="n">MIN_SPI_ID</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">MAX_SPI_ID</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">32</span><span class="p">)</span>
        <span class="n">gicd_write_icenabler</span><span class="p">(</span><span class="n">gicd_base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">);</span>

    <span class="cm">/* 设置 SPI 默认优先级 */</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="n">MIN_SPI_ID</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">MAX_SPI_ID</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">)</span>
        <span class="n">gicd_write_ipriorityr</span><span class="p">(</span><span class="n">gicd_base</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">GIC_HIGHEST_NS_PRIORITY</span><span class="p">);</span>

    <span class="cm">/* 启用 Affinity Routing (ARE_S/ARE_NS) */</span>
    <span class="n">gicd_write_ctlr</span><span class="p">(</span><span class="n">gicd_base</span><span class="p">,</span>
        <span class="n">CTLR_ENABLE_G0_BIT</span> <span class="o">|</span> <span class="n">CTLR_ENABLE_G1S_BIT</span> <span class="o">|</span>
        <span class="n">CTLR_ENABLE_G1NS_BIT</span> <span class="o">|</span> <span class="n">CTLR_ARE_S_BIT</span> <span class="o">|</span> <span class="n">CTLR_ARE_NS_BIT</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>GIC 中断分组策略：</p>

<table>
  <thead>
    <tr>
      <th>中断组</th>
      <th>目标</th>
      <th>触发信号</th>
      <th>用途</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Group 0</td>
      <td>EL3</td>
      <td>FIQ</td>
      <td>安全中断，EL3 直接处理</td>
    </tr>
    <tr>
      <td>Group 1 Secure</td>
      <td>S-EL1 TEE</td>
      <td>FIQ</td>
      <td>TEE 专用中断（TrustZone 外设）</td>
    </tr>
    <tr>
      <td>Group 1 Non-Secure</td>
      <td>EL1/EL2</td>
      <td>IRQ</td>
      <td>Linux 普通中断</td>
    </tr>
  </tbody>
</table>

<h3 id="63-psci-电源管理">6.3 PSCI 电源管理</h3>

<p>PSCI（Power State Coordination Interface）是 Linux 通过 SMC 调用 BL31 实现 CPU 热插拔、系统休眠的标准接口：</p>

<pre><code class="language-mermaid">sequenceDiagram
    participant Linux as Linux Kernel EL1
    participant BL31 as BL31 EL3
    participant HW as 电源管理硬件

    Linux-&gt;&gt;BL31: SMC(PSCI_CPU_OFF)
    BL31-&gt;&gt;BL31: 保存 CPU 上下文
    BL31-&gt;&gt;HW: 关闭 CPU 电源域
    Note over BL31: CPU 进入 OFF 状态

    Linux-&gt;&gt;BL31: SMC(PSCI_CPU_ON, mpidr, entry)
    BL31-&gt;&gt;HW: 上电 CPU 电源域
    BL31-&gt;&gt;Linux: ERET 到指定 entry 地址
</code></pre>

<h3 id="64-smc-调用处理">6.4 SMC 调用处理</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* BL31 SMC 处理入口（简化）*/</span>
<span class="kt">uintptr_t</span> <span class="nf">smc_handler</span><span class="p">(</span><span class="kt">uint32_t</span> <span class="n">smc_fid</span><span class="p">,</span> <span class="n">u_register_t</span> <span class="n">x1</span><span class="p">,</span>
                      <span class="n">u_register_t</span> <span class="n">x2</span><span class="p">,</span> <span class="n">u_register_t</span> <span class="n">x3</span><span class="p">,</span>
                      <span class="n">u_register_t</span> <span class="n">x4</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">cookie</span><span class="p">,</span>
                      <span class="kt">void</span> <span class="o">*</span><span class="n">handle</span><span class="p">,</span> <span class="n">u_register_t</span> <span class="n">flags</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="n">owning_entity</span> <span class="o">=</span> <span class="n">GET_SMC_OEN</span><span class="p">(</span><span class="n">smc_fid</span><span class="p">);</span>

    <span class="k">switch</span> <span class="p">(</span><span class="n">owning_entity</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">case</span> <span class="n">OEN_ARM_START</span> <span class="p">...</span> <span class="n">OEN_ARM_END</span><span class="p">:</span>
        <span class="cm">/* ARM 标准服务：PSCI, SDEI, etc. */</span>
        <span class="k">return</span> <span class="n">arm_svc_smc_handler</span><span class="p">(</span><span class="n">smc_fid</span><span class="p">,</span> <span class="p">...);</span>
    <span class="k">case</span> <span class="n">OEN_SIP_START</span> <span class="p">...</span> <span class="n">OEN_SIP_END</span><span class="p">:</span>
        <span class="cm">/* 厂商 SiP 服务（如 Amlogic 私有服务）*/</span>
        <span class="k">return</span> <span class="n">sip_svc_smc_handler</span><span class="p">(</span><span class="n">smc_fid</span><span class="p">,</span> <span class="p">...);</span>
    <span class="k">case</span> <span class="n">OEN_TOS_START</span> <span class="p">...</span> <span class="n">OEN_TOS_END</span><span class="p">:</span>
        <span class="cm">/* 路由到 TEE OS (BL32) */</span>
        <span class="k">return</span> <span class="n">optee_smc_handler</span><span class="p">(</span><span class="n">smc_fid</span><span class="p">,</span> <span class="p">...);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="七bl32secure-el1-tee-os">七、BL32：Secure EL1 TEE OS</h2>

<p>BL32 通常是 <strong>OP-TEE</strong>（Open Portable Trusted Execution Environment），运行于 <strong>Secure EL1</strong>，提供安全存储、密钥管理、DRM、指纹等可信服务。</p>

<h3 id="71-tee-启动流程">7.1 TEE 启动流程</h3>

<pre><code class="language-mermaid">flowchart TD
    BL31_LAUNCH["BL31 启动 BL32\nERET → S-EL1"] --&gt; OPTEE_RESET
    OPTEE_RESET["OP-TEE head.S\n- 设置 SP_EL1\n- 初始化异常向量\n- 关闭 MMU"] --&gt; PLAT_INIT
    PLAT_INIT["平台初始化\n- Secure UART\n- 平台特定外设"] --&gt; MEM_INIT
    MEM_INIT["安全内存初始化\n- Secure Heap 建立\n- 内存池划分"] --&gt; MMU_INIT
    MMU_INIT["MMU 初始化\n- 安全页表建立\n- TTBR0_EL1 设置\n- 开启 MMU"] --&gt; THREAD_INIT
    THREAD_INIT["线程系统初始化\n- Boot thread\n- IRQ stack"] --&gt; TA_FRAMEWORK
    TA_FRAMEWORK["TA 框架初始化\n- 安全存储 rpmb\n- 密码库 libtomcrypt"] --&gt; NOTIFY_BL31
    NOTIFY_BL31["通知 BL31\n- SMC OPTEE_CALL_RETURN_FROM_RPC\n- TEE OS 初始化完毕"] --&gt; WAIT_NS
    WAIT_NS["等待 Normal World 调用\n通过 SMC 进入 TEE"]
</code></pre>

<h3 id="72-smmu-安全配置">7.2 SMMU 安全配置</h3>

<p>SMMU（System Memory Management Unit）是外设 DMA 的 MMU，BL2/BL32 需配置其安全属性，防止外设 DMA 访问安全内存：</p>

<pre><code class="language-mermaid">graph TB
    subgraph SMMUv3["SMMUv3 架构"]
        direction TB
        NS_STREAM["Non-Secure 设备流\n(NS StreamID)"]
        S_STREAM["Secure 设备流\n(S StreamID)"]
        STB["Stream Table\n(Linear/2-Level)"]
        STE_NS["STE: Stage-1 (NS)\nIOVA → IPA\n+ Stage-2\nIPA → PA"]
        STE_S["STE: S-Stage-1\nIOVA → Secure PA\n只能访问安全内存"]
        CMDQ["Command Queue\nINVALIDATE/SYNC"]
        EVENTQ["Event Queue\n违规上报"]
    end

    NS_STREAM --&gt; STB --&gt; STE_NS
    S_STREAM --&gt; STB --&gt; STE_S
    STE_NS --&gt;|违规| EVENTQ
    CMDQ --&gt;|管理| STB

    BL32["BL32 配置 Secure STE\n绑定安全外设 StreamID"] --&gt; S_STREAM
    BL33["BL33/Kernel 配置 NS STE\n建立 IOVA 页表"] --&gt; NS_STREAM
</code></pre>

<h3 id="73-安全内存隔离">7.3 安全内存隔离</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>物理内存布局示例（基于 TZC-400 保护）：

0x00000000 ┌─────────────────────────────┐
           │  BL31 (EL3 Runtime Code)    │ ← Secure Only
0x04000000 ├─────────────────────────────┤
           │  OP-TEE OS (BL32)           │ ← Secure Only
           │  + Secure Heap              │
0x06000000 ├─────────────────────────────┤
           │  TEE Shared Memory          │ ← NS Read / S RW
0x06100000 ├─────────────────────────────┤
           │  Normal World DRAM          │ ← NS RW (主内存)
           │  (Linux Kernel, 用户空间)   │
0x80000000 └─────────────────────────────┘
</code></pre></div></div>

<hr />

<h2 id="八bl33non-secure-bootloaderu-boot--uefi">八、BL33：Non-Secure Bootloader（U-Boot / UEFI）</h2>

<p>BL31 启动完 BL32（TEE）后，通过 ERET 切换到普通世界，跳转到 BL33（通常是 U-Boot）。BL33 运行于 <strong>EL2 或 EL1，普通世界</strong>。</p>

<h3 id="81-mmu-初始化">8.1 MMU 初始化</h3>

<p>U-Boot 在 <code class="language-plaintext highlighter-rouge">board_init_f()</code> 阶段开启 MMU（用于 Cache 加速和内存保护）：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* U-Boot arch/arm/cpu/armv8/cache.c 简化 */</span>
<span class="kt">void</span> <span class="nf">enable_caches</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="cm">/* 建立平坦映射页表（identity map）*/</span>
    <span class="n">setup_pgtables</span><span class="p">();</span>   <span class="cm">/* TTBR0_EL1/EL2 指向页表基地址 */</span>

    <span class="cm">/* 设置 TCR_EL2：4KB 粒度，48-bit VA */</span>
    <span class="n">write_tcr_el2</span><span class="p">(</span><span class="n">TCR_EL2_PS_BITS_48</span> <span class="o">|</span> <span class="n">TCR_EL2_TG0_4K</span> <span class="o">|</span>
                  <span class="n">TCR_EL2_IRGN0_WBWA</span> <span class="o">|</span> <span class="n">TCR_EL2_ORGN0_WBWA</span> <span class="o">|</span>
                  <span class="n">TCR_EL2_T0SZ</span><span class="p">(</span><span class="mi">16</span><span class="p">));</span>

    <span class="cm">/* MAIR：内存属性配置（Device/Normal/NC）*/</span>
    <span class="n">write_mair_el2</span><span class="p">(</span><span class="n">MAIR_ATTR_DEVICE_nGnRE</span>    <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">0</span> <span class="o">*</span> <span class="mi">8</span><span class="p">)</span> <span class="o">|</span>
                   <span class="n">MAIR_ATTR_NORMAL_WB_NTR_RA_WA</span> <span class="o">&lt;&lt;</span> <span class="p">(</span><span class="mi">1</span> <span class="o">*</span> <span class="mi">8</span><span class="p">));</span>

    <span class="n">isb</span><span class="p">();</span>
    <span class="cm">/* 开启 MMU + D-Cache + I-Cache */</span>
    <span class="n">set_sctlr</span><span class="p">(</span><span class="n">get_sctlr</span><span class="p">()</span> <span class="o">|</span> <span class="n">CR_M</span> <span class="o">|</span> <span class="n">CR_C</span> <span class="o">|</span> <span class="n">CR_I</span><span class="p">);</span>
    <span class="n">isb</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="82-外设驱动初始化">8.2 外设驱动初始化</h3>

<p>U-Boot 的外设初始化顺序（<code class="language-plaintext highlighter-rouge">initcall_run_list</code>）：</p>

<pre><code class="language-mermaid">flowchart LR
    A[board_init_f] --&gt; B[arch_cpu_init\n基础 CPU 配置]
    B --&gt; C[timer_init\n系统定时器]
    C --&gt; D[env_init\n环境变量]
    D --&gt; E[serial_init\nUART 串口]
    E --&gt; F[board_init_r\n完整初始化]
    F --&gt; G[mmc_init\neMMC/SD 驱动]
    F --&gt; H[usb_init\nUSB 驱动]
    F --&gt; I[net_init\n以太网]
    F --&gt; J[pci_init\nPCIe]
    G &amp; H &amp; I &amp; J --&gt; K[启动命令解析\nbootcmd 执行]
    K --&gt; L[加载 Kernel + DTB\nfatload/ext4load]
    L --&gt; M[bootm/booti 命令\n跳转 Kernel]
</code></pre>

<h3 id="83-kernel-image-加载与跳转">8.3 Kernel Image 加载与跳转</h3>

<p>ARM64 Linux Kernel（Image/Image.gz）加载到 DRAM 后，U-Boot 通过 <code class="language-plaintext highlighter-rouge">booti</code> 命令跳转：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># U-Boot 典型启动命令</span>
setenv bootargs <span class="s2">"root=/dev/mmcblk0p2 rootwait console=ttyAML0,115200"</span>
fatload mmc 0:1 <span class="k">${</span><span class="nv">kernel_addr_r</span><span class="k">}</span> Image        <span class="c"># 加载 Kernel</span>
fatload mmc 0:1 <span class="k">${</span><span class="nv">fdt_addr_r</span><span class="k">}</span>    device.dtb   <span class="c"># 加载设备树</span>
booti <span class="k">${</span><span class="nv">kernel_addr_r</span><span class="k">}</span> - <span class="k">${</span><span class="nv">fdt_addr_r</span><span class="k">}</span>        <span class="c"># 跳转</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">booti</code> 实际调用流程（最终跳转到 Kernel entry）：</p>

<pre><code class="language-mermaid">sequenceDiagram
    participant UBoot as U-Boot
    participant ATF as BL31 EL3
    participant Kernel as Linux Kernel

    UBoot-&gt;&gt;UBoot: 校验 ARM64 Image magic (0x644d5241)
    UBoot-&gt;&gt;UBoot: 关闭 MMU/Cache (cleanup_before_linux)
    UBoot-&gt;&gt;UBoot: 设置 x0=fdt地址, x1/x2/x3=0
    Note over UBoot: SPSR 配置目标为 EL2/EL1
    UBoot-&gt;&gt;ATF: SMC(PSCI_SYSTEM_RESET) [可选]\n或直接 br x4 跳转 Kernel entry
    ATF-&gt;&gt;ATF: ERET → EL2/EL1 (Non-Secure)
    ATF-&gt;&gt;Kernel: 跳转到 kernel_entry(fdt, 0, 0, 0)
    Note over Kernel: x0 = 设备树 DTB 物理地址
</code></pre>

<hr />

<h2 id="九linux-kernel-早期启动">九、Linux Kernel 早期启动</h2>

<h3 id="91-heads-汇编阶段">9.1 head.S 汇编阶段</h3>

<p>Linux Kernel 入口 <code class="language-plaintext highlighter-rouge">arch/arm64/kernel/head.S</code> 完成 MMU 开启前的准备工作：</p>

<pre><code class="language-mermaid">flowchart TD
    ENTRY["_head (kernel entry)\nx0=DTB 地址"] --&gt; PRESERVE_DTB["保存 x0 (DTB 地址) 到 x21"]
    PRESERVE_DTB --&gt; EL_CHECK["el2_setup:\n判断当前异常等级\n(EL2 还是 EL1)"]
    EL_CHECK --&gt;|EL2| HYP_STUB["安装 HYP stub\nHVC trap 处理\n降级到 EL1"]
    EL_CHECK --&gt;|EL1| NEXT
    HYP_STUB --&gt; NEXT
    NEXT["set_cpu_boot_mode_flag\n保存启动模式"] --&gt; PRESERVE_ARGS["__preserve_boot_args\n保存 x0-x3"]
    PRESERVE_ARGS --&gt; KASLR["__relocate_kernel\nKASLR 地址随机化 (可选)"]
    KASLR --&gt; PGTABLE["__create_page_tables\n建立初始页表\nidmap_pg_dir + init_pg_dir"]
    PGTABLE --&gt; MMU_ON["__primary_switch\n开启 MMU\nTTBR0 = idmap, TTBR1 = init"]
    MMU_ON --&gt; START_KERNEL["__primary_switched\n→ start_kernel()"]
</code></pre>

<h3 id="92-mmu-与页表建立">9.2 MMU 与页表建立</h3>

<p>ARM64 Linux 使用 4 级页表（4KB 页，48-bit VA），内核地址空间从 <code class="language-plaintext highlighter-rouge">0xFFFF000000000000</code> 开始：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ARM64 虚拟地址空间划分 (48-bit VA, 4KB)：

0x0000000000000000 - 0x0000FFFFFFFFFFFF  用户空间 (TTBR0_EL1)
0xFFFF000000000000 - 0xFFFFFFFFFFFFFFFF  内核空间 (TTBR1_EL1)
                                          ↑ 包含：线性映射、vmalloc、vmemmap
</code></pre></div></div>

<h3 id="93-中断控制器与-gic-初始化">9.3 中断控制器与 GIC 初始化</h3>

<p>Linux 在 <code class="language-plaintext highlighter-rouge">start_kernel()</code> → <code class="language-plaintext highlighter-rouge">init_IRQ()</code> → DT 解析 GIC 节点后初始化 GICv3 驱动：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* drivers/irqchip/irq-gic-v3.c 关键初始化 */</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">gic_init_bases</span><span class="p">(...)</span>
<span class="p">{</span>
    <span class="cm">/* 初始化 Distributor */</span>
    <span class="n">gic_dist_init</span><span class="p">(</span><span class="n">gic_data</span><span class="p">);</span>

    <span class="cm">/* 每个 CPU 初始化 Redistributor + CPU Interface */</span>
    <span class="n">gic_cpu_init</span><span class="p">(</span><span class="n">gic_data</span><span class="p">);</span>        <span class="cm">/* 设置 SRE, PMR, BPR */</span>
    <span class="n">gic_smp_init</span><span class="p">();</span>                <span class="cm">/* 注册 IPI 中断 */</span>

    <span class="cm">/* 设置中断亲和性、优先级、触发方式 */</span>
    <span class="n">set_handle_irq</span><span class="p">(</span><span class="n">gic_handle_irq</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>GIC 中断处理流程：</p>

<pre><code class="language-mermaid">flowchart LR
    IRQ_SRC["外设触发 IRQ\n(SPI/PPI/SGI)"] --&gt; GIC_DIST["GIC Distributor\n仲裁 + 路由"]
    GIC_DIST --&gt; GIC_REDIST["Redistributor\n（目标 CPU）"]
    GIC_REDIST --&gt; CPU_IF["CPU Interface\nICC_IAR1_EL1 读取"]
    CPU_IF --&gt; KERNEL_IRQ["Linux IRQ 向量\nel1_irq / el0_irq"]
    KERNEL_IRQ --&gt; HANDLE["handle_arch_irq()\n→ 设备驱动 handler"]
    HANDLE --&gt; EOI["ICC_EOIR1_EL1\n中断结束 EOI"]
</code></pre>

<hr />

<h2 id="十虚拟化hypervisor-与-guest-os">十、虚拟化：Hypervisor 与 Guest OS</h2>

<h3 id="101-el2-hypervisor-启动">10.1 EL2 Hypervisor 启动</h3>

<p>当系统支持虚拟化时（如运行 KVM），Linux 可作为 Hypervisor 运行于 EL2，或通过 KVM 模块在 EL1 宿主机上管理 EL1 Guest：</p>

<pre><code class="language-mermaid">flowchart TD
    BL33 --&gt;|"SPSR EL2"| KVM_HOST["Linux Host\nEL2 (VHE) 或 EL1"]
    KVM_HOST --&gt; KVM_MOD["KVM 模块加载\n__kvm_hyp_init\n安装 EL2 向量表"]
    KVM_MOD --&gt; VCPU["创建 VCPU\nkvm_vcpu_create()"]
    VCPU --&gt; GUEST_RUN["kvm_arch_vcpu_ioctl_run()\nhyp_entry"]
    GUEST_RUN --&gt; GUEST["Guest OS EL1\n(VM 内核)"]
    GUEST --&gt;|"HVC/物理中断"| KVM_EXIT["VM Exit\nhandle_exit()"]
    KVM_EXIT --&gt; EMULATE["MMIO 模拟\n中断注入\n设备透传"]
    EMULATE --&gt; GUEST_RUN

    style KVM_HOST fill:#2980b9,color:#fff
    style GUEST fill:#27ae60,color:#fff
    style KVM_MOD fill:#e67e22,color:#fff
</code></pre>

<h3 id="102-smmu-虚拟化stage-2-translation">10.2 SMMU 虚拟化（Stage-2 Translation）</h3>

<p>SMMU 支持两阶段地址翻译，配合 Hypervisor 实现外设直通（VFIO/IOMMU）：</p>

<pre><code class="language-mermaid">graph LR
    DEV["外设 DMA\n(Guest StreamID)"]
    S1["Stage-1 翻译\nGuest IOVA → IPA\n(Guest OS 配置)"]
    S2["Stage-2 翻译\nIPA → PA\n(Hypervisor 配置)"]
    MEM["物理内存"]

    DEV --&gt;|IOVA| S1 --&gt;|IPA| S2 --&gt;|PA| MEM

    SMMU_NS["SMMU NS 寄存器\nNSMAP:允许 Guest OS\n更新 Stage-1 页表"] --&gt; S1
    SMMU_HYP["Hypervisor\n控制 Stage-2 页表\n限制 Guest 访问范围"] --&gt; S2
</code></pre>

<hr />

<h2 id="十一完整启动时序图">十一、完整启动时序图</h2>

<pre><code class="language-mermaid">sequenceDiagram
    participant ROM as BL0 ROM (EL3-S)
    participant BL1 as BL1 (EL3-S)
    participant BL2 as BL2 (EL1-S)
    participant BL31 as BL31 EL3 Runtime
    participant TEE as BL32 OP-TEE (S-EL1)
    participant UBoot as BL33 U-Boot (EL2-NS)
    participant Kernel as Linux Kernel (EL1-NS)

    ROM-&gt;&gt;ROM: CPU 复位，SRAM 初始化
    ROM-&gt;&gt;BL1: 验证并跳转 BL1 (EL3)
    BL1-&gt;&gt;BL1: PLL/时钟初始化，eMMC 驱动
    BL1-&gt;&gt;BL2: 加载+验证 BL2，ERET→EL1-S
    BL2-&gt;&gt;BL2: DDR 初始化 (PHY训练/ECC)
    BL2-&gt;&gt;BL2: TZC-400 内存保护配置
    BL2-&gt;&gt;BL31: 加载 BL31 镜像到 EL3
    BL2-&gt;&gt;TEE: 加载 BL32 镜像到 Secure DRAM
    BL2-&gt;&gt;UBoot: 加载 BL33 镜像到 NS DRAM
    BL2-&gt;&gt;BL31: ERET→EL3 执行 BL31

    BL31-&gt;&gt;BL31: GIC 初始化 (Distributor/Redistributor)
    BL31-&gt;&gt;BL31: PSCI 框架注册
    BL31-&gt;&gt;TEE: ERET→S-EL1 启动 OP-TEE
    TEE-&gt;&gt;TEE: 安全内存/堆初始化
    TEE-&gt;&gt;TEE: SMMU 安全流配置
    TEE-&gt;&gt;TEE: TA 框架初始化
    TEE-&gt;&gt;BL31: SMC(OPTEE_RETURN_FROM_RPC) 通知完成
    BL31-&gt;&gt;UBoot: ERET→EL2 NS 执行 U-Boot

    UBoot-&gt;&gt;UBoot: MMU 初始化 (页表+Cache 开启)
    UBoot-&gt;&gt;UBoot: eMMC/USB/网络驱动
    UBoot-&gt;&gt;UBoot: 从存储加载 Image + DTB
    UBoot-&gt;&gt;UBoot: 关闭 MMU/Cache (cleanup_before_linux)
    UBoot-&gt;&gt;Kernel: br kernel_entry (x0=dtb)

    Kernel-&gt;&gt;Kernel: head.S: 异常等级检测/KASLR
    Kernel-&gt;&gt;Kernel: 建立初始页表 (idmap+init)
    Kernel-&gt;&gt;Kernel: 开启 MMU (TTBR0/TTBR1)
    Kernel-&gt;&gt;Kernel: start_kernel(): GIC 驱动注册
    Kernel-&gt;&gt;Kernel: SMMU 驱动初始化
    Kernel-&gt;&gt;Kernel: 设备驱动、文件系统挂载
    Kernel-&gt;&gt;Kernel: init 进程启动 (EL0)
</code></pre>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="Amlogic" /><summary type="html"><![CDATA[ARMv8 平台的启动流程涉及多个引导阶段（BL0~BL33）、安全世界（TrustZone/TEE）、DDR 初始化、MMU/SMMU 配置、中断控制器初始化以及最终跳转到 Linux Kernel。本文从硬件上电复位出发，逐阶段剖析每个 BL 阶段的功能、异常等级切换、TEE 启动机制，并给出 Mermaid 流程图辅助理解。]]></summary></entry><entry><title type="html">Linux DRM 驱动实战：Cn SoC 显示驱动深度解析</title><link href="https://yangchao315.github.io/Cambricon-DRM-Driver-Analysis/" rel="alternate" type="text/html" title="Linux DRM 驱动实战：Cn SoC 显示驱动深度解析" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/Cambricon-DRM-Driver-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/Cambricon-DRM-Driver-Analysis/"><![CDATA[<!-- more -->

<ul>
  <li><a href="#一驱动概述">一、驱动概述</a></li>
  <li><a href="#二整体架构">二、整体架构</a></li>
  <li><a href="#三核心组件分析">三、核心组件分析</a>
    <ul>
      <li><a href="#31-drm-驱动主模块-cambr_drm_drv">3.1 DRM 驱动主模块 (cambr_drm_drv)</a></li>
      <li><a href="#32-vop-驱动-cambr_vop_drv">3.2 VOP 驱动 (cambr_vop_drv)</a></li>
      <li><a href="#33-hdmi-驱动-cambr_hdmi_drv">3.3 HDMI 驱动 (cambr_hdmi_drv)</a></li>
    </ul>
  </li>
  <li><a href="#四crtc-与-plane-实现">四、CRTC 与 Plane 实现</a>
    <ul>
      <li><a href="#41-plane-原子操作">4.1 Plane 原子操作</a></li>
      <li><a href="#42-crtc-模式设置">4.2 CRTC 模式设置</a></li>
      <li><a href="#43-格式支持与-csc">4.3 格式支持与 CSC</a></li>
    </ul>
  </li>
  <li><a href="#五component-框架详解">五、Component 框架详解</a></li>
  <li><a href="#六gem-与-dma-buf-集成">六、GEM 与 DMA-BUF 集成</a></li>
  <li><a href="#七关键寄存器配置">七、关键寄存器配置</a>
    <ul>
      <li><a href="#71-时钟与复位初始化">7.1 时钟与复位初始化</a></li>
      <li><a href="#72-dpi-时序配置">7.2 DPI 时序配置</a></li>
    </ul>
  </li>
  <li><a href="#八总结">八、总结</a></li>
</ul>

<hr />

<h2 id="一驱动概述">一、驱动概述</h2>

<p>本文分析的是一个面向 <strong>Cn（寒武纪）SoC</strong> 的完整 Linux DRM 驱动示例。该驱动展示了现代 DRM 子系统的典型实现模式，包括：</p>
<ul>
  <li>Component 框架进行多组件管理</li>
  <li>DRM Atomic 模式设置</li>
  <li>GEM DMA 内存管理</li>
  <li>VOP（视频输出处理器）显示流水线</li>
  <li>HDMI 显示接口</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cambr_drm_drv.h</span>
<span class="cp">#define DRIVER_NAME    "cndrm"
#define DRIVER_DESC    "Cn SoC DRM"
</span></code></pre></div></div>

<hr />

<h2 id="二整体架构">二、整体架构</h2>

<pre><code class="language-mermaid">graph TB
    subgraph "DRM Framework"
        DRM[DRM Driver]
        GC[Gem Core]
        AMC[Atomic Mode Setting]
    end
    
    subgraph "Component Master"
        MB[cambr_drm_bind]
    end
    
    subgraph "Component Slaves"
        VOP[cambr_vop]
        HDMI[cambr_hdmi]
    end
    
    subgraph "Hardware"
        HW[Video Output Processor]
        ENC[HDMI Encoder]
        PHY[HDMI PHY]
    end
    
    DRM --&gt; GC
    DRM --&gt; AMC
    MB --&gt; VOP
    MB --&gt; HDMI
    VOP --&gt; HW
    HDMI --&gt; ENC
    ENC --&gt; PHY
</code></pre>

<p><strong>显示数据流</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>User Space (Framebuffer)
    ↓
Plane (Primary/Overlay) → OVL (Overlay Engine)
    ↓
RVDMA (Read Video DMA) → DPI (Display Pixel Interface)
    ↓
HDMI Encoder → HDMI PHY → Monitor
</code></pre></div></div>

<hr />

<h2 id="三核心组件分析">三、核心组件分析</h2>

<h3 id="31-drm-驱动主模块-cambr_drm_drv">3.1 DRM 驱动主模块 (cambr_drm_drv)</h3>

<p>主模块负责：</p>
<ol>
  <li>注册 platform driver</li>
  <li>初始化 DRM 核心</li>
  <li>管理 Component 框架</li>
</ol>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cambr_drm_drv.c</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">drm_driver</span> <span class="n">cambr_drm_driver</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">driver_features</span> <span class="o">=</span> <span class="n">DRIVER_MODESET</span> <span class="o">|</span> <span class="n">DRIVER_GEM</span> <span class="o">|</span> <span class="n">DRIVER_ATOMIC</span><span class="p">,</span>
    <span class="p">.</span><span class="n">name</span>            <span class="o">=</span> <span class="n">DRIVER_NAME</span><span class="p">,</span>
    <span class="p">.</span><span class="n">fops</span>            <span class="o">=</span> <span class="o">&amp;</span><span class="n">cambr_drm_driver_fops</span><span class="p">,</span>
    <span class="n">DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE</span><span class="p">(</span><span class="n">drm_gem_dma_dumb_create</span><span class="p">),</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>关键特性</strong>：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">DRIVER_MODESET</code>：支持模式设置</li>
  <li><code class="language-plaintext highlighter-rouge">DRIVER_GEM</code>：使用 GEM 内存管理</li>
  <li><code class="language-plaintext highlighter-rouge">DRIVER_ATOMIC</code>：支持 Atomic 模式设置</li>
</ul>

<p><strong>初始化流程</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">int</span> <span class="nf">cambr_drm_bind</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 分配 DRM 设备</span>
    <span class="n">drm</span> <span class="o">=</span> <span class="n">drm_dev_alloc</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cambr_drm_driver</span><span class="p">,</span> <span class="n">dev</span><span class="p">);</span>
    
    <span class="c1">// 2. 初始化模式配置</span>
    <span class="n">drmm_mode_config_init</span><span class="p">(</span><span class="n">drm</span><span class="p">);</span>
    <span class="n">drm</span><span class="o">-&gt;</span><span class="n">mode_config</span><span class="p">.</span><span class="n">max_width</span> <span class="o">=</span> <span class="n">CN_MAX_FB_WIDTH</span><span class="p">;</span>  <span class="c1">// 4096</span>
    <span class="n">drm</span><span class="o">-&gt;</span><span class="n">mode_config</span><span class="p">.</span><span class="n">max_height</span> <span class="o">=</span> <span class="n">CN_MAX_FB_HEIGHT</span><span class="p">;</span>  <span class="c1">// 4096</span>
    
    <span class="c1">// 3. 初始化 Vblank</span>
    <span class="n">drm_vblank_init</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="n">MAX_CRTC</span><span class="p">);</span>  <span class="c1">// MAX_CRTC = 1</span>
    
    <span class="c1">// 4. 绑定子组件</span>
    <span class="n">component_bind_all</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">drm</span><span class="p">);</span>
    
    <span class="c1">// 5. 注册 DRM 设备</span>
    <span class="n">drm_dev_register</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    
    <span class="c1">// 6. 初始化 fbdev</span>
    <span class="n">drm_fbdev_generic_setup</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="mi">32</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="32-vop-驱动-cambr_vop_drv">3.2 VOP 驱动 (cambr_vop_drv)</h3>

<p>VOP（Video Output Processor）是显示硬件的核心，负责：</p>
<ul>
  <li>Plane 管理</li>
  <li>Overlay 叠加</li>
  <li>DMA 传输</li>
  <li>DPI 接口输出</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cambr_vop_drv.c</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">cambr_vop_bind</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">mdev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 创建 Primary Plane</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">cambr_plane_create</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">plane</span><span class="p">,</span> <span class="n">DRM_PLANE_TYPE_PRIMARY</span><span class="p">);</span>
    
    <span class="c1">// 2. 创建 CRTC</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">cambr_crtc_init</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">crtc</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">plane</span><span class="p">);</span>
    
    <span class="c1">// 3. 注册中断处理</span>
    <span class="n">irq</span> <span class="o">=</span> <span class="n">platform_get_irq</span><span class="p">(</span><span class="n">pdev</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">devm_request_irq</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pdev</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">,</span> <span class="n">irq</span><span class="p">,</span> <span class="n">vop_irq_handler</span><span class="p">,</span> <span class="p">...);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="33-hdmi-驱动-cambr_hdmi_drv">3.3 HDMI 驱动 (cambr_hdmi_drv)</h3>

<p>HDMI 驱动负责：</p>
<ul>
  <li>Encoder 创建与配置</li>
  <li>Connector 检测与模式获取</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cambr_hdmi_drv.c</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">cambr_hdmi_bind</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">mdev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 初始化 Encoder</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_encoder_init</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cndrm_hdmi</span><span class="o">-&gt;</span><span class="n">encoder</span><span class="p">,</span>
                           <span class="n">DRM_MODE_ENCODER_TMDS</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
    
    <span class="c1">// 2. 初始化 Connector</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_connector_init</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cndrm_hdmi</span><span class="o">-&gt;</span><span class="n">connector</span><span class="p">,</span>
                            <span class="n">DRM_MODE_CONNECTOR_HDMIA</span><span class="p">);</span>
    
    <span class="c1">// 3. 关联 Encoder 与 Connector</span>
    <span class="n">drm_connector_attach_encoder</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cndrm_hdmi</span><span class="o">-&gt;</span><span class="n">connector</span><span class="p">,</span> 
                                  <span class="o">&amp;</span><span class="n">cndrm_hdmi</span><span class="o">-&gt;</span><span class="n">encoder</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="四crtc-与-plane-实现">四、CRTC 与 Plane 实现</h2>

<h3 id="41-plane-原子操作">4.1 Plane 原子操作</h3>

<p>Plane 在 Atomic 模式下工作，核心函数：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// cambr_drm_crtc.c</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">cambr_plane_atomic_update</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_plane</span> <span class="o">*</span><span class="n">plane</span><span class="p">,</span>
                                      <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 获取 GEM 对象</span>
    <span class="n">gem</span> <span class="o">=</span> <span class="n">drm_fb_dma_get_gem_obj</span><span class="p">(</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="n">layer_mode</span><span class="p">.</span><span class="n">addr</span> <span class="o">=</span> <span class="n">gem</span><span class="o">-&gt;</span><span class="n">dma_addr</span><span class="p">;</span>
    
    <span class="c1">// 2. 配置 OVL 层</span>
    <span class="n">vop_ovl_config</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">layer_mode</span><span class="p">);</span>
    
    <span class="c1">// 3. 配置 RVDMA</span>
    <span class="n">vop_rvdma_config</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">RCHN_GRP2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">layer_mode</span><span class="p">);</span>
    
    <span class="c1">// 4. 更新地址</span>
    <span class="n">vop_update_plane</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">RCHN_GRP2</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">layer_mode</span><span class="p">);</span>
    
    <span class="c1">// 5. 启用 OVL 层</span>
    <span class="n">vop_ovl_enable</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER2</span><span class="p">,</span> <span class="n">OVL_ENABLE</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="42-crtc-模式设置">4.2 CRTC 模式设置</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">drm_crtc_helper_funcs</span> <span class="n">cambr_crtc_helper_funcs</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">mode_valid</span>   <span class="o">=</span> <span class="n">cambr_crtc_mode_valid</span><span class="p">,</span>
    <span class="p">.</span><span class="n">mode_fixup</span>   <span class="o">=</span> <span class="n">cambr_crtc_mode_fixup</span><span class="p">,</span>
    <span class="p">.</span><span class="n">mode_set_nofb</span> <span class="o">=</span> <span class="n">cambr_crtc_mode_set_nofb</span><span class="p">,</span>
    <span class="p">.</span><span class="n">atomic_flush</span> <span class="o">=</span> <span class="n">cambr_crtc_atomic_flush</span><span class="p">,</span>
    <span class="p">.</span><span class="n">atomic_enable</span> <span class="o">=</span> <span class="n">cambr_crtc_atomic_enable</span><span class="p">,</span>
    <span class="p">.</span><span class="n">atomic_disable</span> <span class="o">=</span> <span class="n">cambr_crtc_atomic_disable</span><span class="p">,</span>
<span class="p">};</span>

<span class="k">static</span> <span class="kt">void</span> <span class="nf">cambr_crtc_atomic_enable</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">,</span>
                                      <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 开启 VBlank 中断</span>
    <span class="n">reg_clear</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">VO_CMN_INTR_MASK</span><span class="p">,</span> 
              <span class="n">RG_DISP_SOF_INTR_MASK</span><span class="p">);</span>
    
    <span class="c1">// 2. 开启 DPI</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_EN</span><span class="p">,</span> <span class="mh">0x00800005</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="43-格式支持与-csc">4.3 格式支持与 CSC</h3>

<p>支持的格式：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="k">struct</span> <span class="n">cndrm_format_info</span> <span class="n">cndrm_format_infos</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_ARGB8888</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_ARGB8888_PACKED</span> <span class="p">},</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_XRGB8888</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_XRGB8888_PACKED</span> <span class="p">},</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_NV12</span><span class="p">,</span>     <span class="p">.</span><span class="n">csc_format</span> <span class="o">=</span> <span class="n">CSC_YUV420_RGB</span><span class="p">,</span>
      <span class="p">.</span><span class="n">csc_conv_type</span> <span class="o">=</span> <span class="n">CSC_BT709_RGB</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_YUV420_SEMI_PLANAR</span> <span class="p">},</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_NV21</span><span class="p">,</span>    <span class="p">.</span><span class="n">csc_format</span> <span class="o">=</span> <span class="n">CSC_YUV420_RGB</span><span class="p">,</span>
      <span class="p">.</span><span class="n">csc_conv_type</span> <span class="o">=</span> <span class="n">CSC_BT709_RGB</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_YVU420_SEMI_PLANAR</span> <span class="p">},</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_NV16</span><span class="p">,</span>    <span class="p">.</span><span class="n">csc_format</span> <span class="o">=</span> <span class="n">CSC_YUV422_RGB</span><span class="p">,</span>
      <span class="p">.</span><span class="n">csc_conv_type</span> <span class="o">=</span> <span class="n">CSC_BT709_RGB</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_YUV422_SEMI_PLANAR</span> <span class="p">},</span>
    <span class="p">{</span> <span class="p">.</span><span class="n">fourcc</span> <span class="o">=</span> <span class="n">DRM_FORMAT_NV61</span><span class="p">,</span>    <span class="p">.</span><span class="n">csc_format</span> <span class="o">=</span> <span class="n">CSC_YUV422_RGB</span><span class="p">,</span>
      <span class="p">.</span><span class="n">csc_conv_type</span> <span class="o">=</span> <span class="n">CSC_BT709_RGB</span><span class="p">,</span> <span class="p">.</span><span class="n">pixel_format</span> <span class="o">=</span> <span class="n">PIXEL_FORMAT_YVU422_SEMI_PLANAR</span> <span class="p">},</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>CSC (Color Space Conversion) 配置</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">format</span><span class="o">-&gt;</span><span class="n">is_yuv</span> <span class="o">==</span> <span class="nb">true</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// 配置 YUV-&gt;RGB 转换</span>
    <span class="n">reg_write_field</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER0_CSC_MAIN_CFG</span><span class="p">,</span> 
                    <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x4</span><span class="p">,</span> <span class="n">layer_mode</span><span class="p">.</span><span class="n">csc_format</span><span class="p">);</span>
    <span class="n">reg_write_field</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER0_CSC_MAIN_CFG</span><span class="p">,</span> 
                    <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x4</span><span class="p">,</span> <span class="n">layer_mode</span><span class="p">.</span><span class="n">csc_conv_type</span><span class="p">);</span>
    <span class="c1">// 启用 CSC</span>
    <span class="n">reg_clear</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER0_CSC_MAIN_CFG</span><span class="p">,</span> <span class="n">CSC_BYPASS</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="c1">// 绕过 CSC</span>
    <span class="n">reg_set</span><span class="p">(</span><span class="n">cndrm_vop</span><span class="o">-&gt;</span><span class="n">regs</span><span class="p">,</span> <span class="n">OVL_LAYER0_CSC_MAIN_CFG</span><span class="p">,</span> <span class="n">CSC_BYPASS</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="五component-框架详解">五、Component 框架详解</h2>

<p>该驱动使用 Linux Component 框架管理多设备：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 1. 主设备定义</span>
<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">component_master_ops</span> <span class="n">cambr_drm_ops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">bind</span> <span class="o">=</span> <span class="n">cambr_drm_bind</span><span class="p">,</span>
    <span class="p">.</span><span class="n">unbind</span> <span class="o">=</span> <span class="n">cambr_drm_unbind</span><span class="p">,</span>
<span class="p">};</span>

<span class="c1">// 2. 子设备绑定</span>
<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">component_ops</span> <span class="n">cambr_vop_ops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">bind</span> <span class="o">=</span> <span class="n">cambr_vop_bind</span><span class="p">,</span>
    <span class="p">.</span><span class="n">unbind</span> <span class="o">=</span> <span class="n">cambr_vop_unbind</span><span class="p">,</span>
<span class="p">};</span>

<span class="c1">// 3. 设备树解析与组件匹配</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">np</span> <span class="o">=</span> <span class="n">of_parse_phandle</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">of_node</span><span class="p">,</span> <span class="s">"ports"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">np</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
    
    <span class="c1">// 添加 ports 节点</span>
    <span class="n">component_match_add</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">match</span><span class="p">,</span> <span class="n">compare_of</span><span class="p">,</span> <span class="n">np</span><span class="p">);</span>
    
    <span class="c1">// 遍历每个 port 的 endpoint</span>
    <span class="n">for_each_endpoint_of_node</span><span class="p">(</span><span class="n">np</span><span class="p">,</span> <span class="n">ep</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">remote</span> <span class="o">=</span> <span class="n">of_graph_get_remote_port_parent</span><span class="p">(</span><span class="n">ep</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">remote</span> <span class="o">&amp;&amp;</span> <span class="n">of_device_is_available</span><span class="p">(</span><span class="n">remote</span><span class="p">))</span> <span class="p">{</span>
            <span class="c1">// 添加远程设备</span>
            <span class="n">component_match_add</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">match</span><span class="p">,</span> <span class="n">compare_of</span><span class="p">,</span> <span class="n">remote</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="c1">// 4. 注册主设备</span>
<span class="n">component_master_add_with_match</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pdev</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">cambr_drm_ops</span><span class="p">,</span> <span class="n">match</span><span class="p">);</span>
</code></pre></div></div>

<hr />

<h2 id="六gem-与-dma-buf-集成">六、GEM 与 DMA-BUF 集成</h2>

<p>使用 <code class="language-plaintext highlighter-rouge">drm_gem_dma_helper</code> 简化 GEM 实现：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 驱动定义使用宏自动生成 GEM 操作</span>
<span class="n">DEFINE_DRM_GEM_DMA_FOPS</span><span class="p">(</span><span class="n">cambr_drm_driver_fops</span><span class="p">);</span>

<span class="k">static</span> <span class="k">struct</span> <span class="n">drm_driver</span> <span class="n">cambr_drm_driver</span> <span class="o">=</span> <span class="p">{</span>
    <span class="c1">// ...</span>
    <span class="n">DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE</span><span class="p">(</span><span class="n">drm_gem_dma_dumb_create</span><span class="p">),</span>
<span class="p">};</span>
</code></pre></div></div>

<p>这会自动实现：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">gem_create</code>：创建 GEM 对象</li>
  <li><code class="language-plaintext highlighter-rouge">gem_mmap</code>：内存映射</li>
  <li><code class="language-plaintext highlighter-rouge">dumb_create</code>：创建 dumb buffer</li>
  <li><code class="language-plaintext highlighter-rouge">dumb_map_offset</code>：获取 mmap offset</li>
</ul>

<p><strong>Framebuffer 映射</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">drm_mode_config_funcs</span> <span class="n">cambr_drm_mode_config_funcs</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">fb_create</span> <span class="o">=</span> <span class="n">drm_gem_fb_create</span><span class="p">,</span>
    <span class="p">.</span><span class="n">atomic_check</span> <span class="o">=</span> <span class="n">drm_atomic_helper_check</span><span class="p">,</span>
    <span class="p">.</span><span class="n">atomic_commit</span> <span class="o">=</span> <span class="n">drm_atomic_helper_commit</span><span class="p">,</span>
<span class="p">};</span>
</code></pre></div></div>

<hr />

<h2 id="七关键寄存器配置">七、关键寄存器配置</h2>

<h3 id="71-时钟与复位初始化">7.1 时钟与复位初始化</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vosys_crg_init</span><span class="p">(</span><span class="k">const</span> <span class="kt">void</span> <span class="n">__iomem</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 视频系统时钟使能</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_VOPROC0_VCLK_CLK_SEL</span><span class="p">,</span> <span class="mh">0x00020002</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_CLK_EN_0</span><span class="p">,</span> <span class="mh">0x80008000</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_CLK_EN_1</span><span class="p">,</span> <span class="mh">0xFFC7FFC7</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_CLK_EN_2</span><span class="p">,</span> <span class="mh">0xFFEFFFEF</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VO_PROC_CRG_CLK_EN</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">);</span>
    
    <span class="c1">// 复位控制</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_RST_CTRL_0</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_RST_CTRL_1</span><span class="p">,</span> <span class="mh">0xFFFFFFFF</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">VOSYS_CRG_RST_CTRL_2</span><span class="p">,</span> <span class="mh">0xFFFFFF9F</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="72-dpi-时序配置">7.2 DPI 时序配置</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">vop_dpi_config</span><span class="p">(</span><span class="kt">void</span> <span class="n">__iomem</span> <span class="o">*</span><span class="n">regs</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// DPI 控制</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_CL_CTRL</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">);</span>
    
    <span class="c1">// 时序参数</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_TIM_CFG0</span><span class="p">,</span> <span class="mh">0x00580094</span><span class="p">);</span>  <span class="c1">// Hsync/Vsync</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_TIM_CFG1</span><span class="p">,</span> <span class="mh">0x0780002C</span><span class="p">);</span>  <span class="c1">// Vbp/Vfp</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_TIM_CFG4</span><span class="p">,</span> <span class="mh">0x00040024</span><span class="p">);</span>  <span class="c1">// Vact</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_TIM_CFG5</span><span class="p">,</span> <span class="mh">0x04380005</span><span class="p">);</span>  <span class="c1">// Hact high</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_TIM_CFG6</span><span class="p">,</span> <span class="mh">0x04380780</span><span class="p">);</span>  <span class="c1">// Hact low</span>
    
    <span class="c1">// 数据复用配置</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_DATA_MUX4</span><span class="p">,</span> <span class="mh">0x3bcdeb38</span><span class="p">);</span>
    <span class="n">reg_write</span><span class="p">(</span><span class="n">regs</span><span class="p">,</span> <span class="n">DISP_DPI_OUTSTAGE_CFG</span><span class="p">,</span> <span class="mh">0x00002406</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h2 id="八总结">八、总结</h2>

<p>该 Cn DRM 驱动展示了现代 Linux DRM 子系统的完整实现模式：</p>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>实现方式</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>多组件管理</strong></td>
      <td>Component 框架</td>
    </tr>
    <tr>
      <td><strong>内存管理</strong></td>
      <td>GEM DMA Helper</td>
    </tr>
    <tr>
      <td><strong>模式设置</strong></td>
      <td>Atomic Mode Setting</td>
    </tr>
    <tr>
      <td><strong>显示引擎</strong></td>
      <td>VOP (OVL + RVDMA + DPI)</td>
    </tr>
    <tr>
      <td><strong>输出接口</strong></td>
      <td>HDMI (TMDS)</td>
    </tr>
    <tr>
      <td><strong>格式支持</strong></td>
      <td>ARGB8888, XRGB8888, NV12/21, NV16/61</td>
    </tr>
    <tr>
      <td><strong>色彩空间</strong></td>
      <td>BT.709 YUV→RGB</td>
    </tr>
  </tbody>
</table>

<p>这个驱动是学习 DRM 子系统的优秀范例，涵盖了从用户空间到底层硬件的完整数据通路。</p>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DRM" /><category term="Display" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">DRM 子系统核心机制详解：问答集锦</title><link href="https://yangchao315.github.io/DRM-Core-Mechanisms-Interview-QA/" rel="alternate" type="text/html" title="DRM 子系统核心机制详解：问答集锦" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/DRM-Core-Mechanisms-Interview-QA</id><content type="html" xml:base="https://yangchao315.github.io/DRM-Core-Mechanisms-Interview-QA/"><![CDATA[<!-- more -->

<ul>
  <li><a href="#一dma-buf-申请与释放流程">一、DMA-buf 申请与释放流程</a>
    <ul>
      <li><a href="#11-gem-对象创建流程">1.1 GEM 对象创建流程</a></li>
      <li><a href="#12-dma-heap-内存分配">1.2 DMA heap 内存分配</a></li>
      <li><a href="#13-内存释放流程">1.3 内存释放流程</a></li>
      <li><a href="#14-高频问题">1.4 高频问题</a></li>
    </ul>
  </li>
  <li><a href="#二fence-同步机制详解">二、Fence 同步机制详解</a>
    <ul>
      <li><a href="#21-dma-fence-核心概念">2.1 DMA-fence 核心概念</a></li>
      <li><a href="#22-present-fence-实现">2.2 Present Fence 实现</a></li>
      <li><a href="#23-video-plane-fence">2.3 Video Plane Fence</a></li>
      <li><a href="#24-fence-等待与回调">2.4 Fence 等待与回调</a></li>
      <li><a href="#25-高频问题">2.5 高频问题</a></li>
    </ul>
  </li>
  <li><a href="#三atomic-commit-流程深度解析">三、Atomic Commit 流程深度解析</a>
    <ul>
      <li><a href="#31-调用链路">3.1 调用链路</a></li>
      <li><a href="#32-state-状态转换">3.2 State 状态转换</a></li>
      <li><a href="#33-planecrtcencoder-配置时序">3.3 Plane/CRTC/Encoder 配置时序</a></li>
      <li><a href="#34-commit-完成回调机制">3.4 Commit 完成回调机制</a></li>
      <li><a href="#35-高频问题">3.5 高频问题</a></li>
    </ul>
  </li>
  <li><a href="#四state-状态管理">四、State 状态管理</a>
    <ul>
      <li><a href="#41-atomic-state-结构">4.1 Atomic State 结构</a></li>
      <li><a href="#42-state-复制与检查">4.2 State 复制与检查</a></li>
      <li><a href="#43-state-交换与回滚">4.3 State 交换与回滚</a></li>
      <li><a href="#44-state-交换与提交-commit">4.4 State 交换与提交 (commit)</a></li>
      <li><a href="#45-acquire_ctx-锁管理机制">4.5 acquire_ctx 锁管理机制</a></li>
      <li><a href="#46-allow_modeset-标志位">4.6 allow_modeset 标志位</a></li>
      <li><a href="#47-state-复制流程详解">4.7 State 复制流程详解</a></li>
      <li><a href="#48-state-错误处理与回滚">4.8 State 错误处理与回滚</a></li>
      <li><a href="#49-legacy-vs-atomic-状态管理差异">4.9 Legacy vs Atomic 状态管理差异</a></li>
      <li><a href="#410-commit-回调执行顺序">4.10 Commit 回调执行顺序</a></li>
      <li><a href="#411-drm_private_state-使用场景">4.11 drm_private_state 使用场景</a></li>
    </ul>
  </li>
  <li><a href="#五多路送显架构">五、多路送显架构</a>
    <ul>
      <li><a href="#51-crtcencoder-注册机制">5.1 CRTC/Encoder 注册机制</a></li>
      <li><a href="#52-资源分配与克隆模式">5.2 资源分配与克隆模式</a></li>
      <li><a href="#53-多路输出配置">5.3 多路输出配置</a></li>
    </ul>
  </li>
  <li><a href="#六性能优化考量">六、性能优化考量</a>
    <ul>
      <li><a href="#61-非阻塞-commit">6.1 非阻塞 Commit</a></li>
      <li><a href="#62-async-update">6.2 Async Update</a></li>
      <li><a href="#63-内存带宽优化">6.3 内存带宽优化</a></li>
    </ul>
  </li>
  <li><a href="#七hdmi-与-tx-hdmi-transmitter-差异">七、HDMI 与 TX (HDMI Transmitter) 差异</a>
    <ul>
      <li><a href="#71-架构定位">7.1 架构定位</a></li>
      <li><a href="#72-信号特性">7.2 信号特性</a></li>
      <li><a href="#73-时序要求">7.3 时序要求</a></li>
    </ul>
  </li>
  <li><a href="#八常见问题与要点">八、常见问题与要点</a></li>
  <li><a href="#十drm-writeback-回写机制">十、DRM Writeback 回写机制</a>
    <ul>
      <li><a href="#101-writeback-核心概念">10.1 Writeback 核心概念</a></li>
      <li><a href="#102-writeback-数据结构">10.2 Writeback 数据结构</a></li>
      <li><a href="#103-writeback-流程解析">10.3 Writeback 流程解析</a></li>
      <li><a href="#104-atomic-commit-流程">10.4 Atomic Commit 流程</a></li>
      <li><a href="#105-capture-port-配置">10.5 Capture Port 配置</a></li>
      <li><a href="#106-典型应用场景">10.6 典型应用场景</a></li>
      <li><a href="#107-高频问题">10.7 高频问题</a></li>
    </ul>
  </li>
  <li><a href="#十一syncasyncnonblock-送显模式">十一、Sync/Async/Nonblock 送显模式</a>
    <ul>
      <li><a href="#111-sync-commit同步送显">11.1 Sync Commit（同步送显）</a></li>
      <li><a href="#112-nonblock-commit非阻塞送显">11.2 Nonblock Commit（非阻塞送显）</a></li>
      <li><a href="#113-async-update异步平面更新">11.3 Async Update（异步平面更新）</a></li>
      <li><a href="#114-legacy-cursor-update传统光标更新">11.4 Legacy Cursor Update（传统光标更新）</a></li>
      <li><a href="#115-三种模式详细对比">11.5 三种模式详细对比</a></li>
      <li><a href="#116-meson-驱动的-commit-模式选择">11.6 Meson 驱动的 Commit 模式选择</a></li>
      <li><a href="#117-高频问题">11.7 高频问题</a></li>
    </ul>
  </li>
  <li><a href="#总结">总结</a></li>
</ul>

<hr />

<h2 id="一dma-buf-申请与释放流程">一、DMA-buf 申请与释放流程</h2>

<h3 id="11-gem-对象创建流程">1.1 GEM 对象创建流程</h3>

<p>在 Meson DRM 驱动中，GEM 对象创建通过 <code class="language-plaintext highlighter-rouge">am_meson_gem_object_create()</code> 函数完成：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_gem.c:636</span>
<span class="k">struct</span> <span class="n">am_meson_gem_object</span> <span class="o">*</span><span class="nf">am_meson_gem_object_create</span><span class="p">(</span>
    <span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span>
    <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">,</span>
    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">size</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 分配 am_meson_gem_object 结构体</span>
    <span class="n">meson_gem_obj</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">meson_gem_obj</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    
    <span class="c1">// 2. 初始化 DRM GEM 对象</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_gem_object_init</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">,</span> <span class="n">size</span><span class="p">);</span>
    
    <span class="c1">// 3. 根据 flags 分配内存缓冲区</span>
    <span class="k">if</span> <span class="p">((</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MESON_USE_VIDEO_PLANE</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MESON_USE_PROTECTED</span><span class="p">))</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">am_meson_gem_alloc_video_secure_buff</span><span class="p">(</span><span class="n">meson_gem_obj</span><span class="p">);</span>  <span class="c1">// 安全内存</span>
    <span class="k">else</span>
        <span class="n">ret</span> <span class="o">=</span> <span class="n">am_meson_gem_alloc_ion_buff</span><span class="p">(</span><span class="n">meson_gem_obj</span><span class="p">,</span> <span class="n">flags</span><span class="p">);</span>    <span class="c1">// ION/DMA heap</span>
    
    <span class="c1">// 4. 如果是 UVM 缓冲区，初始化 uvm_buf_obj</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">is_uvm</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">ubo</span><span class="p">.</span><span class="n">arg</span> <span class="o">=</span> <span class="n">meson_gem_obj</span><span class="p">;</span>
        <span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">ubo</span><span class="p">.</span><span class="n">dev</span> <span class="o">=</span> <span class="n">dev</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="k">return</span> <span class="n">meson_gem_obj</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="12-dma-heap-内存分配">1.2 DMA heap 内存分配</h3>

<p>Meson 驱动支持多种内存分配方式：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_gem.c:60 - 内存分配核心函数</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">am_meson_gem_alloc_ion_buff</span><span class="p">(</span><span class="k">struct</span> <span class="n">am_meson_gem_object</span> <span class="o">*</span><span class="n">meson_gem_obj</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 优先级：heap-fb -&gt; heap-gfx -&gt; heap-codecmm -&gt; system</span>
    <span class="kt">char</span> <span class="n">DMAHEAP</span><span class="p">[][</span><span class="mi">20</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"heap-fb"</span><span class="p">,</span> <span class="s">"heap-gfx"</span><span class="p">,</span> <span class="s">"heap-codecmm"</span><span class="p">};</span>
    
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">heap</span> <span class="o">=</span> <span class="n">dma_heap_find</span><span class="p">(</span><span class="n">DMAHEAP</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="n">dmabuf</span> <span class="o">=</span> <span class="n">dma_heap_buffer_alloc</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">O_RDWR</span><span class="p">,</span> <span class="n">DMA_HEAP_VALID_HEAP_FLAGS</span><span class="p">);</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">IS_ERR_OR_NULL</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">))</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="c1">// 创建 DMA attachment 和 sg_table</span>
    <span class="n">attachment</span> <span class="o">=</span> <span class="n">dma_buf_attach</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">,</span> <span class="n">dev</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">);</span>
    <span class="n">sg_table</span> <span class="o">=</span> <span class="n">dma_buf_map_attachment</span><span class="p">(</span><span class="n">attachment</span><span class="p">,</span> <span class="n">DMA_BIDIRECTIONAL</span><span class="p">);</span>
    
    <span class="c1">// 同步 cache</span>
    <span class="n">dma_sync_sg_for_device</span><span class="p">(</span><span class="n">dev</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">,</span> <span class="n">sg_table</span><span class="o">-&gt;</span><span class="n">sgl</span><span class="p">,</span> <span class="n">sg_table</span><span class="o">-&gt;</span><span class="n">nents</span><span class="p">,</span> <span class="n">DMA_TO_DEVICE</span><span class="p">);</span>
    
    <span class="c1">// 获取物理地址</span>
    <span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">addr</span> <span class="o">=</span> <span class="n">PFN_PHYS</span><span class="p">(</span><span class="n">page_to_pfn</span><span class="p">(</span><span class="n">page</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<callout emoji="💡" background-color="light-blue">
**关键点**：分配顺序是 heap-fb -&gt; heap-gfx -&gt; heap-codecmm -&gt; system，这确保了显示内存的优先分配。
</callout>

<h3 id="13-内存释放流程">1.3 内存释放流程</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_gem.c:306 - GEM 对象释放</span>
<span class="kt">void</span> <span class="nf">meson_gem_object_free</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_gem_object</span> <span class="o">*</span><span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">am_meson_gem_object</span> <span class="o">*</span><span class="n">meson_gem_obj</span> <span class="o">=</span> <span class="n">to_am_meson_gem_obj</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
    
    <span class="c1">// 1. 安全内存释放</span>
    <span class="k">if</span> <span class="p">((</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MESON_USE_VIDEO_PLANE</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">flags</span> <span class="o">&amp;</span> <span class="n">MESON_USE_PROTECTED</span><span class="p">))</span>
        <span class="n">am_meson_gem_free_video_secure_buf</span><span class="p">(</span><span class="n">meson_gem_obj</span><span class="p">);</span>
    <span class="c1">// 2. ION/DMA heap 释放</span>
    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">import_attach</span><span class="p">)</span>
        <span class="n">am_meson_gem_free_ion_buf</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">dev</span><span class="p">,</span> <span class="n">meson_gem_obj</span><span class="p">);</span>
    <span class="c1">// 3. Prime 导入的缓冲区释放</span>
    <span class="k">else</span>
        <span class="n">drm_prime_gem_destroy</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">meson_gem_obj</span><span class="o">-&gt;</span><span class="n">sg</span><span class="p">);</span>
    
    <span class="c1">// 4. 释放 mmap offset</span>
    <span class="n">drm_gem_free_mmap_offset</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
    
    <span class="c1">// 5. 释放 GEM 对象引用</span>
    <span class="n">drm_gem_object_release</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
    
    <span class="n">kfree</span><span class="p">(</span><span class="n">meson_gem_obj</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="14-高频问题">1.4 高频问题</h3>

<table>
  <thead>
    <tr>
      <th>问题</th>
      <th>答案要点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>DMA-buf 与 GEM 的关系？</td>
      <td>GEM 是 DRM 的内存管理抽象，DMA-buf 是跨驱动共享机制，PRIME 是桥接两者的接口</td>
    </tr>
    <tr>
      <td>为什么要用 DMA heap？</td>
      <td>DMA heap 提供专门的内存池（fb/gfx/codecmm），保证内存连续性和带宽</td>
    </tr>
    <tr>
      <td>内存分配的 flags 有什么区别？</td>
      <td>MESON_USE_SCANOUT(扫描输出)、MESON_USE_VIDEO_PLANE(视频)、MESON_USE_PROTECTED(安全)</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="二fence-同步机制详解">二、Fence 同步机制详解</h2>

<h3 id="21-dma-fence-核心概念">2.1 DMA-fence 核心概念</h3>

<p>DMA-fence 是 Linux 内核用于跨设备同步的核心机制，解决硬件操作异步完成时的数据依赖问题。</p>

<pre><code class="language-mermaid">graph TD
    A[用户空间提交 Buffer] --&gt; B[创建 In-fence]
    B --&gt; C[DRM Atomic Commit]
    C --&gt; D{等待 In-fence}
    D --&gt;|Signaled| E[硬件配置]
    E --&gt; F[创建 Out-fence]
    F --&gt; G[返回给用户空间]
    
    H[硬件完成显示] --&gt; I[Signal Out-fence]
    I --&gt; J[用户空间可以重用 Buffer]
</code></pre>

<h3 id="22-present-fence-实现">2.2 Present Fence 实现</h3>

<p>Present Fence 用于用户空间同步页面 flip：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c:236 - Fence ops 定义</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">meson_crtc_fence_get_driver_name</span><span class="p">(</span><span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="n">fence</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="s">"meson"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">meson_crtc_fence_get_timeline_name</span><span class="p">(</span><span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="n">fence</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="s">"present_fence"</span><span class="p">;</span>  <span class="c1">// Timeline 名称</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">dma_fence_ops</span> <span class="n">meson_crtc_fence_ops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">get_driver_name</span> <span class="o">=</span> <span class="n">meson_crtc_fence_get_driver_name</span><span class="p">,</span>
    <span class="p">.</span><span class="n">get_timeline_name</span> <span class="o">=</span> <span class="n">meson_crtc_fence_get_timeline_name</span><span class="p">,</span>
<span class="p">};</span>

<span class="c1">// 创建 fence</span>
<span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="nf">meson_crtc_create_fence</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">fence</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">fence</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    <span class="n">dma_fence_init</span><span class="p">(</span><span class="n">fence</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">meson_crtc_fence_ops</span><span class="p">,</span> <span class="n">lock</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">fence</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>用户空间通过 ioctl 获取 present fence：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c:265 - IOCTL 实现</span>
<span class="kt">int</span> <span class="nf">meson_crtc_creat_present_fence_ioctl</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="k">struct</span> <span class="n">drm_file</span> <span class="o">*</span><span class="n">file_priv</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_meson_present_fence</span> <span class="o">*</span><span class="n">arg</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">am_meson_crtc</span> <span class="o">*</span><span class="n">amcrtc</span> <span class="o">=</span> <span class="p">...;</span>
    
    <span class="c1">// 创建 fence</span>
    <span class="n">fence</span> <span class="o">=</span> <span class="n">meson_crtc_create_fence</span><span class="p">(</span><span class="o">&amp;</span><span class="n">pre_fence</span><span class="o">-&gt;</span><span class="n">lock</span><span class="p">);</span>
    
    <span class="c1">// 导出为 sync_file fd</span>
    <span class="n">sync_file</span> <span class="o">=</span> <span class="n">sync_file_create</span><span class="p">(</span><span class="n">fence</span><span class="p">);</span>
    <span class="n">fd</span> <span class="o">=</span> <span class="n">get_unused_fd_flags</span><span class="p">(</span><span class="n">O_CLOEXEC</span><span class="p">);</span>
    <span class="n">fd_install</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">sync_file</span><span class="o">-&gt;</span><span class="n">file</span><span class="p">);</span>
    
    <span class="n">arg</span><span class="o">-&gt;</span><span class="n">fd</span> <span class="o">=</span> <span class="n">fd</span><span class="p">;</span>
    <span class="n">pre_fence</span><span class="o">-&gt;</span><span class="n">fence</span> <span class="o">=</span> <span class="n">fence</span><span class="p">;</span>
    <span class="n">pre_fence</span><span class="o">-&gt;</span><span class="n">sync_file</span> <span class="o">=</span> <span class="n">sync_file</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="23-video-plane-fence">2.3 Video Plane Fence</h3>

<p>Video Plane 使用独立的 fence 机制管理视频帧释放：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_plane.c:859 - Video fence 创建</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="nf">am_meson_video_create_fence</span><span class="p">(</span><span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">fence</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">fence</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    <span class="n">dma_fence_init</span><span class="p">(</span><span class="n">fence</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">am_meson_video_plane_fence_ops</span><span class="p">,</span> <span class="n">lock</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">fence</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Fence 与 vframe 绑定</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">bind_video_fence_vframe</span><span class="p">(</span><span class="k">struct</span> <span class="n">meson_vpu_video</span> <span class="o">*</span><span class="n">video</span><span class="p">,</span> 
    <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="n">fence</span><span class="p">,</span> <span class="n">u32</span> <span class="n">index</span><span class="p">,</span> <span class="k">struct</span> <span class="n">vframe_s</span> <span class="o">*</span><span class="n">vf</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">info</span><span class="o">-&gt;</span><span class="n">fence</span> <span class="o">=</span> <span class="n">fence</span><span class="p">;</span>
    <span class="n">info</span><span class="o">-&gt;</span><span class="n">vf</span> <span class="o">=</span> <span class="n">vf</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// Fence 信号 - 当视频帧显示完成时调用</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">video_fence_signal</span><span class="p">(</span><span class="k">struct</span> <span class="n">meson_vpu_video</span> <span class="o">*</span><span class="n">video</span><span class="p">,</span> <span class="k">struct</span> <span class="n">vframe_s</span> <span class="o">*</span><span class="n">vf</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">list_for_each_safe</span><span class="p">(...)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">info_cur</span><span class="o">-&gt;</span><span class="n">vf</span> <span class="o">==</span> <span class="n">vf</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">dma_fence_signal</span><span class="p">(</span><span class="n">info_cur</span><span class="o">-&gt;</span><span class="n">fence</span><span class="p">);</span>  <span class="c1">// 信号 fence</span>
            <span class="n">dma_fence_put</span><span class="p">(</span><span class="n">info_cur</span><span class="o">-&gt;</span><span class="n">fence</span><span class="p">);</span>
            <span class="n">info_cur</span><span class="o">-&gt;</span><span class="n">fence</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="24-fence-等待与回调">2.4 Fence 等待与回调</h3>

<p>Atomic commit 中的 fence 等待：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:185 - Commit tail 阶段</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">meson_commit_tail</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">old_state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 等待所有 plane 的 fence</span>
    <span class="n">drm_atomic_helper_wait_for_fences</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">,</span> <span class="nb">false</span><span class="p">);</span>
    
    <span class="c1">// 2. 等待之前的 commit 完成</span>
    <span class="n">meson_drm_atomic_helper_wait_for_dependencies</span><span class="p">(</span><span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 3. 执行硬件配置</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_commit_tail</span><span class="p">)</span>
        <span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_commit_tail</span><span class="p">(</span><span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 4. 标记完成</span>
    <span class="n">drm_atomic_helper_commit_cleanup_done</span><span class="p">(</span><span class="n">old_state</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>用户空间传入的 in-fence 处理：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_async_atomic.c:86 - 读取 in_fence_fd</span>
<span class="err">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="p">(</span><span class="n">property</span> <span class="o">==</span> <span class="n">config</span><span class="o">-&gt;</span><span class="n">prop_in_fence_fd</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">fence</span><span class="p">)</span>
        <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
    
    <span class="n">state</span><span class="o">-&gt;</span><span class="n">fence</span> <span class="o">=</span> <span class="n">sync_file_get_fence</span><span class="p">(</span><span class="n">val</span><span class="p">);</span>  <span class="c1">// 获取用户空间的 fence</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">fence</span><span class="p">)</span>
        <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="25-高频问题">2.5 高频问题</h3>

<table>
  <thead>
    <tr>
      <th>问题</th>
      <th>答案要点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>隐式 fence vs 显式 fence？</td>
      <td>隐式 fence 附加在 buffer 上自动同步；显式 fence 通过 sync_file fd 传递给用户空间可见</td>
    </tr>
    <tr>
      <td>fence 的生命周期？</td>
      <td>创建 -&gt; 添加到 dma_resv -&gt; 等待 -&gt; 信号 -&gt; 释放引用</td>
    </tr>
    <tr>
      <td>为什么需要 timeline fence？</td>
      <td>支持更细粒度的同步，类似 Vulkan semaphore，可查询进度</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="三atomic-commit-流程深度解析">三、Atomic Commit 流程深度解析</h2>

<h3 id="31-调用链路">3.1 调用链路</h3>

<pre><code class="language-mermaid">sequenceDiagram
    participant User as 用户空间
    participant DRM as DRM Framework
    participant Driver as Meson Driver
    participant HW as 硬件
    
    User-&gt;&gt;DRM: drmModeAtomicCommit()
    DRM-&gt;&gt;Driver: meson_atomic_commit()
    
    alt BLOCK 模式
        Driver-&gt;&gt;Driver: meson_commit_tail()
    else NONBLOCK 模式
        Driver-&gt;&gt;Driver: kthread_queue_work()
        Driver--&gt;&gt;DRM: 立即返回
    end
    
    Driver-&gt;&gt;Driver: setup_commit() [创建 commit 结构]
    Driver-&gt;&gt;Driver: prepare_planes() [准备 plane 资源]
    Driver-&gt;&gt;Driver: swap_state() [交换新旧 state]
    
    rect rgb(200, 255, 200)
        Note over Driver,HW: 硬件配置阶段
        Driver-&gt;&gt;HW: commit_modeset_disables()
        Driver-&gt;&gt;HW: commit_modeset_enables()
        Driver-&gt;&gt;HW: commit_planes()
        HW-&gt;&gt;Driver: hw_done 信号
    end
    
    Driver-&gt;&gt;Driver: cleanup_planes()
    Driver-&gt;&gt;DRM: flip_done 信号
    DRM--&gt;&gt;User: 返回
</code></pre>

<h3 id="32-state-状态转换">3.2 State 状态转换</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c:141 - CRTC state 复制</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="o">*</span><span class="nf">meson_crtc_duplicate_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">new_state</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">new_state</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    
    <span class="c1">// 复制基础 state</span>
    <span class="n">__drm_atomic_helper_crtc_duplicate_state</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">);</span>
    
    <span class="c1">// 复制私有 state</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">vmode</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">vmode</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">seamless</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">seamless</span><span class="p">;</span>
    <span class="c1">// ...</span>
    
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="33-planecrtcencoder-配置时序">3.3 Plane/CRTC/Encoder 配置时序</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:652 - Commit tail RPM</span>
<span class="kt">void</span> <span class="nf">meson_atomic_helper_commit_tail_rpm</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">old_state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 禁用不再使用的资源</span>
    <span class="n">drm_atomic_helper_commit_modeset_disables</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 2. 使能需要使用的资源（模式设置）</span>
    <span class="n">drm_atomic_helper_commit_modeset_enables</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 3. 配置 plane（帧缓冲、位置、缩放）</span>
    <span class="n">drm_atomic_helper_commit_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">,</span> <span class="n">DRM_PLANE_COMMIT_ACTIVE_ONLY</span><span class="p">);</span>
    
    <span class="c1">// 4. 伪造 vblank</span>
    <span class="n">drm_atomic_helper_fake_vblank</span><span class="p">(</span><span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 5. 标记硬件完成</span>
    <span class="n">drm_atomic_helper_commit_hw_done</span><span class="p">(</span><span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 6. 等待 vblank</span>
    <span class="n">meson_drm_atomic_helper_wait_for_vblanks</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
    
    <span class="c1">// 7. 清理 plane 资源</span>
    <span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">old_state</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>CRTC 具体实现：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c:655 - CRTC enable</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">am_meson_crtc_atomic_enable</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">,</span> 
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 验证并设置显示模式</span>
    <span class="n">vout_func_validate_vmode</span><span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">mode</span><span class="p">.</span><span class="n">name</span><span class="p">);</span>
    <span class="n">vout_func_set_state</span><span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">mode</span><span class="p">.</span><span class="n">name</span><span class="p">);</span>
    
    <span class="c1">// 更新 VIU 配置</span>
    <span class="n">vout_func_update_viu</span><span class="p">();</span>
    
    <span class="c1">// 开启 vblank 中断</span>
    <span class="n">drm_crtc_vblank_on</span><span class="p">(</span><span class="n">crtc</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="34-commit-完成回调机制">3.4 Commit 完成回调机制</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:120 - 等待 commit 完成</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">meson_drm_crtc_commit_wait</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="o">*</span><span class="n">commit</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 等待硬件编程完成 (100ms 超时)</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">wait_for_completion_timeout</span><span class="p">(</span><span class="o">&amp;</span><span class="n">commit</span><span class="o">-&gt;</span><span class="n">hw_done</span><span class="p">,</span> <span class="n">HZ</span> <span class="o">/</span> <span class="mi">10</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ret</span><span class="p">)</span>
        <span class="k">return</span> <span class="o">-</span><span class="n">ETIMEDOUT</span><span class="p">;</span>
    
    <span class="c1">// 2. 等待 flip 完成</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">wait_for_completion_timeout</span><span class="p">(</span><span class="o">&amp;</span><span class="n">commit</span><span class="o">-&gt;</span><span class="n">flip_done</span><span class="p">,</span> <span class="n">HZ</span> <span class="o">/</span> <span class="mi">10</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">ret</span><span class="p">)</span>
        <span class="k">return</span> <span class="o">-</span><span class="n">ETIMEDOUT</span><span class="p">;</span>
    
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// drm_crtc_commit 结构</span>
<span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">flip_done</span><span class="p">;</span>     <span class="c1">// 用户空间 flip 完成</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">hw_done</span><span class="p">;</span>      <span class="c1">// 硬件编程完成</span>
    <span class="k">struct</span> <span class="n">completion</span> <span class="n">cleanup_done</span><span class="p">;</span> <span class="c1">// 清理完成</span>
    <span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_pending_vblank_event</span> <span class="o">*</span><span class="n">event</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="35-高频问题">3.5 高频问题</h3>

<table>
  <thead>
    <tr>
      <th>问题</th>
      <th>答案要点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>为什么需要 atomic commit？</td>
      <td>保证多对象更新的原子性，避免中间状态导致的闪烁或异常</td>
    </tr>
    <tr>
      <td>blocking vs non-blocking commit？</td>
      <td>Blocking 在 commit 返回前完成硬件配置；non-blocking 立即返回，通过 kthread 异步执行</td>
    </tr>
    <tr>
      <td>如何检测 stall？</td>
      <td>检查 commit_list 中是否有未完成的 commit，防止用户空间提交过快</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="四state-状态管理">四、State 状态管理</h2>

<h3 id="41-atomic-state-结构">4.1 Atomic State 结构</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// DRM framework - drm_atomic_state</span>
<span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_modeset_acquire_ctx</span> <span class="o">*</span><span class="n">acquire_ctx</span><span class="p">;</span>
    
    <span class="c1">// 状态数组指针</span>
    <span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="o">**</span><span class="n">crtc_states</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_plane_state</span> <span class="o">**</span><span class="n">plane_states</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_connector_state</span> <span class="o">**</span><span class="n">connector_states</span><span class="p">;</span>
    
    <span class="c1">// Commit 跟踪</span>
    <span class="k">struct</span> <span class="n">drm_crtc_commit</span> <span class="o">**</span><span class="n">crtcs</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">work_struct</span> <span class="n">commit_work</span><span class="p">;</span>  <span class="c1">// 异步 commit work</span>
    
    <span class="n">bool</span> <span class="n">allow_modeset</span><span class="o">:</span><span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">legacy_cursor_update</span><span class="o">:</span><span class="mi">1</span><span class="p">;</span>
    <span class="n">bool</span> <span class="n">async_update</span><span class="o">:</span><span class="mi">1</span><span class="p">;</span>
<span class="p">};</span>

<span class="c1">// Meson 私有 CRTC state</span>
<span class="k">struct</span> <span class="n">am_meson_crtc_state</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="n">base</span><span class="p">;</span>
    <span class="k">enum</span> <span class="n">vmode_e</span> <span class="n">vmode</span><span class="p">;</span>              <span class="c1">// 当前显示模式</span>
    <span class="k">enum</span> <span class="n">vmode_e</span> <span class="n">preset_vmode</span><span class="p">;</span>       <span class="c1">// 预设模式</span>
    <span class="n">bool</span> <span class="n">seamless</span><span class="p">;</span>                   <span class="c1">// 无缝切换</span>
    <span class="n">bool</span> <span class="n">crtc_dv_enable</span><span class="p">;</span>            <span class="c1">// Dolby Vision</span>
    <span class="n">bool</span> <span class="n">crtc_hdr_enable</span><span class="p">;</span>           <span class="c1">// HDR</span>
    <span class="n">u8</span> <span class="n">crtc_hdr_process_policy</span><span class="p">;</span>     <span class="c1">// HDR 处理策略</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="42-state-复制与检查">4.2 State 复制与检查</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c:841 - CRTC atomic check</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">meson_crtc_atomic_check</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">,</span> 
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">am_meson_crtc_state</span> <span class="o">*</span><span class="n">new_state</span> <span class="o">=</span> <span class="n">to_am_meson_crtc_state</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 检查 HDR/DV 参数变化</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span> <span class="o">!=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span> <span class="o">||</span>
        <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span> <span class="o">!=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">.</span><span class="n">mode_changed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="c1">// VPU pipeline 检查</span>
    <span class="k">return</span> <span class="n">vpu_pipeline_check</span><span class="p">(</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">pipeline</span><span class="p">,</span> <span class="n">crtc</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="43-state-交换与回滚">4.3 State 交换与回滚</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// drm_atomic_helper_swap_state - 交换新旧 state</span>
<span class="kt">int</span> <span class="nf">drm_atomic_helper_swap_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span> <span class="n">bool</span> <span class="n">commit</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 遍历所有 CRTC</span>
    <span class="n">for_each_crtc_in_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">crtc</span><span class="p">,</span> <span class="n">old_crtc_state</span><span class="p">,</span> <span class="n">new_crtc_state</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 1. 保存当前硬件状态到 old_crtc_state</span>
        <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_flush</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="n">old_crtc_state</span><span class="p">);</span>
        
        <span class="c1">// 2. 用 new_crtc_state 替换 crtc-&gt;state</span>
        <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_crtc_state</span><span class="p">;</span>
        <span class="n">new_crtc_state</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">state</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="c1">// 同样的逻辑应用于 plane 和 connector</span>
<span class="p">}</span>
</code></pre></div></div>

<hr />

<h3 id="44-state-交换与提交-commit">4.4 State 交换与提交 (commit)</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// drm_atomic_helper_swap_state - 交换新旧 state</span>
<span class="kt">int</span> <span class="nf">drm_atomic_helper_swap_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span> <span class="n">bool</span> <span class="n">commit</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 遍历所有 CRTC</span>
    <span class="n">for_each_crtc_in_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">crtc</span><span class="p">,</span> <span class="n">old_crtc_state</span><span class="p">,</span> <span class="n">new_crtc_state</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 1. 保存当前硬件状态到 old_crtc_state</span>
        <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">funcs</span><span class="o">-&gt;</span><span class="n">atomic_flush</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="n">old_crtc_state</span><span class="p">);</span>
        
        <span class="c1">// 2. 用 new_crtc_state 替换 crtc-&gt;state</span>
        <span class="n">crtc</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">new_crtc_state</span><span class="p">;</span>
        <span class="n">new_crtc_state</span><span class="o">-&gt;</span><span class="n">state</span> <span class="o">=</span> <span class="n">state</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="c1">// 同样的逻辑应用于 plane 和 connector</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="45-acquire_ctx-锁管理机制">4.5 acquire_ctx 锁管理机制</h3>

<p><code class="language-plaintext highlighter-rouge">acquire_ctx</code> (<code class="language-plaintext highlighter-rouge">struct drm_modeset_acquire_ctx</code>) 是 modeset 锁获取的上下文管理器，用于死锁避免：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_async_atomic.c - 锁初始化</span>
<span class="k">struct</span> <span class="n">drm_modeset_acquire_ctx</span> <span class="n">ctx</span><span class="p">;</span>
<span class="n">drm_modeset_acquire_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">state</span><span class="o">-&gt;</span><span class="n">acquire_ctx</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">ctx</span><span class="p">;</span>

<span class="c1">// 死锁处理</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ret</span> <span class="o">==</span> <span class="o">-</span><span class="n">EDEADLK</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">drm_atomic_state_clear</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
    <span class="n">drm_modeset_backoff</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">);</span>  <span class="c1">// 随机化锁获取顺序</span>
    <span class="k">goto</span> <span class="n">retry</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="46-allow_modeset-标志位">4.6 allow_modeset 标志位</h3>

<p><code class="language-plaintext highlighter-rouge">allow_modeset</code> 控制是否允许完整 modeset 操作：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_async_atomic.c</span>
<span class="n">state</span><span class="o">-&gt;</span><span class="n">allow_modeset</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>  <span class="c1">// Async atomic 禁用 modeset</span>

<span class="c1">// meson_crtc.c - 强制 mode changed</span>
<span class="k">if</span> <span class="p">(</span><span class="n">atomic_state</span><span class="o">-&gt;</span><span class="n">allow_modeset</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span> <span class="o">!=</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span><span class="p">)</span>
        <span class="n">crtc_state</span><span class="o">-&gt;</span><span class="n">mode_changed</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="47-state-复制流程详解">4.7 State 复制流程详解</h3>

<p><strong>CRTC State 复制</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c - 复制 state</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">drm_crtc_state</span> <span class="o">*</span><span class="nf">meson_crtc_duplicate_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_crtc</span> <span class="o">*</span><span class="n">crtc</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">am_meson_crtc_state</span> <span class="o">*</span><span class="n">new_state</span><span class="p">,</span> <span class="o">*</span><span class="n">cur_state</span><span class="p">;</span>
    <span class="n">cur_state</span> <span class="o">=</span> <span class="n">to_am_meson_crtc_state</span><span class="p">(</span><span class="n">crtc</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">);</span>
    
    <span class="n">new_state</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">new_state</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    <span class="n">__drm_atomic_helper_crtc_duplicate_state</span><span class="p">(</span><span class="n">crtc</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">);</span>
    
    <span class="c1">// 复制 Meson 特定状态</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_hdr_process_policy</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">crtc_dv_enable</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">vmode</span> <span class="o">=</span> <span class="n">cur_state</span><span class="o">-&gt;</span><span class="n">vmode</span><span class="p">;</span>
    <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">seamless</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>  <span class="c1">// 新状态默认非 seamless</span>
    
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">new_state</span><span class="o">-&gt;</span><span class="n">base</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>深拷贝 vs 浅拷贝字段</strong>：</p>

<table>
  <thead>
    <tr>
      <th>字段类型</th>
      <th>复制方式</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fb</code> (framebuffer)</td>
      <td>引用计数 +1</td>
      <td>浅拷贝，共享指针</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">fence</code></td>
      <td>需要深拷贝</td>
      <td>每个 state 独立 fence</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">driver-private</code></td>
      <td>驱动实现</td>
      <td>通常深拷贝</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">property values</code></td>
      <td>直接复制值</td>
      <td>浅拷贝</td>
    </tr>
  </tbody>
</table>

<h3 id="48-state-错误处理与回滚">4.8 State 错误处理与回滚</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 失败时的恢复机制</span>
<span class="kt">void</span> <span class="nf">drm_atomic_state_clear</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
    
    <span class="c1">// 清理 connector states</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">state</span><span class="o">-&gt;</span><span class="n">num_connector</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">connectors</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">state</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">drm_connector_state_put</span><span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">connectors</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">state</span><span class="p">);</span>
            <span class="n">state</span><span class="o">-&gt;</span><span class="n">connectors</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">state</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="c1">// 同样的逻辑用于 CRTC 和 Plane</span>
<span class="p">}</span>

<span class="c1">// Meson 驱动错误处理</span>
<span class="n">err</span><span class="o">:</span>
    <span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="49-legacy-vs-atomic-状态管理差异">4.9 Legacy vs Atomic 状态管理差异</h3>

<p><strong>Legacy Cursor Update</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c</span>
<span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_setup_commit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">nonblock</span><span class="p">);</span>
    <span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>Legacy Cursor</th>
      <th>Atomic</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>锁获取</td>
      <td>非阻塞快速路径</td>
      <td>标准 modeset 锁</td>
    </tr>
    <tr>
      <td>VBlank 等待</td>
      <td>跳过（完全异步）</td>
      <td>可选等待</td>
    </tr>
    <tr>
      <td>事件发送</td>
      <td>即时</td>
      <td>提交完成时</td>
    </tr>
  </tbody>
</table>

<h3 id="410-commit-回调执行顺序">4.10 Commit 回调执行顺序</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────────────────────────┐
│  PHASE 1: Check &amp; Prepare                                       │
│  ─────────────────────────────────────────────                  │
│  1. drm_atomic_helper_commit_duplicated_flags()                 │
│  2. [Driver] .atomic_check() callbacks                         │
│     ├── plane-&gt;helper_private-&gt;atomic_check()                  │
│     ├── crtc-&gt;helper_private-&gt;atomic_check()                    │
│     └── connector-&gt;helper_private-&gt;atomic_check()               │
│                                                                  │
│  PHASE 2: Hardware Commit                                        │
│  ─────────────────────────────────────────────                  │
│  3. drm_atomic_helper_swap_state()  // 原子交换 new ↔ old state  │
│  4. drm_atomic_helper_commit_modeset_disables()                 │
│  5. drm_atomic_helper_commit_modeset_enables()                  │
│  6. drm_atomic_helper_commit_planes()                           │
│  7. [Driver] .atomic_flush()                                    │
│                                                                  │
│  PHASE 3: Completion                                             │
│  ─────────────────────────────────────────────                  │
│  8. drm_atomic_helper_commit_hw_done()                          │
│  9. drm_atomic_helper_wait_for_vblanks()                        │
│  10. drm_atomic_helper_cleanup_planes()                         │
└─────────────────────────────────────────────────────────────────┘
</code></pre></div></div>

<h3 id="411-drm_private_state-使用场景">4.11 drm_private_state 使用场景</h3>

<p><code class="language-plaintext highlighter-rouge">drm_private_state</code> 用于驱动自定义的私有状态，不属于标准 CRTC/Plane/Connector：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_crtc.c - Pipeline 级别状态</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">meson_crtc_atomic_print_state</span><span class="p">(...)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">meson_vpu_pipeline_state</span> <span class="o">*</span><span class="n">mvps</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_private_state</span> <span class="o">*</span><span class="n">obj_state</span><span class="p">;</span>
    
    <span class="n">obj_state</span> <span class="o">=</span> <span class="n">priv</span><span class="o">-&gt;</span><span class="n">pipeline</span><span class="o">-&gt;</span><span class="n">obj</span><span class="p">.</span><span class="n">state</span><span class="p">;</span>
    <span class="n">mvps</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">obj_state</span><span class="p">,</span> <span class="k">struct</span> <span class="n">meson_vpu_pipeline_state</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>典型使用场景</strong>：</p>
<ul>
  <li>Pipeline 级别状态（如 meson 的 VPU pipeline）</li>
  <li>跨多个 CRTC 的共享资源状态</li>
  <li>驱动特定硬件块的状态</li>
</ul>

<hr />

<h2 id="五多路送显架构">五、多路送显架构</h2>

<h3 id="51-crtcencoder-注册机制">5.1 CRTC/Encoder 注册机制</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_drv.c:283 - DRM bind</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">am_meson_drm_bind</span><span class="p">(</span><span class="k">struct</span> <span class="n">device</span> <span class="o">*</span><span class="n">dev</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 初始化 DRM 设备</span>
    <span class="n">drm</span> <span class="o">=</span> <span class="n">drm_dev_alloc</span><span class="p">(</span><span class="o">&amp;</span><span class="n">meson_driver</span><span class="p">,</span> <span class="n">dev</span><span class="p">);</span>
    
    <span class="c1">// 2. 初始化 mode config</span>
    <span class="n">drm_mode_config_init</span><span class="p">(</span><span class="n">drm</span><span class="p">);</span>
    
    <span class="c1">// 3. 初始化 VPU topology</span>
    <span class="n">vpu_topology_init</span><span class="p">(</span><span class="n">pdev</span><span class="p">,</span> <span class="n">priv</span><span class="p">);</span>
    
    <span class="c1">// 4. 绑定所有子组件驱动 (HDMI, LCD, CVBS)</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">component_bind_all</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">bound_data</span><span class="p">);</span>
    
    <span class="c1">// 5. 初始化 per-CRTC commit 线程</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">meson_worker_thread_init</span><span class="p">(</span><span class="n">priv</span><span class="p">,</span> <span class="n">drm</span><span class="o">-&gt;</span><span class="n">mode_config</span><span class="p">.</span><span class="n">num_crtc</span><span class="p">);</span>
    
    <span class="c1">// 6. 注册 DRM 设备</span>
    <span class="n">drm_dev_register</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="52-资源分配与克隆模式">5.2 资源分配与克隆模式</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_of_parser.c - 设备树解析</span>
<span class="k">struct</span> <span class="n">meson_of_conf</span> <span class="p">{</span>
    <span class="n">u32</span> <span class="n">crtc_masks</span><span class="p">[</span><span class="n">ENCODER_MAX</span><span class="p">];</span>  <span class="c1">// 每个 encoder 可用的 CRTC</span>
    <span class="n">u32</span> <span class="n">crtcmask_osd</span><span class="p">;</span>             <span class="c1">// OSD 层 CRTC 映射</span>
    <span class="n">u32</span> <span class="n">crtcmask_video</span><span class="p">;</span>           <span class="c1">// Video 层 CRTC 映射</span>
<span class="p">};</span>

<span class="c1">// 默认配置</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">ENCODER_MAX</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
    <span class="n">conf</span><span class="o">-&gt;</span><span class="n">crtc_masks</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 默认使用 CRTC0</span>

<span class="c1">// 设备树覆盖示例:</span>
<span class="c1">// crtc_masks = &lt;0x1&gt;, &lt;0x2&gt;, &lt;0x4&gt;  // HDMI-&gt;CRTC0, LCD-&gt;CRTC1, CVBS-&gt;CRTC2</span>
</code></pre></div></div>

<h3 id="53-多路输出配置">5.3 多路输出配置</h3>

<pre><code class="language-mermaid">graph TB
    subgraph "DRM Framework"
        CRTC0[CRTC 0] --&gt; E0[Encoder HDMI]
        CRTC1[CRTC 1] --&gt; E1[Encoder LCD]
        CRTC2[CRTC 2] --&gt; E2[Encoder CVBS]
    end
    
    subgraph "Output"
        E0 --&gt; C0[Connector HDMI]
        E1 --&gt; C1[Connector LCD Panel]
        E2 --&gt; C2[Connector CVBS]
    end
    
    subgraph "Device Tree"
        DT["ports = &lt;&amp;vpu&gt;, &lt;&amp;hdmitx&gt;, &lt;&amp;lcd&gt;"]
    end
</code></pre>

<callout emoji="💡" background-color="light-blue">
**多路模式**：
- **克隆模式**：多个 encoder 使用相同 CRTC，显示相同内容
- **扩展模式**：每个 encoder 独立 CRTC，显示不同内容
- **混合模式**：部分共享，部分独立
</callout>

<hr />

<h2 id="六性能优化考量">六、性能优化考量</h2>

<h3 id="61-非阻塞-commit">6.1 非阻塞 Commit</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:470 - commit 入口</span>
<span class="kt">int</span> <span class="nf">meson_atomic_commit</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span> 
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">,</span> <span class="n">bool</span> <span class="n">nonblock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 设置 commit 跟踪结构</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">meson_drm_atomic_helper_setup_commit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">nonblock</span><span class="p">);</span>
    
    <span class="c1">// 准备 plane 资源</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_prepare_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 交换 state</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_swap_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
    
    <span class="k">if</span> <span class="p">(</span><span class="n">nonblock</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 创建 kthread work</span>
        <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">crtc_id</span> <span class="o">=</span> <span class="n">crtc_index</span><span class="p">;</span>
        <span class="n">kthread_init_work</span><span class="p">(</span><span class="o">&amp;</span><span class="n">work_item</span><span class="o">-&gt;</span><span class="n">kthread_work</span><span class="p">,</span> <span class="n">meson_commit_work</span><span class="p">);</span>
        
        <span class="c1">// 队列到 per-CRTC worker</span>
        <span class="n">worker</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">commit_thread</span><span class="p">[</span><span class="n">crtc_index</span><span class="p">].</span><span class="n">worker</span><span class="p">;</span>
        <span class="n">kthread_queue_work</span><span class="p">(</span><span class="n">worker</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">work_item</span><span class="o">-&gt;</span><span class="n">kthread_work</span><span class="p">);</span>
        
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1">// 立即返回</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="c1">// 同步等待完成</span>
        <span class="n">meson_commit_tail</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="62-async-update">6.2 Async Update</h3>

<p>对于纯 plane 更新（非模式切换），可以走 async 路径：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:491 - async update 路径</span>
<span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">async_update</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// 准备 plane</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_prepare_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 交换 state</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_swap_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
    
    <span class="c1">// 直接执行 plane update，不走完整 commit</span>
    <span class="n">meson_atomic_helper_async_commit</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 清理</span>
    <span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="63-内存带宽优化">6.3 内存带宽优化</h3>

<table>
  <thead>
    <tr>
      <th>优化点</th>
      <th>实现方式</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>DMA heap 优先级</td>
      <td>heap-fb &gt; heap-gfx &gt; heap-codecmm</td>
    </tr>
    <tr>
      <td>Cache 策略</td>
      <td>对非缓存内存使用 <code class="language-plaintext highlighter-rouge">pgprot_writecombine()</code></td>
    </tr>
    <tr>
      <td>零拷贝</td>
      <td>通过 DMA-buf 直接共享，无需 memcpy</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="七hdmi-与-tx-hdmi-transmitter-差异">七、HDMI 与 TX (HDMI Transmitter) 差异</h2>

<h3 id="71-架构定位">7.1 架构定位</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>         CPU                  HDMI Transmitter          Display Device
    +-----------+            +-------------+           +-------------+
    |   VPU     |   ---PCIe--|   HDMI TX   |---TMDS----|   Monitor   |
    | (显示引擎)|            |  (物理层)   |           |             |
    +-----------+            +-------------+           +-------------+
    
    DRM 驱动层                VOUT/HDMI TX 驱动
    meson_drm.ko              hdmitx21.ko
</code></pre></div></div>

<ul>
  <li><strong>DRM (meson_drm.ko)</strong>：负责显示管线管理、模式设置、buffer 提交</li>
  <li><strong>HDMI TX (hdmitx21.ko)</strong>：负责物理层信号生成、EDID、HDCP、InfoFrame</li>
</ul>

<h3 id="72-信号特性">7.2 信号特性</h3>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>DRM (显示引擎)</th>
      <th>HDMI TX (发送器)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>信号类型</td>
      <td>内部 RGB/CSC 格式</td>
      <td>外部 TMDS/FRL</td>
    </tr>
    <tr>
      <td>时钟域</td>
      <td>像素时钟 (pixel clock)</td>
      <td>串行时钟 (serdes clock)</td>
    </tr>
    <tr>
      <td>数据宽度</td>
      <td>48/64-bit 并行</td>
      <td>1.65-3.4 Gbps 串行</td>
    </tr>
    <tr>
      <td>同步方式</td>
      <td>VSYNC/HSYNC 内部</td>
      <td>CEA-861 标准</td>
    </tr>
  </tbody>
</table>

<h3 id="73-时序要求">7.3 时序要求</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// hdmitx21/hdmi_tx_video.c - 视频参数配置</span>
<span class="k">struct</span> <span class="n">hdmi_video_format</span> <span class="p">{</span>
    <span class="n">u32</span> <span class="n">hsync_width</span><span class="p">;</span>    <span class="c1">// 水平同步宽度</span>
    <span class="n">u32</span> <span class="n">hback_porch</span><span class="p">;</span>   <span class="c1">// 后沿</span>
    <span class="n">u32</span> <span class="n">hactive</span><span class="p">;</span>       <span class="c1">// 有效像素</span>
    <span class="n">u32</span> <span class="n">hfront_porch</span><span class="p">;</span>  <span class="c1">// 前沿</span>
    
    <span class="n">u32</span> <span class="n">vsync_width</span><span class="p">;</span>   <span class="c1">// 垂直同步</span>
    <span class="n">u32</span> <span class="n">vback_porch</span><span class="p">;</span>
    <span class="n">u32</span> <span class="n">vactive</span><span class="p">;</span>
    <span class="n">u32</span> <span class="n">vfront_porch</span><span class="p">;</span>
    
    <span class="n">u32</span> <span class="n">pixel_repeat</span><span class="p">;</span>  <span class="c1">// 像素重复</span>
    <span class="n">u32</span> <span class="n">color_depth</span><span class="p">;</span>   <span class="c1">// 色深 (8/10/12-bit)</span>
<span class="p">};</span>
</code></pre></div></div>

<callout emoji="⚠️" background-color="light-yellow">
**关键差异**：HDMI TX 需要遵循 EIA/CEA-861 标准，包含严格的时序参数要求；而 DRM 内部可以使用更灵活的内部时序。
</callout>

<hr />

<h2 id="八常见问题与要点">八、常见问题与要点</h2>

<callout emoji="📝" background-color="pale-gray">
**高频问题汇总**
</callout>

<ol>
  <li><strong>DMA-buf 的核心作用是什么？</strong>
    <ul>
      <li>跨设备零拷贝共享内存</li>
    </ul>
  </li>
  <li><strong>fence 如何解决同步问题？</strong>
    <ul>
      <li>显式同步：用户空间管理 fence fd</li>
      <li>隐式同步：附加到 buffer 自动等待</li>
    </ul>
  </li>
  <li><strong>atomic commit 为什么要设计成原子的？</strong>
    <ul>
      <li>避免多对象更新时的中间状态</li>
    </ul>
  </li>
  <li><strong>如何实现多路显示？</strong>
    <ul>
      <li>多个 CRTC + encoder + connector</li>
      <li>设备树配置 crtc_masks</li>
    </ul>
  </li>
  <li><strong>commit 超时如何处理？</strong>
    <ul>
      <li>设置超时检测 (100ms)</li>
      <li>打印错误信息并返回 -ETIMEDOUT</li>
    </ul>
  </li>
  <li><strong>异步更新和普通更新的区别？</strong>
    <ul>
      <li>异步更新只更新 plane，不触发完整模式设置</li>
    </ul>
  </li>
  <li><strong>HDMI 和 TX 的关系？</strong>
    <ul>
      <li>DRM 负责模式和数据，TX 负责物理层发送</li>
    </ul>
  </li>
  <li><strong>遇到黑屏如何调试？</strong>
    <ul>
      <li>检查 dmesg 日志</li>
      <li>验证 drm_atomic_check 返回值</li>
      <li>确认 vblank 中断状态</li>
    </ul>
  </li>
</ol>

<hr />

<h2 id="十drm-writeback-回写机制">十、DRM Writeback 回写机制</h2>

<h3 id="101-writeback-核心概念">10.1 Writeback 核心概念</h3>

<p>DRM Writeback 是 DRM 4.20 引入的框架，允许硬件将显示管线的内容捕获回写到内存缓冲区。这与传统的”显示输出”相反——不是把 buffer 送到屏幕，而是把屏幕内容写回 buffer。</p>

<pre><code class="language-mermaid">graph LR
    subgraph "显示管线"
        A[Plane 0] --&gt; B[Plane 1]
        B --&gt; C[CRTC Mixer]
    end
    
    subgraph "输出"
        C --&gt; D[Encoder]
        D --&gt; E[Display]
    end
    
    subgraph "Writeback"
        C --&gt; W[Writeback Connector]
        W --&gt; F[FrameBuffer in Memory]
    end
</code></pre>

<p><strong>典型应用场景</strong>：</p>
<ul>
  <li><strong>屏幕录制</strong>：捕获屏幕内容用于录制</li>
  <li><strong>帧缓冲复制</strong>：复制当前显示内容到另一个缓冲区</li>
  <li><strong>后处理管线</strong>：捕获显示内容进行软件处理后再显示</li>
  <li><strong>调试/诊断</strong>：保存当前显示状态用于调试</li>
</ul>

<h3 id="102-writeback-数据结构">10.2 Writeback 数据结构</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_writeback.h - Amlogic 扩展的 writeback 结构</span>
<span class="k">struct</span> <span class="n">am_drm_writeback</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">meson_connector</span> <span class="n">base</span><span class="p">;</span>                    <span class="c1">// 基类</span>
    <span class="k">struct</span> <span class="n">drm_writeback_connector</span> <span class="n">wb_connector</span><span class="p">;</span>   <span class="c1">// DRM writeback connector</span>
    <span class="k">struct</span> <span class="n">drm_device</span> <span class="n">drm_dev</span><span class="p">;</span>                    <span class="c1">// DRM 设备</span>
    <span class="k">struct</span> <span class="n">work_struct</span> <span class="n">writeback_work</span><span class="p">;</span>             <span class="c1">// 捕获工作队列</span>
    <span class="k">struct</span> <span class="n">workqueue_struct</span> <span class="o">*</span><span class="n">writeback_wq</span><span class="p">;</span>        <span class="c1">// workqueue</span>
    <span class="k">struct</span> <span class="n">drm_framebuffer</span> <span class="o">*</span><span class="n">fb</span><span class="p">;</span>                   <span class="c1">// 目标帧缓冲</span>
    <span class="n">u32</span> <span class="n">capture_port</span><span class="p">;</span>                             <span class="c1">// 捕获端口</span>
    <span class="k">struct</span> <span class="n">drm_property</span> <span class="o">*</span><span class="n">capture_port_prop</span><span class="p">;</span>        <span class="c1">// 捕获端口属性</span>
<span class="p">};</span>

<span class="c1">// DRM framework - writeback connector</span>
<span class="k">struct</span> <span class="n">drm_writeback_connector</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_connector</span> <span class="n">base</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_encoder</span> <span class="n">encoder</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="103-writeback-流程解析">10.3 Writeback 流程解析</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_writeback.c:396 - Writeback 初始化</span>
<span class="kt">int</span> <span class="nf">am_meson_writeback_create</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">drm</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 分配 writeback 结构</span>
    <span class="n">drm_writeback</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">drm_writeback</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    
    <span class="c1">// 2. 设置 encoder 的 CRTC 掩码</span>
    <span class="n">wb_connector</span><span class="o">-&gt;</span><span class="n">encoder</span><span class="p">.</span><span class="n">possible_crtcs</span> <span class="o">=</span> <span class="n">BIT</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
    
    <span class="c1">// 3. 获取支持的像素格式</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">meson_writeback_get_format</span><span class="p">(</span><span class="n">writeback_fmts</span><span class="p">);</span>
    
    <span class="c1">// 4. 注册 writeback connector</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_writeback_connector_init</span><span class="p">(</span><span class="n">drm</span><span class="p">,</span> <span class="n">wb_connector</span><span class="p">,</span>
        <span class="o">&amp;</span><span class="n">am_writeback_connector_funcs</span><span class="p">,</span>
        <span class="o">&amp;</span><span class="n">am_writeback_encoder_helper_funcs</span><span class="p">,</span>
        <span class="n">writeback_fmts</span><span class="p">,</span> <span class="n">ARRAY_SIZE</span><span class="p">(</span><span class="n">writeback_fmts</span><span class="p">));</span>
    
    <span class="c1">// 5. 创建 workqueue</span>
    <span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">writeback_wq</span> <span class="o">=</span> <span class="n">alloc_workqueue</span><span class="p">(</span><span class="s">"writeback_capture"</span><span class="p">,</span>
        <span class="n">WQ_HIGHPRI</span> <span class="o">|</span> <span class="n">WQ_CPU_INTENSIVE</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
    
    <span class="c1">// 6. 初始化 work</span>
    <span class="n">INIT_WORK</span><span class="p">(</span><span class="o">&amp;</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">writeback_work</span><span class="p">,</span> <span class="n">meson_writeback_capture_work</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="104-atomic-commit-流程">10.4 Atomic Commit 流程</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_writeback.c:50 - Atomic check</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">meson_writeback_connector_atomic_check</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_connector</span> <span class="o">*</span><span class="n">conn</span><span class="p">,</span>
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">conn_state</span> <span class="o">=</span> <span class="n">drm_atomic_get_new_connector_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">conn</span><span class="p">);</span>
    
    <span class="c1">// 检查是否有 writeback job</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">conn_state</span><span class="o">-&gt;</span><span class="n">writeback_job</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    
    <span class="n">crtc_state</span> <span class="o">=</span> <span class="n">drm_atomic_get_new_crtc_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">conn_state</span><span class="o">-&gt;</span><span class="n">crtc</span><span class="p">);</span>
    <span class="n">fb</span> <span class="o">=</span> <span class="n">conn_state</span><span class="o">-&gt;</span><span class="n">writeback_job</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">;</span>
    
    <span class="c1">// 检查帧缓冲尺寸是否匹配</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">width</span> <span class="o">!=</span> <span class="n">crtc_state</span><span class="o">-&gt;</span><span class="n">mode</span><span class="p">.</span><span class="n">hdisplay</span> <span class="o">||</span>
        <span class="n">fb</span><span class="o">-&gt;</span><span class="n">height</span> <span class="o">!=</span> <span class="n">crtc_state</span><span class="o">-&gt;</span><span class="n">mode</span><span class="p">.</span><span class="n">vdisplay</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">DRM_ERROR</span><span class="p">(</span><span class="s">"Invalid framebuffer size %ux%u</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fb</span><span class="o">-&gt;</span><span class="n">width</span><span class="p">,</span> <span class="n">fb</span><span class="o">-&gt;</span><span class="n">height</span><span class="p">);</span>
        <span class="k">return</span> <span class="o">-</span><span class="n">EINVAL</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="c1">// 检查像素格式是否支持</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">ARRAY_SIZE</span><span class="p">(</span><span class="n">writeback_fmts</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">fb</span><span class="o">-&gt;</span><span class="n">format</span><span class="o">-&gt;</span><span class="n">format</span> <span class="o">==</span> <span class="n">writeback_fmts</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
            <span class="k">break</span><span class="p">;</span>
    <span class="p">}</span>
    
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// meson_writeback.c:194 - Atomic commit</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">meson_writeback_connector_atomic_commit</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_connector</span> <span class="o">*</span><span class="n">conn</span><span class="p">,</span>
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">old_atomic_state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">conn_state</span> <span class="o">=</span> <span class="n">drm_atomic_get_old_connector_state</span><span class="p">(</span><span class="n">old_atomic_state</span><span class="p">,</span> <span class="n">conn</span><span class="p">);</span>
    <span class="n">drm_writeback</span> <span class="o">=</span> <span class="n">connector_to_am_writeback</span><span class="p">(</span><span class="n">conn</span><span class="p">);</span>
    <span class="n">fb</span> <span class="o">=</span> <span class="n">conn_state</span><span class="o">-&gt;</span><span class="n">writeback_job</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">;</span>
    <span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">fb</span> <span class="o">=</span> <span class="n">fb</span><span class="p">;</span>
    
    <span class="c1">// 队列到 workqueue 执行捕获</span>
    <span class="n">drm_writeback_queue_job</span><span class="p">(</span><span class="o">&amp;</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">wb_connector</span><span class="p">,</span> <span class="n">conn_state</span><span class="p">);</span>
    <span class="n">queue_work</span><span class="p">(</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">writeback_wq</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">writeback_work</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// meson_writeback.c:182 - Work 处理</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">meson_writeback_capture_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">work_struct</span> <span class="o">*</span><span class="n">work</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">drm_writeback</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">work</span><span class="p">,</span> <span class="k">struct</span> <span class="n">am_drm_writeback</span><span class="p">,</span> <span class="n">writeback_work</span><span class="p">);</span>
    
    <span class="c1">// 执行实际捕获</span>
    <span class="n">meson_writeback_capture_picture</span><span class="p">(</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">,</span> <span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">capture_port</span><span class="p">);</span>
    
    <span class="c1">// 通知完成</span>
    <span class="n">drm_writeback_signal_completion</span><span class="p">(</span><span class="o">&amp;</span><span class="n">drm_writeback</span><span class="o">-&gt;</span><span class="n">wb_connector</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="105-capture-port-配置">10.5 Capture Port 配置</h3>

<p>Meson 支持多种捕获端口：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_writeback.c:352 - 捕获端口枚举</span>
<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">drm_prop_enum_list</span> <span class="n">writeback_capture_port_enum_list</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">{</span> <span class="n">TVIN_PORT_VIU1_WB0_VD1</span><span class="p">,</span> <span class="s">"video"</span> <span class="p">},</span>      <span class="c1">// 仅视频层</span>
    <span class="p">{</span> <span class="n">TVIN_PORT_VIU1_WB0_OSD1</span><span class="p">,</span> <span class="s">"osd"</span> <span class="p">},</span>       <span class="c1">// 仅 OSD 层</span>
    <span class="p">{</span> <span class="n">TVIN_PORT_VIU1_WB0_VPP</span><span class="p">,</span> <span class="s">"video&amp;osd"</span> <span class="p">},</span> <span class="c1">// 视频和 OSD 混合</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>硬件架构</strong>：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">TVIN_PORT_VIU1_WB0_VD1</code>：Video Decoder 输入</li>
  <li><code class="language-plaintext highlighter-rouge">TVIN_PORT_VIU1_WB0_OSD1</code>：OSD1 层</li>
  <li><code class="language-plaintext highlighter-rouge">TVIN_PORT_VIU1_WB0_VPP</code>：Video Post Processor 输出（全部混合）</li>
</ul>

<h3 id="106-典型应用场景">10.6 典型应用场景</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 用户空间使用示例</span>
<span class="k">struct</span> <span class="n">drm_mode_capture</span> <span class="p">{</span>
    <span class="n">u32</span> <span class="n">fb_id</span><span class="p">;</span>          <span class="c1">// 捕获目标帧缓冲</span>
    <span class="n">u32</span> <span class="n">out_fence</span><span class="p">;</span>       <span class="c1">// 输出 fence</span>
    <span class="n">u32</span> <span class="n">connector_id</span><span class="p">;</span>    <span class="c1">// writeback connector ID</span>
    <span class="n">u32</span> <span class="n">flags</span><span class="p">;</span>
<span class="p">};</span>

<span class="c1">// 1. 创建用于捕获的帧缓冲</span>
<span class="n">drmModeFB2Create</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">DRM_FORMAT_NV12</span><span class="p">,</span> <span class="n">handles</span><span class="p">,</span> <span class="n">pitches</span><span class="p">,</span> <span class="n">offsets</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fb_id</span><span class="p">);</span>

<span class="c1">// 2. 提交 writeback job</span>
<span class="n">drm_writeback_queue_job</span><span class="p">(</span><span class="n">connector</span><span class="p">,</span> <span class="n">fb_id</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">out_fence</span><span class="p">);</span>

<span class="c1">// 3. 等待捕获完成</span>
<span class="n">sync_file_wait</span><span class="p">(</span><span class="n">out_fence</span><span class="p">,</span> <span class="mi">1000</span><span class="p">);</span>

<span class="c1">// 4. 使用捕获的缓冲区</span>
<span class="c1">// ... 对捕获内容进行处理</span>
</code></pre></div></div>

<h3 id="107-高频问题">10.7 高频问题</h3>

<table>
  <thead>
    <tr>
      <th>问题</th>
      <th>答案要点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Writeback 和普通 Plane 的区别？</td>
      <td>Plane 是数据源，Writeback 是数据汇；Plane 输出到屏幕，Writeback 捕获屏幕内容</td>
    </tr>
    <tr>
      <td>Writeback 为什么用 workqueue？</td>
      <td>捕获操作可能耗时，不能在 atomic commit 回调中同步完成</td>
    </tr>
    <tr>
      <td>Capture Port 是什么？</td>
      <td>选择捕获哪个 pipeline 节点：video only / osd only / mixed</td>
    </tr>
    <tr>
      <td>Writeback 和 V4L2 capture 的区别？</td>
      <td>Writeback 是 DRM 框架的一部分，与 DRM atomic commit 集成更好</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="十一syncasyncnonblock-送显模式">十一、Sync/Async/Nonblock 送显模式</h2>

<p>在 DRM 中，根据用户空间的需求和硬件能力，存在三种不同的 commit 模式，适用于不同场景。</p>

<h3 id="111-sync-commit同步送显">11.1 Sync Commit（同步送显）</h3>

<p>同步 commit 是最基础的模式，用户空间的 <code class="language-plaintext highlighter-rouge">drmModeAtomicCommit()</code> 会阻塞直到硬件配置完成。</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:573 - 同步 commit 路径</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">nonblock</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">meson_commit_reenter_inc</span><span class="p">(</span><span class="n">priv</span><span class="p">,</span> <span class="n">crtc_index</span><span class="p">,</span> <span class="n">BLOCK_MODE</span><span class="p">);</span>
    <span class="n">meson_commit_tail</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>  <span class="c1">// 同步等待完成</span>
    <span class="n">meson_commit_reenter_dec</span><span class="p">(</span><span class="n">priv</span><span class="p">,</span> <span class="n">crtc_index</span><span class="p">,</span> <span class="n">BLOCK_MODE</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>特点</strong>：</p>
<ul>
  <li>IOCTL 会在硬件配置完成后才返回</li>
  <li>简单可靠，但可能导致用户空间卡顿</li>
  <li>适用于关键显示场景（如模式切换）</li>
</ul>

<p><strong>阻塞点分析</strong>：</p>

<table>
  <thead>
    <tr>
      <th>阶段</th>
      <th>阻塞原因</th>
      <th>典型耗时</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>modeset_disables</td>
      <td>等待 CRTC 禁用完成</td>
      <td>1-2 帧</td>
    </tr>
    <tr>
      <td>modeset_enables</td>
      <td>等待 CRTC 启用 + 模式设置</td>
      <td>2-3 帧</td>
    </tr>
    <tr>
      <td>commit_planes</td>
      <td>等待 plane 配置完成</td>
      <td>&lt;1 帧</td>
    </tr>
    <tr>
      <td>wait_for_vblank</td>
      <td>等待 VBLANK 中断</td>
      <td>1 帧</td>
    </tr>
  </tbody>
</table>

<p><strong>典型应用场景</strong>：</p>
<ul>
  <li>初始化时的首次显示配置</li>
  <li>分辨率/刷新率切换（模式切换）</li>
  <li>HDMI 热插拔后的恢复</li>
  <li>显示设备唤醒</li>
</ul>

<h3 id="112-nonblock-commit非阻塞送显">11.2 Nonblock Commit（非阻塞送显）</h3>

<p>非阻塞 commit 立即返回，硬件配置通过 kthread 异步完成：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:564 - 非阻塞 commit 入口</span>
<span class="k">if</span> <span class="p">(</span><span class="n">nonblock</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">work_item</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">work_item</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">work</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">commit_work</span><span class="p">;</span>
    <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">crtc_id</span> <span class="o">=</span> <span class="n">crtc_id</span><span class="p">;</span>
    <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">commit_flag</span> <span class="o">=</span> <span class="n">nonblock</span><span class="p">;</span>
    
    <span class="c1">// 初始化 kthread work</span>
    <span class="n">kthread_init_work</span><span class="p">(</span><span class="o">&amp;</span><span class="n">work_item</span><span class="o">-&gt;</span><span class="n">kthread_work</span><span class="p">,</span> <span class="n">meson_commit_work</span><span class="p">);</span>
    
    <span class="c1">// 队列到 per-CRTC worker</span>
    <span class="n">worker</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">priv</span><span class="o">-&gt;</span><span class="n">commit_thread</span><span class="p">[</span><span class="n">crtc_index</span><span class="p">].</span><span class="n">worker</span><span class="p">;</span>
    <span class="n">kthread_queue_work</span><span class="p">(</span><span class="n">worker</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">work_item</span><span class="o">-&gt;</span><span class="n">kthread_work</span><span class="p">);</span>
    
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>  <span class="c1">// 立即返回，不等待完成</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>kthread worker 处理</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:238 - 异步执行</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">meson_commit_work</span><span class="p">(</span><span class="k">struct</span> <span class="n">kthread_work</span> <span class="o">*</span><span class="n">work</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">meson_commit_work_item</span> <span class="o">*</span><span class="n">work_item</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">work</span><span class="p">,</span>
        <span class="k">struct</span> <span class="n">meson_commit_work_item</span><span class="p">,</span> <span class="n">kthread_work</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span> <span class="o">=</span> <span class="n">container_of</span><span class="p">(</span><span class="n">work_item</span><span class="o">-&gt;</span><span class="n">work</span><span class="p">,</span>
        <span class="k">struct</span> <span class="n">drm_atomic_state</span><span class="p">,</span> <span class="n">commit_work</span><span class="p">);</span>
    
    <span class="n">meson_commit_reenter_inc</span><span class="p">(</span><span class="n">priv</span><span class="p">,</span> <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">crtc_id</span><span class="p">,</span> <span class="n">NONBLOCK_MODE</span><span class="p">);</span>
    <span class="n">meson_commit_tail</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>  <span class="c1">// 在 kthread 中执行</span>
    <span class="n">meson_commit_reenter_dec</span><span class="p">(</span><span class="n">priv</span><span class="p">,</span> <span class="n">work_item</span><span class="o">-&gt;</span><span class="n">crtc_id</span><span class="p">,</span> <span class="n">NONBLOCK_MODE</span><span class="p">);</span>
    <span class="n">kfree</span><span class="p">(</span><span class="n">work_item</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>per-CRTC kthread 初始化</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_drv.c:233 - 为每个 CRTC 创建独立线程</span>
<span class="k">static</span> <span class="kt">int</span> <span class="nf">meson_worker_thread_init</span><span class="p">(</span><span class="k">struct</span> <span class="n">meson_drm</span> <span class="o">*</span><span class="n">priv</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">num_crtcs</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">num_crtcs</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">worker</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">drm_thread</span><span class="o">-&gt;</span><span class="n">worker</span><span class="p">;</span>
        <span class="n">kthread_init_worker</span><span class="p">(</span><span class="n">worker</span><span class="p">);</span>
        
        <span class="c1">// 创建高优先级线程 (SCHED_FIFO, priority=16)</span>
        <span class="n">snprintf</span><span class="p">(</span><span class="n">thread_name</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="s">"crtc%d_commit"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
        <span class="n">drm_thread</span><span class="o">-&gt;</span><span class="kr">thread</span> <span class="o">=</span> <span class="n">kthread_run</span><span class="p">(</span><span class="n">kthread_worker_fn</span><span class="p">,</span> <span class="n">worker</span><span class="p">,</span> <span class="n">thread_name</span><span class="p">);</span>
        
        <span class="n">sched_setscheduler</span><span class="p">(</span><span class="n">drm_thread</span><span class="o">-&gt;</span><span class="kr">thread</span><span class="p">,</span> <span class="n">SCHED_FIFO</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">param</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>典型应用场景</strong>：</p>
<ul>
  <li>游戏渲染循环（高帧率需求）</li>
  <li>视频播放（平滑播放）</li>
  <li>UI 动画（桌面动画、窗口拖动）</li>
  <li>多窗口合成</li>
</ul>

<callout emoji="💡" background-color="light-blue">
**关键设计**：每个 CRTC 有独立的 kthread，确保多路输出的并行性，一个 CRTC 阻塞不影响其他。
</callout>

<h3 id="113-async-update异步平面更新">11.3 Async Update（异步平面更新）</h3>

<p>异步更新是最高效的模式，专门针对纯 plane 更新（不涉及模式切换）：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:491 - async update 路径</span>
<span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">async_update</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">priv</span><span class="o">-&gt;</span><span class="n">pan_async_commit_ran</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
    
    <span class="c1">// 准备 plane 资源</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_prepare_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 交换 state</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_helper_swap_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
    
    <span class="c1">// 直接执行 plane 更新，跳过完整 commit</span>
    <span class="n">meson_atomic_helper_async_commit</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="c1">// 清理</span>
    <span class="n">drm_atomic_helper_cleanup_planes</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>触发条件</strong>：</p>
<ul>
  <li>仅修改 plane 属性（位置、缩放、帧缓冲）</li>
  <li>不涉及 CRTC 启用/禁用或模式切换</li>
  <li>DRM 框架自动检测并设置 <code class="language-plaintext highlighter-rouge">state-&gt;async_update = true</code></li>
</ul>

<p><strong>Plane 的 async_update 回调</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_plane.c:1740 - Video plane 异步更新</span>
<span class="kt">void</span> <span class="nf">meson_video_plane_async_update</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_plane</span> <span class="o">*</span><span class="n">plane</span><span class="p">,</span> <span class="k">struct</span> <span class="n">drm_atomic_state</span> <span class="o">*</span><span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">new_state</span> <span class="o">=</span> <span class="n">drm_atomic_get_new_plane_state</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">plane</span><span class="p">);</span>
    
    <span class="c1">// 更新 plane 状态（原地修改）</span>
    <span class="n">plane</span><span class="o">-&gt;</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">fb</span> <span class="o">=</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">fb</span><span class="p">;</span>
    <span class="n">plane</span><span class="o">-&gt;</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">src_x</span> <span class="o">=</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">src_x</span><span class="p">;</span>
    <span class="n">plane</span><span class="o">-&gt;</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">crtc_x</span> <span class="o">=</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">crtc_x</span><span class="p">;</span>
    
    <span class="c1">// 准备 video fence（如果是新帧）</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">meson_video_plane_is_repeat_frame</span><span class="p">(</span><span class="n">plane</span><span class="p">,</span> <span class="n">new_state</span><span class="p">))</span>
        <span class="n">meson_video_prepare_fence</span><span class="p">(</span><span class="n">plane</span><span class="p">,</span> <span class="n">new_state</span><span class="p">,</span> <span class="n">mvv</span><span class="p">);</span>
    
    <span class="c1">// 更新硬件</span>
    <span class="n">vpu_pipeline_video_update</span><span class="p">(</span><span class="n">sub_pipe</span><span class="p">,</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Async Update vs Nonblock 关键差异</strong>：</p>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>Async Update</th>
      <th>Nonblock Commit</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>跳过 stages</td>
      <td>跳过 modeset</td>
      <td>跳过 modeset</td>
    </tr>
    <tr>
      <td>modeset 逻辑</td>
      <td><strong>完全跳过</strong></td>
      <td><strong>完全跳过</strong></td>
    </tr>
    <tr>
      <td>commit 等待</td>
      <td>无等待</td>
      <td>hw_done/flip_done</td>
    </tr>
    <tr>
      <td>适用操作</td>
      <td>Plane 位置/缩放</td>
      <td>Plane 新增/删除</td>
    </tr>
    <tr>
      <td>fence 等待</td>
      <td>无</td>
      <td>可选</td>
    </tr>
  </tbody>
</table>

<p><strong>典型应用场景</strong>：</p>
<ul>
  <li>视频播放中的帧更新</li>
  <li>OSD 菜单显示/隐藏</li>
  <li>窗口缩放/移动（不改变分辨率）</li>
  <li>Cursor 位置更新</li>
</ul>

<h3 id="114-legacy-cursor-update传统光标更新">11.4 Legacy Cursor Update（传统光标更新）</h3>

<p>对于游标更新，DRM 提供了完全异步的路径：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_async_atomic.c:375 - 设置 legacy 标志</span>
<span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">ret</span> <span class="o">=</span> <span class="n">drm_atomic_commit</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
</code></pre></div></div>

<p><strong>特殊处理</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:376 - legacy cursor 特殊处理</span>
<span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">ret</span> <span class="o">=</span> <span class="n">meson_drm_atomic_helper_setup_commit</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">nonblock</span><span class="p">);</span>
    <span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>  <span class="c1">// 强制清除</span>
    <span class="n">DRM_DEBUG_ATOMIC</span><span class="p">(</span><span class="s">"legacy_cursor_update force to false!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>Legacy Cursor 的独特特性</strong>：</p>
<ul>
  <li>不等待之前的 commit 完成</li>
  <li>允许新 cursor commit 覆盖旧 cursor commit</li>
  <li>适用于高频光标移动场景</li>
</ul>

<h3 id="115-三种模式详细对比">11.5 三种模式详细对比</h3>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>Sync Commit</th>
      <th>Nonblock Commit</th>
      <th>Async Update</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>IOCTL 返回时机</strong></td>
      <td>硬件完成</td>
      <td>立即返回</td>
      <td>立即返回</td>
    </tr>
    <tr>
      <td><strong>执行线程</strong></td>
      <td>调用线程</td>
      <td>per-CRTC kthread</td>
      <td>调用线程</td>
    </tr>
    <tr>
      <td><strong>阻塞点</strong></td>
      <td>全部</td>
      <td>无</td>
      <td>无</td>
    </tr>
    <tr>
      <td><strong>适用场景</strong></td>
      <td>模式切换/初始化</td>
      <td>高帧率渲染</td>
      <td>纯 plane 更新</td>
    </tr>
    <tr>
      <td><strong>modeset 支持</strong></td>
      <td>✅ 完整</td>
      <td>✅ 完整</td>
      <td>❌ 跳过</td>
    </tr>
    <tr>
      <td><strong>framebuffer 引用</strong></td>
      <td>旧 FB 等待释放</td>
      <td>旧 FB 可立即释放</td>
      <td>旧 FB 可立即释放</td>
    </tr>
    <tr>
      <td><strong>性能</strong></td>
      <td>低</td>
      <td>中</td>
      <td>高</td>
    </tr>
    <tr>
      <td><strong>帧同步</strong></td>
      <td>强</td>
      <td>中</td>
      <td>弱</td>
    </tr>
    <tr>
      <td><strong>死锁风险</strong></td>
      <td>低</td>
      <td>中</td>
      <td>低</td>
    </tr>
    <tr>
      <td><strong>commit 依赖</strong></td>
      <td>无</td>
      <td>可选等待</td>
      <td>无</td>
    </tr>
  </tbody>
</table>

<p><strong>性能数据对比</strong>：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sync Commit 延迟构成：
├─ prepare_planes:    ~100μs
├─ swap_state:       ~50μs
├─ modeset_disables: ~16ms (1帧 @60Hz)
├─ modeset_enables:  ~33ms (2帧 @60Hz)
└─ wait_for_vblank:  ~16ms (1帧 @60Hz)
总计:                 ~65ms

Nonblock Commit 延迟构成：
├─ prepare_planes:   ~100μs (阻塞)
├─ swap_state:       ~50μs (阻塞)
└─ kthread 队列:     ~1μs (立即返回)
总计:                 ~150μs (返回时间)

Async Update 延迟构成：
├─ prepare_planes:   ~100μs
├─ swap_state:       ~50μs
└─ plane 更新:       ~10μs
总计:                 ~160μs
</code></pre></div></div>

<p><strong>应用场景决策树</strong>：</p>

<pre><code class="language-mermaid">graph TD
    A[需要送显] --&gt; B{涉及模式切换?]
    B --&gt;|是| C[Sync Commit]
    B --&gt;|否| D{涉及 CRTC 启用/禁用?]
    D --&gt;|是| E[Nonblock Commit]
    D --&gt;|否| F{只修改 Plane?]
    F --&gt;|是| G{HDR/色彩变化?]
    G --&gt;|否| H[Async Update]
    G --&gt;|是| E
    F --&gt;|否| E
</code></pre>

<h3 id="116-meson-驱动的-commit-模式选择">11.6 Meson 驱动的 Commit 模式选择</h3>

<p><strong>驱动如何决定使用哪种模式</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// meson_atomic.c:470 - 入口判断</span>
<span class="kt">int</span> <span class="nf">meson_atomic_commit</span><span class="p">(...,</span> <span class="n">bool</span> <span class="n">nonblock</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// 1. 检查是否是 async_update</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">async_update</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 走 Async Update 快速路径</span>
        <span class="k">return</span> <span class="n">handle_async_update</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    <span class="p">}</span>
    
    <span class="c1">// 2. 检查是否是 legacy_cursor_update</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">state</span><span class="o">-&gt;</span><span class="n">legacy_cursor_update</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 走 Legacy Cursor 路径</span>
        <span class="k">return</span> <span class="n">handle_legacy_cursor</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
    <span class="p">}</span>
    
    <span class="c1">// 3. 根据 nonblock 标志选择</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">nonblock</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// 队列到 kthread，异步执行</span>
        <span class="n">kthread_queue_work</span><span class="p">(...);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="c1">// 同步执行</span>
        <span class="n">meson_commit_tail</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>
        <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>用户空间如何指定模式</strong>：</p>

<table>
  <thead>
    <tr>
      <th>IOCTL Flags</th>
      <th>模式</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_NONBLOCK</code></td>
      <td>Nonblock Commit</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">DRM_MODE_ATOMIC_ASYNC</code></td>
      <td>Async Update（框架自动设置）</td>
    </tr>
    <tr>
      <td>无 flags</td>
      <td>Sync Commit</td>
    </tr>
  </tbody>
</table>

<h3 id="117-高频问题">11.7 高频问题</h3>

<table>
  <thead>
    <tr>
      <th>问题</th>
      <th>答案要点</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>nonblock 和 async_update 有什么区别？</td>
      <td>nonblock 是完整的 atomic commit 走异步路径；async_update 只更新 plane，跳过模式设置</td>
    </tr>
    <tr>
      <td>为什么要用 per-CRTC kthread？</td>
      <td>确保多路输出的并行性，一个 CRTC 阻塞不影响其他</td>
    </tr>
    <tr>
      <td>legacy_cursor_update 为什么特殊处理？</td>
      <td>游标更新频率高，DRM 允许完全异步，不需要等待之前的 commit</td>
    </tr>
    <tr>
      <td>commit 超时如何处理？</td>
      <td>检测 flip_done 和 hw_done 超时（100ms），打印错误并返回</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="总结">总结</h2>

<p>DRM 子系统是 Linux 显示驱动的核心框架，涉及内存管理、同步机制、状态管理多个复杂模块。本文通过 Meson 驱动代码分析了：</p>

<ul>
  <li><strong>DMA-buf</strong>：通过 GEM 对象管理内存，支持多种分配策略</li>
  <li><strong>Fence</strong>：Present fence 和 Video fence 实现跨设备同步</li>
  <li><strong>Atomic Commit</strong>：完整的原子更新流程和状态管理</li>
  <li><strong>多路显示</strong>：通过设备树配置实现灵活的多输出支持</li>
</ul>

<p>掌握这些核心机制，对于从事显示驱动开发和都有重要帮助。</p>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DRM" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Linux DRM GPU Scheduler 深度解析：架构、调度策略与未来发展</title><link href="https://yangchao315.github.io/DRM-GPU-Scheduler-Analysis/" rel="alternate" type="text/html" title="Linux DRM GPU Scheduler 深度解析：架构、调度策略与未来发展" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/DRM-GPU-Scheduler-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/DRM-GPU-Scheduler-Analysis/"><![CDATA[<!-- more -->

<ul>
  <li><a href="#一背景与问题">一、背景与问题</a></li>
  <li><a href="#二drm-gpu-scheduler-核心架构">二、DRM GPU Scheduler 核心架构</a>
    <ul>
      <li><a href="#21-核心数据结构">2.1 核心数据结构</a></li>
      <li><a href="#22-schedulerentityrun-queue-关系">2.2 Scheduler、Entity、Run Queue 关系</a></li>
      <li><a href="#23-job-生命周期">2.3 Job 生命周期</a></li>
    </ul>
  </li>
  <li><a href="#三调度策略详解">三、调度策略详解</a>
    <ul>
      <li><a href="#31-fifo-策略">3.1 FIFO 策略</a></li>
      <li><a href="#32-rr-策略">3.2 RR 策略</a></li>
      <li><a href="#33-fairer-调度器--cfs-inspired">3.3 Fair(er) 调度器 - CFS -inspired</a></li>
    </ul>
  </li>
  <li><a href="#四依赖管理与同步机制">四、依赖管理与同步机制</a></li>
  <li><a href="#五超时与错误处理">五、超时与错误处理</a></li>
  <li><a href="#六drm-jobqueue--下一代基础设施">六、DRM Jobqueue - 下一代基础设施</a>
    <ul>
      <li><a href="#61-解决的问题">6.1 解决的问题</a></li>
      <li><a href="#62-架构设计">6.2 架构设计</a></li>
      <li><a href="#63-与-drm-scheduler-的对比">6.3 与 DRM Scheduler 的对比</a></li>
      <li><a href="#64-目标用户">6.4 目标用户</a></li>
      <li><a href="#65-状态与未来">6.5 状态与未来</a></li>
    </ul>
  </li>
  <li><a href="#七总结与展望">七、总结与展望</a></li>
</ul>

<hr />

<h2 id="一背景与问题">一、背景与问题</h2>

<p>现代 Linux 系统中的 GPU 工作负载日益复杂：多个渲染上下文同时提交任务、图形应用与计算任务并发执行、不同优先级的作业需要公平调度。<strong>DRM GPU Scheduler</strong> 正是为解决这些挑战而设计的共享基础设施。</p>

<callout emoji="💡" background-color="light-blue">
DRM GPU Scheduler 是 Linux 内核 DRM 子系统中的共享组件，被 AMD、Intel、NVIDIA、Mesa 等多种 GPU 驱动用于管理作业提交、依赖解析、超时检测和调度算法。
</callout>

<p>传统 FIFO（先入先出）调度存在以下问题：</p>
<ul>
  <li><strong>公平性问题</strong>：长时间运行的作业会阻塞短时交互式任务</li>
  <li><strong>优先级饥饿</strong>：高优先级作业可能因低优先级作业长期占用而延迟</li>
  <li><strong>延迟抖动</strong>：交互式应用的响应时间不可预测</li>
</ul>

<hr />

<h2 id="二drm-gpu-scheduler-核心架构">二、DRM GPU Scheduler 核心架构</h2>

<h3 id="21-核心数据结构">2.1 核心数据结构</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// include/drm/gpu_scheduler.h</span>
<span class="k">enum</span> <span class="n">drm_sched_priority</span> <span class="p">{</span>
    <span class="n">DRM_SCHED_PRIORITY_MIN</span><span class="p">,</span>
    <span class="n">DRM_SCHED_PRIORITY_NORMAL</span><span class="p">,</span>
    <span class="n">DRM_SCHED_PRIORITY_HIGH</span><span class="p">,</span>
    <span class="n">DRM_SCHED_PRIORITY_KERNEL</span><span class="p">,</span>
    <span class="n">DRM_SCHED_PRIORITY_COUNT</span>
<span class="p">};</span>

<span class="cm">/* 调度策略 */</span>
<span class="cp">#define DRM_SCHED_POLICY_RR    0   // Round Robin
#define DRM_SCHED_POLICY_FIFO  1   // First In First Out (default)
</span><span class="k">extern</span> <span class="kt">int</span> <span class="n">drm_sched_policy</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="22-schedulerentityrun-queue-关系">2.2 Scheduler、Entity、Run Queue 关系</h3>

<pre><code class="language-mermaid">graph TB
    subgraph Hardware
        HWQ[Hardware Queue/Ring]
    end
    
    subgraph DRM_Scheduler
        S[drm_gpu_scheduler]
        RQ1[RQ - KERNEL]
        RQ2[RQ - HIGH]
        RQ3[RQ - NORMAL]
        RQ4[RQ - MIN]
    end
    
    subgraph Entities
        E1[Entity 1]
        E2[Entity 2]
        E3[Entity 3]
        E_n[Entity N]
    end
    
    S --&gt; RQ1
    S --&gt; RQ2
    S --&gt; RQ3
    S --&gt; RQ4
    
    RQ1 --&gt; E1
    RQ2 --&gt; E2
    RQ3 --&gt; E3
    E_n --&gt; RQ4
    
    E1 --&gt; HWQ
    E2 --&gt; HWQ
    E3 --&gt; HWQ
</code></pre>

<p><strong>核心概念</strong>：</p>
<ul>
  <li><strong>drm_gpu_scheduler</strong>：每个硬件 Ring 对应一个调度器实例</li>
  <li><strong>drm_sched_rq</strong>：按优先级分类的运行队列</li>
  <li><strong>drm_sched_entity</strong>：作业容器，通常绑定到 DRM 文件句柄</li>
  <li><strong>drm_sched_job</strong>：实际要执行的任务单元</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 调度器结构 - include/drm/gpu_scheduler.h</span>
<span class="k">struct</span> <span class="n">drm_gpu_scheduler</span> <span class="p">{</span>
    <span class="k">const</span> <span class="k">struct</span> <span class="n">drm_sched_backend_ops</span>    <span class="o">*</span><span class="n">ops</span><span class="p">;</span>
    <span class="kt">unsigned</span> <span class="kt">int</span>            <span class="n">hw_submission_limit</span><span class="p">;</span>  <span class="c1">// 硬件队列最大长度</span>
    <span class="n">timeout_t</span>               <span class="n">timeout</span><span class="p">;</span>              <span class="c1">// 作业超时时间</span>
    <span class="k">const</span> <span class="kt">char</span>              <span class="o">*</span><span class="n">name</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_sched_rq</span>     <span class="n">sched_rq</span><span class="p">[</span><span class="n">DRM_SCHED_PRIORITY_COUNT</span><span class="p">];</span>  <span class="c1">// 优先级队列数组</span>
    <span class="k">struct</span> <span class="n">task_struct</span>     <span class="o">*</span><span class="kr">thread</span><span class="p">;</span>               <span class="c1">// 调度线程</span>
    <span class="c1">// ...</span>
<span class="p">};</span>

<span class="c1">// 运行队列</span>
<span class="k">struct</span> <span class="n">drm_sched_rq</span> <span class="p">{</span>
    <span class="n">spinlock_t</span>              <span class="n">lock</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_gpu_scheduler</span> <span class="o">*</span><span class="n">sched</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">list_head</span>        <span class="n">entities</span><span class="p">;</span>              <span class="c1">// 实体链表</span>
    <span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="o">*</span><span class="n">current_entity</span><span class="p">;</span>      <span class="c1">// 当前执行的实体</span>
    <span class="k">struct</span> <span class="n">rb_root_cached</span>   <span class="n">rb_tree_root</span><span class="p">;</span>         <span class="c1">// FIFO 调度的红黑树</span>
<span class="p">};</span>

<span class="c1">// 实体 - 作业容器</span>
<span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">list_head</span>        <span class="n">list</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">drm_sched_rq</span>     <span class="o">*</span><span class="n">rq</span><span class="p">;</span>
    <span class="k">enum</span> <span class="n">drm_sched_priority</span> <span class="n">priority</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="23-job-生命周期">2.3 Job 生命周期</h3>

<pre><code class="language-mermaid">stateDiagram-v2
    [*] --&gt; Created: drm_sched_job_init()
    Created --&gt; Queued: drm_sched_entity_push_job()
    Queued --&gt; Pending: 依赖满足
    Pending --&gt; Running: drm_sched_backend_ops.run_job()
    Running --&gt; Completed: fence signaled
    Running --&gt; Timeout: 超时检测
    Timeout --&gt; Recovery: timedout_job callback
    Completed --&gt; [*]: free_job
    
    note right of Running: 作业在硬件上执行
    note right of Queued: 等待依赖解析
</code></pre>

<hr />

<h2 id="三调度策略详解">三、调度策略详解</h2>

<h3 id="31-fifo-策略">3.1 FIFO 策略</h3>

<p>默认调度策略，按照作业提交时间选择下一个执行实体：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// drivers/gpu/drm/scheduler/sched_main.c</span>
<span class="k">static</span> <span class="n">__always_inline</span> <span class="n">bool</span> <span class="nf">drm_sched_entity_compare_before</span><span class="p">(</span><span class="k">struct</span> <span class="n">rb_node</span> <span class="o">*</span><span class="n">a</span><span class="p">,</span>
                                                            <span class="k">const</span> <span class="k">struct</span> <span class="n">rb_node</span> <span class="o">*</span><span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="o">*</span><span class="n">ent_a</span> <span class="o">=</span> <span class="n">rb_entry</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="k">struct</span> <span class="n">drm_sched_entity</span><span class="p">,</span> <span class="n">rb_tree_node</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="o">*</span><span class="n">ent_b</span> <span class="o">=</span> <span class="n">rb_entry</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="k">struct</span> <span class="n">drm_sched_entity</span><span class="p">,</span> <span class="n">rb_tree_node</span><span class="p">);</span>
    
    <span class="k">return</span> <span class="n">ktime_before</span><span class="p">(</span><span class="n">ent_a</span><span class="o">-&gt;</span><span class="n">oldest_job_waiting</span><span class="p">,</span> <span class="n">ent_b</span><span class="o">-&gt;</span><span class="n">oldest_job_waiting</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>问题</strong>：</p>
<ul>
  <li>长作业阻塞短作业</li>
  <li>交互式应用响应延迟不可预测</li>
  <li>无法区分”紧急”和”普通”作业</li>
</ul>

<h3 id="32-rr-策略">3.2 RR 策略</h3>

<p>轮询策略，时间片轮转：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// drivers/gpu/drm/scheduler/sched_main.c</span>
<span class="n">MODULE_PARM_DESC</span><span class="p">(</span><span class="n">sched_policy</span><span class="p">,</span> 
    <span class="s">"Specify the scheduling policy for entities on a run-queue, "</span>
    <span class="n">__stringify</span><span class="p">(</span><span class="n">DRM_SCHED_POLICY_RR</span><span class="p">)</span> <span class="s">" = Round Robin, "</span>
    <span class="n">__stringify</span><span class="p">(</span><span class="n">DRM_SCHED_POLICY_FIFO</span><span class="p">)</span> <span class="s">" = FIFO (default)."</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="33-fairer-调度器---cfs-inspired">3.3 Fair(er) 调度器 - CFS-inspired</h3>

<p>2025 年 Igalia 团队提出的<strong>Fair(er) Scheduler</strong>，灵感来自 Linux CFS（完全公平调度器）：</p>

<pre><code class="language-mermaid">graph LR
    subgraph Before_Fair
        F1[FIFO Queue]
        F1 --&gt;|长作业阻塞| F2[交互任务延迟高]
    end
    
    subgraph After_Fair
        C1[虚拟 GPU 时间]
        C1 --&gt;|最少时间先执行| C2[公平调度]
        C2 --&gt;|交互任务优先| C3[低延迟]
    end
</code></pre>

<p><strong>核心改进</strong>：</p>
<ol>
  <li><strong>虚拟 GPU 时间</strong>：每个实体记录已消耗的 GPU 时间</li>
  <li><strong>红黑树排序</strong>：按虚拟时间选择下一个执行实体</li>
  <li><strong>交互客户端友好</strong>：略微偏好短作业</li>
</ol>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 新的调度策略 - 基于虚拟时间</span>
<span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="p">{</span>
    <span class="c1">// ...</span>
    <span class="n">u64</span>                     <span class="n">gpu_time</span><span class="p">;</span>         <span class="c1">// 已消耗的 GPU 时间</span>
    <span class="n">u64</span>                     <span class="n">vruntime</span><span class="p">;</span>         <span class="c1">// 虚拟运行时间 (CFS 概念)</span>
    <span class="c1">// ...</span>
<span class="p">};</span>
</code></pre></div></div>

<callout emoji="✅" background-color="light-green">
Fair(er) Scheduler 已于 2025 年从 RFC 阶段毕业，正在推进进入 Linux 主线。
</callout>

<hr />

<h2 id="四依赖管理与同步机制">四、依赖管理与同步机制</h2>

<p>DRM Scheduler 利用 <strong>DMA-fence</strong> 实现作业间依赖：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// include/drm/gpu_scheduler.h</span>
<span class="k">struct</span> <span class="n">drm_sched_backend_ops</span> <span class="p">{</span>
    <span class="cm">/**
     * @prepare_job: 准备作业，检查并等待依赖 fence
     */</span>
    <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">prepare_job</span><span class="p">)(</span><span class="k">struct</span> <span class="n">drm_sched_job</span> <span class="o">*</span><span class="n">sched_job</span><span class="p">,</span>
                                     <span class="k">struct</span> <span class="n">drm_sched_entity</span> <span class="o">*</span><span class="n">s_entity</span><span class="p">);</span>
                                     
    <span class="cm">/**
     * @run_job: 依赖满足后，实际提交到硬件
     */</span>
    <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="p">(</span><span class="o">*</span><span class="n">run_job</span><span class="p">)(</span><span class="k">struct</span> <span class="n">drm_sched_job</span> <span class="o">*</span><span class="n">sched_job</span><span class="p">);</span>
<span class="p">};</span>

<span class="c1">// Scheduler fence 结构</span>
<span class="k">struct</span> <span class="n">drm_sched_fence</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">dma_fence</span>        <span class="n">scheduled</span><span class="p">;</span>   <span class="c1">// 作业调度时信号</span>
    <span class="k">struct</span> <span class="n">dma_fence</span>        <span class="n">finished</span><span class="p">;</span>    <span class="c1">// 作业完成时信号</span>
    <span class="k">struct</span> <span class="n">dma_fence</span>       <span class="o">*</span><span class="n">parent</span><span class="p">;</span>      <span class="c1">// 硬件 fence</span>
    <span class="k">struct</span> <span class="n">drm_gpu_scheduler</span> <span class="o">*</span><span class="n">sched</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>依赖流程</strong>：</p>

<pre><code class="language-mermaid">sequenceDiagram
    participant User as 用户空间
    participant Driver as DRM Driver
    participant Scheduler as DRM Scheduler
    participant GPU as GPU Hardware
    
    User-&gt;&gt;Driver: ioctl(提交作业)
    Driver-&gt;&gt;Driver: drm_sched_job_init()
    Driver-&gt;&gt;Scheduler: drm_sched_entity_push_job()
    Scheduler-&gt;&gt;Scheduler: prepare_job() 等待依赖
    Scheduler-&gt;&gt;Scheduler: run_job() 提交硬件
    Scheduler-&gt;&gt;GPU: 创建 fence
    GPU--&gt;&gt;Scheduler: fence signal
    Scheduler--&gt;&gt;User: 返回完成 fence
</code></pre>

<hr />

<h2 id="五超时与错误处理">五、超时与错误处理</h2>

<p>当作业执行超时（GPU hang）时，调度器触发恢复流程：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// include/drm/gpu_scheduler.h</span>
<span class="k">enum</span> <span class="nf">drm_gpu_sched_stat</span> <span class="p">(</span><span class="o">*</span><span class="n">timedout_job</span><span class="p">)(</span><span class="k">struct</span> <span class="n">drm_sched_job</span> <span class="o">*</span><span class="n">sched_job</span><span class="p">);</span>

<span class="cm">/* 返回状态 */</span>
<span class="k">enum</span> <span class="n">drm_gpu_sched_stat</span> <span class="p">{</span>
    <span class="n">DRM_GPU_SCHED_STAT_NOMINAL</span><span class="p">,</span>   <span class="c1">// 正常</span>
    <span class="n">DRM_GPU_SCHED_STAT_ENODEV</span><span class="p">,</span>    <span class="c1">// 设备不可用</span>
    <span class="n">DRM_GPU_SCHED_STAT_RESET</span><span class="p">,</span>     <span class="c1">// 已开始恢复</span>
    <span class="n">DRM_GPU_SCHED_STAT_NO_HANG</span>    <span class="c1">// GPU 未挂起，跳过重置</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>超时处理流程</strong>（2025 年新改进）：</p>

<ol>
  <li>超时定时器触发 <code class="language-plaintext highlighter-rouge">drm_sched_job_timedout()</code></li>
  <li>调用驱动的 <code class="language-plaintext highlighter-rouge">timedout_job()</code> 回调</li>
  <li>驱动执行 GPU reset 或返回 <code class="language-plaintext highlighter-rouge">DRM_GPU_SCHED_STAT_NO_HANG</code></li>
  <li>恢复后重新提交作业</li>
</ol>

<callout emoji="⚠️" background-color="light-yellow">
2025 年新增的 `DRM_GPU_SCHED_STAT_NO_HANG` 状态允许驱动跳过不必要的 GPU reset，优化了某些工作负载下的恢复效率。
</callout>

<hr />

<h2 id="六drm-jobqueue---下一代基础设施">六、DRM Jobqueue - 下一代基础设施</h2>

<p>对于固件负责调度的现代 GPU（如某些 AMD/NVIDIA 驱动），DRM Scheduler 显得过于复杂。<strong>DRM Jobqueue</strong> 应运而生，旨在成为固件调度 GPU 的轻量级负载均衡器、依赖管理器和超时处理器。</p>

<h3 id="61-解决的问题">6.1 解决的问题</h3>

<p>当前 DRM Scheduler 存在的历史负担：</p>

<pre><code class="language-mermaid">graph LR
    subgraph Problems
        P1[Entity/Scheduler 所有权转移复杂]
        P2[spsc_queue 单生产者限制未文档化]
        P3[Run Queue 锁定不清晰]
        P4[内存生命周期管理混乱]
    end
</code></pre>

<ul>
  <li><strong>所有权转移复杂</strong>：Job 从 Entity 转移到 Scheduler，Ownership 语义不清晰</li>
  <li><strong>竞态条件</strong>：<code class="language-plaintext highlighter-rouge">drm_sched_entity_push_job()</code> 不能并行调用同一 Entity</li>
  <li><strong>内存泄漏</strong>：Teardown 时 pending_list 可能非空导致 <code class="language-plaintext highlighter-rouge">free_job()</code> 永不调用</li>
</ul>

<h3 id="62-架构设计">6.2 架构设计</h3>

<pre><code class="language-mermaid">graph TB
    subgraph Userspace
        U[Application]
    end
    
    subgraph Jobqueue_API
        JQ[jq_submit_job]
        JD[jq_add_dependency]
    end
    
    subgraph Job_Ownership
        JO1[用户空间]
        JO2[Jobqueue]
        JO3[Driver]
    end
    
    U --&gt; JQ
    JQ --&gt; JO1
    JO1 --&gt;|提交时转移| JO2
    JO2 --&gt;|执行时转移| JO3
</code></pre>

<p><strong>核心 API 设计</strong>：</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// rust/kernel/drm/jq.rs - 简洁的 API</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">jq_submit_job</span><span class="p">(</span><span class="n">job</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Job</span><span class="p">,</span> <span class="n">dependencies</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="n">DmaFence</span><span class="p">])</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="p">()</span><span class="o">&gt;</span>

<span class="c1">// 作业所有权转移：</span>
<span class="c1">// 1. 用户空间 -&gt; Jobqueue (jq_submit_job)</span>
<span class="c1">// 2. Jobqueue -&gt; Driver (执行时)</span>
</code></pre></div></div>

<h3 id="63-与-drm-scheduler-的对比">6.3 与 DRM Scheduler 的对比</h3>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>DRM Scheduler</th>
      <th>DRM Jobqueue</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>架构复杂度</strong></td>
      <td>高（Entity/RunQueue/Scheduler 多层）</td>
      <td>极简（单一 Queue）</td>
    </tr>
    <tr>
      <td><strong>调度功能</strong></td>
      <td>完整调度 + 负载均衡</td>
      <td>仅负载均衡</td>
    </tr>
    <tr>
      <td><strong>所有权模型</strong></td>
      <td>Job 在多组件间流转</td>
      <td>线性转移（用户→队列→驱动）</td>
    </tr>
    <tr>
      <td><strong>实现语言</strong></td>
      <td>C</td>
      <td>Rust（与新驱动集成）</td>
    </tr>
    <tr>
      <td><strong>适用场景</strong></td>
      <td>内核调度 GPU</td>
      <td>固件调度 GPU</td>
    </tr>
  </tbody>
</table>

<h3 id="64-目标用户">6.4 目标用户</h3>

<ol>
  <li><strong>NVIDIA Nova 驱动</strong>：新一代开源驱动，使用固件调度</li>
  <li><strong>AMD GPU（部分）</strong>：某些型号固件负责作业排序</li>
  <li><strong>未来 Rust 驱动</strong>：新驱动多采用 Rust 实现</li>
</ol>

<h3 id="65-状态与未来">6.5 状态与未来</h3>

<callout emoji="🔧" background-color="light-blue">
Jobqueue 仍处于开发阶段，2025 年 11 月 XDC 大会上展示了初始 Rust 原型。
</callout>

<ul>
  <li><strong>当前状态</strong>：RFC/WIP 阶段，Rust 骨架代码已提交</li>
  <li><strong>设计目标</strong>：提供 C 兼容接口，兼容现有 C 驱动</li>
  <li><strong>长期愿景</strong>：统一 DRM 作业提交接口，保留 Scheduler 给需要它的驱动</li>
</ul>

<hr />

<h2 id="七总结与展望">七、总结与展望</h2>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>FIFO</th>
      <th>RR</th>
      <th>Fair(er)</th>
      <th>Jobqueue</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>调度算法</td>
      <td>提交时间</td>
      <td>时间片轮转</td>
      <td>虚拟 GPU 时间</td>
      <td>负载均衡</td>
    </tr>
    <tr>
      <td>公平性</td>
      <td>低</td>
      <td>中</td>
      <td>高</td>
      <td>N/A</td>
    </tr>
    <tr>
      <td>适用场景</td>
      <td>简单</td>
      <td>有限</td>
      <td>图形+计算混合</td>
      <td>固件调度 GPU</td>
    </tr>
    <tr>
      <td>实现语言</td>
      <td>C</td>
      <td>C</td>
      <td>C</td>
      <td>Rust</td>
    </tr>
    <tr>
      <td>主线状态</td>
      <td>已支持</td>
      <td>已支持</td>
      <td>推进中</td>
      <td>RFC/WIP</td>
    </tr>
    <tr>
      <td>所有权模型</td>
      <td>Entity→Scheduler 多层</td>
      <td>同上</td>
      <td>同上</td>
      <td>线性转移</td>
    </tr>
  </tbody>
</table>

<p>DRM GPU Scheduler 经历了从简单 FIFO 到智能调度的演进，Fair(er) Scheduler 的加入将显著提升交互式应用的体验，而 Jobqueue 则为未来架构铺平道路。</p>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DRM" /><category term="GPU" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">DisplayPort协议详解</title><link href="https://yangchao315.github.io/DisplayPort-Protocol-Analysis/" rel="alternate" type="text/html" title="DisplayPort协议详解" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/DisplayPort-Protocol-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/DisplayPort-Protocol-Analysis/"><![CDATA[<!-- more -->
<ul>
  <li><a href="#displayport协议详解">DisplayPort协议详解</a>
    <ul>
      <li><a href="#1-displayport概述">1. DisplayPort概述</a>
        <ul>
          <li><a href="#11-dp版本演进">1.1 DP版本演进</a></li>
          <li><a href="#12-dp接口特性">1.2 DP接口特性</a></li>
        </ul>
      </li>
      <li><a href="#2-dp协议分层">2. DP协议分层</a>
        <ul>
          <li><a href="#21-物理层phy">2.1 物理层(PHY)</a></li>
          <li><a href="#22-数据链路层mpcp">2.2 数据链路层(MPCP)</a></li>
          <li><a href="#23-传输层as">2.3 传输层(AS)</a></li>
          <li><a href="#24-应用层">2.4 应用层</a></li>
        </ul>
      </li>
      <li><a href="#3-link-training过程">3. Link Training过程</a>
        <ul>
          <li><a href="#31-training准备阶段">3.1 Training准备阶段</a></li>
          <li><a href="#32-通道偏斜校正channel-eq">3.2 通道偏斜校正(Channel EQ)</a></li>
          <li><a href="#33-cr阶段channel-equalization">3.3 CR阶段(Channel Equalization)</a></li>
          <li><a href="#34-eq阶段emphasis">3.4 EQ阶段(Emphasis)</a></li>
          <li><a href="#35-完整link-training流程">3.5 完整Link Training流程</a></li>
        </ul>
      </li>
      <li><a href="#4-aux-ch通信">4. AUX CH通信</a></li>
      <li><a href="#5-rk3588-dp控制器">5. RK3588 DP控制器</a></li>
    </ul>
  </li>
</ul>

<h1 id="displayport协议详解">DisplayPort协议详解</h1>

<h2 id="1-displayport概述">1. DisplayPort概述</h2>

<p>DisplayPort(简称DP)是由视频电子标准协会(VESA)制定的数字显示接口标准，主要用于连接电脑和显示器，也可用于连接电视、投影仪等设备。</p>

<h3 id="11-dp版本演进">1.1 DP版本演进</h3>

<table>
  <thead>
    <tr>
      <th>版本</th>
      <th>最大带宽</th>
      <th>最大分辨率@刷新率</th>
      <th>主要特性</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>DP 1.0</td>
      <td>8.64 Gbps</td>
      <td>2560×1600@60Hz</td>
      <td>初始版本</td>
    </tr>
    <tr>
      <td>DP 1.2</td>
      <td>17.28 Gbps</td>
      <td>3840×2160@60Hz</td>
      <td>多流传输(MST)</td>
    </tr>
    <tr>
      <td>DP 1.3</td>
      <td>25.92 Gbps</td>
      <td>5120×2880@60Hz</td>
      <td>DSC压缩</td>
    </tr>
    <tr>
      <td>DP 1.4</td>
      <td>32.4 Gbps</td>
      <td>7680×4320@60Hz</td>
      <td>HDR、DP IN</td>
    </tr>
    <tr>
      <td>DP 2.0</td>
      <td>80 Gbps</td>
      <td>7680×4320@60Hz</td>
      <td>128b/132b编码</td>
    </tr>
  </tbody>
</table>

<h3 id="12-dp接口特性">1.2 DP接口特性</h3>

<ul>
  <li><strong>主链路(Main Link)</strong>: 1/2/4条Lane，支持1.62/2.7/5.4/8.1/10 Gbps速率</li>
  <li><strong>AUX通道(AUX CH)</strong>: 1 Mbps差分双向通信，用于配置和EDID读取</li>
  <li><strong>热插拔检测(HPD)</strong>: Sink发出中断信号通知Source</li>
</ul>

<h2 id="2-dp协议分层">2. DP协议分层</h2>

<pre><code class="language-mermaid">graph TB
    subgraph 应用层
        A[视频音频数据]
    end
    subgraph 传输层AS
        B[微封包组装]
    end
    subgraph 数据链路层MPCP
        C[多路复用]
        D[8b/10b编码]
    end
    subgraph 物理层
        E[串行器]
        F[均衡器]
    end
    A --&gt; B --&gt; C --&gt; D --&gt; E --&gt; F
</code></pre>

<h3 id="21-物理层phy">2.1 物理层(PHY)</h3>

<p>物理层负责高速串行数据的发送和接收，包括：</p>

<ul>
  <li><strong>串行器/解串器</strong>: 并行/串行转换</li>
  <li><strong>发送端预加重(Pre-emphasis)</strong>: 补偿信道损耗</li>
  <li><strong>接收端均衡(EQ)</strong>: 恢复信号完整性</li>
  <li><strong>时钟恢复(CDR)</strong>: 从数据流中提取时钟</li>
</ul>

<h3 id="22-数据链路层mpcp">2.2 数据链路层(MPCP)</h3>

<p>MPCP(MAC/PHY Control Protocol)实现：</p>

<ul>
  <li><strong>8b/10b编码</strong>: 直流平衡、确保跳变密度</li>
  <li><strong>通道分配</strong>: 多Lane时的数据分发</li>
  <li><strong>时钟同步</strong>: 嵌入时钟恢复</li>
  <li><strong>BCH纠错</strong>: 检测和纠正传输错误</li>
</ul>

<h3 id="23-传输层as">2.3 传输层(AS)</h3>

<p>AS(Assembly Sub-layer)负责：</p>

<ul>
  <li><strong>数据分帧</strong>: 定义SA、DA、SPD等字段</li>
  <li><strong>视频数据封装</strong>: CEA-861格式</li>
  <li><strong>音频数据封装</strong>: IEC 60958格式</li>
</ul>

<h3 id="24-应用层">2.4 应用层</h3>

<ul>
  <li><strong>视频格式</strong>: 支持CEA-861/VESA格式</li>
  <li><strong>色彩空间</strong>: RGB、YCbCr444/422/420</li>
  <li><strong>位深</strong>: 6/8/10/12/16 bit</li>
  <li><strong>音频</strong>: LPCM、Dolby、DTS等</li>
</ul>

<h2 id="3-link-training过程">3. Link Training过程</h2>

<p>Link Training是DP Source和Sink建立高速链路的关键过程，通过AUX CH交换配置参数，确保信号可靠传输。</p>

<h3 id="31-training准备阶段">3.1 Training准备阶段</h3>

<p>Source首先读取Sink的EDID获取支持能力：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DPCD Register 0x000: Max LINK_RATE
DPCD Register 0x001: Max LANE_COUNT
DPCD Register 0x002: Supported power levels
</code></pre></div></div>

<p>Source设置link rate和lane count后，进入Training状态：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 设置Link配置</span>
<span class="n">DPCD</span> <span class="mh">0x100</span> <span class="o">=</span> <span class="n">link_rate</span><span class="p">;</span>      <span class="c1">// 0x06=1.62G, 0x0A=2.7G, 0x14=5.4G, 0x1E=8.1G</span>
<span class="n">DPCD</span> <span class="mh">0x101</span> <span class="o">=</span> <span class="n">lane_count</span><span class="p">;</span>     <span class="c1">// 1/2/4 lanes</span>
<span class="n">DPCD</span> <span class="mh">0x102</span> <span class="o">|=</span> <span class="mh">0x01</span><span class="p">;</span>          <span class="c1">// 设置Link Training开始</span>
</code></pre></div></div>

<h3 id="32-通道偏斜校正channel-eq">3.2 通道偏斜校正(Channel EQ)</h3>

<p>训练信号Pattern为D10.2(高频时钟序列)，用于：</p>

<ol>
  <li><strong>信号完整性检测</strong>: 验证链路可传输高速数据</li>
  <li><strong>电压幅度测量</strong>: 确定最优驱动强度</li>
  <li><strong>通道偏斜检测</strong>: 测量各Lane延迟差异</li>
</ol>

<h3 id="33-cr阶段channel-equalization">3.3 CR阶段(Channel Equalization)</h3>

<p>CR阶段调整均衡器参数：</p>

<table>
  <thead>
    <tr>
      <th>参数</th>
      <th>寄存器</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Voltage Swing</td>
      <td>DPCD 0x103-0x106</td>
      <td>信号幅度(0-3级)</td>
    </tr>
    <tr>
      <td>Pre-emphasis</td>
      <td>DPCD 0x107-0x10A</td>
      <td>预加重电平(0-3级)</td>
    </tr>
  </tbody>
</table>

<p>均衡器设置组合：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Swing/Pre-emphasis组合</span>
<span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">},</span>
<span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">},</span> <span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span>
<span class="p">{</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">}</span>
</code></pre></div></div>

<h3 id="34-eq阶段emphasis">3.4 EQ阶段(Emphasis)</h3>

<p>EQ阶段使用PRBS7/CR-Pattern验证：</p>

<ul>
  <li><strong>眼图质量</strong>: 判断信号眼图开度</li>
  <li><strong>误码率</strong>: BER &lt; 10^-9</li>
  <li><strong>FFE设置</strong>: 决定最终均衡参数</li>
</ul>

<h3 id="35-完整link-training流程">3.5 完整Link Training流程</h3>

<pre><code class="language-mermaid">sequenceDiagram
    participant Source
    participant Sink
    participant AUX

    Source-&gt;&gt;Sink: 读取EDID/DPCD能力
    Source-&gt;&gt;Sink: 设置LANE_COUNT, LINK_RATE
    Source-&gt;&gt;Sink: 发送D10.2 Pattern
    
    loop CR Phase
        Source-&gt;&gt;Sink: 调整Swing/Pre-emphasis
        Sink--&gt;&gt;Source: 报告Lock状态
    end
    
    loop EQ Phase
        Source-&gt;&gt;Sink: 发送CR Pattern
        Sink--&gt;&gt;Source: 报告EQ状态
    end
    
    Source-&gt;&gt;Sink: 开始视频传输
</code></pre>

<p>关键寄存器状态检查：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// CR阶段状态</span>
<span class="n">DPCD</span> <span class="mh">0x202</span><span class="o">:</span> <span class="n">LANE0_1_STATUS</span>
<span class="c1">// bit[1] = lane1_symbol_locked</span>
<span class="c1">// bit[0] = lane0_symbol_locked</span>

<span class="c1">// EQ阶段状态  </span>
<span class="n">DPCD</span> <span class="mh">0x204</span><span class="o">:</span> <span class="n">LANE0_1_2_3_5_EQUALIZER</span>
<span class="c1">// bit[3] = lane3_eq_done</span>
<span class="c1">// bit[2] = lane2_eq_done</span>
<span class="c1">// bit[1] = lane1_eq_done</span>
<span class="c1">// bit[0] = lane0_eq_done</span>
</code></pre></div></div>

<h2 id="4-aux-ch通信">4. AUX CH通信</h2>

<p>AUX CH是DP的带外配置通道，支持：</p>

<ul>
  <li><strong>地址空间</strong>: 16-bit地址，寻址能力寄存器、EDID、HPD</li>
  <li><strong>传输速率</strong>: 1 Mbps</li>
  <li><strong>协议格式</strong>: I2C-like，带握手和重试</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// AUX CH读写示例</span>
<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
    <span class="n">AUX_CMD_WRITE</span>  <span class="o">=</span> <span class="mh">0x8</span><span class="p">,</span>  <span class="c1">// Native Write</span>
    <span class="n">AUX_CMD_READ</span>   <span class="o">=</span> <span class="mh">0x9</span><span class="p">,</span>  <span class="c1">// Native Read</span>
    <span class="n">AUX_CMD_I2C_WR</span> <span class="o">=</span> <span class="mh">0x0</span><span class="p">,</span>  <span class="c1">// I2C Write</span>
    <span class="n">AUX_CMD_I2C_RD</span> <span class="o">=</span> <span class="mh">0x1</span><span class="p">,</span>  <span class="c1">// I2C Read</span>
<span class="p">}</span> <span class="n">aux_cmd_t</span><span class="p">;</span>
</code></pre></div></div>

<p>常用DPCD地址：</p>

<table>
  <thead>
    <tr>
      <th>地址</th>
      <th>功能</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0x000-0x00F</td>
      <td>能力寄存器</td>
      <td>版本、速率、lane数</td>
    </tr>
    <tr>
      <td>0x100-0x1FF</td>
      <td>Link配置</td>
      <td>训练参数</td>
    </tr>
    <tr>
      <td>0x200-0x2FF</td>
      <td>Link状态</td>
      <td>训练结果</td>
    </tr>
    <tr>
      <td>0x600-0x6FF</td>
      <td>HDCP</td>
      <td>内容保护</td>
    </tr>
  </tbody>
</table>

<h2 id="5-rk3588-dp控制器">5. RK3588 DP控制器</h2>

<p>RK3588集成Synopsys DesignWare DP TX控制器：</p>

<ul>
  <li><strong>DP版本</strong>: DP 1.4a</li>
  <li><strong>最大带宽</strong>: 32.4 Gbps (4 Lane × 8.1 Gbps)</li>
  <li><strong>分辨率</strong>: 最高8K@60Hz (需DSC)</li>
  <li><strong>视频格式</strong>: RGB/YUV444/YUV422/YUV420</li>
</ul>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// RK3588 DP主要寄存器</span>
<span class="k">struct</span> <span class="n">rockchip_dp</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">reg_base</span> <span class="o">*</span><span class="n">regs</span><span class="p">;</span>          <span class="c1">// 基址</span>
    <span class="k">struct</span> <span class="n">clk</span> <span class="o">*</span><span class="n">pclk</span><span class="p">;</span>                <span class="c1">// APB时钟</span>
    <span class="k">struct</span> <span class="n">clk</span> <span class="o">*</span><span class="n">grf_clk</span><span class="p">;</span>            <span class="c1">// GRF时钟</span>
    <span class="k">struct</span> <span class="n">reset</span> <span class="o">*</span><span class="n">rst</span><span class="p">;</span>              <span class="c1">//复位</span>
    <span class="k">struct</span> <span class="n">phy</span> <span class="o">*</span><span class="n">phy</span><span class="p">;</span>                 <span class="c1">// SerDes PHY</span>
    <span class="k">enum</span> <span class="n">dp_pixel_encoding</span> <span class="n">encoding</span><span class="p">;</span> <span class="c1">// 像素编码格式</span>
    <span class="kt">int</span> <span class="n">lane_count</span><span class="p">;</span>                  <span class="c1">// Lane数量</span>
    <span class="kt">int</span> <span class="n">link_rate</span><span class="p">;</span>                   <span class="c1">// 链路速率</span>
<span class="p">};</span>
</code></pre></div></div>

<p>RK3588 DP软件架构：</p>

<pre><code class="language-mermaid">graph LR
    subgraph DRM Framework
        DRM[DRM Driver]
    end
    subgraph Rockchip Driver
        DP[DP Controller Driver]
        PHY[DP PHY Driver]
    end
    subgraph Hardware
        CTRL[DP Controller]
        SERDES[SerDes PHY]
    end
    DRM --&gt; DP --&gt; PHY --&gt; CTRL --&gt; SERDES
</code></pre>

<hr />
<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DisplayPort" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">HDMI 2.1 FRL协议详解</title><link href="https://yangchao315.github.io/HDMI-21-FRL-Protocol-Analysis/" rel="alternate" type="text/html" title="HDMI 2.1 FRL协议详解" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/HDMI-21-FRL-Protocol-Analysis</id><content type="html" xml:base="https://yangchao315.github.io/HDMI-21-FRL-Protocol-Analysis/"><![CDATA[<!-- more -->
<ul>
  <li><a href="#hdmi-21-frl协议详解">HDMI 2.1 FRL协议详解</a>
    <ul>
      <li><a href="#1-frl概述">1. FRL概述</a>
        <ul>
          <li><a href="#11-为什么需要frl">1.1 为什么需要FRL</a></li>
          <li><a href="#12-frl速率等级">1.2 FRL速率等级</a></li>
        </ul>
      </li>
      <li><a href="#2-edid能力发现">2. EDID能力发现</a>
        <ul>
          <li><a href="#21-hf-vsdb字段">2.1 HF-VSDB字段</a></li>
        </ul>
      </li>
      <li><a href="#3-scdc寄存器配置">3. SCDC寄存器配置</a>
        <ul>
          <li><a href="#31-scdc地址空间">3.1 SCDC地址空间</a></li>
          <li><a href="#32-frl_rate配置">3.2 FRL_RATE配置</a></li>
          <li><a href="#33-状态标志寄存器">3.3 状态标志寄存器</a></li>
        </ul>
      </li>
      <li><a href="#4-link-training状态机">4. Link Training状态机</a>
        <ul>
          <li><a href="#41-lts状态说明">4.1 LTS状态说明</a></li>
          <li><a href="#42-完整训练流程">4.2 完整训练流程</a></li>
        </ul>
      </li>
      <li><a href="#5-ltp训练序列">5. LTP训练序列</a></li>
      <li><a href="#6-tmds传输周期">6. TMDS传输周期</a>
        <ul>
          <li><a href="#61-三种传输周期">6.1 三种传输周期</a></li>
          <li><a href="#62-control-period">6.2 Control Period</a></li>
          <li><a href="#63-video-data-period">6.3 Video Data Period</a></li>
          <li><a href="#64-data-island-period">6.4 Data Island Period</a></li>
          <li><a href="#65-周期时序关系">6.5 周期时序关系</a></li>
        </ul>
      </li>
      <li><a href="#7-hdmi-vs-dp对比">7. HDMI vs DP对比</a></li>
      <li><a href="#8-packet传输机制详解">8. Packet传输机制详解</a>
        <ul>
          <li><a href="#81-tmds-vs-frl-packet传输差异">8.1 TMDS vs FRL Packet传输差异</a></li>
          <li><a href="#82-tmds-packet类型">8.2 TMDS Packet类型</a></li>
          <li><a href="#83-infoframe发送流程">8.3 InfoFrame发送流程</a></li>
          <li><a href="#84-frl-super-block结构">8.4 FRL Super Block结构</a></li>
          <li><a href="#85-ltp训练序列详解">8.5 LTP训练序列详解</a></li>
          <li><a href="#86-ffe-feed-forward-equalizer-控制">8.6 FFE (Feed-Forward Equalizer) 控制</a></li>
        </ul>
      </li>
      <li><a href="#9-问答精选">9. 问答精选</a>
        <ul>
          <li><a href="#q1-hdmi-21为什么需要frl而不是继续使用tmds">Q1: HDMI 2.1为什么需要FRL而不是继续使用TMDS?</a></li>
          <li><a href="#q2-hdmi-frl训练失败后如何处理">Q2: HDMI FRL训练失败后如何处理?</a></li>
          <li><a href="#q3-hdmi和dp的主要区别是什么">Q3: HDMI和DP的主要区别是什么？</a></li>
          <li><a href="#q4-hdmi的data-island-period和video-data-period有什么区别">Q4: HDMI的Data Island Period和Video Data Period有什么区别？</a></li>
          <li><a href="#q5-frl-link-training过程中sink如何请求特定的ltp">Q5: FRL Link Training过程中，Sink如何请求特定的LTP？</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h1 id="hdmi-21-frl协议详解">HDMI 2.1 FRL协议详解</h1>

<h2 id="1-frl概述">1. FRL概述</h2>

<p>FRL(Fixed Rate Link)是HDMI 2.1引入的高速传输模式，用于替代传统的TMDS(Transition-Minimized Differential Signaling)模式，支持最高48Gbps带宽。</p>

<h3 id="11-为什么需要frl">1.1 为什么需要FRL</h3>

<table>
  <thead>
    <tr>
      <th>对比项</th>
      <th>TMDS (HDMI 2.0)</th>
      <th>FRL (HDMI 2.1)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>最大带宽</td>
      <td>18 Gbps</td>
      <td>48 Gbps</td>
    </tr>
    <tr>
      <td>编码方式</td>
      <td>8b/10b</td>
      <td>16b/18b</td>
    </tr>
    <tr>
      <td>最大分辨率</td>
      <td>4K@60Hz</td>
      <td>8K@120Hz, 10K</td>
    </tr>
    <tr>
      <td>时钟嵌入</td>
      <td>独立时钟</td>
      <td>内嵌于数据流</td>
    </tr>
    <tr>
      <td>训练机制</td>
      <td>无</td>
      <td>Link Training</td>
    </tr>
  </tbody>
</table>

<h3 id="12-frl速率等级">1.2 FRL速率等级</h3>

<p>HDMI 2.1定义了6种FRL速率：</p>

<table>
  <thead>
    <tr>
      <th>FRL等级</th>
      <th>Lane数</th>
      <th>每Lane速率</th>
      <th>总带宽</th>
      <th>典型应用</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>FRL1</td>
      <td>3</td>
      <td>3 Gbps</td>
      <td>9 Gbps</td>
      <td>4K@30Hz</td>
    </tr>
    <tr>
      <td>FRL2</td>
      <td>3</td>
      <td>6 Gbps</td>
      <td>18 Gbps</td>
      <td>4K@60Hz</td>
    </tr>
    <tr>
      <td>FRL3</td>
      <td>4</td>
      <td>6 Gbps</td>
      <td>24 Gbps</td>
      <td>4K@120Hz</td>
    </tr>
    <tr>
      <td>FRL4</td>
      <td>4</td>
      <td>8 Gbps</td>
      <td>32 Gbps</td>
      <td>8K@30Hz</td>
    </tr>
    <tr>
      <td>FRL5</td>
      <td>4</td>
      <td>10 Gbps</td>
      <td>40 Gbps</td>
      <td>8K@60Hz</td>
    </tr>
    <tr>
      <td>FRL6</td>
      <td>4</td>
      <td>12 Gbps</td>
      <td>48 Gbps</td>
      <td>8K@120Hz, 10K</td>
    </tr>
  </tbody>
</table>

<blockquote>
  <p>注：FRL1/FRL2向后兼容TMDS模式</p>
</blockquote>

<h2 id="2-edid能力发现">2. EDID能力发现</h2>

<h3 id="21-hf-vsdb字段">2.1 HF-VSDB字段</h3>

<p>Source首先通过DDC(I2C地址0xA0/0xA1)读取Sink的EDID，解析HF-VSDB(HDMI Forum Vendor-Specific Data Block)字段：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>EDID Extension Block → CEA-861 Extension → HF-VSDB

关键字段：
├── FRL_Max_Rate     // 最大支持FRL速率 (1-6)
├── FRL_Max_Lanes    // 最大Lane数 (3或4)
├── SCDC_Present     // 必须为1才支持FRL
└── ...              // 其他能力字段
</code></pre></div></div>

<p>Sink支持FRL的判断条件：</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">FRL_Max_Rate</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">&amp;&amp;</span> <span class="n">SCDC_Present</span> <span class="o">==</span> <span class="mi">1</span> <span class="o">&amp;&amp;</span> <span class="n">Sink_Version</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Sink支持FRL模式</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="3-scdc寄存器配置">3. SCDC寄存器配置</h2>

<h3 id="31-scdc地址空间">3.1 SCDC地址空间</h3>

<p>SCDC(Status and Control Data Channel)是HDMI 2.1的配置接口，通过DDC访问(地址0xA8/0xA9)：</p>

<table>
  <thead>
    <tr>
      <th>地址范围</th>
      <th>功能</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0x00-0x0F</td>
      <td>版本信息</td>
      <td>SCDC版本、源版本</td>
    </tr>
    <tr>
      <td>0x10-0x1F</td>
      <td>更新标志</td>
      <td>配置变更通知</td>
    </tr>
    <tr>
      <td>0x20-0x2F</td>
      <td>配置寄存器</td>
      <td>TMDS/FRL模式配置</td>
    </tr>
    <tr>
      <td>0x30-0x3F</td>
      <td>FRL配置</td>
      <td>FRL速率、训练参数</td>
    </tr>
    <tr>
      <td>0x40-0x4F</td>
      <td>状态标志</td>
      <td>链路锁定状态</td>
    </tr>
    <tr>
      <td>0x50-0xFF</td>
      <td>扩展功能</td>
      <td>CED(误码统计)等</td>
    </tr>
  </tbody>
</table>

<h3 id="32-frl_rate配置">3.2 FRL_RATE配置</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SCDC 0x31 - Sink Configuration Register</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">FFE_LEVELS</span> <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// 前置加重电平</span>
    <span class="kt">uint8_t</span> <span class="n">FRL_RATE</span>    <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// FRL速率配置</span>
<span class="p">}</span> <span class="n">scdc_frl_control_t</span><span class="p">;</span>

<span class="c1">// FRL_RATE字段</span>
<span class="o">|</span> <span class="err">值</span>  <span class="o">|</span> <span class="err">速率配置</span>        <span class="o">|</span>
<span class="o">|-----|----------------|</span>
<span class="o">|</span> <span class="mi">0</span>   <span class="o">|</span> <span class="err">禁用</span><span class="n">FRL</span><span class="p">(</span><span class="n">TMDS</span><span class="p">)</span>  <span class="o">|</span>
<span class="o">|</span> <span class="mi">1</span>   <span class="o">|</span> <span class="mi">3</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">3</span> <span class="n">lanes</span><span class="o">|</span>
<span class="o">|</span> <span class="mi">2</span>   <span class="o">|</span> <span class="mi">6</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">3</span> <span class="n">lanes</span><span class="o">|</span>
<span class="o">|</span> <span class="mi">3</span>   <span class="o">|</span> <span class="mi">6</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">4</span> <span class="n">lanes</span><span class="o">|</span>
<span class="o">|</span> <span class="mi">4</span>   <span class="o">|</span> <span class="mi">8</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">4</span> <span class="n">lanes</span><span class="o">|</span>
<span class="o">|</span> <span class="mi">5</span>   <span class="o">|</span> <span class="mi">10</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">4</span> <span class="n">lanes</span><span class="o">|</span>
<span class="o">|</span> <span class="mi">6</span>   <span class="o">|</span> <span class="mi">12</span><span class="n">Gbps</span> <span class="err">×</span> <span class="mi">4</span> <span class="n">lanes</span><span class="o">|</span>
</code></pre></div></div>

<h3 id="33-状态标志寄存器">3.3 状态标志寄存器</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SCDC 0x40 - Status Flag Register</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">CLK_DETECTED</span>   <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 时钟检测</span>
    <span class="kt">uint8_t</span> <span class="n">CH0_LOCKED</span>     <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// Lane0锁定</span>
    <span class="kt">uint8_t</span> <span class="n">CH1_LOCKED</span>     <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// Lane1锁定</span>
    <span class="kt">uint8_t</span> <span class="n">CH2_LOCKED</span>     <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// Lane2锁定</span>
    <span class="kt">uint8_t</span> <span class="n">CH3_LOCKED</span>     <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// Lane3锁定</span>
    <span class="kt">uint8_t</span> <span class="n">FLT_READY</span>      <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 训练就绪</span>
    <span class="kt">uint8_t</span> <span class="n">FAIL</span>           <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 训练失败</span>
    <span class="kt">uint8_t</span> <span class="n">DSC_DECODE</span>     <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// DSC解码状态</span>
<span class="p">}</span> <span class="n">scdc_status_flag_t</span><span class="p">;</span>

<span class="c1">// SCDC 0x10 - Source Test Update Register</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">RR_TEST</span>        <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 读写测试</span>
    <span class="kt">uint8_t</span> <span class="n">UPDATE</span>         <span class="o">:</span> <span class="mi">1</span><span class="p">;</span>  <span class="c1">// 配置更新</span>
    <span class="kt">uint8_t</span> <span class="p">...</span>            <span class="o">:</span> <span class="mi">6</span><span class="p">;</span>
<span class="p">}</span> <span class="n">scdc_test_update_t</span><span class="p">;</span>
</code></pre></div></div>

<h2 id="4-link-training状态机">4. Link Training状态机</h2>

<h3 id="41-lts状态说明">4.1 LTS状态说明</h3>

<table>
  <thead>
    <tr>
      <th>状态</th>
      <th>名称</th>
      <th>Source行为</th>
      <th>Sink行为</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LTS:1</td>
      <td>Read EDID</td>
      <td>读取解析EDID</td>
      <td>提供EDID，设置SCDC</td>
    </tr>
    <tr>
      <td>LTS:2</td>
      <td>Prepare for FRL</td>
      <td>轮询FLT_READY</td>
      <td>准备完成后设置FLT_READY=1</td>
    </tr>
    <tr>
      <td>LTS:3</td>
      <td>Training in Progress</td>
      <td>发送LTP Pattern</td>
      <td>评估信号，请求Pattern类型</td>
    </tr>
    <tr>
      <td>LTS:4</td>
      <td>FRL Rate Change</td>
      <td>调整FRL Rate</td>
      <td>请求新速率(可选)</td>
    </tr>
    <tr>
      <td>LTS:P</td>
      <td>Pass</td>
      <td>开始视频传输</td>
      <td>准备接收视频数据</td>
    </tr>
    <tr>
      <td>LTS:L</td>
      <td>Fail</td>
      <td>回退TMDS模式</td>
      <td>进入TMDS</td>
    </tr>
  </tbody>
</table>

<h3 id="42-完整训练流程">4.2 完整训练流程</h3>

<pre><code class="language-mermaid">sequenceDiagram
    participant Source
    participant Sink
    
    Note over Source,Sink: LTS:1 - Read EDID
    Source-&gt;&gt;Sink: DDC读取EDID
    Sink--&gt;&gt;Source: 返回HF-VSDB(FRL能力)
    Note over Source: 判断FRL_Max_Rate&gt;0&lt;br/&gt;SCDC_Present=1
    
    Note over Source,Sink: LTS:2 - Prepare for FRL
    loop 轮询FLT_READY
        Source-&gt;&gt;Sink: 读取SCDC 0x40
        Sink--&gt;&gt;Source: 返回FLT_READY状态
    end
    Sink-&gt;&gt;Sink: 设置FLT_READY=1
    Source-&gt;&gt;Sink: 写入SCDC 0x31 (FRL_RATE)
    Source-&gt;&gt;Sink: 设置FRL_START=1
    
    Note over Source,Sink: LTS:3 - Training in Progress
    loop 均衡训练
        Source-&gt;&gt;Sink: 发送LTP训练序列
        Sink-&gt;&gt;Source: 写入SCDC 0x41/0x42&lt;br/&gt;(LTP_REQ请求特定Pattern)
        Sink-&gt;&gt;Source: 更新锁定状态到0x40
    end
    Sink-&gt;&gt;Sink: 所有Lane锁定
    
    alt 训练成功
        Sink-&gt;&gt;Source: 设置FLT_READY=0, FRL_START=0
        Sink-&gt;&gt;Source: 设置FRL_TRANSMITTER_ON=1
        Note over Source,Sink: LTS:P - Pass
        Source-&gt;&gt;Sink: 开始FRL视频传输
    else 训练失败
        Sink-&gt;&gt;Source: 设置FAIL=1
        Note over Source,Sink: LTS:L - Fail
        Source-&gt;&gt;Sink: 回退到TMDS模式
    end
</code></pre>

<h2 id="5-ltp训练序列">5. LTP训练序列</h2>

<p>LTP(Link Training Pattern)是FRL训练使用的特殊序列：</p>

<table>
  <thead>
    <tr>
      <th>LTP类型</th>
      <th>用途</th>
      <th>说明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>LTP1</td>
      <td>时钟恢复</td>
      <td>低频训练序列</td>
    </tr>
    <tr>
      <td>LTP2</td>
      <td>通道特性</td>
      <td>中频特性测量</td>
    </tr>
    <tr>
      <td>LTP3</td>
      <td>均衡训练</td>
      <td>高频均衡调整</td>
    </tr>
    <tr>
      <td>LTP4</td>
      <td>全景验证</td>
      <td>综合眼图验证</td>
    </tr>
    <tr>
      <td>PRBS</td>
      <td>误码检测</td>
      <td>伪随机序列BER测试</td>
    </tr>
  </tbody>
</table>

<p>Sink通过SCDC配置请求特定LTP：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SCDC 0x41 - Lane 0/1 LTP请求</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">LN0_LTP_REQ</span> <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// Lane0请求的LTP类型</span>
    <span class="kt">uint8_t</span> <span class="n">LN1_LTP_REQ</span> <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// Lane1请求的LTP类型</span>
<span class="p">}</span> <span class="n">ln01_ltp_req_t</span><span class="p">;</span>

<span class="c1">// SCDC 0x42 - Lane 2/3 LTP请求</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">LN2_LTP_REQ</span> <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// Lane2请求的LTP类型</span>
    <span class="kt">uint8_t</span> <span class="n">LN3_LTP_REQ</span> <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// Lane3请求的LTP类型</span>
<span class="p">}</span> <span class="n">ln23_ltp_req_t</span><span class="p">;</span>
</code></pre></div></div>

<p>Source根据Sink反馈调整：</p>
<ul>
  <li><strong>FFE(Feed-Forward Equalization)</strong> 电平</li>
  <li><strong>驱动电压幅度</strong></li>
  <li><strong>均衡器增益</strong></li>
</ul>

<h2 id="6-tmds传输周期">6. TMDS传输周期</h2>

<p>HDMI使用TMDS编码，在一个视频帧的传输过程中，有三种交替的传输周期。理解这些周期对于HDMI协议解析和调试至关重要。</p>

<h3 id="61-三种传输周期">6.1 三种传输周期</h3>

<pre><code class="language-mermaid">graph TB
    subgraph 帧结构
        CP1[Control Period&lt;br/&gt;控制周期]
        VDP[Video Data Period&lt;br/&gt;视频数据周期]
        DIP[Data Island Period&lt;br/&gt;数据岛周期]
        CP2[Control Period]
    end
    
    CP1 --&gt; |Preamble 1000| VDP
    VDP --&gt; |Blank区| CP2
    CP2 --&gt; |Preamble 1010| DIP
    DIP --&gt; |Blank区| CP1
</code></pre>

<table>
  <thead>
    <tr>
      <th>周期类型</th>
      <th>编码方式</th>
      <th>每周期bit</th>
      <th>位置</th>
      <th>主要内容</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Control Period</td>
      <td>2b/10b</td>
      <td>6bit</td>
      <td>消隐区</td>
      <td>HS/VS同步, Preamble</td>
    </tr>
    <tr>
      <td>Video Data Period</td>
      <td>8b/10b</td>
      <td>24bit</td>
      <td>有效像素</td>
      <td>RGB/YCbCr像素数据</td>
    </tr>
    <tr>
      <td>Data Island Period</td>
      <td>4b/10b</td>
      <td>12bit</td>
      <td>消隐区</td>
      <td>音频/InfoFrame</td>
    </tr>
  </tbody>
</table>

<h3 id="62-control-period">6.2 Control Period</h3>

<p><strong>作用</strong>：</p>
<ul>
  <li>传输HSYNC、VSYNC同步信号</li>
  <li>传输Preamble前导码，告知下一个周期类型</li>
  <li>Sink字符同步恢复</li>
  <li>任何两个非Control Period之间<strong>必须</strong>有Control Period</li>
</ul>

<p><strong>CTL编码</strong>：
| CTL3:0 | 下一个周期类型 |
|——–|—————|
| 1000 | Video Data Period |
| 1010 | Data Island Period |</p>

<p><strong>编码方式</strong>：使用特殊10bit控制码，每通道传输2bit(HS/VS/CTL0/CTL1)，共6bit</p>

<h3 id="63-video-data-period">6.3 Video Data Period</h3>

<p><strong>位置</strong>：传输有效视频像素</p>

<p><strong>结构</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Preamble 8字符] → [Leading Guard Band 2字符] → [有效像素数据]
</code></pre></div></div>

<p><strong>数据映射</strong>：
| TMDS Channel | RGB模式 | YCbCr模式 |
|————–|———|———–|
| Channel 0 | Blue | Cr/Cb |
| Channel 1 | Green | Y |
| Channel 2 | Red | Cb/Cr |</p>

<p><strong>编码方式</strong>：8b/10b，每时钟周期传输24bit像素</p>

<p><strong>Guard Band码</strong>：</p>
<ul>
  <li>Channel 2/1: <code class="language-plaintext highlighter-rouge">0b1011001100</code></li>
  <li>Channel 0: <code class="language-plaintext highlighter-rouge">0b0100110011</code></li>
</ul>

<h3 id="64-data-island-period">6.4 Data Island Period</h3>

<p><strong>位置</strong>：水平/垂直消隐期间</p>

<p><strong>传输内容</strong>：</p>
<ul>
  <li>音频数据包(Audio Sample Packets)</li>
  <li>InfoFrame信息帧(AVI, Audio, Vendor等)</li>
  <li>辅助数据</li>
</ul>

<p><strong>结构</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Preamble 8字符] → [Leading Guard Band 2字符] → [数据包] × N → [Trailing Guard Band 2字符]
</code></pre></div></div>

<p><strong>数据映射</strong>：</p>
<ul>
  <li>Channel 0/1/2: 各4bit</li>
  <li>每TMDS时钟周期传输12bit</li>
  <li>使用TERC4编码(TMDS Error Reduction Coding)</li>
</ul>

<p><strong>Guard Band码</strong>：</p>
<ul>
  <li>Channel 2/1: <code class="language-plaintext highlighter-rouge">0b0100110011</code></li>
  <li>Channel 0: 保留</li>
</ul>

<h3 id="65-周期时序关系">6.5 周期时序关系</h3>

<p><strong>行级视角</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>         ┌─────────────────────────────────────────────────────────────┐
         │                    一行视频数据传输                            │
         ├──────────┬────────────────────┬──────────────┬─────────────┤
         │ Control  │   Video Data       │   Control    │  Data       │
         │ Period   │   Period           │   Period     │  Island     │
         ├──────────┼────────────────────┼──────────────┼─────────────┤
  同步信号│  HS/VS   │   Active Video    │   HS/VS      │   HS/VS     │
  Preamble│  1000    │   (像素数据)       │   1010       │             │
  编码方式│  2b/10b  │   8b/10b          │   2b/10b     │   4b/10b    │
  数据内容│  同步/控制│   RGB/YCbCr像素   │   同步/控制   │   音频/Info │
         └──────────┴────────────────────┴──────────────┴─────────────┘
                           有效像素                消隐区(含音频)
</code></pre></div></div>

<p><strong>帧级视角</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────────────────────────┐
│ Frame (完整帧)                                                   │
├─────────────────────────────────────────────────────────────────┤
│ 第1场/帧头 Control ──&gt; Video Data ──&gt; Control ──&gt; Data Island ──►│
├─────────────────────────────────────────────────────────────────┤
│ Active Line N     Control ──&gt; Video Data ──&gt; Control ──► DI ──►│
├─────────────────────────────────────────────────────────────────┤
│ Blanking Lines    Control ──&gt; Data Island ──&gt; Control ──► DI ──►│
│ (消隐区传输音频)                                                    │
├─────────────────────────────────────────────────────────────────┤
│ 最后一帧尾     Control ──&gt; Video Data ──&gt; Control              │
└─────────────────────────────────────────────────────────────────┘

关键点：
1. Control Period是"交通灯"，告诉Sink下一个要进入什么模式
2. Video Data传输有效图像像素
3. Data Island分散在消隐区，传输音频和InfoFrame
4. 消隐区 = Back Porch + Sync + Front Porch
</code></pre></div></div>

<h2 id="7-hdmi-vs-dp对比">7. HDMI vs DP对比</h2>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>HDMI 2.1 FRL</th>
      <th>DisplayPort 1.4</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>最大带宽</td>
      <td>48 Gbps</td>
      <td>32.4 Gbps</td>
    </tr>
    <tr>
      <td>训练配置</td>
      <td>SCDC寄存器</td>
      <td>DPCD寄存器</td>
    </tr>
    <tr>
      <td>配置通道</td>
      <td>DDC(I2C)</td>
      <td>AUX CH</td>
    </tr>
    <tr>
      <td>编码方式</td>
      <td>16b/18b</td>
      <td>8b/10b</td>
    </tr>
    <tr>
      <td>纠错机制</td>
      <td>Reed-Solomon FEC</td>
      <td>BCH</td>
    </tr>
    <tr>
      <td>训练状态</td>
      <td>LTS:1/2/3/P/L</td>
      <td>CR/EQ阶段</td>
    </tr>
    <tr>
      <td>热插拔</td>
      <td>HPD脉冲</td>
      <td>HPD中断</td>
    </tr>
    <tr>
      <td>内容保护</td>
      <td>HDCP 2.2/2.3</td>
      <td>HDCP 2.2/2.3</td>
    </tr>
  </tbody>
</table>

<p>| 特性 | HDMI 2.1 FRL | DisplayPort 2.0 UHBR |
|——|—————|———————|
| 最大带宽 | 48 Gbps | 80 Gbps |
| 编码方式 | 16b/18b | 128b/132b |
| 训练机制 | SCDC+LTS状态机 | DPRX状态机 |</p>
<h2 id="8-packet传输机制详解">8. Packet传输机制详解</h2>

<p>在HDMI协议中，Packet是传输辅助数据（音频、InfoFrame、厂商特定信息）的基本单元。理解Packet的传输机制对于实现HDMI功能至关重要。</p>

<h3 id="81-tmds-vs-frl-packet传输差异">8.1 TMDS vs FRL Packet传输差异</h3>

<pre><code class="language-mermaid">graph LR
    subgraph TMDS模式
        T1[Data Island Period&lt;br/&gt;TERC4编码] --&gt; T2[12bit/时钟周期]
    end
    
    subgraph FRL模式
        F1[Super Block&lt;br/&gt;18bit编码] --&gt; F2[36bit/时钟周期]
    end
    
    T2 --&gt;|带宽| F2
</code></pre>

<table>
  <thead>
    <tr>
      <th>特性</th>
      <th>TMDS模式</th>
      <th>FRL模式</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>编码方式</td>
      <td>TERC4 (4b/10b)</td>
      <td>16b/18b</td>
    </tr>
    <tr>
      <td>每时钟周期</td>
      <td>12bit</td>
      <td>36bit</td>
    </tr>
    <tr>
      <td>数据岛周期</td>
      <td>分散在消隐区</td>
      <td>嵌入Super Block</td>
    </tr>
    <tr>
      <td>传输类型</td>
      <td>包(Packet)</td>
      <td>流(Stream)</td>
    </tr>
  </tbody>
</table>

<h3 id="82-tmds-packet类型">8.2 TMDS Packet类型</h3>

<p>HDMI定义了多种Packet类型，通过Header + Body结构传输：</p>

<table>
  <thead>
    <tr>
      <th>Packet Type</th>
      <th>HB[0]</th>
      <th>用途</th>
      <th>传输频率</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Audio Sample Packet</td>
      <td>0x02</td>
      <td>音频采样数据</td>
      <td>每帧</td>
    </tr>
    <tr>
      <td>Audio InfoFrame</td>
      <td>0x04</td>
      <td>音频通道配置</td>
      <td>帧期间隔</td>
    </tr>
    <tr>
      <td>AVI InfoFrame</td>
      <td>0x06</td>
      <td>视频格式信息</td>
      <td>每帧</td>
    </tr>
    <tr>
      <td>Vendor-Specific VSIF</td>
      <td>0x81</td>
      <td>厂商特定信息</td>
      <td>需时</td>
    </tr>
    <tr>
      <td>SPD InfoFrame</td>
      <td>0x83</td>
      <td>Source设备信息</td>
      <td>需时</td>
    </tr>
    <tr>
      <td>GCP (General Control)</td>
      <td>0x08</td>
      <td>颜色深度/3D信息</td>
      <td>需时</td>
    </tr>
    <tr>
      <td>VSI (Vendor-Specific Info)</td>
      <td>0xA0</td>
      <td>HDMI许可信息</td>
      <td>需时</td>
    </tr>
  </tbody>
</table>

<p><strong>Packet结构</strong>：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Packet Header - 4字节] → [Packet Body - 28字节]
    ├── HB0: Packet Type
    ├── HB1: Packet Version
    ├── HB2: Length
    └── HB3: Party/Reserved
    
    └── DB0-DB27: 数据内容
</code></pre></div></div>

<h3 id="83-infoframe发送流程">8.3 InfoFrame发送流程</h3>

<pre><code class="language-mermaid">flowchart TD
    A[应用层配置InfoFrame] --&gt; B[计算Checksum]
    B --&gt; C[写入TPI寄存器]
    C --&gt; D[设置发送使能]
    D --&gt; E[等待VSync触发]
    E --&gt; F[自动发送]
    F --&gt; G[清除使能]
</code></pre>

<p><strong>代码实现示例</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// HDMI TX Packet管理 - hdmi_tx_pktmgmt.c</span>
<span class="k">static</span> <span class="kt">void</span> <span class="nf">tpi_info_send</span><span class="p">(</span><span class="n">u8</span> <span class="n">sel</span><span class="p">,</span> <span class="n">u8</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">bool</span> <span class="n">no_chksum_flag</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">u32</span> <span class="n">checksum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">u32</span> <span class="n">i</span><span class="p">;</span>
    
    <span class="c1">// 1. 选择InfoFrame类型</span>
    <span class="n">hdmitx21_wr_reg</span><span class="p">(</span><span class="n">TPI_INFO_FSEL_IVCTX</span><span class="p">,</span> <span class="n">sel</span><span class="p">);</span>
    
    <span class="c1">// 2. 计算Checksum (前30字节累加，取反)</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">no_chksum_flag</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">30</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">checksum</span> <span class="o">+=</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="n">checksum</span> <span class="o">=</span> <span class="p">(</span><span class="n">u8</span><span class="p">)(</span><span class="mh">0x100</span> <span class="o">-</span> <span class="p">(</span><span class="n">checksum</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">));</span>
        <span class="n">data</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">=</span> <span class="n">checksum</span><span class="p">;</span>  <span class="c1">// AVI DB1位置</span>
    <span class="p">}</span>
    
    <span class="c1">// 3. 写入数据到TPI寄存器</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">30</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">hdmitx21_wr_reg</span><span class="p">(</span><span class="n">TPI_INFO_BYTE00_IVCTX</span> <span class="o">+</span> <span class="n">i</span><span class="p">,</span> <span class="n">data</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    
    <span class="c1">// 4. 使能发送 (AVI + Audio + GCP)</span>
    <span class="n">hdmitx21_wr_reg</span><span class="p">(</span><span class="n">TPI_INFO_EN_IVCTX</span><span class="p">,</span> <span class="mh">0xe0</span><span class="p">);</span>
<span class="p">}</span>

<span class="c1">// InfoFrame类型选择 (sel值映射)</span>
<span class="k">enum</span> <span class="n">info_frame_sel</span> <span class="p">{</span>
    <span class="n">INFOFRAME_AVI</span>      <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>  <span class="c1">// AVI InfoFrame</span>
    <span class="n">INFOFRAME_EMP_VRR</span>  <span class="o">=</span> <span class="mi">1</span><span class="p">,</span>  <span class="c1">// EMP (VRR/QMS)</span>
    <span class="n">INFOFRAME_AUDIO</span>   <span class="o">=</span> <span class="mi">2</span><span class="p">,</span>  <span class="c1">// Audio InfoFrame</span>
    <span class="n">INFOFRAME_SPD</span>     <span class="o">=</span> <span class="mi">3</span><span class="p">,</span>  <span class="c1">// SPD InfoFrame</span>
    <span class="n">INFOFRAME_EMP_SBTM</span> <span class="o">=</span> <span class="mi">4</span><span class="p">,</span> <span class="c1">// EMP SBTM</span>
    <span class="n">INFOFRAME_VSIF</span>    <span class="o">=</span> <span class="mi">5</span><span class="p">,</span>  <span class="c1">// Vendor VSIF</span>
    <span class="n">INFOFRAME_DRM</span>     <span class="o">=</span> <span class="mi">6</span><span class="p">,</span>  <span class="c1">// DRM InfoFrame</span>
    <span class="n">INFOFRAME_GCP</span>     <span class="o">=</span> <span class="mi">7</span><span class="p">,</span>  <span class="c1">// GCP</span>
    <span class="n">INFOFRAME_HFVSIF</span>  <span class="o">=</span> <span class="mi">8</span><span class="p">,</span>  <span class="c1">// HF-VSIF</span>
    <span class="n">INFOFRAME_EMP2</span>    <span class="o">=</span> <span class="mi">9</span><span class="p">,</span>  <span class="c1">// EMP</span>
    <span class="n">INFOFRAME_SBTM</span>    <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="c1">// SBTM</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="84-frl-super-block结构">8.4 FRL Super Block结构</h3>

<p>FRL模式使用Super Block作为基本传输单元，相比TMDS具有更高效率：</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Super Block结构 (4个FRL时钟周期):
┌──────────────────────────────────────────────────────────────────┐
│ Lane 0     │ Lane 1     │ Lane 2     │ Lane 3     │             │
├────────────┼────────────┼────────────┼────────────┤             │
│ 18bit × 4  │ 18bit × 4  │ 18bit × 4  │ 18bit × 4  │ = 288bit    │
└─────────────────────────────────────────────────────────────────┘

每18bit组成:
┌────────────────┬────────────────┬────────────────┐
│  Data (16bit)  │  ECC (2bit)    │                │
└────────────────┴────────────────┴────────────────┘
</code></pre></div></div>

<p><strong>Super Block类型</strong>：</p>

<table>
  <thead>
    <tr>
      <th>类型</th>
      <th>用途</th>
      <th>数据内容</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Video Super Block</td>
      <td>有效像素行</td>
      <td>RGB/YCrCb像素数据</td>
    </tr>
    <tr>
      <td>Audio Super Block</td>
      <td>音频数据</td>
      <td>Audio Sample Packets</td>
    </tr>
    <tr>
      <td>Control Super Block</td>
      <td>控制信息</td>
      <td>InfoFrame/同步</td>
    </tr>
    <tr>
      <td>Idle Super Block</td>
      <td>空闲填充</td>
      <td>0x0000</td>
    </tr>
  </tbody>
</table>

<h3 id="85-ltp训练序列详解">8.5 LTP训练序列详解</h3>

<p>LTP(Link Training Pattern)是FRL Link Training的核心，用于调整Source和Sink之间的信号特性：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// LTP Pattern定义</span>
<span class="k">enum</span> <span class="n">ltp_pattern</span> <span class="p">{</span>
    <span class="n">LTP_D10_2</span>      <span class="o">=</span> <span class="mh">0x1111</span><span class="p">,</span>  <span class="c1">// D10.2训练序列</span>
    <span class="n">LTP_SCRAMBLER</span>  <span class="o">=</span> <span class="mh">0x2222</span><span class="p">,</span>  <span class="c1">// 扰码训练序列</span>
    <span class="n">LTP_NONE2</span>      <span class="o">=</span> <span class="mh">0x3333</span><span class="p">,</span>  <span class="c1">// 无训练</span>
    <span class="n">LTP_PRBS7</span>      <span class="o">=</span> <span class="mh">0x4444</span><span class="p">,</span>  <span class="c1">// PRBS7误码测试</span>
    <span class="n">LTP_PRBS15</span>     <span class="o">=</span> <span class="mh">0x5555</span><span class="p">,</span>  <span class="c1">// PRBS15误码测试</span>
    <span class="n">LTP_PRBS31</span>     <span class="o">=</span> <span class="mh">0x6666</span><span class="p">,</span>  <span class="c1">// PRBS31误码测试</span>
    <span class="n">LTP_EEEE</span>       <span class="o">=</span> <span class="mh">0xEEEE</span><span class="p">,</span>  <span class="c1">// FFE更新请求</span>
    <span class="n">LTP_FFFF</span>       <span class="o">=</span> <span class="mh">0xFFFF</span><span class="p">,</span>  <span class="c1">// 速率切换请求</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>训练序列作用</strong>：</p>

<table>
  <thead>
    <tr>
      <th>训练阶段</th>
      <th>LTP类型</th>
      <th>目的</th>
      <th>Sink评估指标</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>阶段1</td>
      <td>LTP_D10_2</td>
      <td>基础时钟恢复</td>
      <td>时钟锁定</td>
    </tr>
    <tr>
      <td>阶段2</td>
      <td>LTP_SCRAMBLER</td>
      <td>通道特性测量</td>
      <td>眼图开启</td>
    </tr>
    <tr>
      <td>阶段3</td>
      <td>LTP_PRBS7</td>
      <td>高频特性</td>
      <td>BER &lt; 10^-9</td>
    </tr>
    <tr>
      <td>阶段4</td>
      <td>LTP_EEEE</td>
      <td>FFE调整</td>
      <td>信号质量最优</td>
    </tr>
  </tbody>
</table>

<h3 id="86-ffe-feed-forward-equalizer-控制">8.6 FFE (Feed-Forward Equalizer) 控制</h3>

<p>FFE是FRL训练中的关键参数，用于补偿信道损耗：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SCDC FFE配置</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
    <span class="kt">uint8_t</span> <span class="n">FFE_LEVELS</span>     <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// FFE强度等级</span>
    <span class="kt">uint8_t</span> <span class="n">FRL_RATE</span>       <span class="o">:</span> <span class="mi">4</span><span class="p">;</span>  <span class="c1">// FRL速率</span>
<span class="p">}</span> <span class="n">scdc_frl_control_t</span><span class="p">;</span>

<span class="c1">// FFE等级与补偿关系</span>
<span class="c1">// FFE等级越高，高频增益越大</span>
<span class="c1">// 补偿公式: Gain(dB) = FFE_LEVEL × 3dB</span>

<span class="c1">// 训练过程中Sink通过LTP反馈调整FFE:</span>
<span class="kt">void</span> <span class="nf">update_ffe_level</span><span class="p">(</span><span class="kt">int</span> <span class="n">lane</span><span class="p">,</span> <span class="kt">int</span> <span class="n">level</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// 写入SCDC 0x31 FFE_LEVELS字段</span>
    <span class="kt">uint8_t</span> <span class="n">val</span> <span class="o">=</span> <span class="p">(</span><span class="n">level</span> <span class="o">&amp;</span> <span class="mh">0x0F</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">current_frl_rate</span> <span class="o">&lt;&lt;</span> <span class="mi">4</span><span class="p">);</span>
    <span class="n">scdc_write</span><span class="p">(</span><span class="mh">0x31</span><span class="p">,</span> <span class="n">val</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>FFE与线缆长度的关系</strong>：</p>

<table>
  <thead>
    <tr>
      <th>线缆类型</th>
      <th>推荐FFE等级</th>
      <th>补偿能力</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>短线(&lt;1m)</td>
      <td>0-1</td>
      <td>最小</td>
    </tr>
    <tr>
      <td>标准线(1-3m)</td>
      <td>2-3</td>
      <td>中等</td>
    </tr>
    <tr>
      <td>长线(&gt;3m)</td>
      <td>4</td>
      <td>最大</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="9-问答精选">9. 问答精选</h2>

<h3 id="q1-hdmi-21为什么需要frl而不是继续使用tmds">Q1: HDMI 2.1为什么需要FRL而不是继续使用TMDS?</h3>

<p><strong>参考答案</strong>：</p>
<ul>
  <li>TMDS最大带宽仅18Gbps，无法支持8K@60Hz或更高分辨率</li>
  <li>FRL使用16b/18b编码（vs TMDS的8b/10b），效率提升约11%</li>
  <li>FRL支持4 Lane（TMDS仅3 Lane），理论带宽达48Gbps</li>
  <li>FRL引入Link Training机制，可自适应调整信号特性</li>
</ul>

<h3 id="q2-hdmi-frl训练失败后如何处理">Q2: HDMI FRL训练失败后如何处理?</h3>

<p><strong>参考答案</strong>：</p>
<ol>
  <li>训练失败标志：SCDC 0x40[5] FAIL=1</li>
  <li>回退策略：
    <ul>
      <li>尝试降低FRL速率（FRL6→FRL5→…→FRL1）</li>
      <li>降级到TMDS模式（4K@60Hz可满足）</li>
    </ul>
  </li>
  <li>恢复流程：
    <ul>
      <li>设置FRL_START=0, FRL_RATE=0</li>
      <li>重新进入TMDS模式</li>
      <li>通知上层应用降级显示</li>
    </ul>
  </li>
</ol>

<h3 id="q3-hdmi和dp的主要区别是什么">Q3: HDMI和DP的主要区别是什么？</h3>

<p><strong>参考答案</strong>：
| 特性 | HDMI 2.1 | DisplayPort 1.4/2.0 |
|——|———-|———————|
| 配置通道 | DDC(I2C) | AUX CH |
| 编码 | 16b/18b / 8b/10b | 8b/10b / 128b/132b |
| 训练接口 | SCDC | DPCD |
| 热插拔 | HPD脉冲 | HPD中断+Irq |
| 授权 | 需要HDMI许可 | 免费 |</p>

<h3 id="q4-hdmi的data-island-period和video-data-period有什么区别">Q4: HDMI的Data Island Period和Video Data Period有什么区别？</h3>

<p><strong>参考答案</strong>：</p>
<ul>
  <li>Video Data Period：传输有效像素，使用8b/10b编码，每时钟24bit</li>
  <li>Data Island Period：传输辅助数据（音频/InfoFrame），使用TERC4编码，每时钟12bit</li>
  <li>两者通过Control Period的Preamble (1000/1010) 区分</li>
</ul>

<h3 id="q5-frl-link-training过程中sink如何请求特定的ltp">Q5: FRL Link Training过程中，Sink如何请求特定的LTP？</h3>

<p><strong>参考答案</strong>：
Sink通过SCDC寄存器请求：</p>
<ul>
  <li>SCDC 0x41: Lane 0/1 LTP请求 (LN0_LTP_REQ[3:0], LN1_LTP_REQ[3:0])</li>
  <li>SCDC 0x42: Lane 2/3 LTP请求 (LN2_LTP_REQ[3:0], LN3_LTP_REQ[3:0])</li>
</ul>

<p>Source根据请求发送对应LTP，Sink评估信号质量后调整FFE_LEVELS参数。</p>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="HDMI" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Linux DMA-buf 与 DMA-fence 机制深度解析：DRM 框架中的 Prime 实现</title><link href="https://yangchao315.github.io/Linux-DMA-buf-DMA-fence-PRIME/" rel="alternate" type="text/html" title="Linux DMA-buf 与 DMA-fence 机制深度解析：DRM 框架中的 Prime 实现" /><published>2026-03-23T00:00:00+00:00</published><updated>2026-03-23T00:00:00+00:00</updated><id>https://yangchao315.github.io/Linux-DMA-buf-DMA-fence-PRIME</id><content type="html" xml:base="https://yangchao315.github.io/Linux-DMA-buf-DMA-fence-PRIME/"><![CDATA[<!-- more -->

<ul>
  <li><a href="#一背景与问题">一、背景与问题</a></li>
  <li><a href="#二dma-buf-核心机制">二、DMA-buf 核心机制</a>
    <ul>
      <li><a href="#21-基本概念">2.1 基本概念</a></li>
      <li><a href="#22-核心数据结构">2.2 核心数据结构</a></li>
      <li><a href="#22-exporter-与-importer">2.3 Exporter 与 Importer</a></li>
      <li><a href="#24-dma-buf-文件系统">2.4 dma-buf 文件系统</a></li>
    </ul>
  </li>
  <li><a href="#三dma-fence-同步机制">三、DMA-fence 同步机制</a>
    <ul>
      <li><a href="#31-为什么需要-fence">3.1 为什么需要 fence</a></li>
      <li><a href="#32-fence-数据结构">3.2 fence 数据结构</a></li>
      <li><a href="#33-fence-等待与信号">3.3 fence 等待与信号</a></li>
      <li><a href="#34-典型使用流程">3.4 典型使用流程</a></li>
    </ul>
  </li>
  <li><a href="#四drm-中的-prime-机制">四、DRM 中的 PRIME 机制</a>
    <ul>
      <li><a href="#41-prime-简介">4.1 PRIME 简介</a></li>
      <li><a href="#42-export-流程">4.2 Export 流程</a></li>
      <li><a href="#43-import-流程">4.3 Import 流程</a></li>
      <li><a href="#44-prime-缓存机制">4.4 PRIME 缓存机制</a></li>
    </ul>
  </li>
  <li><a href="#五代码示例">五、代码示例</a>
    <ul>
      <li><a href="#51-exporter-示例">5.1 Exporter 示例</a></li>
      <li><a href="#52-dma-fence-示例">5.2 DMA-fence 示例</a></li>
    </ul>
  </li>
  <li><a href="#六总结">六、总结</a></li>
</ul>

<hr />

<h2 id="一背景与问题">一、背景与问题</h2>

<p>在现代 Linux 系统中，显示子系统涉及多个硬件组件的协同工作：GPU、视频解码器、显示控制器、摄像头等。这些组件之间需要高效地共享视频帧数据。传统方式是通过内存拷贝，但这种方式在 4K 视频、GPU 渲染等高带宽场景下效率极低。</p>

<p><strong>DMA-buf</strong> 应运而生，它提供了一种无需拷贝的缓冲区共享机制，使得不同硬件设备可以直接访问同一块物理内存。</p>

<callout emoji="💡" background-color="light-blue">
DMA-buf 的核心思想：将物理内存页描述为可在设备间流转的"文件句柄"，通过文件描述符传递实现零拷贝共享。
</callout>

<hr />

<h2 id="二dma-buf-核心机制">二、DMA-buf 核心机制</h2>

<h3 id="21-基本概念">2.1 基本概念</h3>

<p>DMA-buf 的本质是 <strong>buffer 与 file 的结合</strong>：</p>
<ul>
  <li><strong>Buffer</strong>：实际的物理内存页</li>
  <li><strong>File</strong>：Linux 文件描述符，用于在进程和驱动之间传递</li>
</ul>

<p>这样设计的好处是：</p>
<ol>
  <li>统一的传递媒介（file descriptor）</li>
  <li>引用计数管理生命周期</li>
  <li>跨进程共享变得简单</li>
</ol>

<h3 id="22-核心数据结构">2.2 核心数据结构</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// include/linux/dma-buf.h</span>
<span class="k">struct</span> <span class="n">dma_buf</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">module</span> <span class="o">*</span><span class="n">owner</span><span class="p">;</span>
    <span class="k">const</span> <span class="k">struct</span> <span class="n">dma_buf_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">;</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">priv</span><span class="p">;</span>
    <span class="kt">size_t</span> <span class="n">size</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>dma_buf_ops</strong> 是 Exporter 必须实现的核心接口：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">dma_buf_ops</span> <span class="p">{</span>
    <span class="n">bool</span> <span class="n">cache_sgt_mapping</span><span class="p">;</span>
    
    <span class="cm">/* 附件管理 */</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">attach</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">dma_buf_attachment</span> <span class="o">*</span><span class="p">);</span>
    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">detach</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">dma_buf_attachment</span> <span class="o">*</span><span class="p">);</span>
    
    <span class="cm">/* DMA 映射 - 核心接口 */</span>
    <span class="k">struct</span> <span class="n">sg_table</span> <span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="n">map_dma_buf</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf_attachment</span> <span class="o">*</span><span class="p">,</span>
                     <span class="k">enum</span> <span class="n">dma_data_direction</span><span class="p">);</span>
    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">unmap_dma_buf</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf_attachment</span> <span class="o">*</span><span class="p">,</span>
                  <span class="k">struct</span> <span class="n">sg_table</span> <span class="o">*</span><span class="p">,</span>
                  <span class="k">enum</span> <span class="n">dma_data_direction</span><span class="p">);</span>
                  
    <span class="cm">/* CPU 访问 */</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">begin_cpu_access</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">dma_data_direction</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">end_cpu_access</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">,</span> <span class="k">enum</span> <span class="n">dma_data_direction</span><span class="p">);</span>
    
    <span class="cm">/* 内存映射 */</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">mmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">,</span> <span class="k">struct</span> <span class="n">vm_area_struct</span> <span class="o">*</span><span class="n">vma</span><span class="p">);</span>
    <span class="kt">int</span> <span class="p">(</span><span class="o">*</span><span class="n">vmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="n">dmabuf</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iosys_map</span> <span class="o">*</span><span class="n">map</span><span class="p">);</span>
    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">vunmap</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="n">dmabuf</span><span class="p">,</span> <span class="k">struct</span> <span class="n">iosys_map</span> <span class="o">*</span><span class="n">map</span><span class="p">);</span>
    
    <span class="cm">/* 释放 */</span>
    <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">release</span><span class="p">)(</span><span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="23-exporter-与-importer">2.3 Exporter 与 Importer</h3>

<table>
  <thead>
    <tr>
      <th>角色</th>
      <th>职责</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Exporter</strong></td>
      <td>分配物理内存，实现 dma_buf_ops，将 dmabuf 导出为 fd</td>
    </tr>
    <tr>
      <td><strong>Importer</strong></td>
      <td>接收 fd，附加到设备，获取 scatter-gather 列表进行 DMA</td>
    </tr>
  </tbody>
</table>

<p><strong>Exporter 工作流程</strong>：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">int</span> <span class="nf">exporter_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">DEFINE_DMA_BUF_EXPORT_INFO</span><span class="p">(</span><span class="n">exp_info</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="n">dmabuf</span><span class="p">;</span>

    <span class="n">exp_info</span><span class="p">.</span><span class="n">ops</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">exp_dmabuf_ops</span><span class="p">;</span>    <span class="c1">// 实现 dma_buf_ops</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">PAGE_SIZE</span><span class="p">;</span>          <span class="c1">// buffer 大小</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="n">O_CLOEXEC</span><span class="p">;</span>         <span class="c1">// 文件标志</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">priv</span> <span class="o">=</span> <span class="s">" exporter私有数据"</span><span class="p">;</span>

    <span class="n">dmabuf</span> <span class="o">=</span> <span class="n">dma_buf_export</span><span class="p">(</span><span class="o">&amp;</span><span class="n">exp_info</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">IS_ERR</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">PTR_ERR</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="24-dma-buf-文件系统">2.4 dma-buf 文件系统</h3>

<p>Linux 提供 debugfs 接口查看当前系统的 dmabuf 对象：</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /sys/kernel/debug/dma_buf/bufinfo
</code></pre></div></div>

<p>输出示例：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Dma-buf Objects:
size            flags           mode            count           exp_name        ino
00004096        00000000        00080005        00000001        dma_buf 00000088
        Attached Devices:
Total 0 devices attached

Total 1 objects, 4096 bytes
</code></pre></div></div>

<hr />

<h2 id="三dma-fence-同步机制">三、DMA-fence 同步机制</h2>

<h3 id="31-为什么需要-fence">3.1 为什么需要 fence</h3>

<p>当多个设备（GPU、VPU、Display）共享同一个 buffer 时，必须解决同步问题：</p>
<ul>
  <li>GPU 还在写入时，Display 可能已经开始读取</li>
  <li>必须保证”生产者”完成工作后，”消费者”才能使用</li>
</ul>

<p><strong>DMA-fence</strong> 提供了一种优雅的同步机制，通过 fence 信号来协调不同硬件设备的操作顺序。</p>

<h3 id="32-fence-数据结构">3.2 fence 数据结构</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">dma_fence</span> <span class="p">{</span>
    <span class="n">spinlock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">;</span>
    <span class="k">const</span> <span class="k">struct</span> <span class="n">dma_fence_ops</span> <span class="o">*</span><span class="n">ops</span><span class="p">;</span>
    <span class="n">u64</span> <span class="n">context</span><span class="p">;</span>      <span class="c1">// 唯一上下文 ID</span>
    <span class="n">u64</span> <span class="n">seqno</span><span class="p">;</span>       <span class="c1">// 序列号</span>
    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">flags</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">list_head</span> <span class="n">cb_list</span><span class="p">;</span>
    <span class="c1">// ...</span>
<span class="p">};</span>
</code></pre></div></div>

<p><strong>fence 操作</strong>：</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">dma_fence_signal()</code> - 标记 fence 已完成</li>
  <li><code class="language-plaintext highlighter-rouge">dma_fence_wait()</code> - 等待 fence 信号</li>
  <li><code class="language-plaintext highlighter-rouge">dma_fence_add_callback()</code> - 添加回调函数</li>
</ul>

<h3 id="33-fence-等待与信号">3.3 fence 等待与信号</h3>

<p>fence 支持两种等待模式：</p>
<ol>
  <li><strong>阻塞等待</strong> - <code class="language-plaintext highlighter-rouge">dma_fence_wait(fence, true)</code></li>
  <li><strong>非阻塞轮询</strong> - <code class="language-plaintext highlighter-rouge">dma_fence_wait(fence, false)</code></li>
</ol>

<h3 id="34-典型使用流程">3.4 典型使用流程</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 创建 fence</span>
<span class="k">static</span> <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="nf">create_fence</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="n">fence</span><span class="p">;</span>
    <span class="n">fence</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">fence</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
    <span class="n">dma_fence_init</span><span class="p">(</span><span class="n">fence</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fence_ops</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fence_lock</span><span class="p">,</span> <span class="n">context</span><span class="p">,</span> <span class="n">seqno</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">fence</span><span class="p">;</span>
<span class="p">}</span>

<span class="c1">// 等待 fence（用户空间）</span>
<span class="n">ret</span> <span class="o">=</span> <span class="n">ioctl</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">DMA_FENCE_IN_CMD</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">in_fence_fd</span><span class="p">);</span>
<span class="n">in_fence</span> <span class="o">=</span> <span class="n">sync_file_get_fence</span><span class="p">(</span><span class="n">in_fence_fd</span><span class="p">);</span>
<span class="n">dma_fence_wait</span><span class="p">(</span><span class="n">in_fence</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>  <span class="c1">// 阻塞等待</span>

<span class="c1">// 发出 fence（生产者完成）</span>
<span class="n">dma_fence_signal</span><span class="p">(</span><span class="n">out_fence</span><span class="p">);</span>

<span class="c1">// 创建 sync_file 供用户空间获取</span>
<span class="n">sync_file</span> <span class="o">=</span> <span class="n">sync_file_create</span><span class="p">(</span><span class="n">out_fence</span><span class="p">);</span>
<span class="n">out_fence_fd</span> <span class="o">=</span> <span class="n">get_unused_fd_flags</span><span class="p">(</span><span class="n">O_CLOEXEC</span><span class="p">);</span>
<span class="n">fd_install</span><span class="p">(</span><span class="n">out_fence_fd</span><span class="p">,</span> <span class="n">sync_file</span><span class="o">-&gt;</span><span class="n">file</span><span class="p">);</span>
</code></pre></div></div>

<hr />

<h2 id="四drm-中的-prime-机制">四、DRM 中的 PRIME 机制</h2>

<h3 id="41-prime-简介">4.1 PRIME 简介</h3>

<p>PRIME 是 DRM 框架中用于用户空间缓冲区分享的机制：</p>
<ul>
  <li><strong>Export</strong>：将 GEM buffer 导出为 dmabuf，返回 fd 给用户空间</li>
  <li><strong>Import</strong>：从用户空间接收 fd，转换为 GEM buffer</li>
</ul>

<callout emoji="💡" background-color="light-blue">
PRIME 的命名来源于 "Pixel Resource Import/Export"，是跨进程、跨设备缓冲共享的标准方案。
</callout>

<h3 id="42-export-流程">4.2 Export 流程</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>用户空间请求 GEM buffer 的 fd
        ↓
drm_gem_prime_export()
        ↓
dma_buf_export()
        ↓
返回 fd 给用户空间
</code></pre></div></div>

<p>核心代码：</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// drm_prime.c</span>
<span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="nf">drm_gem_dmabuf_export</span><span class="p">(</span><span class="k">struct</span> <span class="n">drm_device</span> <span class="o">*</span><span class="n">dev</span><span class="p">,</span>
                                       <span class="k">struct</span> <span class="n">drm_gem_object</span> <span class="o">*</span><span class="n">obj</span><span class="p">,</span>
                                       <span class="k">struct</span> <span class="n">dma_buf_export_info</span> <span class="o">*</span><span class="n">exp_info</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">exp_info</span><span class="o">-&gt;</span><span class="n">ops</span> <span class="o">=</span> <span class="n">dev</span><span class="o">-&gt;</span><span class="n">driver</span><span class="o">-&gt;</span><span class="n">gem_prime_ops</span><span class="o">-&gt;</span><span class="n">ops</span><span class="p">;</span>
    <span class="n">exp_info</span><span class="o">-&gt;</span><span class="n">priv</span> <span class="o">=</span> <span class="n">obj</span><span class="p">;</span>
    
    <span class="k">return</span> <span class="n">dma_buf_export</span><span class="p">(</span><span class="n">exp_info</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="43-import-流程">4.3 Import 流程</h3>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>用户空间传递 fd 给 DRM driver
        ↓
drm_gem_prime_import()
        ↓
dma_buf_attach() + dma_buf_map_dma_buf()
        ↓
创建 GEM object 并返回
</code></pre></div></div>

<h3 id="44-prime-缓存机制">4.4 PRIME 缓存机制</h3>

<p>DRM 使用红黑树缓存 import/export 关系，避免重复创建：</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">drm_prime_member</span> <span class="p">{</span>
    <span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="n">dma_buf</span><span class="p">;</span>
    <span class="kt">uint32_t</span> <span class="n">handle</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">rb_node</span> <span class="n">dmabuf_rb</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">rb_node</span> <span class="n">handle_rb</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>

<p>这确保：</p>
<ul>
  <li>同一个 buffer 在同一进程内只有一个 handle</li>
  <li>用户空间可以检测重复 import</li>
</ul>

<hr />

<h2 id="五代码示例">五、代码示例</h2>

<h3 id="51-exporter-示例">5.1 Exporter 示例</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;linux/dma-buf.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/module.h&gt;</span><span class="cp">
</span>
<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">dma_buf_ops</span> <span class="n">exp_dmabuf_ops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">map_dma_buf</span> <span class="o">=</span> <span class="n">exporter_map_dma_buf</span><span class="p">,</span>
    <span class="p">.</span><span class="n">unmap_dma_buf</span> <span class="o">=</span> <span class="n">exporter_unmap_dma_buf</span><span class="p">,</span>
    <span class="p">.</span><span class="n">release</span> <span class="o">=</span> <span class="n">exporter_release</span><span class="p">,</span>
<span class="p">};</span>

<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">exporter_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">DEFINE_DMA_BUF_EXPORT_INFO</span><span class="p">(</span><span class="n">exp_info</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">dma_buf</span> <span class="o">*</span><span class="n">dmabuf</span><span class="p">;</span>

    <span class="n">exp_info</span><span class="p">.</span><span class="n">ops</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">exp_dmabuf_ops</span><span class="p">;</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">PAGE_SIZE</span><span class="p">;</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">flags</span> <span class="o">=</span> <span class="n">O_CLOEXEC</span><span class="p">;</span>
    <span class="n">exp_info</span><span class="p">.</span><span class="n">priv</span> <span class="o">=</span> <span class="s">"exporter"</span><span class="p">;</span>

    <span class="n">dmabuf</span> <span class="o">=</span> <span class="n">dma_buf_export</span><span class="p">(</span><span class="o">&amp;</span><span class="n">exp_info</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">IS_ERR</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">PTR_ERR</span><span class="p">(</span><span class="n">dmabuf</span><span class="p">);</span>

    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">MODULE_INFO</span><span class="p">(</span><span class="n">import_ns</span><span class="p">,</span> <span class="s">"DMA_BUF"</span><span class="p">);</span>
<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL v2"</span><span class="p">);</span>
</code></pre></div></div>

<h3 id="52-dma-fence-示例">5.2 DMA-fence 示例</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;linux/dma-fence.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/sync_file.h&gt;</span><span class="cp">
</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="nf">dma_fence_get_name</span><span class="p">(</span><span class="k">struct</span> <span class="n">dma_fence</span> <span class="o">*</span><span class="n">fence</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="s">"example-fence"</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">dma_fence_ops</span> <span class="n">fence_ops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">get_driver_name</span> <span class="o">=</span> <span class="n">dma_fence_get_name</span><span class="p">,</span>
    <span class="p">.</span><span class="n">get_timeline_name</span> <span class="o">=</span> <span class="n">dma_fence_get_name</span><span class="p">,</span>
<span class="p">};</span>

<span class="c1">// 创建 fence</span>
<span class="n">fence</span> <span class="o">=</span> <span class="n">kzalloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="o">*</span><span class="n">fence</span><span class="p">),</span> <span class="n">GFP_KERNEL</span><span class="p">);</span>
<span class="n">dma_fence_init</span><span class="p">(</span><span class="n">fence</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fence_ops</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">fence_lock</span><span class="p">,</span> <span class="n">context</span><span class="p">,</span> <span class="n">seqno</span><span class="p">);</span>

<span class="c1">// 信号 fence（生产者完成）</span>
<span class="n">dma_fence_signal</span><span class="p">(</span><span class="n">fence</span><span class="p">);</span>

<span class="c1">// 创建 sync_file 返回给用户空间</span>
<span class="n">sync_file</span> <span class="o">=</span> <span class="n">sync_file_create</span><span class="p">(</span><span class="n">fence</span><span class="p">);</span>
<span class="n">fd</span> <span class="o">=</span> <span class="n">get_unused_fd_flags</span><span class="p">(</span><span class="n">O_CLOEXEC</span><span class="p">);</span>
<span class="n">fd_install</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="n">sync_file</span><span class="o">-&gt;</span><span class="n">file</span><span class="p">);</span>
</code></pre></div></div>

<hr />

<h2 id="六总结">六、总结</h2>

<table>
  <thead>
    <tr>
      <th>机制</th>
      <th>作用</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>DMA-buf</strong></td>
      <td>提供跨设备、跨进程的缓冲区共享机制，通过 fd 传递</td>
    </tr>
    <tr>
      <td><strong>DMA-fence</strong></td>
      <td>提供缓冲区同步机制，解决生产者和消费者的时序问题</td>
    </tr>
    <tr>
      <td><strong>PRIME</strong></td>
      <td>DRM 框架中用户空间的导入/导出接口，连接 GEM 和 dma-buf</td>
    </tr>
  </tbody>
</table>

<p>三者配合工作流程：</p>

<pre><code class="language-mermaid">graph TD
    A[GPU 分配 Buffer] --&gt; B[dma_buf_export]
    B --&gt; C[PRIME Export 返回 fd]
    C --&gt; D[用户空间通过 Socket 传给另一个进程]
    D --&gt; E[另一个进程 PRIME Import]
    E --&gt; F[dma_buf_attach + map]
    F --&gt; G[获取 sg_table 进行 DMA]
    
    H[GPU 完成渲染] --&gt; I[dma_fence_signal]
    I --&gt; J[Display 等待 fence]
    J --&gt; K[Display 读取 buffer 显示]
</code></pre>

<p>理解这三个机制是深入 Linux 显示子系统的必经之路，特别是在研究 GPU 渲染、Video Codec、Camera 捕获等场景时尤为重要。</p>

<hr />

<p>感谢阅读！</p>]]></content><author><name>yangchao</name></author><category term="DRM" /><category term="DMA-buf" /><summary type="html"><![CDATA[]]></summary></entry></feed>