MTK Command Mode 下,LCM 驱动通过 MIPI DSI 向 LCD IC 发送图像更新前置命令的实现。它虽不直接搬运像素数据,却是触发屏幕刷新的关键一步。下面从代码细节到协议层逐步解释数据是如何“写入”LCD IC 的。
1. 函数意图:设置更新窗口并打开 GRAM 写通道
在 MIPI DCS(Display Command Set)标准中,IC 内部的 GRAM 写入通常分三步:
- 2Ah:设置列地址(Column Address),即 X 方向范围。
- 2Bh:设置页/行地址(Page/Row Address),即 Y 方向范围。
- 2Ch:写内存开始(Write Memory Start)。发完这个命令后,IC 内部状态机进入“等待像素数据”模式,后续 DSI 主机送来的任何长包数据都会被自动写入已设定的矩形区域。
lcm_update 的参数 x, y, width, height 就决定了这个矩形区域。函数里先算出结束坐标 x1, y1,然后分别拆成 8 位量,通过命令 2Ah/2Bh 发给 IC,最后补一个 2Ch 命令。注意:这段代码里没有看到像素数据本身,这是因为像素数据是通过 CMDQ 引擎在 2Ch 之后自动从 framebuffer 搬运的,这个函数只负责“预备动作”。
2. 数据打包:data_array的结构与含义
每个 data_array 元素是一个 32 位字,它们共同描述一个DSI 协议命令包,交由 dsi_set_cmdq 投递给硬件。
2.1 设置列地址(2Ah)的包
data_array[0] = 0x00093902; data_array[1] = (0x00 << 24) | (x0_MSB << 16) | (0x00 << 8) | 0x2a; data_array[2] = (0x00 << 24) | (x1_MSB << 16) | (0x00 << 8) | x0_LSB; data_array[3] = (x1_LSB); dsi_set_cmdq(data_array, 4, 1);
第 [0] 个字0x00093902是 MTK DSI 驱动的“长包描述符头”,将它按小端字节序拆开:
- 字节0:0x02 → 标志位(通常表示虚拟通道 VC=0、使用 HS 模式等)
- 字节1:0x39 →Data ID = 0x39,即 MIPI DCS Long Write(长写)
- 字节2:0x09 → 有效负载长度低字节
- 字节3:0x00 → 有效负载长度高字节 → 负载总长度 = 0x0009 = 9 字节。
后续 data_array[1] ~ [3] 共 3 个 32 位字,只取其低 8 位拼凑出 9 字节 payload(最后 x1_LSB 单独占一个字节,其余高 24 位为 0,硬件会忽略)。这 9 字节正是:
0x2A, 0x00, x0_MSB, 0x00, x0_LSB, 0x00, x1_MSB, 0x00, x1_LSB
为什么这么多 0x00?MIPI DCS 要求 16 位坐标参数以大端序传输,所以每个参数后跟 0x00 高字节,本质上就是 4 个参数:Xstart_Hi=0, Xstart_Lo=x0, Xend_Hi=0, Xend_Lo=x1,共 8 字节,外加命令码本身 1 字节,总共 9 字节。
2.2 设置页地址(2Bh)的包
构造方式与 2Ah 完全一样,只是命令码换成 0x2B,参数换为 Y 方向坐标。dsi_set_cmdq(data_array, 4, 1) 再次将 Y 范围发送出去。
2.3 写内存启动(2Ch)的包
data_array[0] = 0x002c3909; dsi_set_cmdq(data_array, 1, 0);
这一次只传递一个 32 位字。0x002c3909 按小端解读:
- 字节0:0x09 → 标志(同上)
- 字节1:0x39 → Data ID 仍为 Long Write
- 字节2:0x2C → 负载长度低位 = 0x2C?这明显不符逻辑(不可能长度 44 字节)。实际上这里 MTK 驱动进行了特殊编码:当负载长度为 0 时,这个 32 位字直接内嵌了短命令。 更合理的解释是:这个字构成了一个DCS Short Write 包——命令 0x2C 不带参数。对应的 MIPI Data ID 应为 0x05(Short Write 1 byte),而 0x09 可能指代带参数的短写?但无论如何,硬件通过这个描述符就能发送一个仅包含 0x2C 的命令,不用附加数据。参数 1 和 0 分别表示一次发送的字数和模式(HS/LP,这里 0 常代表 High Speed)。
3.dsi_set_cmdq与底层硬件工作流程
dsi_set_cmdq 是 MTK 平台提供的 DSI 命令传输接口。它做的事情:
- 将 data_array 中的描述符直接写入DSI 控制器的 Command Queue(CMDQ)或Config Register。
- DSI 控制器硬件解析描述符,生成符合 MIPI 协议的Serial Packet:
- 对于前两个包(2Ah/2Bh),构造一个Long Packet:
- SoT(Start of Transmission)→Packet Header(Data ID=0x39, Word Count=9, ECC)→Payload(9 字节)→EoT。
- 对于最后一个包(2Ch),构造一个Short Packet(Data ID 0x05 或 0x15):
- SoT → Packet Header(Data ID 短写类型, 命令码 0x2C, ECC)→ EoT。
- 物理层MIPI D-PHY将并行的 Packet 串行化,通过数据 Lane 的差分线发送到 LCM。
关键点:当 IC 收到 2Ch 命令后,内部状态机已准备接收像素数据。此时,与 CMDQ 联动的DMA(直接接在 framebuffer 的物理地址上)会自动启动下一段传输——将一整帧像素数据以DSI Long Packet(Data ID 0x39)的形式,紧跟着 2Ch 命令送出。这个 DMA 传输并非在 lcm_update 函数内直接触发,而是由 CMDQ 调度引擎在命令序列完成后自动衔接的。因此,lcm_update 只是将“触发命令”推入队列,实际的数据海量传输全部由硬件自动完成,CPU 完全不参与搬运。