基于 NXP i.MX8QM Bumblebee 智能座舱 MIPI 接口 HannStar HSD123KPW2 屏幕调试


一. 前言

WPI  i.MX8QM Bumblebee 智能座舱项目需要调试  HSD123KPW2 的屏幕 ,主板有两路 MIPI 信号输出,屏的分辨率为 1920 X 720 ,屏幕通过 Serdes 的方式与主板相连 ,主板串行器为 TI DS90UB941 ,屏幕解串器为 TI DS90UB941 ,主板把 MIPI 信号通过 TI DS90UB941 串行器发送给屏幕解串器 DS90UB948 , DS90UB948 输出双 MIPI 信号给屏幕进行显示



                                                                                                                   图1 信号数据流程图

二. 屏幕调试环境


2.1.  软件环境 :

使用软件版本为 imx-automotive-10.0.0_1.1.0 , 推荐使用 Android 10 及以上版本 ,对应的 Linux 版本为 :L4.19.42

Lunch 选择 :mek_8q-userdebug

2.2.  硬件环境 :

Bumblebee-MB_V1.0(i.MX8QM 智能座舱)

HSD123KPW2  , 1920 X 720 , 12.3 寸的屏幕


                             
图2 Bumblebee-MB_V1.0

三. 实现 Serdes 数据通信

3.1 对 DS90UB941 进行上电

 使能 DSI0_VDD1V8 ,DSI0_VDD_1V1 这两个电平


                                                       
             图3 DS90UB941 原理图

3.2 配置 MODE_SEL0 和 MODE_SEL1 电平


                                                
图4 DS90UB941 MODE_SEL0 电路图

     
      MODE_SEL0 电平配置 :

                                                                  图5 MODE_SEL0 配置说明
   
 MODE_SEL1 电平配置 :


                                                                               图6 MODE_SEL1 配置说明

以上设置完成后可以检查到 DS90UB941 和 DS90UB948 这两个设备

四.  驱动程序编写

4.1 DS90UB941 & DS90UB948 寄存器配置

在 vendor\nxp-opensource\kernel_imx\drivers\gpu\drm\bridge 目录下添加驱动程序 ti941.c

4.1.1  DS90UB941 I2C WRITE 函数 

struct STi941_config
{
   unsigned char ti941_reg;
   unsigned char ti941_data;
};

struct sTI941
{
  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 ti941_write_reg(struct sTI941 *ti941, u8 reg, u8 val)
{
  struct regmap *regmap = ti941->lvds_regmap;
  int ret;

  ret = regmap_write(regmap, reg, val);

  return ret;
}

4.1.2  DS90UB941 I2C READ 函数

static int ti941_read_reg(struct sTI941 *ti941, u8 reg)
{
  struct regmap *regmap = ti941->lvds_regmap;
  int ret;
  unsigned int status;

  ret = regmap_read(regmap, reg, &status);

  reg = status;

  return ret;
}

4.1.3   使能 DSI0_VDD1V8 和 DSI0_VDD_1V1

#define IMX_GPIO_NR(bank, pin)  (480 - (bank * 32) + (pin & 0x1f))
#define LSIO_GPIO2_IO29 IMX_GPIO_NR(2, 29)      /* GPIO2_29 */
#define LSIO_GPIO2_IO30 IMX_GPIO_NR(2, 30)      /* GPIO2_30 */

static void Ti941_StartUp(void)
{
  gpio_request(LSIO_GPIO2_IO29, "gpio2_io22_DSI0_1V1_EN");
  gpio_direction_output(LSIO_GPIO2_IO29, 1);

  gpio_request(LSIO_GPIO2_IO30, "gpio2_io23_DSI0_1V8_EN");
  gpio_direction_output(LSIO_GPIO2_IO30, 1);
}

4.1.4    DS90UB941 初始化函数

static int ti941_init(struct sTI941 *ti941)
{   
    int i,num;
    num = ARRAYSIZE(ti941_para);
    for ( i = 0; i< num; i++)
    {
      u8 reg = ti941_para[i].ti941_reg;
      u8 val = ti941_para[i].ti941_data;
      printk("ti941 num %d:0x%02x 0x%02x \r\n",i,reg,val);

      if (ti941_write_reg(ti941,reg,val) < 0)
      {
        printk("ti941_write_reg fail : reg = 0x%02x.\n", reg);

      }
    }
}

4.1.5  注册 DS90UB941 & DS90UB948  I2C 设置

#define TI941_I2C_ADDR                0x10
#define DSI0_TI948_I2C_ADDR     0x34

static int ti941_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    。。。。。。。。。。。。。。。。。。。。。。。。
     ti941->lvds_i2c = i2c_new_dummy(client->adapter , TI941_I2C_ADDR) ;
     
     ti948->lvds_i2c = i2c_new_dummy(client->adapter , DSI0_TI948_I2C_ADDR);

     Ti941_StartUp();

      ti941_init(ti941); 
}

DS90UB948 I2C 设备初始化可以参考 DS90UB941 部分

4.1.6  DS90UB941 寄存器配置

struct STi941_config ti941_para[] =
{
  {0x03, 0x9a}, {0x05, 0x04}, {0x1e, 0x01}, {0x07, 0x32}, {0x08, 0x32}, {0x0d, 0x33},
  {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, 0xe2}, {0x64, 0x70}, {0x65, 0x04}, {0x66, 0x03}, {0x67, 0x02}
};

4.2 HannStar HSD123KPW2  屏幕参数配置

我们首先了解一下这块屏的 Timing


                                                                            图7 hanstar hsd123kpw2 Timing

根据以上信息 ,我们在 vendor\nxp-opensource\kernel_imx\drivers\gpu\drm\panel 添加 panel-hanstar-hsd123kpw2.c 屏幕驱动

Panel 初始化 :

static int rad_panel_probe(struct mipi_dsi_device *dsi)
{
  。。。。。。。。。。。。。。。。。。。。。。。。。。

  videomode_from_timing(&rad_default_timing, &panel->vm); 
  if ( ret < 0 )
      return ret;

  drm_panel_init(&panel->base);
  panel->base.funcs = &rad_panel_funcs; panel->base.dev = dev;

  ret = drm_panel_add(&panel->base);
  if (ret < 0)
      return ret;

 ret = mipi_dsi_attach(dsi);
 if (ret < 0)
     drm_panel_remove(&panel->base);
}

屏幕 Timing 设置 :

static const struct display_timing rad_default_timing = {
.pixelclock = { 75000000, 75000000, 75000000  },
.hactive = { 1920, 1920, 1920 },
.hfront_porch = { 40, 40, 40 },
.hsync_len = { 20, 60, 100 },
.hback_porch = { 220, 220, 220 },
.vactive = { 720, 720, 720 },
.vfront_porch = { 7, 7, 7 },
.vsync_len = { 10, 10, 10 },
.vback_porch = { 21, 21, 21 },
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH| DISPLAY_FLAGS_PIXDATA_NEGEDGE,};
};


4.3 i.MX8 MIPI 信号输出


修改 vendor\nxp-opensource\kernel_imx\arch\arm64\boot\dts\freescale\fsl-imx8qm-mek.dtsi

diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi
+/*
&i2c0_mipi_dsi0 {
#address-cells = <1>;
#size-cells = <0>;
@@ -1479,6 +1483,23 @@
};
};
};
+*/

+
+&i2c0_mipi_dsi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mipi0_lpi2c0>;
+ clock-frequency = <100000>;
+ status = "okay";
+
+ ti941_bridge@3d {
+ compatible = "ti,ti941";
+ reg = <0x3d>;
+ status = "okay";
+ };
+};
+

+/*
&mipi_dsi_bridge1 {
status = "okay";

@@ -1498,6 +1520,31 @@
};
};
};
+*/

+
+&mipi_dsi_bridge1 {
+ status = "okay";
+
+ panel@0 {
+ compatible = "hanstar,hsd123kpw2";
+ reg = <0>;
+ dsi-lanes = <4>;
+ panel-width-mm = <68>;
+ panel-height-mm = <121>;
+
+ port {
+ panel1_in: endpoint {
+ remote-endpoint = <&mipi_bridge1_out>;
+ };
+ };
+ };
+
+ port@2 {
+ mipi_bridge1_out: endpoint {
+ remote-endpoint = <&panel1_in>;
+ };
+ };
+};



五. 点亮屏幕



                               
图8  点亮屏幕 

对 Bumblebee 智能座舱  HSD123KPW2 屏幕进行调试 , 首先是打通 DS90UB941 和 DS90UB948 之间的通信 ,需要使能 1.8V 和 1.1V ,

设置 MODE_SEL 模式 ,这样可以打通 DS90UB941 和 DS90UB948 之间的通信 ,接着是对  DS90UB941 和 DS90UB948 进行初始化 ,

然后是设置屏的 Timing 和 MIPI 信号输出 ,通过以上内容相信大家已经了解怎样通过 Serdes 的方式调试 MIPI 信号输出的屏幕

六 参考文档

【1】 DS90UB941-q1.pdf  SNLS640 –DECEMBER 2018 
【2】 DS90UB948-q1.pdf  ZHCSEN7A –OCTOBER 2014–REVISED JANUARY 2016
【3】 HSD123KPW2-A10 Formal Specification 2.0.pdf    DC140-002917    Revision : 2.0
【4】 Android_User's_Guide.pdf  Rev. automotive-10.0.0_1.1.0 — 24 March 2020

相关视频

【视频博文】基于 NXP i.MX8QM Bumblebee 智能座舱 MIPI 接口 HannStar HSD123KPW2 屏幕调试

基于 NXP i.MX8QM Bumblebee 智能座舱 MIPI 接口 HannStar HSD123KPW2 屏幕调试 , 主板有两路 MIPI 信号输出,屏的分辨率为 1920 X 720 ,

屏幕通过 Serdes 的方式与主板相连 ,主板串行器为 TI DS90UB941 ,屏幕解串器为 TI DS90UB941 ,主板把 MIPI 信号通过 TI DS90UB941

串行器发送给屏幕解串器 DS90UB948 , DS90UB948 输出双 MIPI 信号给屏幕进行显示 ,对 Bumblebee 智能座舱  HSD123KPW2 屏幕进行调试 ,

首先是打通 DS90UB941 和 DS90UB948 之间的通信 ,需要使能 1.8V 和 1.1V ,设置 MODE_SEL 模式 ,这样可以打通 DS90UB941 和 DS90UB948 之间的通信 ,

接着是对  DS90UB941 和 DS90UB948 进行初始化 ,然后是设置屏的 Timing 和 MIPI 信号输出 ,经过以上操作 ,屏幕可以正常显示

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论

hahaha123

hahaha123

7 个月前
您好,请问方便分享一下驱动代码和dts配置作为参考吗,在调941的时候碰到了一些问题,谢谢!
Delver

Delver

2021年10月20日
博主你好!我使用的是i.mx8qxp, ds90ub941+ds90ub928,slave i2c通信正常。但是ds90ub941提示mipi dsi protocol err,请问是怎么回事?请问你的941的device tree是怎么配置的?谢谢!