赞
踩
目录
DSI-2 是 MIPI 联盟定义的一组通信协议的一部分, DWC-MIPI-DSI2 是一个实现 MIPI-DSI2 规范中定义的所有协议功能的数字核控制器,可以兼容 D-PHY 和 C-PHY 的物理接口,支持两路的 Display Stream Compression (DSC) 数据传输, RK3588 有两个 DSI-2 控制器和两个独立的物理的 D/C-PHY, 可以同时最多支持两路 MIPI 输出。
MIPI DSI-2 除了可以兼容 MIPI DSI 的所有协议功能外, 还增加支持 MIPI C-PHY.
RK3588 平台 MIPI DPHY 不同以往平台 MIPI DPHY 版本, 其带宽最高可以到 4.5 Gbps.
MIPI DSI基于差分信号传输,可以降低引脚数量和硬件设计复杂度,并保持良好的硬件兼容性。另外,基于MIPI DSI协议的IP还具备低功耗、低EMI的特性。
其应用领域如下图:
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
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;
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 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOZ8oGbq-1657674965348)(Rockchip_RK3588_Developer_Guide_MIPI_DSI2/Display-Timing.png)]
默认情况, MIPI DPHY 的时钟通道是连续模式,如下图:
当 MIPI_DSI_CLOCK_NON_CONTINUOUS 追加到 dsi,flags 时,MIPI DPHY 的时钟通道将会配置成非连续模式,如下图:
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 波形:
在数据通道,一般存在一行会有两个 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 |
如 DSI0 挂载在 VP3:
&dsi0_in_vp2 {
status = "disabled";
};
&dsi0_in_vp3 {
status = "okay";
};
如 DSI1 挂载 VP2:
&dsi1_in_vp2 {
status = "okay";
};
&dsi1_in_vp3 {
status = "disabled";
};
例如 vp3->dsi0 或 vp3->dsc0->dsi0:
&route_dsi0 {
status = "okay";
connect = <&vp3_out_dsi0>;
};
例如 vp2->dsi1 或 vp2->dsc1->dsi1:
&route_dsi1 {
status = "okay";
connect = <&vp2_out_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>;
};
ports
以下实例中 ports 是用来 Dispaly Interface 和 panel 之间进行关联。
详细配置说明参阅如下文档:
Documentation/devicetree/bindings/graph.txt
&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 { 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"; };
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"; };
&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"; };
实际应用配置中默认是配置成D-PHY,通过屏端配置介绍可知,通过下面可以配置成 C-PHY:
dsi0_panel: panel@0 {
...
phy-c-option;
...
};
1. Up to 4.5 Gbps per lane in D-PHY
2. 一个D-PHY port 最多4lanes,每个lane由两条差分线组成
1. Up to 2.0 Gsps per trio in C-PHY
2. 一个C-PHY port 最多3lanes,每个lane由 tree-wire-trios 组成
下表罗列在 DPHY Lane 正常操作中可能出现的所有通道状态。
DSI 数据通道可以驱动到如下三种模式:
这三种模式和它们进入对应模式的序列定义如下:
当数据通道处于 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 模式, 发送器应该发送 8-bit Escape Comands 指示请求行为,Escape Comands 如下:
当数据通道进入 Escape 模式且向显示模块发送 Low-Power Data Transmission(LPDT) 序列,Soc 的 MIPI DSI TX 可以通过 LPDT 模式向显示模块发送数据, 一般就是通过这种方式向 MIPI 显示模块下载初始化序列。
通过示波器捕获 LPDT 波形如下:
当 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 波形如下:
当需要从显示模块获取信息时,Soc DPHY 的第一数据通道可以通过执行总线翻转步骤。操作步骤如下:
通过示波器在 HSDT 时向显示模块回读并捕获 BTA 波形如下:
无论是在 LP 和 HS 数据传输模式,数据都是以长包和短包形式打包并传输给显示模块。
Example:
通过示波器在 LPDT 时向显示模块发送如上 SPa 并捕获波形如下:
通过示波器在 HSDT 时向显示模块发送如上 SPa 并捕获波形如下:
Example:
通过示波器在 LPDT 时向显示模块发送如上 LPa 并捕获波形如下:
通过示波器在 HSDT 时向显示模块发送如上 LPa 并捕获波形如下:
如上 SPa 和 LPa 中都有一个 Data Identification (DI), 一个包是长短包就是由 DI 决定,DI 是包头的一部分,由两个部分组成:
MIPI 协议中目前定义的绝大部分数据类型如下:
通过示波器捕获 Non Burst Sync Pulse 波形如下:
通过示波器捕获 Video Burst 波形如下:
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
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 速率的指定有两种,一种是驱动自动计算:
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>;
...
}
根据显示路由选择对应的命令:
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
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
console:/ # dmesg | grep backlight
[ 3.164274] pwm-backlight: probe of backlight failed with error -16
为防止图像显示撕裂,显示控制器刷帧的频率应该和显示模组从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 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/
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
驱动默认如下配置:
level 参考如下:
echo level > reg_400m
level 参考如下:
echo level > cap_peaking
level: 0~7
如下图中信号红色框中的信号参数都是可以调整的。
如下信号调整count值可以在回读基础上做调整修改,比如Tlpx:
cat lpx
echo count > lpx
echo count > hs_prepare_or_prepare_3
echo count > hs_zero_or_prebegin_3
echo count > hs_trail_or_post_3
echo count > hs_exit
echo level > res_up
level参考如下:
echo level > res_dn
level 参考如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。