MIPI(移动行业处理器接口)是Mobile Industry Processor Interface的缩写。MIPI(移动行业处理器接口)是MIPI联盟发起的为移动应用处理器制定的开放标准。其中 DSI(Display Serial Interface)定义了一个位于处理器和显示模组之间的高速串行接口。目前MIPI DSI是大多数SOC上面的标配。RK3399上面有两组DSI,Tinker board 2将其中一组DSI引出。本文以YYT_MIPI7LCD_2203为例介绍如何在tinker board 2s的Debian下面使用MIPI DSI接口。另外,与移动应用处理器适配的屏幕通常会带有触摸功能,本文也一并介绍。
要针对 MIPI-DSI接口触摸屏 定制Debian固件,需要先进行如下准备工作
修改好的Debian固件需要用瑞芯微烧录工具烧录。不能使用balena-etcher烧录。
其中Debian固件笔者用的是下图的这个,这个可以直接用瑞芯微烧录工具烧录,调试起来较为方便,如果使用的是其他固件,可以用dd命令直接烧录某个分区以替代。

无论用哪个固件,需要先把整个debian系统烧录到Tinker board 2里面,适配 MIPI-DSI接口触摸屏 只需要修改内核部分,其他部分不需要修改。
下面将分别介绍MIPI-DSI接口的适配方法和I2C触摸功能的适配方法
除了Tinkerboard 2/2S以及触摸屏之外,建议准备个大功率的电源,电源要用12V 2A的,不然带不动屏幕,屏幕电源要由主板提供,且电源质量要比较好,不然会干扰屏幕显示。
在购买YYT MIPI7 LCD 2203的时候,会附带一个转接板,其定义如下

然后需要接线,在上图中已经标明了转接板上面的接口,其中
接线的图如下

触摸复位 触摸中断 TCON电源 TCON使能脚 可以根据实际情况另外选择,此处只是给出一种参考
无论通过github还是网盘下载源码,都至少需要kernel和prebuilts两个目录,前者是内核源码目录,后者是交叉编译器目录,这两个文件夹必须在同一文件夹下,否则无法编译

如果读者希望直接修改,并不想了解其原理,可以略过下面的部分,直接看 相关源码下载与替换说明 章节。
简单介绍一下目前 RK3399的显示框架。目前的Debian采用的都是Linux DRM框架进行显示,在DRM框架中,其显示通路如下图所示

图中的几个组成部分
Framebuffer:显存,嵌入式系统使用的是内存的一部分
CRTC:显示控制器,在RK3399平台是SOC 内部VOP,RK3399里面包含两个VOP;
Encoder:输出转换器,指RGB、LVDS、DSI、eDP、HDMI、CVBS、VGA 等显示接口,它本质就是一个编码器,将CRTC提供过来的信号编码为对应显示接口需要的信号。
Connector:连接器,指encoder 和panel 之间交互的接口部分;
Panel:各种具体的屏幕
因此,要驱动DSI屏幕,有三个部分需要配置,包括VOP,DSI控制器,屏幕的参数。
首先开启vopb与vopl,设置时钟与MMU
&vopb {
    //打开vopb的功能
    status = "okay";
    //指定vopb的时钟,接HDMI的那个VOP clock-parents必须指定为PLL_VPLL
    assigned-clocks = <&cru DCLK_VOP0_DIV>;
    assigned-clock-parents = <&cru PLL_VPLL>;
    support-multi-area;
};
//启用mmu
&vopb_mmu {
    status = "okay";
};
&vopl {
    //打开vopl的功能
    status = "okay";
    //指定vopl的时钟,不接HDMI的VOP clock-parents用PLL_CPLL
    assigned-clocks = <&cru DCLK_VOP1_DIV>;
    assigned-clock-parents = <&cru PLL_CPLL>;
    support-multi-area;
};
//启用mmu
&vopl_mmu {
    status = "okay";
};
然后需要设置vop与显示接口之间的绑定关系,以DSI+HDMI为例
// vopl绑定到dsi
&dsi_in_vopl {
    status = "okay";
};
&dsi_in_vopb {
    status = "disabled";
};
// vopb绑定到hdmi
&hdmi_in_vopb {
    status = "okay";
};
&hdmi_in_vopl {
    status = "disabled";
};
修改DSI和panel的配置。其中panel的配置,是参考风火轮的wiki, http://wiki.smartfire.cn/Tinkerboard2/lcd
&dsi {
    status = "okay";
    //配置dsi每个lane的频率,一般出现花屏,条纹等可以调整这个值改善
    //如果这个值不配置,DSI驱动会自动计算
    rockchip,lane-rate = <500>;
    panel@0 {
        //屏幕的具体参数,使用dsi接口的屏幕其属性必须是simple-panel-dsi
        compatible = "simple-panel-dsi";
        reg = <0>;
        //背光,即使不启用背光调节功能,这个属性也必须配置,且backlight的节点必须是有效的
        //否则驱动会加载失败
        backlight = <&backlight>;
        //使能脚,如果enable 接到一个gpio,这个属性必须设置
        enable-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
        //这些根据规格书填写即可
        bpc = <8>;
        bus-format = <0x100a>;
        width-mm = <476>;
        height-mm = <267>;
        
        dsi,flags = <3>;
        dsi,format = <0>;
        dsi,lanes = <4>;
        //屏幕初始化序列,屏厂会提供
        panel-init-sequence = [
            15 00 02 80 ac
            15 00 02 81 b8
            15 00 02 82 09
            15 00 02 83 78
            15 00 02 84 7f
            15 00 02 85 bb
            15 00 02 86 70
        ];
        display-timings {
            native-mode = <&timing2>;
            //下面timing的参数按wiki上面的
            timing2: timing2 {
                clock-frequency = <52000000>; //DCLK
                hactive = <1024>;             //hactive
                vactive = <600>;              //vactive
                hfront-porch = <160>;         //hfp
                hback-porch = <160>;          //hbp
                hsync-len = <10>;             //hsa
                vfront-porch = <12>;          //vfp
                vsync-len = <1>;              //vsa
                vback-porch = <23>;           //vbp
                hsync-active = <0>;           //hync 极性控制 置 1 反转极性
                vsync-active = <0>;           //vsync 极性控制 置 1 反转极性
                de-active = <1>;              //DEN 极性控制
                pixelclk-active = <0>;        //dclk 极性控制
            };
        };
        //这个ports是panel的,这个port要和dsi对应的port绑定
        ports {
            #address-cells = <1>;
            #size-cells = <0>;
            port@0 {
                reg = <0>;
                panel_in_dsi: endpoint {
                    remote-endpoint = <&dsi_out_panel>;
                };
            };
        };
    };
    //这个ports是dsi的,这个port要和目标panel的port绑定
    ports {
        #address-cells = <1>;
        #size-cells = <0>;
        port@1 {
            reg = <1>;
            dsi_out_panel: endpoint {
                remote-endpoint = <&panel_in_dsi>;
            };
        };
    };
};
除了设备树之外,DSI的驱动和panel的驱动也需要修改,因为asus为了适配其他的屏幕,修改过rk原始的代码,所以要更换回rk原始的代码,可以直接在文末下载
到这里,MIPI-DSI部分的修改就完成了
7寸屏幕的触摸芯片为GT911,这是汇顶科技的触摸芯片,支持7-8寸屏,最多5点触摸。内核自带其驱动,路径为drivers/input/touchscreen/gt9xx。内核config要将CONFIG_TOUCHSCREEN_GT9XX设置为Y。默认的config文件已经配置好,不需要修改
然后设备树需要将gt911加入i2c8下,如下
&i2c8 {
    goodix_ts@5d {
        compatible = "goodix,gt9xx";
        reg = <0x5d>;                                   //也可以填0x14
        touch-gpio = <&gpio2 RK_PC3 GPIO_ACTIVE_LOW>;   //中断IO
        reset-gpio = <&gpio2 RK_PC2 GPIO_ACTIVE_LOW>;   //复位IO
        max-x = <1024>;                                 //x方向解析度
        max-y = <600>;                                  //y方向解析度
        tp-size = <911>;                                //与源码中选择的配置相关
        status = "okay"; 
    };
};
通过配置GT911上电时中断脚和复位脚电平时序,可以切换其I2C地址为0x5d和0x14的其中之一,这一设计是为了解决I2C冲突,这里可以任选一个
touch-gpio是中断脚,reset-gpio是复位脚,配置和硬件接线一致
max-x和max-y分别是x方向和y方向最大值,按屏的分辨率填写即可
tp-size对应的是源码中触摸配置文件的选择,这里填911
源码中有几个点需要修改一下。在gt9xx目录中找到gt9xx.c,

这里将gtp_change_x2y设置为false,不交换x和y的坐标上报值
然后找到gt9xx_cfg.h,将配置文件换掉,配置文件可以从下一章的源码下载中获取,将整个gt911目录下载下来里面就有,文件名为GT911_Config_20220510_094105.cfg

这里简单提一下GT911的工作原理。GT911的寄存器地址从0x8047开始,到0x8100,总共186个字节,为GT911的配置文件,datasheet中部分寄存器的功能说明如下

完整版本的可以直接查阅GT911 datasheet。这些寄存器的值与外屏,触摸芯片的贴合,接线等强相关,一般屏厂会提供这些信息,然后将这些值放到一个cfg文件中。下面可以大致看下其源码

在gt9xx_cfg.h中,将GT911_Config_20220510_094105.cfg中186个字节赋值给数组gtp_dat_gt11
然后在gt9xx.c中,将这个gtp_dat_gt11中的内容memcpy到名为config的数组中,然后在初始化的时候,会将名为config的数组内容写入到0x8047开头的寄存器中。这就是配置文件下载的流程
替换文件 drivers/gpu/drm/rockchip/dw-mipi-dsi.c
替换文件 drivers/gpu/drm/panel/panel-simple.c
替换文件 arch/arm64/boot/dts/rockchip/rk3399-tinker_board_2.dts
替换文件 arch/arm64/boot/dts/rockchip/rk3399-tinker_board_2.dtsi
解压后替换文件夹 drivers/input/touchscreen/gt9xx 注意替换之后整个文件夹给777权限
如果替换之后没有生效,请检查源文件修改的时间是不是早于.o输出文件的修改时间,按gcc的编译规则,这种情况是不会重新编译的
如果用户在上方的 debian源码百度盘下载 链接处下载了完整版本的SDK,此时可以按照上一章节的方法替换源码,内核源码在sdk里面的kernel目录,如下图

此外,目前asus使用了dtbo机制,编译系统的时候,会生成若干个适配了其他屏幕的dtbo文件在oem目录下,这些dtbo会对设备树进行overlay操作,导致上一章节针对设备树的修改失效,因此可以参考下面的patch,修改device/rockchip/tinker_board_2下面的编译脚本
替换之后,在sdk目录下执行
./build.sh
会生成固件,固件位于 rockdev/update.img

烧录参考下面的章节,先使开发板进入maskrom模式
然后按照下图的方式进行烧录

按上述方式修改并编译,下载到板上之后,注意查看串口的log
这个log里面显示dsi的时钟及分辨率,说明dsi控制器已经工作,dsi控制器已经绑定到drm框架中,dsi控制器和panel已经绑定,且输出这个log的时候,一般屏幕上面会显示一些图像

这个log说明触摸已经能正常工作

最终显示的效果如下

另外说明一下,目前debian上面如果接双屏,虽然能异显,但是不能异触,就是触摸只有一个,所以,如果同时接DSI和HDMI时,要注意选择当前操作的屏幕
如果用户使用的是其他的屏幕,可以直接找供应商拿到屏幕参数和触摸配置文件,触摸配置文件直接替换gt9xx中的配置,而屏参直接填入设备树