一. 前言
WPI i.MX8QM Bumblebee 智能座舱项目需要调试 HSD123KPW2 的屏幕 ,屏幕的接口为 LVDS ,分辨率为 1920 X 720 ,屏幕通过 Serdes 的方式与主板相连 ,主板串行器为 TI DS90UB947 ,屏幕解串器为 TI DS90UB948 ,主板把 LVDS 信号通过 TI DS90UB947 串行器发送给屏幕解串器 DS90UB948 , DS90UB948 输出双 LVDS 信号给屏幕进行显示
图1 信号数据流程图
二. 屏幕调试环境
2.1. 软件环境 :
使用的是 imx-yocto_L4.14.98_0.0.0
2.2. 硬件环境 :
Bumblebee-MB_V1.0(i.MX8QM 智能座舱)
HSD123KPW2 , 1920 X 720 , 12.3 寸的屏幕
图2 Bumblebee-MB_V1.0
三. 实现 Serdes 数据通信
通过 i2cdetect 工具检查不到 TI947 和 TI948 这两个设备 ,通过电路图发现 :需要使能 LVDS0_VDD1V8 ,LVDS0_VDD_1V1 这两个电平
图3 DS90UB947 原理图
LVDS0_VDD1V8 对应的 i.MX8QM 芯片引脚是 ESAI0_FST,LVDS0_VDD_1V1 对应的 i.MX8QM 芯片引脚是 ESAI0_FSR ,
图4 i.MX8QM 芯片引脚图
使能上面两个电压后通过 i2cdetect 工具还是检查不到 DS90UB947 和 DS90UB948 这两个设备 ,通过查看 DS90UB947-Q1 的规格书了解到 :
DS90UB947 有一个 I2CSEL 的引脚 ,I2C 选择为 1.8V ,这个脚需要上拉
图5 TI947 I2CSEL 使用方法
在进行了以上操作后 ,通过 i2cdetect 工具 可以识别到 DS90UB947 和 DS90UB94948 这两个设备
从下图可以知道 DS90UB947 的设备地址为 0X0C
图6 TI947 设备地址
通过读取 DS90UB947 0X06 的地址 ,知道 Des ID 7 位地址为 0X34
图7 DS90UB947 0X06 寄存器
图8 DS90UB948 设备地址
四. 驱动程序编写
4.1 DS90UB947 & DS90UB948 寄存器配置
在 kernel-source/drivers/gpu/drm/bridge 路径下添加驱动程序 ti947.c
4.1.1 DS90UB947 I2C WRITE 函数
struct STi947_config {
unsigned char ti947_reg;
unsigned char ti947_data;
};
struct sTI947 {
struct i2c_client *lvds_i2c;
struct regmap *lvds_regmap;
struct drm_bridge bridge;
struct drm_connector connector;
struct gpio_desc *reset_gpio;
bool is_hdmi;
bool split_mode;
};
static int ti947_write_reg(struct sTI947 *ti947, u8 reg, u8 val)
{
struct regmap *regmap = ti947->lvds_regmap;
int ret;
ret = regmap_write(regmap, reg, val);
return ret;
}
4.1.2 DS90UB947 I2C READ 函数
static int ti947_read_reg(struct sTI947 *ti947, u8 reg)
{
struct regmap *regmap = ti947->lvds_regmap;
int ret;
unsigned int status;
ret = regmap_read(regmap, reg, &status);
reg = status;
return ret;
}
4.1.3 使能 LVDS0_VDD1V8 和 LVDS0_VDD_1V1
#define IMX_GPIO_NR(bank, pin) (480 - (bank * 32) + (pin & 0x1f))
#define LSIO_GPIO2_IO27 IMX_GPIO_NR(2, 27) /* GPIO2_27 LVDS1_1V1_EN */
#define LSIO_GPIO2_IO28 IMX_GPIO_NR(2, 28) /* GPIO2_28 LVDS1_1V8_EN */
static void Ti947_StartUp(void)
{
gpio_request(LSIO_GPIO2_IO27, "gpio2_io27_LVDS1_1V1_EN");
gpio_direction_output(LSIO_GPIO2_IO27, 1);
gpio_request(LSIO_GPIO2_IO28, "lsio_gpio2_io28_LVDS1_1V8_EN");
gpio_direction_output(LSIO_GPIO2_IO28, 1);
}
4.1.4 DS90UB947 初始化函数
static int ti947_init(struct sTI947 *ti947)
{
int i,num;
num = ARRAYSIZE(ti947_para);
for ( i = 0; i< num; i++)
{
u8 reg = ti947_para[i].ti947_reg;
u8 val = ti947_para[i].ti947_data;
if (ti947_write_reg(ti947,reg,val) < 0)
{
printk("ti947_write_reg fail : reg = 0x%02x.\n", reg);
}
}
}
4.1.5 注册 DS90UB947 & DS90UB948 I2C 设置
#define LVDS1_TI947_I2C_ADDR 0x0C
#define LVDS1_TI948_I2C_ADDR 0x34
static int ti947_probe(struct i2c_client *client,static int ti947_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
。。。。。。。。。。。。。。。。。。。。。。。。
ti947->lvds_i2c = i2c_new_dummy(client->adapter , LVDS1_TI947_I2C_ADDR) ;
ti948->lvds_i2c = i2c_new_dummy(client->adapter , LVDS1_TI948_I2C_ADDR);
Ti947_StartUp();
ti947_init(ti947);
}
DS90UB948 I2C 设备初始化可以参考 DS90UB947 部分
4.1.6 DS90UB947 寄存器配置
struct STi947_config ti947_para[] = {
{0x03, 0x9a},
{0x05, 0x04},
{0x1e, 0x01},
{0x07, 0x32},
{0x08, 0x32},
{0x0d, 0x23},
{0x0e, 0x73},
{0x0f, 0x07},
{0x10, 0x33},
{0x11, 0x33},
{0x12, 0x00},
{0x14, 0x04},
{0x17, 0x1e},
{0x30, 0x00},
{0x4f, 0x8c},
{0x54, 0x00},
{0x56, 0x00},
{0x5b, 0x21},
{0x5c, 0x67},
{0x64, 0x70},
{0x65, 0x04},
{0x66, 0x03},
{0x67, 0x02},
{0x6e, 0x20},
{0x70, 0x30},
{0x77, 0x30},
{0x71, 0x94},
{0x78, 0x94},
WPI i.MX8QM Bumblebee 智能座舱项目需要调试 HSD123KPW2 的屏幕 ,屏幕的接口为 LVDS ,分辨率为 1920 X 720 ,屏幕通过 Serdes 的方式与主板相连 ,主板串行器为 TI DS90UB947 ,屏幕解串器为 TI DS90UB948 ,主板把 LVDS 信号通过 TI DS90UB947 串行器发送给屏幕解串器 DS90UB948 , DS90UB948 输出双 LVDS 信号给屏幕进行显示
图1 信号数据流程图
二. 屏幕调试环境
2.1. 软件环境 :
使用的是 imx-yocto_L4.14.98_0.0.0
2.2. 硬件环境 :
Bumblebee-MB_V1.0(i.MX8QM 智能座舱)
HSD123KPW2 , 1920 X 720 , 12.3 寸的屏幕
图2 Bumblebee-MB_V1.0
三. 实现 Serdes 数据通信
通过 i2cdetect 工具检查不到 TI947 和 TI948 这两个设备 ,通过电路图发现 :需要使能 LVDS0_VDD1V8 ,LVDS0_VDD_1V1 这两个电平
图3 DS90UB947 原理图
LVDS0_VDD1V8 对应的 i.MX8QM 芯片引脚是 ESAI0_FST,LVDS0_VDD_1V1 对应的 i.MX8QM 芯片引脚是 ESAI0_FSR ,
图4 i.MX8QM 芯片引脚图
使能上面两个电压后通过 i2cdetect 工具还是检查不到 DS90UB947 和 DS90UB948 这两个设备 ,通过查看 DS90UB947-Q1 的规格书了解到 :
DS90UB947 有一个 I2CSEL 的引脚 ,I2C 选择为 1.8V ,这个脚需要上拉
图5 TI947 I2CSEL 使用方法
在进行了以上操作后 ,通过 i2cdetect 工具 可以识别到 DS90UB947 和 DS90UB94948 这两个设备
从下图可以知道 DS90UB947 的设备地址为 0X0C
图6 TI947 设备地址
通过读取 DS90UB947 0X06 的地址 ,知道 Des ID 7 位地址为 0X34
图7 DS90UB947 0X06 寄存器
图8 DS90UB948 设备地址
四. 驱动程序编写
4.1 DS90UB947 & DS90UB948 寄存器配置
在 kernel-source/drivers/gpu/drm/bridge 路径下添加驱动程序 ti947.c
4.1.1 DS90UB947 I2C WRITE 函数
struct STi947_config {
unsigned char ti947_reg;
unsigned char ti947_data;
};
struct sTI947 {
struct i2c_client *lvds_i2c;
struct regmap *lvds_regmap;
struct drm_bridge bridge;
struct drm_connector connector;
struct gpio_desc *reset_gpio;
bool is_hdmi;
bool split_mode;
};
static int ti947_write_reg(struct sTI947 *ti947, u8 reg, u8 val)
{
struct regmap *regmap = ti947->lvds_regmap;
int ret;
ret = regmap_write(regmap, reg, val);
return ret;
}
4.1.2 DS90UB947 I2C READ 函数
static int ti947_read_reg(struct sTI947 *ti947, u8 reg)
{
struct regmap *regmap = ti947->lvds_regmap;
int ret;
unsigned int status;
ret = regmap_read(regmap, reg, &status);
reg = status;
return ret;
}
4.1.3 使能 LVDS0_VDD1V8 和 LVDS0_VDD_1V1
#define IMX_GPIO_NR(bank, pin) (480 - (bank * 32) + (pin & 0x1f))
#define LSIO_GPIO2_IO27 IMX_GPIO_NR(2, 27) /* GPIO2_27 LVDS1_1V1_EN */
#define LSIO_GPIO2_IO28 IMX_GPIO_NR(2, 28) /* GPIO2_28 LVDS1_1V8_EN */
static void Ti947_StartUp(void)
{
gpio_request(LSIO_GPIO2_IO27, "gpio2_io27_LVDS1_1V1_EN");
gpio_direction_output(LSIO_GPIO2_IO27, 1);
gpio_request(LSIO_GPIO2_IO28, "lsio_gpio2_io28_LVDS1_1V8_EN");
gpio_direction_output(LSIO_GPIO2_IO28, 1);
}
4.1.4 DS90UB947 初始化函数
static int ti947_init(struct sTI947 *ti947)
{
int i,num;
num = ARRAYSIZE(ti947_para);
for ( i = 0; i< num; i++)
{
u8 reg = ti947_para[i].ti947_reg;
u8 val = ti947_para[i].ti947_data;
if (ti947_write_reg(ti947,reg,val) < 0)
{
printk("ti947_write_reg fail : reg = 0x%02x.\n", reg);
}
}
}
4.1.5 注册 DS90UB947 & DS90UB948 I2C 设置
#define LVDS1_TI947_I2C_ADDR 0x0C
#define LVDS1_TI948_I2C_ADDR 0x34
static int ti947_probe(struct i2c_client *client,static int ti947_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
。。。。。。。。。。。。。。。。。。。。。。。。
ti947->lvds_i2c = i2c_new_dummy(client->adapter , LVDS1_TI947_I2C_ADDR) ;
ti948->lvds_i2c = i2c_new_dummy(client->adapter , LVDS1_TI948_I2C_ADDR);
Ti947_StartUp();
ti947_init(ti947);
}
DS90UB948 I2C 设备初始化可以参考 DS90UB947 部分
4.1.6 DS90UB947 寄存器配置
struct STi947_config ti947_para[] = {
{0x03, 0x9a},
{0x05, 0x04},
{0x1e, 0x01},
{0x07, 0x32},
{0x08, 0x32},
{0x0d, 0x23},
{0x0e, 0x73},
{0x0f, 0x07},
{0x10, 0x33},
{0x11, 0x33},
{0x12, 0x00},
{0x14, 0x04},
{0x17, 0x1e},
{0x30, 0x00},
{0x4f, 0x8c},
{0x54, 0x00},
{0x56, 0x00},
{0x5b, 0x21},
{0x5c, 0x67},
{0x64, 0x70},
{0x65, 0x04},
{0x66, 0x03},
{0x67, 0x02},
{0x6e, 0x20},
{0x70, 0x30},
{0x77, 0x30},
{0x71, 0x94},
{0x78, 0x94},
{0x72, 0x96},
{0x79, 0x96},
{0x73, 0x90},
{0x7a, 0x90}
};
4.1.7 DS90UB948 寄存器配置
struct ti948_config ti948_para[] =
{
{0x03, 0x78},
{0x05, 0x1e},
{0x34, 0x01},
{0x1d, 0x19},
{0x1e, 0x39},
{0x1f, 0x03},
{0x20, 0x59},
{0x21, 0x55},
{0x23, 0x30},
{0x26, 0x15},
{0x27, 0x15},
{0x43, 0x03},
{0x49, 0xe1},
{0x64, 0x70},
{0x65, 0x04},
{0x66, 0x03},
{0x67, 0x02}
};
4.2 HannStar HSD123KPW2 屏幕参数配置
我们首先了解一下这块屏的 Timing
图9 HSD123KPW2 Timing
根据以上信息 ,我们在 drivers/gpu/drm/panel/panel-simple.c 添加 HSD123KPW2 屏幕参数部分
添加 hannstar_hsd100pxn1_timing :
@@ -977,6 +977,19 @@ static const struct display_timing hannstar_hsd100pxn1_timing = { .flags = DISPLAY_FLAGS_DE_HIGH, }; +static const struct display_timing hannstar_hsd123kp2_timing = { + .pixelclock = { 55000000, 65000000, 75000000 }, + .hactive = { 1920, 1920, 1920 }, + .hfront_porch = { 40, 40, 40 }, + .hback_porch = { 220, 220, 220 }, + .hsync_len = { 20, 60, 100 }, + .vactive = { 720, 720, 720 }, + .vfront_porch = { 7, 7, 7 }, + .vback_porch = { 21, 21, 21 }, + .vsync_len = { 10, 10, 10 }, + .flags = DISPLAY_FLAGS_DE_HIGH, +}; + |
添加 panel_desc hannstar_hsd100pxn1 关于数据格式信息 :
@@ -988,6 +1001,17 @@ static const struct panel_desc hannstar_hsd100pxn1 = { .bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, }; +static const struct panel_desc hannstar_hsd123kpw2_timing= { + .timings = &hannstar_hsd123kp2_timing, + .num_timings = 1, + .bpc = 6, + .size = { + .width = 203, + .height = 152, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, +}; + |
添加 platform_of_match :
@@ -2049,6 +2073,10 @@ static const struct of_device_id platform_of_match[] = { .compatible = "hannstar,hsd100pxn1", .data = &hannstar_hsd100pxn1, }, { + .compatible = "hanstar,hsd123kpw2", + .data = &hannstar_hsd123kpw2_timing, + }, { + }, { .compatible = "hit,tx23d38vm0caa", .data = &hitachi_tx23d38vm0caa }, { |
4.3 i.MX8 LVDS 信号输出
修改 /arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi
+&i2c1_lvds0 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lvds0_lpi2c1_M>; + clock-frequency = <100000>; + status = "okay"; + + lvds-to-Panel@4c { + compatible = "ti,ti947"; + reg = <0x4c>; + + port { + ti947_0_in: endpoint { + clock-lanes = <3>; + data-lanes = <0 1 2 4>; + remote-endpoint = <&lvds0_out>; }; }; }; }; |
+&i2c1_lvds1 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lvds1_lpi2c1>; + clock-frequency = <100000>; + status = "okay"; + + lvds-to-hdmi-bridge@4c { + compatible = "ti,ti947"; + reg = <0x4c>; + + port { + ti947_1_in: endpoint { + clock-lanes = <3>; + data-lanes = <0 1 2 4>; + remote-endpoint = <&lvds1_out>; + }; + }; + }; +}; + |
添加一个 fsl-imx8qm-mek-hanstar-hsd123kpw2-lvds-panel.dts 文件 :
+++ b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek-hanstar-hsd123kpw2-lvds-panel.dts @@ -0,0 +1,90 @@ +/* + * Copyright 2017-2018 NXP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "fsl-imx8qm-mek.dts" + +/ { + lvds0_panel { + compatible = "hanstar,hsd123kpw2"; + backlight = <&lvds_backlight1>; + + port { + panel_lvds0_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; + + lvds1_panel { + compatible = "hanstar,hsd123kpw2"; + backlight = <&lvds_backlight1>; + + port { + panel_lvds1_in: endpoint { + remote-endpoint = <&lvds1_out>; + }; + }; + }; + +}; + + +&ldb1_phy { + status = "okay"; +}; + +&ldb1 { + status = "okay"; + fsl,dual-channel; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + + port@1 { + reg = <1>; + + lvds0_out: endpoint { + remote-endpoint = <&panel_lvds0_in>; + }; + }; + }; +}; + +&ldb2_phy { + status = "disabled"; +}; + +&ldb2 { + status = "disabled"; + fsl,dual-channel; + + lvds-channel@0 { + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + status = "disabled"; + + port@1 { + reg = <1>; + lvds1_out: endpoint { + remote-endpoint = <&panel_lvds1_in>; + }; + }; + }; +}; + |
五. 点亮屏幕
运行 root@imx8qmmek:/opt/viv_samples/vdk# ./tutorial1
图10 三角形画面
运行 root@imx8qmmek:/opt/viv_samples/vdk# ./tutorial2
图11 长方体画面
对 Bumblebee 智能座舱 HSD123KPW2 屏幕进行调试 , 首先是打通 DS90UB947 和 DS90UB948 之间的通信 ,需要使能 1.8V 和 1.1V ,然后是对 I2CSEL PIN 脚进行上拉 ,这样可以打通 DS90UB947 和 DS90UB948 之间的通信 ,接着是对 DS90UB947 和 DS90UB948 进行初始化 ,然后是设置屏的 Timing 和 LVDS 信号输出 ,通过以上内容相信大家已经了解怎样通过 Serdes 的方式调试 LVDS 信号输出的屏幕
六 参考文档
【1】 DS90UB947-q1.pdf SNLS454A –NOVEMBER 2014–REVISED MARCH 2019
【2】 DS90UB948-q1.pdf ZHCSEN7A –OCTOBER 2014–REVISED JANUARY 2016
【3】 HSD123KPW2-A10 Formal Specification 2.0.pdf DC140-002917 Revision : 2.0
评论
enn
2022年3月21日
enn
2022年3月21日