Rockchip RK3588:MIPI-DSI2深度解析

Rockchip RK3588 MIPI-DSI2 详解

目录

文章目录

  • Rockchip RK3588 MIPI-DSI2 详解
  • @[toc]
  • Introduction
  • MIPI-DSI2 Features
  • MIPI DSI-2 Host 与 MIPI DSI Host 的差别
  • MIPI DPHY 差别
  • 应用领域
  • 驱动代码说明:
  • uboot
  • 驱动位置
  • 驱动配置
  • kernel
  • 驱动位置
  • 驱动配置
  • 参考设备树
  • 屏端配置
  • DTS 配置
  • 配置说明
  • 通用配置
  • display Timing
  • dsi,flags
  • CLK Type
  • Eotp
  • BLANK_HS_EN
  • 屏上电时序
  • 屏下电时序
  • 初始化序列常见数据类型
  • Display Route
  • MIPI with DSC
  • MIPI with DSC Bypass
  • DTS 配置
  • 开机LOGO
  • route_dsi0
  • route_dsi1
  • route_dsi0 && route_dsi1
  • DSI HOST
  • 单 DSI
  • DSI0
  • DSI1
  • 双通道 DSI
  • Dual-link DSI
  • DCPHY
  • D-PHY
  • C-PHY
  • 协议分析
  • DSI Layer Definitions
  • D Option
  • Lane states and line levels
  • Global Operation Flow Diagram
  • Escape Modes
  • Escape Commands
  • LPDT
  • ULPS
  • HSDT
  • BTA
  • Endian Policy
  • SPa
  • LPDT-SPa
  • HSDT-SPa
  • LPa
  • LPDT-LPa
  • HSDT-LPa
  • DI
  • Video Mode Interface Timing
  • Horizontal Display Timing (Video mode)
  • Non-Burst Mode with Sync Pulses
  • Burst Mode
  • 常见问题
  • 查看VOP timing 和 Connector 信息
  • 查看 DSI2 相关 clk tree
  • 如何查看指定 DSI lane 速率
  • MIPI DSI2 HOST 没有自己color bar 功能,通过如下命令可以让 VOP2 投显 color bar
  • 如何判断显示异常的时候,MIPI DSI2 和 panel 是否通信正常
  • backlight驱动probe失败
  • Command Mode 显示模组如何配置 TE
  • 双通道MIPI切换主从顺序
  • 调试节点
  • Patch
  • 驱动强度
  • 共模电压
  • cap peaking
  • 信号timing
  • Tlpx
  • Ths_prepare_or_prepare_3
  • Ths_zero_or_prebegin_3
  • Ths_trail_or_post_3
  • Ths_exit
  • High-Speed Driver Up Resistor Control
  • High-Speed Driver Down Resistor Control
  • Introduction

    DSI-2 是 MIPI 联盟定义的一组通信协议的一部分, DWC-MIPI-DSI2 是一个实现 MIPI-DSI2 规范中定义的所有协议功能的数字核控制器,可以兼容 D-PHY 和 C-PHY 的物理接口,支持两路的 Display Stream Compression (DSC) 数据传输, RK3588 有两个 DSI-2 控制器和两个独立的物理的 D/C-PHY, 可以同时最多支持两路 MIPI 输出。

    MIPI-DSI2 Features

    1. MIPI® Alliance Specification for Display Serial Interface 2 (DSI-2) Version 1.1
    2. MIPI® Alliance Specification for Display Command Set (DCS) Version 1.4
    3. MIPI® Alliance Specification for D-PHY v2.0
    4. MIPI® Alliance Specification for C-PHY v1.1
    5. Four data lanes on D-PHY and three data trios on C-PHY
    6. Bidirectional communication and escape mode through data lane 0
    7. Continuous and non-continuous clock modes on D-PHY and non-continuous clock mode on C-PHY
    8. End of Transmission packet (EoTp)
    9. Scrambling
    10. VESA DSC 1.1/1.2a
    11. Up to 4.5 Gbps per lane in D-PHY
    12. Up to 2.0 Gsps per trio in C-PHY

    MIPI DSI-2 Host 与 MIPI DSI Host 的差别

    MIPI DSI-2 除了可以兼容 MIPI DSI 的所有协议功能外, 还增加支持 MIPI C-PHY.

    MIPI DPHY 差别

    RK3588 平台 MIPI DPHY 不同以往平台 MIPI DPHY 版本, 其带宽最高可以到 4.5 Gbps.

    应用领域

    MIPI DSI基于差分信号传输,可以降低引脚数量和硬件设计复杂度,并保持良好的硬件兼容性。另外,基于MIPI DSI协议的IP还具备低功耗、低EMI的特性。

    其应用领域如下图:

    驱动代码说明:

    uboot

    驱动位置

    drivers/video/drm/dw_mipi_dsi2.c
    drivers/video/drm/samsung_mipi_dcphy.c
    

    驱动配置

    CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI2=y
    CONFIG_DRM_ROCKCHIP_SAMSUNG_MIPI_DCPHY=y
    

    kernel

    驱动位置

    MIPI DSI-2 host controller:
    drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
    
    MIPI DCPHY:
    drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
    

    驱动配置

    cONFIG_ROCKCHIP_DW_MIPI_DSI=y
    CONFIG_PHY_ROCKCHIP_SAMSUNG_DCPHY=y
    

    参考设备树

    DTS 路径:

    arch/arm64/boot/dts/rockchip/rk3588-evb.dtsi
    arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi
    arch/arm64/boot/dts/rockchip/rk3588-evb2-lp4.dtsi
    arch/arm64/boot/dts/rockchip/rk3588-evb3-lp5.dtsi
    arch/arm64/boot/dts/rockchip/rk3588-evb4-lp4.dtsi
    arch/arm64/boot/dts/rockchip/rk3588s-evb.dtsi
    arch/arm64/boot/dts/rockchip/rk3588s-evb1-lp4x.dtsi
    arch/arm64/boot/dts/rockchip/rk3588s-evb2-lp5.dtsi
    arch/arm64/boot/dts/rockchip/rk3588s-evb4-lp4x.dtsi
    

    dts 配置用例场景说明:

    rk3588-evb1: dsi0->dphy->1080p_panel && dsi1->dphy->1080p_panel;
    rk3588-evb2: dsi1->dphy->1080p_panel;
    rk3588-evb3: dsi0->dphy->1080p_panel && dsi1->cphy->cphy_panel;
    rk3588-evb4: dsi0->dphy->1080p_panel;
    rk3588s-evb1: dsi0->dphy->1080p_panel && dsi1->dphy->cmd_no_dsc_panel;
    rk3588s-evb2: dsi0->cphy->cphy_panel & dsi1->dphy->1080p_panel;
    rk3588s-evb4: dsi0->dphy->1080p_panel && dsi1->dphy->cmd_dsc_panel;
    

    屏端配置

    DTS 配置

    dsi0_panel: panel@0 {
    	status = "okay";
    	compatible = "simple-panel-dsi";
    	reg = <0>;
    	power-supply = <&vcc3v3_lcd_n>;
    	backlight = <&backlight>;
    	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_LOW>;
    	reset-delay-ms = <10>;
    	enable-delay-ms = <10>;
    	prepare-delay-ms = <10>;
    	unprepare-delay-ms = <10>;
    	disable-delay-ms = <60>;
    	dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
    		MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>;
    	dsi,format = <MIPI_DSI_FMT_RGB888>;
    	dsi,lanes  = <4>;
    	//phy-c-option;
    	//compressed-data;
    	//slice-width = <720>;
    	//slice-height = <65>;
    	//version-major = <1>;
    	//version-minor = <1>;
    
    	panel-init-sequence = [
    		...
    		05 78 01 11
    		05 00 01 29
    	];
    
    	panel-exit-sequence = [
    		05 00 01 28
    		05 00 01 10
    	];
    
    	disp_timings0: display-timings {
    		native-mode = <&dsi0_timing0>;
    		dsi0_timing0: timing0 {
    			clock-frequency = <132000000>;
    			hactive = <1080>;
    			vactive = <1920>;
    			hfront-porch = <15>;
    			hsync-len = <4>;
    			hback-porch = <30>;
    			vfront-porch = <15>;
    			vsync-len = <2>;
    			vback-porch = <15>;
    			hsync-active = <0>;
    			vsync-active = <0>;
    			de-active = <0>;
    			pixelclk-active = <0>;
    		};
    	};
    };
    

    配置说明

    通用配置

    Property Description Value
    compatible compatible simple-panel-dsi
    power-supply 屏端供电 [option] 相关regulator引用
    backlight 背光 背光引用
    enable-gpios 屏使能GPIO [option] GPIO引用描述
    reset-gpios 屏复位GPIO GPIO引用描述
    reset-delay-ms panel sequence delay 参考 panel spec
    enable-delay-ms
    prepare-delay-ms
    unprepare-delay-ms
    disable-delay-ms
    dsi,flags DSI2 工作模式 cmd mode:
    MIPI_DSI_MODE_LPM |
    MIPI_DSI_MODE_EOT_PACKET
    video mode:
    MIPI_DSI_MODE_VIDEO |
    MIPI_DSI_MODE_VIDEO_BURST |
    MIPI_DSI_MODE_LPM |
    MIPI_DSI_MODE_EOT_PACKET
    dsi,format 像素数据格式 MIPI_DSI_FMT_RGB888
    MIPI_DSI_FMT_RGB666
    MIPI_DSI_FMT_RGB666_PACKED
    MIPI_DSI_FMT_RGB565
    dsi,lanes mipi data 通道数 1/2/3 trios [cphy]
    6 trios [cphy 双通道]
    1/2/3/4 lanes [dphy]
    8 lanes [dphy 双通道]
    phy-c-option C-PHY panel [option] 布尔类型string
    compressed-data 带DSC panel [option] 布尔类型string
    slice-width 定义dsc slice宽 [option] 参照panel spec
    slice-height 定义dsc slice高 [option]
    version-major 定义dsc版本 [option] 参照panel spec
    version-minor
    panel-init-sequence 屏上电初始化序列 [hex]
    data_type delay_ms payload_lenth payload
    panel-exit-sequence 屏下电初始化序列
    display-timing panel timing 参考panel spec

    display Timing

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOZ8oGbq-1657674965348)(Rockchip_RK3588_Developer_Guide_MIPI_DSI2/Display-Timing.png)]

    dsi,flags

    CLK Type

    默认情况, MIPI DPHY 的时钟通道是连续模式,如下图:

    当 MIPI_DSI_CLOCK_NON_CONTINUOUS 追加到 dsi,flags 时,MIPI DPHY 的时钟通道将会配置成非连续模式,如下图:

    Eotp

    Eotp 是一个短包用于指示数据链路上高速传输的结束。Eotp 主要作用是增强系统高速传输通信的稳健性,出于这个目的,DSI 不需要在 LP 模式发送 Eotp。

    Eotp 不同于其他 DSI 包,它有固定的格式:

    Data Type = DI [5:0] = 0b001000
    Virtual Channel = DI [7:6] = 0b00
    Payload Data [15:0] = 0x0F0F
    ECC [7:0] = 0x01

    将 MIPI_DSI_MODE_EOT_PACKET 追加到 dsi,flags 属性可以开关 Soc MIPI DSI TX 在高速模式发送 Eotp。
    如下是在 HSDT 模式下捕获 Eotp 波形:

    BLANK_HS_EN

    在数据通道,一般存在一行会有两个 LP11 消隐, 如下图:

    但往往有些显示模组或者外接 MIPI 转接芯片,不支持在 Hblank阶段有两个 LP-11, 可以将 BLK_HFP_HS_EN 或 BLK_HBP_HS_EN 追加到 dsi,flags 属性,使HFP 或 HBP 以高速的形式存在。

    屏上电时序

    屏下电时序

    初始化序列常见数据类型

    data type description packet size
    0x03 Generic Short WRITE, no parameters short
    0x13 Generic Short WRITE, 1 parameters short
    0x23 Generic Short WRITE, 2 parameters short
    0x29 Generic long WRITE, long
    0x05 DCS Short WRITE, no parameters short
    0x15 DCS Short WRITE, 1 parameters short
    0x07 DCS Short WRITE, 1 parameters, DSC EN short
    0x0a DCS long WRITE, PPS, 128 bytes long

    Display Route

    MIPI with DSC

    MIPI with DSC Bypass

    DTS 配置

    如 DSI0 挂载在 VP3:

    &dsi0_in_vp2 {
    	status = "disabled";
    };
    
    &dsi0_in_vp3 {
    	status = "okay";
    };
    

    如 DSI1 挂载 VP2:

    &dsi1_in_vp2 {
    	status = "okay";
    };
    
    &dsi1_in_vp3 {
    	status = "disabled";
    };
    

    开机LOGO

    route_dsi0

    例如 vp3->dsi0 或 vp3->dsc0->dsi0:

    &route_dsi0 {
    	status = "okay";
    	connect = <&vp3_out_dsi0>;
    };
    

    route_dsi1

    例如 vp2->dsi1 或 vp2->dsc1->dsi1:

    &route_dsi1 {
    	status = "okay";
    	connect = <&vp2_out_dsi1>;
    };
    

    route_dsi0 && route_dsi1

    例如 (vp3->dsi0 或 vp3->dsc0->dsi0) && (vp2->dsi1 或 vp2->dsc1->dsi1):

    &route_dsi0 {
    	status = "okay";
    	connect = <&vp3_out_dsi0>;
    };
    
    &route_dsi1 {
    	status = "okay";
    	connect = <&vp2_out_dsi1>;
    };
    

    DSI HOST

    ports
    以下实例中 ports 是用来 Dispaly Interface 和 panel 之间进行关联。
    详细配置说明参阅如下文档:

    Documentation/devicetree/bindings/graph.txt
    

    单 DSI

    DSI0

    &dsi0 {
    	status = "okay";
    	//rockchip,lane-rate = <1000>;
    	dsi0_panel: panel@0 {
    		status = "okay";
    		compatible = "simple-panel-dsi";
    		...
    
    		ports {
    			#address-cells = <1>;
    			#size-cells = <0>;
    
    			port@0 {
    				reg = <0>;
    				panel_in_dsi: endpoint {
    					remote-endpoint = <&dsi_out_panel>;
    				};
    			};
    		};
    	};
    
    	ports {
    		#address-cells = <1>;
    		#size-cells = <0>;
    
    		port@1 {
    			reg = <1>;
    			dsi_out_panel: endpoint {
    				remote-endpoint = <&panel_in_dsi>;
    			};
    		};
    	};
    
    };
    
    &mipi_dcphy0 {
    	status = "okay";
    };
    
    

    DSI1

    &dsi1 {
    	status = "okay";
    	//rockchip,lane-rate = <1000>;
    	dsi1_panel: panel@0 {
    		status = "okay";
    		compatible = "simple-panel-dsi";
    		...
    
    		ports {
    			#address-cells = <1>;
    			#size-cells = <0>;
    
    			port@0 {
    				reg = <0>;
    				panel_in_dsi1: endpoint {
    					remote-endpoint = <&dsi1_out_panel>;
    				};
    			};
    		};
    	};
    
    	ports {
    		#address-cells = <1>;
    		#size-cells = <0>;
    
    		port@1 {
    			reg = <1>;
    			dsi1_out_panel: endpoint {
    				remote-endpoint = <&panel_in_dsi1>;
    			};
    		};
    	};
    };
    
    &mipi_dcphy1 {
    	status = "okay";
    };
    

    双通道 DSI

    MODE1:

    MODE2:

    双通道的配置注意如下标红属性:
    rockchip,dual-channel = <&dsi1>
    dsi,lanes = <8>;//DPHY 屏, CPHY 屏值改成 6

    &dsi0 {
    	status = "okay";
    	rockchip,dual-channel = <&dsi1>;
    
    	dsi0_panel {
    		status = "okay";
    		compatible = "simple-panel-dsi";
    		dsi,lanes  = <8>;
    		...
    
    		display-timings {
    			native-mode = <&timing0>;
    
    			timing0: timing0 {
    				clock-frequency = <260000000>;
    				hactive = <1440>;
    				vactive = <2560>;
    				hfront-porch = <150>;
    				hsync-len = <30>;
    				hback-porch = <60>;
    				vfront-porch = <8>;
    				vsync-len = <4>;
    				vback-porch = <4>;
    				hsync-active = <0>;
    				vsync-active = <0>;
    				de-active = <0>;
    				pixelclk-active = <0>;
    			};
    		};
    
    		ports {
    			#address-cells = <1>;
    			#size-cells = <0>;
    
    			port@0 {
    				reg = <0>;
    				panel_in_dsi0: endpoint {
    					remote-endpoint = <&dsi0_out_panel>;
    				};
    			};
    		};
    	};
    
    	ports {
    		#address-cells = <1>;
    		#size-cells = <0>;
    
    		port@1 {
    			reg = <1>;
    			dsi0_out_panel: endpoint {
    				remote-endpoint = <&panel_in_dsi0>;
    			};
    		};
    	};
    };
    
    &dsi1 {
    	status = "okay";
    };
    
    &mipi_dcphy0 {
    	status = "okay";
    };
    
    &mipi_dcphy1 {
    	status = "okay";
    };
    

    Dual-link DSI

    &dsi0 {
    	status = "okay";
    	//rockchip,lane-rate = <1000>;
    	dsi0_panel: panel@0 {
    		status = "okay";
    		compatible = "simple-panel-dsi";
    		...
    
    		ports {
    			#address-cells = <1>;
    			#size-cells = <0>;
    
    			port@0 {
    				reg = <0>;
    				panel_in_dsi: endpoint {
    					remote-endpoint = <&dsi_out_panel>;
    				};
    			};
    		};
    	};
    
    	ports {
    		#address-cells = <1>;
    		#size-cells = <0>;
    
    		port@1 {
    			reg = <1>;
    			dsi_out_panel: endpoint {
    				remote-endpoint = <&panel_in_dsi>;
    			};
    		};
    	};
    
    };
    
    &dsi1 { status = "okay";
    	//rockchip,lane-rate = <1000>;
    	dsi1_panel: panel@0 {
    		status = "okay";
    		compatible = "simple-panel-dsi";
    		...
    
    		ports {
    			#address-cells = <1>;
    			#size-cells = <0>;
    
    			port@0 {
    				reg = <0>;
    				panel_in_dsi1: endpoint {
    					remote-endpoint = <&dsi1_out_panel>;
    				};
    			};
    		};
    	};
    
    	ports {
    		#address-cells = <1>;
    		#size-cells = <0>;
    
    		port@1 {
    			reg = <1>;
    			dsi1_out_panel: endpoint {
    				remote-endpoint = <&panel_in_dsi1>;
    			};
    		};
    	};
    };
    
    &mipi_dcphy0 {
    	status = "okay";
    };
    
    &mipi_dcphy1 {
    	status = "okay";
    };
    

    DCPHY

    实际应用配置中默认是配置成D-PHY,通过屏端配置介绍可知,通过下面可以配置成 C-PHY:

    dsi0_panel: panel@0 {
    	...
    	phy-c-option;
    	...
    };
    

    D-PHY

    1. Up to 4.5 Gbps per lane in D-PHY
    2. 一个D-PHY port 最多4lanes,每个lane由两条差分线组成

    C-PHY

    1. Up to 2.0 Gsps per trio in C-PHY
    2. 一个C-PHY port 最多3lanes,每个lane由 tree-wire-trios 组成

    协议分析

    DSI Layer Definitions

    D Option

    Lane states and line levels

    下表罗列在 DPHY Lane 正常操作中可能出现的所有通道状态。

    Global Operation Flow Diagram

    DSI 数据通道可以驱动到如下三种模式:

    1. Escape Mode (只有 Dp0/Dn0 会操作在该模式);
    2. Bus Turnaround Request (只有 Dp0/Dn0 会操作在该模式);
    3. High-Speed Data Transmission。

    这三种模式和它们进入对应模式的序列定义如下:

    Escape Modes

    当数据通道处于 LP 模式,数据通道0用于 Escape Mode, 数据通道应通过 LP-11->LP-10->LP-00->LP-01->LP-00 进入 Escape Mode,通过 LP-00->LP-10->LP-11 退出 Escape Mode.

    Escape Commands

    一旦数据通道进入 Escape 模式, 发送器应该发送 8-bit Escape Comands 指示请求行为,Escape Comands 如下:

    LPDT

    当数据通道进入 Escape 模式且向显示模块发送 Low-Power Data Transmission(LPDT) 序列,Soc 的 MIPI DSI TX 可以通过 LPDT 模式向显示模块发送数据, 一般就是通过这种方式向 MIPI 显示模块下载初始化序列。

    通过示波器捕获 LPDT 波形如下:

    ULPS

    HSDT

    当 DPHY 的时钟通道在高速时钟模式时,显示模块可以进入高速数据传输模式,所有的数据通道同时进入高速数据传输模式,但可以不同时退出高速模式。数据通道通过如下序列进入高速模式:
    LP-11 -> LP-01 -> LP-00 -> HS-0 -> SoT(0001_1101).

    1. Start: LP-11
    2. HS-Request: LP-01
    3. HS-Settle: LP-00 -> HS-0 (RX: Lane Termination Enable)
    4. Rx Synchronization: SoT(0001_1101)
    5. End: High-Speed Data Transmission (HSDT) - Ready to receive High-Speed Data Load
    

    数据通道退出高速数据传输模式流程:在最后一个有效负载数据之后立即切换差分状态位并保持该状态一段时间 Ths-trail。

    通过示波器捕获 HSDT 波形如下:

    BTA

    当需要从显示模块获取信息时,Soc DPHY 的第一数据通道可以通过执行总线翻转步骤。操作步骤如下:

    通过示波器在 HSDT 时向显示模块回读并捕获 BTA 波形如下:

    Endian Policy

    无论是在 LP 和 HS 数据传输模式,数据都是以长包和短包形式打包并传输给显示模块。

    SPa

    Example:

    LPDT-SPa

    通过示波器在 LPDT 时向显示模块发送如上 SPa 并捕获波形如下:

    HSDT-SPa

    通过示波器在 HSDT 时向显示模块发送如上 SPa 并捕获波形如下:

    LPa

    Example:

    LPDT-LPa

    通过示波器在 LPDT 时向显示模块发送如上 LPa 并捕获波形如下:

    HSDT-LPa

    通过示波器在 HSDT 时向显示模块发送如上 LPa 并捕获波形如下:

    DI

    如上 SPa 和 LPa 中都有一个 Data Identification (DI), 一个包是长短包就是由 DI 决定,DI 是包头的一部分,由两个部分组成:

    MIPI 协议中目前定义的绝大部分数据类型如下:

    Video Mode Interface Timing

    Horizontal Display Timing (Video mode)

    Non-Burst Mode with Sync Pulses

    通过示波器捕获 Non Burst Sync Pulse 波形如下:

    Burst Mode

    通过示波器捕获 Video Burst 波形如下:

    常见问题

    查看VOP timing 和 Connector 信息

    console:/ # cat /d/dri/0/summary
    Video Port0: DISABLED
    Video Port1: DISABLED
    Video Port2: DISABLED
    Video Port3: ACTIVE
        Connector: DSI-2
            bus_format[100a]: RGB888_1X24
            overlay_mode[0] output_mode[0] color_space[0]
        Display mode: 1080x1920p60
            clk[132000] real_clk[132000] type[48] flag[a]
            H: 1080 1095 1099 1129
            V: 1920 1935 1937 1952
        Cluster3-win0: ACTIVE
            win_id: 6
            format: AB24 little-endian (0x34324241) SDR[0] color_space[0] glb_alpha[0xff]
            rotate: xmirror: 0 ymirror: 0 rotate_90: 0 rotate_270: 0
            csc: y2r[0] r2y[0] csc mode[0]
            zpos: 0
            src: pos[0, 0] rect[1080 x 1920]
            dst: pos[0, 0] rect[1080 x 1920]
            buf[0]: addr: 0x000000000376e000 pitch: 4352 offset: 0
    

    查看 DSI2 相关 clk tree

    console:/ # cat /d/clk/clk_summary | grep vop
        clk_vop_pmu                       0        0        0    24000000          0     0  50000
              dclk_vop3                   1        2        0    33000000          0     0  50000
              dclk_vop1_src               0        1        0   594000000          0     0  50000
                 dclk_vop1                0        1        0   594000000          0     0  50000
              dclk_vop0_src               0        1        0   594000000          0     0  50000
                 dclk_vop0                0        1        0   594000000          0     0  50000
                 aclk_vop_low_root        1        1        0   396000000          0     0  50000
                 hclk_vop_root            2        4        0   198000000          0     0  50000
                    hclk_vop              1        3        0   198000000          0     0  50000
              aclk_vop_root               1        1        0   500000000          0     0  50000
                 aclk_vop_doby            0        0        0   500000000          0     0  50000
                 aclk_vop_sub_src         1        1        0   500000000          0     0  50000
                    aclk_vop              1        4        0   500000000          0     0  50000
                 pclk_vop_root            3        5        0   100000000          0     0  50000
              dclk_vop2_src               1        1        0   148500000          0     0  50000
                 dclk_vop2                1        2        0   148500000          0     0  50000
    console:/ # cat /d/clk/clk_summary | grep dsi
                    pclk_dsihost1         1        2        0   100000000          0     0  50000
                    pclk_dsihost0         1        2        0   100000000          0     0  50000
        clk_dsihost1                      1        2        0   351000000          0     0  50000
        clk_dsihost0                      1        2        0   351000000          0     0  50000
    console:/ # cat /d/clk/clk_summary | grep mipi
              mipi1_clk_src               0        0        0    33000000          0     0  50000
                 mipi1_pixclk             0        0        0    33000000          0     0  50000
              mipi0_clk_src               0        0        0   148500000          0     0  50000
                 mipi0_pixclk             0        0        0   148500000          0     0  50000
        clk_usbdpphy_mipidcpphy_ref       5        5        0    24000000          0     0  50000
        clk_mipi_camaraout_m4             0        0        0    24000000          0     0  50000
        clk_mipi_camaraout_m3             0        0        0    24000000          0     0  50000
        clk_mipi_camaraout_m2             0        0        0    24000000          0     0  50000
        clk_mipi_camaraout_m0             0        0        0    24000000          0     0  50000
              clk_mipi_camaraout_m1       0        0        0    37125000          0     0  50000
                    pclk_mipi_dcphy1       1        1        0   100000000          0     0  50000
                    pclk_mipi_dcphy0       1        1        0   100000000          0     0  50000
    console:/ #
    

    如何查看指定 DSI lane 速率

    DSI lane 速率的指定有两种,一种是驱动自动计算:

    dmesg | grep dsi
    
    [   77.369812] dw-mipi-dsi2 fde20000.dsi: [drm:dw_mipi_dsi2_encoder_enable] final DSI-Link bandwidth: 879 x 4 Mbps
    

    一种是通过如下属性手动指定:

    &dsi0 {
    	...
    	rockchip,lane-rate = <1000>;
    	...
    }
    

    MIPI DSI2 HOST 没有自己color bar 功能,通过如下命令可以让 VOP2 投显 color bar

    根据显示路由选择对应的命令:

    vp0:
    io -4 0xfdd90c08 0x1 && io -4 0xfdd90000 0xffffffff
    
    vp1:
    io -4 0xfdd90d08 0x1 && io -4 0xfdd90000 0xffffffff
    
    vp2:
    io -4 0xfdd90e08 0x1 && io -4 0xfdd90000 0xffffffff
    
    vp3:
    io -4 0xfdd90f08 0x1 && io -4 0xfdd90000 0xffffffff
    

    如何判断显示异常的时候,MIPI DSI2 和 panel 是否通信正常

    uboot:

    --- a/drivers/video/drm/rockchip_panel.c
    +++ b/drivers/video/drm/rockchip_panel.c
    @@ -260,6 +260,7 @@ static void panel_simple_prepare(struct rockchip_panel *panel)
     	struct rockchip_panel_priv *priv = dev_get_priv(panel->dev);
     	struct mipi_dsi_device *dsi = dev_get_parent_platdata(panel->dev);
     	int ret;
    +	u8 mode;
    
     	if (priv->prepared)
     		return;
    @@ -285,6 +286,8 @@ static void panel_simple_prepare(struct rockchip_panel *panel)
     	if (plat->delay.init)
     		mdelay(plat->delay.init);
    
    +	mipi_dsi_dcs_get_power_mode(dsi, &mode);
    +	printf("===>mode: 0x%x\n", mode);
     	if (plat->on_cmds) {
     		if (priv->cmd_type == CMD_TYPE_SPI)
     			ret = rockchip_panel_send_spi_cmds(panel->state,
    @@ -298,6 +301,8 @@ static void panel_simple_prepare(struct rockchip_panel *panel)
     			printf("failed to send on cmds: %d\n", ret);
     	}
    
    +	mipi_dsi_dcs_get_power_mode(dsi, &mode);
    +	printf("===>mode: 0x%x\n", mode);
     	priv->prepared = true;
     }
    

    kernel

    --- a/drivers/gpu/drm/panel/panel-simple.c
    +++ b/drivers/gpu/drm/panel/panel-simple.c
    @@ -506,6 +506,7 @@ static int panel_simple_prepare(struct drm_panel *panel)
     	unsigned int delay;
     	int err;
     	int hpd_asserted;
    +	u8 mode;
    
     	if (p->prepared)
     		return 0;
    @@ -554,6 +555,8 @@ static int panel_simple_prepare(struct drm_panel *panel)
     		}
     	}
    
    +	mipi_dsi_dcs_get_power_mode(p->dsi, &mode);
    +	printk("===>mode: 0x%x\n, mode");
     	if (p->desc->init_seq)
     		if (p->dsi)
     			panel_simple_xfer_dsi_cmd_seq(p, p->desc->init_seq);
    @@ -561,6 +564,9 @@ static int panel_simple_prepare(struct drm_panel *panel)
     	if (p->desc->delay.init)
     		msleep(p->desc->delay.init);
    
    +	mipi_dsi_dcs_get_power_mode(p->dsi, &mode);
    +	printk("===>mode: 0x%x\n, mode");
    +
     	p->prepared = true;
    
     	return 0;
    

    通信正常会有如下打印,否者排查屏端时序确保屏是否就绪:

    ===> mode: 0x8
    ===> mode: 0x9c
    

    backlight驱动probe失败

    console:/ # dmesg | grep backlight
    [    3.164274] pwm-backlight: probe of backlight failed with error -16
    

    Command Mode 显示模组如何配置 TE

    为防止图像显示撕裂,显示控制器刷帧的频率应该和显示模组从GRAM中刷图的频率保持一致。RK3588只支持显示模组将TE信号外部反馈的方式。

    &dsi0 {
    	...
    	/* 显示模组TE信号连接到MIPI_TE0 */
    	pinctrl-names = "default";
    	pinctrl-0 = <&mipi_te0>;
    	...
    };
    
    &dsi1 {
    	...
    	/* 显示模组TE信号连接到MIPI_TE1 */
    	pinctrl-names = "default";
    	pinctrl-0 = <&mipi_te1>;
    	...
    };
    

    下图捕获MIPI DSI发送数据信号场频和显示模组TE信号频率一致波形:

    双通道MIPI切换主从顺序

    如果硬件设计将双通道的两个MIPI Ports接反了,可以通过如下配置进行软件纠正:

    &dsi0 {
    	...
    	rockchip,data-swap;
    	rockchip,dual-channel = <&dsi1>;
    	...
    };
    
    &dsi1 {
    	status = "okay";
    };
    

    调试节点

    在MIPI DSI信号测试过程中需要对信号进行调整,如下是相关调试节点路径:

    dcphy0:
    cd /sys/devices/platform/feda0000.phy/
    dcphy1:
    cd /sys/devices/platform/fedb0000.phy/
    

    Patch

    diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
    index 1d5db69ee..c5d11f30c 100644
    --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
    +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
    @@ -142,6 +142,25 @@
     #define T_TA_GET(x)		UPDATE(x, 7, 4)
     #define T_TA_GO(x)		UPDATE(x, 3, 0)
    
    +
    +#define REG_400M_MASK		GENMASK(6, 4)
    +#define REG_400M(x)		UPDATE(x, 6, 4)
    +#define BIAS_CON4		0x0010
    +#define I_MUX_SEL_MASK		GENMASK(6, 5)
    +#define I_MUX_SEL(x)		UPDATE(x, 6, 5)
    +#define CAP_PEAKING_MASK	GENMASK(14, 12)
    +#define CAP_PEAKING(x)		UPDATE(x, 14, 12)
    +#define RES_UP_MASK		GENMASK(7, 4)
    +#define RES_UP(x)		UPDATE(x, 7, 4)
    +#define RES_DN_MASK		GENMASK(3, 0)
    +#define RES_DN(x)		UPDATE(x, 3, 0)
    +#define T_HS_ZERO_MASK		GENMASK(15, 8)
    +#define T_HS_PREPARE_MASK	GENMASK(7, 0)
    +#define T_HS_EXIT_MASK		GENMASK(15, 8)
    +#define T_HS_TRAIL_MASK		GENMASK(7, 0)
    +#define T_TA_GET_MASK		GENMASK(7, 4)
    +#define T_TA_GO_MASK		GENMASK(3, 0)
    +
     /* MIPI_CDPHY_GRF registers */
     #define MIPI_DCPHY_GRF_CON0	0x0000
     #define S_CPHY_MODE		HIWORD_UPDATE(1, 3, 3)
    @@ -1194,6 +1213,421 @@ struct samsung_mipi_cphy_timing samsung_mipi_cphy_timing_table[] = {
     	{   80,  1, 50, 25,  2,  0, 2 },
     };
    
    +static ssize_t
    +reg_400m_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int level;
    +
    +	regmap_read(samsung->regmap, BIAS_CON2, &val);
    +	level = (val & REG_400M_MASK) >> 4;
    +
    +	return sprintf(buf, "%d\n", level);
    +
    +}
    +
    +static ssize_t
    +reg_400m_store(struct device *device, struct device_attribute *attr,
    +		     const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +
    +	if (val > 7)
    +		val = 7;
    +
    +	regmap_update_bits(samsung->regmap, BIAS_CON2, REG_400M_MASK, REG_400M(val));
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(reg_400m);
    +
    +static ssize_t
    +cap_peaking_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int level;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_ANA_CON0, &val);
    +	level = (val & CAP_PEAKING_MASK) >> 12;
    +
    +	return sprintf(buf, "%d\n", level);
    +
    +}
    +
    +static ssize_t
    +cap_peaking_store(struct device *device, struct device_attribute *attr,
    +		     const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +
    +	if (val > 7)
    +		val = 7;
    +
    +	regmap_update_bits(samsung->regmap, DPHY_MC_ANA_CON0, CAP_PEAKING_MASK, CAP_PEAKING(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_ANA_CON0, CAP_PEAKING_MASK, CAP_PEAKING(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_ANA_CON0, CAP_PEAKING_MASK, CAP_PEAKING(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_ANA_CON0, CAP_PEAKING_MASK, CAP_PEAKING(val));
    +	regmap_update_bits(samsung->regmap, DPHY_MD3_ANA_CON0, CAP_PEAKING_MASK, CAP_PEAKING(val));
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(cap_peaking);
    +
    +static ssize_t
    +res_up_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int level;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_ANA_CON0, &val);
    +	level = (val & RES_UP_MASK) >> 4;
    +
    +	return sprintf(buf, "%d\n", level);
    +
    +}
    +
    +static ssize_t
    +res_up_store(struct device *device, struct device_attribute *attr,
    +		     const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +
    +	if (val > 15)
    +		val = 15;
    +
    +	regmap_update_bits(samsung->regmap, DPHY_MC_ANA_CON0, RES_UP_MASK, RES_UP(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_ANA_CON0, RES_UP_MASK, RES_UP(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_ANA_CON0, RES_UP_MASK, RES_UP(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_ANA_CON0, RES_UP_MASK, RES_UP(val));
    +	regmap_update_bits(samsung->regmap, DPHY_MD3_ANA_CON0, RES_UP_MASK, RES_UP(val));
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(res_up);
    +
    +static ssize_t
    +res_dn_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int level;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_ANA_CON0, &val);
    +	level = (val & RES_DN_MASK);
    +
    +	return sprintf(buf, "%d\n", level);
    +
    +}
    +
    +static ssize_t
    +res_dn_store(struct device *device, struct device_attribute *attr,
    +		     const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +
    +	if (val > 15)
    +		val = 15;
    +
    +	regmap_update_bits(samsung->regmap, DPHY_MC_ANA_CON0, RES_DN_MASK, RES_DN(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_ANA_CON0, RES_DN_MASK, RES_DN(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_ANA_CON0, RES_DN_MASK, RES_DN(val));
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_ANA_CON0, RES_DN_MASK, RES_DN(val));
    +	regmap_update_bits(samsung->regmap, DPHY_MD3_ANA_CON0, RES_DN_MASK, RES_DN(val));
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(res_dn);
    +
    +static ssize_t
    +output_voltage_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int level;
    +
    +	regmap_read(samsung->regmap, BIAS_CON4, &val);
    +	level = (val & I_MUX_SEL_MASK) >> 5;
    +
    +	return sprintf(buf, "%d\n", level);
    +
    +}
    +
    +static ssize_t
    +output_voltage_store(struct device *device, struct device_attribute *attr,
    +		     const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +
    +	if (val > 3)
    +		val = 3;
    +
    +	regmap_update_bits(samsung->regmap, BIAS_CON4,
    +			   I_MUX_SEL_MASK, I_MUX_SEL(val));
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(output_voltage);
    +
    +static ssize_t
    +hs_exit_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int hs_exit;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_TIME_CON2, &val);
    +	hs_exit = (val & GENMASK(15, 8)) >> 8;
    +
    +	return sprintf(buf, "%d\n", hs_exit);
    +
    +}
    +
    +static ssize_t hs_exit_store(struct device *device, struct device_attribute *attr,
    +			 const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +	unsigned long hs_exit;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +	hs_exit = T_HS_EXIT(val);
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_TIME_CON2, T_HS_EXIT_MASK, hs_exit);
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_TIME_CON2, T_HS_EXIT_MASK, hs_exit);
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_TIME_CON2, T_HS_EXIT_MASK, hs_exit);
    +
    +	if (!samsung->c_option) {
    +		regmap_update_bits(samsung->regmap, DPHY_MC_TIME_CON2, T_HS_EXIT_MASK, hs_exit);
    +		regmap_update_bits(samsung->regmap, DPHY_MD3_TIME_CON2, T_HS_EXIT_MASK, hs_exit);
    +	}
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(hs_exit);
    +
    +static ssize_t
    +hs_trail_or_post_3_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int hs_trail;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_TIME_CON2, &val);
    +	hs_trail = val & GENMASK(7, 0);
    +
    +	return sprintf(buf, "%d\n", hs_trail);
    +
    +}
    +
    +static ssize_t hs_trail_or_post_3_store(struct device *device, struct device_attribute *attr,
    +			 const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +	unsigned long hs_trail;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +	hs_trail = T_HS_TRAIL(val);
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_TIME_CON2, T_HS_TRAIL_MASK, hs_trail);
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_TIME_CON2, T_HS_TRAIL_MASK, hs_trail);
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_TIME_CON2, T_HS_TRAIL_MASK, hs_trail);
    +
    +	if (!samsung->c_option) {
    +		regmap_update_bits(samsung->regmap, DPHY_MC_TIME_CON2, T_HS_TRAIL_MASK, hs_trail);
    +		regmap_update_bits(samsung->regmap, DPHY_MD3_TIME_CON2, T_HS_TRAIL_MASK, hs_trail);
    +	}
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(hs_trail_or_post_3);
    +
    +static ssize_t
    +hs_zero_or_prebegin_3_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int hs_zero;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_TIME_CON1, &val);
    +	hs_zero = (val & GENMASK(15, 8)) >> 8;
    +
    +	return sprintf(buf, "%d\n", hs_zero);
    +
    +}
    +
    +static ssize_t hs_zero_or_prebegin_3_store(struct device *device, struct device_attribute *attr,
    +			 const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +	unsigned long hs_zero;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +	hs_zero = T_HS_ZERO(val);
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_TIME_CON1,
    +			   T_HS_ZERO_MASK, hs_zero);
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_TIME_CON1,
    +			   T_HS_ZERO_MASK, hs_zero);
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_TIME_CON1,
    +			   T_HS_ZERO_MASK, hs_zero);
    +
    +	if (!samsung->c_option) {
    +		regmap_update_bits(samsung->regmap, DPHY_MC_TIME_CON1,
    +				   T_HS_ZERO_MASK, hs_zero);
    +		regmap_update_bits(samsung->regmap, DPHY_MD3_TIME_CON1,
    +				   T_HS_ZERO_MASK, hs_zero);
    +	}
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(hs_zero_or_prebegin_3);
    +
    +static ssize_t
    +hs_prepare_or_prepare_3_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int hs_prepare;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_TIME_CON1, &val);
    +	hs_prepare = val & GENMASK(7, 0);
    +
    +	return sprintf(buf, "%d\n", hs_prepare);
    +}
    +
    +static ssize_t hs_prepare_or_prepare_3_store(struct device *device, struct device_attribute *attr,
    +			 const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +	unsigned long hs_prepare;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +	hs_prepare = T_HS_PREPARE(val);
    +	regmap_update_bits(samsung->regmap, COMBO_MD0_TIME_CON1,
    +			   T_HS_PREPARE_MASK, hs_prepare);
    +	regmap_update_bits(samsung->regmap, COMBO_MD1_TIME_CON1,
    +			   T_HS_PREPARE_MASK, hs_prepare);
    +	regmap_update_bits(samsung->regmap, COMBO_MD2_TIME_CON1,
    +			   T_HS_PREPARE_MASK, hs_prepare);
    +
    +	if (!samsung->c_option) {
    +		regmap_update_bits(samsung->regmap, DPHY_MC_TIME_CON1,
    +				   T_HS_PREPARE_MASK, hs_prepare);
    +		regmap_update_bits(samsung->regmap, DPHY_MD3_TIME_CON1,
    +				   T_HS_PREPARE_MASK, hs_prepare);
    +	}
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(hs_prepare_or_prepare_3);
    +
    +static ssize_t
    +lpx_show(struct device *device, struct device_attribute *attr, char *buf)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned int val;
    +	unsigned int lpx;
    +
    +	regmap_read(samsung->regmap, COMBO_MD0_TIME_CON0, &val);
    +	lpx = (val & GENMASK(11, 4)) >> 4;
    +
    +	return sprintf(buf, "%d\n", lpx);
    +
    +}
    +
    +static ssize_t lpx_store(struct device *device, struct device_attribute *attr,
    +			 const char *buf, size_t count)
    +{
    +	struct samsung_mipi_dcphy *samsung = dev_get_drvdata(device);
    +	unsigned long val;
    +	unsigned long lpx = 0;
    +
    +	if (kstrtoul(buf, 10, &val))
    +		return -EINVAL;
    +
    +	lpx |= T_LPX(val);
    +	/*  T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */
    +	regmap_write(samsung->regmap, COMBO_MD0_TIME_CON0, lpx);
    +	regmap_write(samsung->regmap, COMBO_MD1_TIME_CON0, lpx);
    +	regmap_write(samsung->regmap, COMBO_MD2_TIME_CON0, lpx);
    +
    +	if (!samsung->c_option) {
    +		regmap_write(samsung->regmap, DPHY_MC_TIME_CON0, lpx);
    +		regmap_write(samsung->regmap, DPHY_MD3_TIME_CON0, lpx);
    +	}
    +
    +	return count;
    +}
    +static DEVICE_ATTR_RW(lpx);
    +
    +static struct attribute *samsung_mipi_dcphy_cts_attrs[] = {
    +	&dev_attr_lpx.attr,
    +	&dev_attr_hs_prepare_or_prepare_3.attr,
    +	&dev_attr_hs_zero_or_prebegin_3.attr,
    +	&dev_attr_hs_trail_or_post_3.attr,
    +	&dev_attr_hs_exit.attr,
    +	&dev_attr_output_voltage.attr,
    +	&dev_attr_res_up.attr,
    +	&dev_attr_res_dn.attr,
    +	&dev_attr_cap_peaking.attr,
    +	&dev_attr_reg_400m.attr,
    +	NULL
    +};
    +
    +static const struct attribute_group samsung_mipi_dcphy_cts_attr_group = {
    +	.attrs = samsung_mipi_dcphy_cts_attrs,
    +};
    +
    +static int samsung_mipi_dcphy_cts_sysfs_add(struct samsung_mipi_dcphy *samsung)
    +{
    +	struct device *dev = samsung->dev;
    +	int ret;
    +
    +	ret = sysfs_create_group(&dev->kobj, &samsung_mipi_dcphy_cts_attr_group);
    +	if (ret) {
    +		dev_err(dev, "failed to register sysfs. err: %d\n", ret);
    +		return ret;
    +	};
    +
    +	return 0;
    +}
    +
     static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung)
     {
     	regmap_write(samsung->regmap, BIAS_CON0, 0x0010);
    @@ -1912,6 +2346,11 @@ static int samsung_mipi_dcphy_probe(struct platform_device *pdev)
     		return PTR_ERR(phy_provider);
     	}
    
    +
    +	ret = samsung_mipi_dcphy_cts_sysfs_add(samsung);
    +	if (ret)
    +		return ret;
    +
     	pm_runtime_enable(dev);
    
     	return 0;
    
    

    驱动强度

    echo level > output_voltage
    

    驱动默认如下配置:

    1. D-PHY: 2’b00
    2. C-PHY: 2’b10

    level 参考如下:

    1. 2b’00 : 400mV
    2. 2b’01 : 200mV
    3. 2b’10 : 530mV
    4. 2b’11 : 530mV

    共模电压

    echo level > reg_400m
    

    level 参考如下:

    1. 3’b000: 380mV / 230mV
    2. 3’b001: 390mV / 220mV
    3. 3’b010: 400mV / 210mV
    4. 3’b011: 410mV / 200mV
    5. 3’b100: 420mV / 190mV
    6. 3’b101: 430mV / 180mV
    7. 3’b110: 440mV / 170mV
    8. 3’b111: 450mV / 160mV

    cap peaking

    echo level > cap_peaking
    
    level: 0~7
    

    信号timing

    如下图中信号红色框中的信号参数都是可以调整的。

    如下信号调整count值可以在回读基础上做调整修改,比如Tlpx:

    cat lpx
    
    Tlpx
    echo count > lpx
    
    Ths_prepare_or_prepare_3
    echo count > hs_prepare_or_prepare_3
    
    Ths_zero_or_prebegin_3
    echo count > hs_zero_or_prebegin_3
    
    Ths_trail_or_post_3
    echo count > hs_trail_or_post_3
    
    Ths_exit
    echo count > hs_exit
    

    High-Speed Driver Up Resistor Control

    echo level > res_up
    

    level参考如下:

    1. 4’b0000: 43 ohm
    2. 4’b0001: 46 ohm
    3. 4’b0010: 49 ohm
    4. 4’b0011: 52 ohm
    5. 4’b0100: 56 ohm
    6. 4’b0101: 60 ohm
    7. 4’b0110: 66 ohm
    8. 4’b0111: 73 ohm
    9. 4’b1000: 30 ohm
    10. 4’b1001: 31.2 ohm
    11. 4’b1010: 32.5 ohm
    12. 4’b1011: 34 ohm
    13. 4’b1100: 35.5 ohm
    14. 4’b1101: 37 ohm
    15. 4’b1110: 39 ohm
    16. 4’b1111: 41 ohm

    High-Speed Driver Down Resistor Control

    echo level > res_dn
    

    level 参考如下:

    1. 4’b0000: 43 ohm
    2. 4’b0001: 46 ohm
    3. 4’b0010: 49 ohm
    4. 4’b0011: 52 ohm
    5. 4’b0100: 56 ohm
    6. 4’b0101: 60 ohm
    7. 4’b0110: 66 ohm
    8. 4’b0111: 73 ohm
    9. 4’b1000: 30 ohm
    10. 4’b1001: 31.2 ohm
    11. 4’b1010: 32.5 ohm
    12. 4’b1011: 34 ohm
    13. 4’b1100: 35.5 ohm
    14. 4’b1101: 37 ohm
    15. 4’b1110: 39 ohm
    16. 4’b1111: 41 ohm
    物联沃分享整理
    物联沃-IOTWORD物联网 » Rockchip RK3588:MIPI-DSI2深度解析

    发表评论