4. MIPI DSI(SDK V6.3.4开始)

概述

Display Serial Interface(DSI)接口是移动行业处理器接口联盟 (Mobile Industry Processor Interface alliance, MIPI联盟) 定义的一种高速串行接口,主要用于处理器和显示模块之间的连接。

本章介绍如何在 CVITEK 处理器解决方案上开发调试 MIPI LCD 屏, 以帮助客户有序快速开发 MIPI LCD 业务。

4.1. 环境准备

4.1.1. MIPI DSI 屏幕接口介绍

MIPI DSI 屏幕一般有以下几种信号,如图所示。

  • MIPI 时钟线(CLK)

  • MIPI 数据线(DATA),最大为 4 Lane(仅可以为 1/2/4 Lane)

  • 背光控制信号(BACKLIGHT)

  • 复位引脚(RESET)

  • Panel 电源供电(POWER)

MIPI DSI 接口连线示意图

_images/MIPIDS002.png

4.1.2. 硬件连线确认

检查硬件连线,确认无异常。具体有些引脚差异,需对照屏幕厂商提供的规格书及 电路原理图确认。

4.2. PanelSupportList 框架概览

SDK 通过 PanelSupportList 仓库统一管理所有屏参头文件, u-boot、cvi_mpi 和 AliOS 共用同一套屏参数据,但配置方式各有不同。

框架结构如下:

  • 屏参头文件:全部放在 PanelSupportList/panels/ 目录下,按规范命名。

三种系统的屏参引用方式:

  • u-boot / cvi_alios:通过 PanelSupportList/cvi_panels.h 汇总入口, 使用 CONFIG_ 宏在编译期选定唯一一块屏。cvi_panels.h 只支持单选, 不能同时使能多块屏。

  • cvi_mpi:在 sample_panel.h 中直接 #include 所有屏参头文件, 运行时通过 --panel= 命令行参数动态选择,可同时编译进所有屏参。

对接一块新 MIPI 屏的基本步骤:

  1. PanelSupportList/panels/ 下编写规范命名的屏参头文件。

  2. 根据目标系统选择注册方式(见下文)。

  3. 配置使能并构建。

4.3. 配置 MIPI 屏(统一流程)

4.3.1. 第 1 步:编写屏参头文件

4.3.1.1. 命名规范

头文件统一放在 PanelSupportList/panels/ 下,命名格式:

dsi_{driveric}_{wxh}_{moduleid}_{lanenum}lane_{fps}fps[_vN].h
  • driveric:驱动 IC,小写,例如 hx8394

  • wxh:有效分辨率,例如 720x1280

  • moduleid:屏幕模组 ID;不确定时用 NULL

  • lanenum:物理 DSI lane 数,例如 4lane

  • fps:目标刷新率,例如 60fps

  • _vN(可选):当同一 IC + 分辨率 + lane + fps 仍需区分不同硬件版本时使用。

示例:

dsi_hx8394_720x1280_NULL_4lane_60fps.h
dsi_st7701_480x640_NULL_2lane_60fps.h

4.3.1.2. 头文件内容模板

每个头文件必须包含 panel_platform.h(提供平台适配层和 DSI_CMD 等宏), 然后按顺序定义 timing 宏、设备配置、HS timing 和初始化命令。

以下是一个完整的范例:

#include "panel_platform.h"

/* ---- Timing 宏 ---- */
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_VACT   1280
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_VSA    16
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_VBP    4
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_VFP    6
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_HACT   720
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_HSA    64
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_HBP    36
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_HFP    128
#define DSI_HX8394_720X1280_NULL_4LANE_60FPS_FPS    60

/* ---- MIPI Tx 设备配置 ---- */
struct combo_dev_cfg_s dev_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps = {
    .devno = 0,
    .lane_id = {MIPI_TX_LANE_0, MIPI_TX_LANE_1, MIPI_TX_LANE_CLK,
                MIPI_TX_LANE_2, MIPI_TX_LANE_3},
    .lane_pn_swap = {true, true, true, true, true},
    .output_mode = OUTPUT_MODE_DSI_VIDEO,
    .video_mode = BURST_MODE,
    .output_format = OUT_FORMAT_RGB_24_BIT,
    .sync_info = {
        .vid_hsa_pixels = DSI_HX8394_720X1280_NULL_4LANE_60FPS_HSA,
        .vid_hbp_pixels = DSI_HX8394_720X1280_NULL_4LANE_60FPS_HBP,
        .vid_hfp_pixels = DSI_HX8394_720X1280_NULL_4LANE_60FPS_HFP,
        .vid_hline_pixels = DSI_HX8394_720X1280_NULL_4LANE_60FPS_HACT,
        .vid_vsa_lines = DSI_HX8394_720X1280_NULL_4LANE_60FPS_VSA,
        .vid_vbp_lines = DSI_HX8394_720X1280_NULL_4LANE_60FPS_VBP,
        .vid_vfp_lines = DSI_HX8394_720X1280_NULL_4LANE_60FPS_VFP,
        .vid_active_lines = DSI_HX8394_720X1280_NULL_4LANE_60FPS_VACT,
        .vid_vsa_pos_polarity = false,
        .vid_hsa_pos_polarity = true,
    },
    .pixel_clk = PIXEL_CLK(DSI_HX8394_720X1280_NULL_4LANE_60FPS),
};

/* ---- HS timing 配置 ---- */
struct hs_settle_s hs_timing_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps = {
    .prepare = 6, .zero = 32, .trail = 1
};

/* ---- 初始化命令 ---- */
struct dsc_instr dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps[] = {
    DSI_CMD(0,   0xb9, 0xff, 0x83, 0x94),
    DSI_CMD(0,   0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, 0x71, 0x31,
            0x4d, 0x2f, 0x56, 0x73, 0x02, 0x02),
    /* ... 更多初始化命令 ... */
    DSI_CMD(120, 0x11),       /* Sleep Out, delay 120ms */
    DSI_CMD(20,  0x29),       /* Display On, delay 20ms  */
};

4.3.1.3. 关键数据结构的说明

combo_dev_cfg_s(MIPI Tx 设备属性)

struct combo_dev_cfg_s {
    unsigned int devno;
    enum mipi_tx_lane_id lane_id[LANE_MAX_NUM];
    enum output_mode_e output_mode;
    enum video_mode_e video_mode;
    enum output_format_e output_format;
    struct sync_info_s sync_info;
    unsigned int pixel_clk;
    bool lane_pn_swap[LANE_MAX_NUM];
};

成员名称

描述

devno

MIPI Tx 设备号,默认 0

lane_id

主控端和屏端 Lane 号的对应关系,未使用的 Lane 填 -1 即可。

共 5 个成员,依序分别代表主控端的 MIPI_TX_0 ~ MIPI_TX_4, 实际填写的内容需要根据对应到屏端的 MIPI lane 号。

例如,第一个成员是主控 MIPI_TX_0,查电路原理图对应到屏端的 MIPI lane3, 就填写为 MIPI_TX_LANE_3。

对应关系不正确,将导致屏幕无法点亮。

output_mode

MIPI Tx 输出模式,默认 OUTPUT_MODE_DSI_VIDEO

video_mode

MIPI Tx 视频模式,默认 BURST_MODE

output_format

MIPI Tx 输出格式,默认 OUT_FORMAT_RGB_24_BIT

sync_info

MIPI Tx 设备的同步信息(详见下方)

pixel_clk

像素时钟,单位为 KHz。

使用 PIXEL_CLK(x) 宏自动计算:

#define PIXEL_CLK(x) \
    ((x##_VACT + x##_VSA + x##_VBP + x##_VFP) \
     * (x##_HACT + x##_HSA + x##_HBP + x##_HFP) * x##_FPS / 1000)

lane_clk 根据 pixel_clk 反推,换算公式:

lane_clk = pixel_clk × 24 / 4 / 2(24 表示 RGB888 每个 pixel 占 24 bits, 4 表示使用了 4 条 Data Lane,2 表示 MIPI clk 是双边沿触发)

lane_pn_swap

MIPI Tx 的 Lane P/N 极是否交换

true:交换 false:不交换

sync_info_s(MIPI Tx 设备同步信息)

struct sync_info_s {
    unsigned short vid_hsa_pixels;
    unsigned short vid_hbp_pixels;
    unsigned short vid_hfp_pixels;
    unsigned short vid_hline_pixels;
    unsigned short vid_vsa_lines;
    unsigned short vid_vbp_lines;
    unsigned short vid_vfp_lines;
    unsigned short vid_active_lines;
    bool vid_vsa_pos_polarity;
    bool vid_hsa_pos_polarity;
};

成员名称

描述

vid_hsa_pixels

水平同步脉冲(HSA),单位为像素

vid_hbp_pixels

水平消隐后肩(HBP),单位为像素

vid_hfp_pixels

水平消隐前肩(HFP),单位为像素

vid_hline_pixels

水平有效区(HACT),单位为像素

vid_vsa_lines

垂直同步脉冲(VSA),单位为行

vid_vbp_lines

垂直消隐后肩(VBP),单位为行

vid_vfp_lines

垂直消隐前肩(VFP),单位为行

vid_active_lines

垂直有效区(VACT),单位为行

vid_vsa_pos_polarity

垂直有效信号的极性,false 为高有效,true 为低有效

vid_hsa_pos_polarity

水平有效信号的极性,false 为高有效,true 为低有效

MIPI DSI 协议下 MIPI 像素区域示意图

_images/MIPIDS003.png

建议先将屏厂规格书中的 timing 参数定义为宏(使用头文件 stem 的大写形式作为前缀), 再在 sync_info 中引用,避免裸常量分散在各处难以维护。

hs_settle_s(MIPI Tx HS timing)

struct hs_settle_s {
    unsigned char prepare;
    unsigned char zero;
    unsigned char trail;
};

成员名称

描述

prepare

MIPI Tx prepare 信号,默认值 6

zero

MIPI Tx zero 信号,默认值 32

trail

MIPI Tx trail 信号,默认值 1

MIPI Tx 时序图

_images/MIPIDS004.png

4.3.1.4. 初始化命令

屏幕初始化命令通过 DSI_CMD() 宏定义,不需要手动写 data_typesize。 宏会自动按数据字节数选择 data type:

  • 1 字节 → 0x05(只有寄存器地址,无数据)

  • 2 字节 → 0x15(寄存器地址 + 1 个数据)

  • 3 字节及以上 → 0x29(寄存器地址 + 2 个及以上数据)

/* 第一个参数始终是 delay(发送后延时,单位 ms),后面是寄存器地址 + 数据 */
#define DSI_CMD(delay_ms, ...)  \
    {.delay = (delay_ms),       \
     .data_type = ...,          \
     .size = sizeof(...),       \
     .data = (CVI_U8[]){__VA_ARGS__} }

使用示例:

struct dsc_instr dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps[] = {
    DSI_CMD(0,   0xb9, 0xff, 0x83, 0x94),  /* 多字节,自动选 0x29 */
    DSI_CMD(0,   0x36, 0x02),               /* 2 字节,自动选 0x15 */
    DSI_CMD(120, 0x11),                     /* Sleep Out,1 字节 → 0x05 */
    DSI_CMD(20,  0x29),                     /* Display On */
};

如果屏厂指定了不同的 data type(如 0x230x39),使用 DSI_CMD_TYPE 显式指定:

DSI_CMD_TYPE(0, 0x39, 0xff, 0x77, 0x01, 0x00),

初始化序列由屏厂商提供,具体指令含义请在屏厂规格书或 Driver IC Datasheet 中查找。

4.3.2. 第 2 步:注册屏参头文件

根据目标系统选择对应的注册方式。

4.3.2.1. u-boot / cvi_alios 注册方式(cvi_panels.h)

PanelSupportList/cvi_panels.h 中增加一个 #elif 块。 cvi_panels.h 是 u-boot 和 cvi_alios 共用的编译期单选入口, 通过 CONFIG_ 宏决定使用哪一块屏,不能同时选择多块屏

#elif CONFIG_DSI_HX8394_720X1280_NULL_4LANE_60FPS
#include "panels/dsi_hx8394_720x1280_NULL_4lane_60fps.h"
static struct panel_desc_s panel_desc = {
    .panel_name = "HX8394-720x1280-NULL-4lane-60fps",
    .dev_cfg = &dev_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps,
    .hs_timing_cfg = &hs_timing_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps,
    .dsi_init_cmds = dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps,
    .dsi_init_cmds_size = ARRAY_SIZE(dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps),
};

说明:

  • CONFIG_ 宏由头文件 stem 大写派生(dsi_hx8394_720x1280_NULL_4lane_60fpsCONFIG_DSI_HX8394_720X1280_NULL_4LANE_60FPS)。

  • 不再使用旧式 MIPI_PANEL_HX8394 等别名,统一使用 CONFIG_ 宏。

4.3.2.2. cvi_mpi 注册方式(sample_panel.h + sample_panel.c)

cvi_mpi 不使用 cvi_panels.h,而是在 sample_panel.h 中直接 include 所有屏参头文件,运行时通过命令行参数选择。

  1. sample_panel.h 中添加 #include

#include "dsi_hx8394_720x1280_NULL_4lane_60fps.h"
  1. sample_panel.cSAMPLE_SET_PANEL_DESC 函数中增加 case:

case DSI_PANEL_HX8394_EVB:
    g_panel_desc.panel_type = PANEL_MODE_DSI;
    g_panel_desc.stdsicfg.dev_cfg =
        (struct combo_dev_cfg_s *)&dev_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps;
    g_panel_desc.stdsicfg.hs_timing_cfg =
        &hs_timing_cfg_dsi_hx8394_720x1280_NULL_4lane_60fps;
    g_panel_desc.stdsicfg.dsi_init_cmds =
        dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps;
    g_panel_desc.stdsicfg.dsi_init_cmds_size =
        ARRAY_SIZE(dsi_init_cmds_dsi_hx8394_720x1280_NULL_4lane_60fps);
    break;

cvi_mpi 方式支持编译进所有屏参,运行时用 ./sample_panel --panel=xxx 切换,适合调试阶段快速验证。

4.3.3. 第 3 步:配置使能并构建

4.3.3.1. u-boot 配置

首先运行脚本生成 Kconfig(扫描 panels/ 目录下所有 .h 文件):

cd PanelSupportList
python3 gen_panel_config.py

生成的 Kconfig.panels 供 u-boot 使用,包含类似以下内容:

config DSI_HX8394_720X1280_NULL_4LANE_60FPS
    bool "dsi_hx8394_720x1280_NULL_4lane_60fps"
    help
      "y" Config dsi_hx8394_720x1280_NULL_4lane_60fps.

然后通过以下任一方式使能:

  • make u-boot-menuconfig 进入图形界面选择面板。

  • 或在 build/boards/<board>/u-boot/<board>_defconfig 中添加 CONFIG_DSI_HX8394_720X1280_NULL_4LANE_60FPS=y

4.3.3.2. cvi_alios 配置

cvi_alios/solutions/normboot/package_yamls/package.yaml.turnkey 中设置对应的宏为 1,其余置 0:

CONFIG_DSI_HX8394_720X1280_NULL_4LANE_60FPS: 1
CONFIG_PANEL_HX8394: 0

注:旧的 CONFIG_PANEL_xxx 别名保留但置 0,新屏统一用 CONFIG_DSI_xxx

4.3.3.3. cvi_mpi 配置

cvi_mpi 无需编译期配置,所有屏参已在 sample_panel.h 中 include。 编译后通过命令行选择:

./sample_panel --panel=HX8394_EVB

4.3.3.4. 构建

完成上述配置后,执行 build_all 即可完成全系统构建。

4.4. RESET / POWER / BACKLIGHT 管脚配置

三种系统中仅 u-boot 支持通过设备树自动控制 GPIO; cvi_mpi 和 cvi_alios 需要在代码中手动操作 GPIO。

4.4.1. u-boot 配置方式(DTS)

u-boot 通过设备树(DTS)配置 GPIO。 在 build/boards/default/dts/cv184x/cv184x_base.dtsimipi_tx 节点中配置:

mipi_tx: mipi_tx {
    compatible = "cvitek,mipi_tx";
    reset-gpio = <&porte 2 GPIO_ACTIVE_LOW>;
    pwm-gpio = <&porte 0 GPIO_ACTIVE_HIGH>;
    power-ct-gpio = <&porte 1 GPIO_ACTIVE_HIGH>;
    clocks = <&clk CV181X_CLK_DISP_VIP>, <&clk CV181X_CLK_DSI_MAC_VIP>;
    clock-names = "clk_disp", "clk_dsi";
};

说明:

  • reset-gpio:复位引脚,按屏规格书填写 GPIO 组、序号和有效电平。 驱动根据 GPIO_ACTIVE_LOW / GPIO_ACTIVE_HIGH 自动产生 high-low-high(或 low-high-low)复位时序。

  • pwm-gpio:背光控制。调试阶段可先用 GPIO 控制点亮背光; 后续如需调节亮度,配置 pinmux 为 PWM 功能后将此行删除,改用 PWM 方式。

  • power-ct-gpio:Panel 电源控制。如屏幕直接供电无需软件控制则删除。

  • 管脚对应的 GPIO 组号和序号,对照《CV184X_PINOUT_CN》确认。

  • 不需要的管脚直接不写对应 DTS 属性,驱动加载时自动跳过。

4.4.2. cvi_mpi 配置方式(手动 GPIO)

cvi_mpi 不解析 DTS 中的 GPIO 属性,需在应用层通过 sysfs 或 sample_panel 命令行参数手动控制。

4.4.2.1. 方式一:sample_panel 命令行参数(仅调试用,代码中已注释)

运行时传入 GPIO 编号:

./sample_panel --panel=HX8394_EVB --gpio=354,0,353,1,352,1

三个 GPIO 依次为 RESET、POWER、PWM,每个 GPIO 两个参数(编号 + 电平)。

4.4.2.2. 方式二:shell 手动操作 sysfs

先通过 cat /sys/kernel/debug/gpio 查看 GPIO 编号范围, 确认各 GPIO 组对应的起始编号后,计算目标管脚的全局编号:

# 假设 RESET=GPIOE2(354), POWER=GPIOE1(353), PWM=GPIOE0(352)
echo 352 > /sys/class/gpio/export
echo 353 > /sys/class/gpio/export
echo 354 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio352/direction
echo out > /sys/class/gpio/gpio353/direction
echo out > /sys/class/gpio/gpio354/direction
echo 1 > /sys/class/gpio/gpio352/value    # 背光点亮
echo 1 > /sys/class/gpio/gpio353/value    # 电源使能
echo 1 > /sys/class/gpio/gpio354/value    # RESET 拉高
sleep 0.02
echo 0 > /sys/class/gpio/gpio354/value    # RESET 拉低
sleep 0.02
echo 1 > /sys/class/gpio/gpio354/value    # RESET 拉高

调试阶段背光可先用 GPIO 控制;后续需调节亮度时, 在 u-boot 中配置 pinmux 为 PWM 功能,则在命令中省略背光 GPIO。

4.4.3. cvi_alios 配置方式(PLATFORM_PanelInit)

cvi_alios 不解析设备树,GPIO 控制在 PLATFORM_PanelInit 接口中手动完成。 该函数位于板级定制目录下,例如:

cvi_alios/solutions/normboot/customization/<board>/src/custom_platform.c

PLATFORM_PanelInit 中通过 _GPIOSetValue 手动控制各管脚:

int PLATFORM_PanelInit(void)
{
#if CONFIG_PANEL_HX8394
    u8 pw_port, pw_pin, bl_port, bl_pin, rst_port, rst_pin;
    pw_port = 4;  pw_pin = 1;   /* POWER  → GPIOE1 */
    bl_port = 4;  bl_pin = 0;   /* BACKLIGHT → GPIOE0 */
    rst_port = 4; rst_pin = 2;  /* RESET  → GPIOE2 */
    _GPIOSetValue(pw_port, pw_pin, 1);
    _GPIOSetValue(bl_port, bl_pin, 1);
    _GPIOSetValue(rst_port, rst_pin, 1);
    udelay(20 * 1000);
    _GPIOSetValue(rst_port, rst_pin, 0);
    udelay(20 * 1000);
    _GPIOSetValue(rst_port, rst_pin, 1);
    udelay(20 * 1000);
#endif
    return CVI_SUCCESS;
}

说明:

  • port 为 GPIO 组号:0 = GPIOA, 1 = GPIOB, …, 4 = GPIOE。

  • pin 为组内序号,对照《CV184X_PINOUT_CN》确认。

  • 复位时序需参考屏规格书,通常为 high-low-high(或 low-high-low)。

  • 新增屏参时需在 PLATFORM_PanelInit 中添加对应的 #if CONFIG_xxx 分支。

  • 如需 PWM 调节背光亮度,另外配置 pinmux 和 PWM 寄存器,此处仅做 GPIO 控制。

4.6. 编译烧写验证

在上述步骤均完成后,重新编译烧写。上电后可验证 MIPI 屏是否正常点亮。

如果未正常显示,按以下步骤排查:

  1. 确认背光点亮。

  2. 确认 RESET 管脚电平状态达到预期(如 high-low-high)。

  3. 确认屏幕供电正常。

  4. 执行 devmem 0x0a094094 32 0x0701000a 使能 VO test pattern, 如果屏幕初始化成功,会看到 colorbar。

test pattern 寄存器如下图:

_images/MIPIDS005.png

如果 test pattern 正常但无显示画面,问题通常在初始化序列或 timing 参数; 如果 test pattern 也不正常,检查 MIPI Lane 顺序、RESET/POWER/PWM 配置, 并使用万用表/示波器确认电路电平。

建议查看 Driver IC datasheet 或咨询屏幕厂商,开启屏的 BIST mode (通常是调整初始化序列中的某个寄存器值),可快速判断是主控端配置问题还是 屏幕本身问题。

  • BIST 不正常 → 检查 Lane 顺序 / RESET / POWER / PWM 及硬件电路,或咨询屏厂。

  • BIST 正常 → 配置与硬件无异常,重点调整 sync_info_s 中的 timing 参数。

调试技巧:可先在 cvi_mpi 侧用 sample_panel 工具快速验证屏参, 命令格式为 ./sample_panel --panel=<PANEL_NAME>。调通后再全系统构建验证, 避免反复烧写 u-boot。