平台:STM32MP157
屏幕:mipi-dsi接口,1024x600
内核版本:linux5-4

本人是第一次调试mipi屏,在157这个平台上遇到的问题有一点多,接下来简单的描述下我的调试经验

一、先配置一下设备树DTB

&ltdc {port {#address-cells = <1>;#size-cells = <0>;ltdc_ep1_out: endpoint@1 {reg = <1>;remote-endpoint = <&dsi_in>;};};
};&dsi {#address-cells = <1>;#size-cells = <0>;status = "okay";ports {#address-cells = <1>;#size-cells = <0>;port@0 {reg = <0>;dsi_in: endpoint {remote-endpoint = <&ltdc_ep1_out>;};};port@1 {reg = <1>;dsi_out: endpoint {remote-endpoint = <&dsi_panel_in>;};};};panel@0 {compatible = "Hyb-Mipi";reg = <0>;enable-gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>;   reset-gpios = <&gpioe 4 GPIO_ACTIVE_HIGH>;status = "okay";port {dsi_panel_in: endpoint {remote-endpoint = <&dsi_out>;};};};
};

二、驱动选择

在STM32MP157的源码中,自带了一个文件名为panel-simple.c通用驱动。之前已经在这个文件调通了LCD屏幕,打开文件可以看到,其实这个文件也是可以兼容mipi-dsi的屏幕。可能有些屏幕可以使用这个文件去调试,注意是看看CONFIG_DRM_MIPI_DSI这个选项有无有选择。

static int __init panel_simple_init(void)
{int err;err = platform_driver_register(&panel_simple_platform_driver);if (err < 0)return err;if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {err = mipi_dsi_driver_register(&panel_simple_dsi_driver);if (err < 0)return err;}return 0;
}
module_init(panel_simple_init);

而我接下来调试的屏幕无法使用这个文件。

找一个类似的驱动去进行修改填充

大家可以在driver/gpu/drm/panel/源码目录下找到一个其他屏幕厂商的驱动代码进行修改。

接下来驱动代码修改:
首先是驱动和设备树适配

static const struct of_device_id hyb_of_match[] = {{ .compatible = "Hyb-Mipi", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, hyb_of_match);static struct mipi_dsi_driver hyb_driver = {.probe = hyb_dsi_probe,.remove = hyb_dsi_remove,.driver = {.name = "Hyb-Mipi",.of_match_table = hyb_of_match,},
};

适配成功后进入hyb_dsi_probe函数,这个函数接口主要是获取一下设备树设置的一些参数,配置一下DSI格式。

static int hyb_dsi_probe(struct mipi_dsi_device *dsi)
{struct hyb *ctx;int ret;ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);if (!ctx)return -ENOMEM;mipi_dsi_set_drvdata(dsi, ctx);ctx->dsi = dsi;drm_panel_init(&ctx->panel);ctx->panel.dev = &dsi->dev;ctx->panel.funcs = &hyb_funcs;ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_HIGH);if (IS_ERR(ctx->reset)) {DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");return PTR_ERR(ctx->reset);} else {DRM_DEV_ERROR(&dsi->dev, "Success get our reset GPIO\n");gpiod_set_value(ctx->reset, 1);}ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_HIGH);if (IS_ERR(ctx->enable)) {DRM_DEV_ERROR(&dsi->dev, "Couldn't get our enable GPIO\n");return PTR_ERR(ctx->enable);} else {DRM_DEV_ERROR(&dsi->dev, "Success get our enable GPIO\n");gpiod_set_value(ctx->enable, 1);}ret = drm_panel_add(&ctx->panel);if (ret < 0)return ret;dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |MIPI_DSI_CLOCK_NON_CONTINUOUS|MIPI_DSI_MODE_VIDEO_BURST;dsi->format = MIPI_DSI_FMT_RGB888;//显示格式dsi->lanes = 2;//通道return mipi_dsi_attach(dsi);
}

接下来进入hyb_get_modes()函数,这函数主要是配置屏幕参数

static const struct drm_display_mode hyb_default_mode = {.clock     = 51200,.hdisplay  = 1024,.hsync_start    = 1024 + 60,.hsync_end    = 1024 + 60 + 60,.htotal     = 1024 + 60 + 60 + 90,.vdisplay = 600,.vsync_start = 600 + 12,.vsync_end = 600 + 10 + 5,.vtotal       = 600 + 10 + 5 + 2,.vrefresh    = 60,.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
};static int hyb_get_modes(struct drm_panel *panel)
{struct drm_connector *connector = panel->connector;struct hyb *ctx = panel_to_hyb(panel);struct drm_display_mode *mode;mode = drm_mode_duplicate(panel->drm, &hyb_default_mode);if (!mode) {DRM_DEV_ERROR(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",hyb_default_mode.hdisplay,hyb_default_mode.vdisplay,hyb_default_mode.vrefresh);return -ENOMEM;}drm_mode_set_name(mode);drm_mode_probed_add(connector, mode);return 1;
}

接下来就是进入hyb_prepare()函数,MIPI_DSI_MODE_LPM表示默认在 LP 模式下发送初始化序列。这个很重要,因为需要我们发送一个初始化序列到mipi屏上。

static const struct hyb_init_cmd hyb_init_cmds[] = {{ .data = { 0x80, 0x8B } },{ .data = { 0x81, 0x78 } },{ .data = { 0x82, 0x78 } },{ .data = { 0x83, 0x78 } },{ .data = { 0x84, 0x78 } },{ .data = { 0x85, 0x78 } },{ .data = { 0x86, 0x78 } },
};static int hyb_prepare(struct drm_panel *panel)
{struct hyb *ctx = panel_to_hyb(panel);struct mipi_dsi_device *dsi = ctx->dsi;unsigned int i;int ret;gpiod_set_value(ctx->reset, 1);dsi->mode_flags |= MIPI_DSI_MODE_LPM;msleep(200);/* Select User Command Set table (CMD1) */ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xfe, 0x00 }, 2);if (ret < 0) {DRM_DEV_ERROR(dev, "Failed to Set table (%d)\n", ret);    }/* Software reset */ret = mipi_dsi_dcs_soft_reset(dsi);       /* 0x01 */if (ret < 0) {DRM_DEV_ERROR(dev, "Failed to do Software Reset (%d)\n", ret);//return -1;}usleep_range(5000, 10000);      /* > 5ms *///发送初始化序列for (i = 0; i < ARRAY_SIZE(hyb_init_cmds); i++) {const struct hyb_init_cmd *cmd =&hyb_init_cmds[i];ret = mipi_dsi_dcs_write_buffer(dsi, cmd->data,HYB_INIT_CMD_LEN);if (ret < 0) {return ret;}}ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2);if (ret < 0) {printk("Failed to set DSI mode\n");  //dev_err(dev, "Failed to set DSI mode (%d)\n", ret);//goto fail;}ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xB2, 0x10 }, 2);if (ret < 0) {//dev_err(dev, "Failed to set DSI mode (%d)\n", ret);//goto fail;}u8 buffer[2] = {0xB2, 0x10};int value = 0;ret = mipi_dsi_generic_read(dsi, &buffer[0], 1, (void *)&value, sizeof(value));printk("MIPI_DSI_DEBUG: Reg.%02x Set.%02x Get.%02x Ret.%d Flag.%c\n",buffer[0], buffer[1], value, ret, ((buffer[1] == value) ? 'T' : 'F'));/* Set pixel format */ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);//dev_dbg(dev, "Interface color format set to 0x%x\n", color_format);if (ret < 0) {printk("Failed to set pixel format\n");//dev_err(dev, "Failed to set pixel format (%d)\n", ret);//goto fail;}/* Exit sleep mode */ret = mipi_dsi_dcs_exit_sleep_mode(dsi);   /* 0x11 */if (ret < 0) {printk("Failed to exit sleep mode\n");//DRM_DEV_ERROR(&dsi->dev, "Failed to exit sleep mode (%d)\n", ret);//goto fail;}usleep_range(120000, 125000);              /* > 120ms */ret = mipi_dsi_dcs_set_display_on(dsi);        /* 0x29 */if (ret < 0) {printk("Failed to set display ON\n");//DRM_DEV_ERROR(&dsi->dev, "Failed to set display ON (%d)\n", ret);//goto fail;}usleep_range(5000, 10000);                   /* > 5ms */return 0;
}

由于这个屏幕默认是四个通道,但是STM32MP157最多只有两个通道,通过厂商提供的手册,可以通过寄存器进行通道选择的配置。这时候我们在发完初始化序列后,再发配置通道的指令语句,然后,为了验证发送的指令是否改变了MIPI芯片的寄存器,可以进行读取。这样可以保证万无一失,也可以确定是否发送成功,走少很多弯路。

//写入参数
ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xB2, 0x10 }, 2);if (ret < 0) {}u8 buffer[2] = {0xB2, 0x10};int value = 0;//读取对应的寄存器ret = mipi_dsi_generic_read(dsi, &buffer[0], 1, (void *)&value, sizeof(value));printk("MIPI_DSI_DEBUG: Reg.%02x Set.%02x Get.%02x\n",buffer[0], buffer[1], value);

如果顺利的话,基本上开机就能正常启动屏幕了。

调试过程中遇到的坑

第一个问题:在驱动加载中IO口申请失败

我在这个问题停留了有一段时间,用了各种办法都不知道,然后进入系统,手动申请又可以成功。然后把驱动变成模块进去就可以申请成功了,那这个问题就很明显是驱动加载顺序的问题导致的。
问题解决方案:
在内核源码中include/linux/init.h文件定义了加载优先级


我看了一下引脚子系统加载的优先级是arch_initcall
而我们经常使用的module_init()是 device_initcall(fn),驱动对应的加载的优先级为6。所以可以在之后在加载。

static int __init panel_simple_init(void)
{int err;if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {err = mipi_dsi_driver_register(&hyb_driver);if (err < 0)return err;}return 0;
}
module_init(panel_simple_init);
static void __exit panel_simple_exit(void)
{if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))mipi_dsi_driver_unregister(&hyb_driver);}
module_exit(panel_simple_exit);
//module_mipi_dsi_driver(hyb_driver);把这个给屏蔽了,把module_init()添加进去

第二个问题:一直报stm32-display-dsi 5a000000.dsi: Read payload FIFO is empty

[    3.000353] Hyb-Mipi 5a000000.dsi.0: [drm:hyb_dsi_probe]  Success get our reset GPIO
[    3.007902] Hyb-Mipi 5a000000.dsi.0: [drm:hyb_dsi_probe]  Success get our enable GPIO
[    3.020736] [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[    3.025898] [drm] Driver supports precise vblank timestamp query.
[    3.033213] [drm] Initialized stm 1.0.0 20170330 for 5a001000.display-controller on minor 0
[    3.388206] stm32-display-dsi 5a000000.dsi: Read payload FIFO is empty
[    3.409780] stm32-display-dsi 5a000000.dsi: Read payload FIFO is empty
[    3.431353] stm32-display-dsi 5a000000.dsi: Read payload FIFO is empty
[    3.431368] MIPI_DSI_DEBUG: Reg.b2 Set.10 Get.00
[    3.819225] Console: switching to colour frame buffer device 128x37
[    3.880960] stm32-display 5a001000.display-controller: fb0: stmdrmfb frame buffer device


这个问题是没有在代码中添加dsi->mode_flags |= MIPI_DSI_MODE_LPM;
这个直接关于能否正常发送指令和获取寄存器值。

总结:

在现有的条件下,多去对比类似的驱动编写的模式,从中找到规律,并且结合自身的屏幕问题去修改和补充。

基于STM32MP157调试MIPI-DSI屏幕相关推荐

  1. 全志A83T平台调试MIPI DSI屏幕心得

    最近刚调试完全志平台的MIPI屏幕,总的感觉就是简单但网络资料匮乏,却到处都是转载和抄袭,理论知识满天飞,就是很难看见具体的操作步骤,没有步骤可供参考,讲解一大堆官方的MIPI spec有何用,主要是 ...

  2. RK3568—基于GM8775C的MIPI转双通道LVDS屏幕调试

    Rockchip RK3568 原生显示接口不支持双通道LVDS屏幕的数据输出,因此需要借助显示转换芯片才能实现双通道LVDS屏幕的驱动.本文介绍使用GM8775C芯片方案,在 RK3568 平台实现 ...

  3. 全志 Tina Linux LCD显示屏调试指南 支持MIPI DSI RGB LVDS I8080 SPI等接口,开发板支持百问网T113 D1-H哪吒 DongshanPI-D1s V853

    1 概述 编写目的 本文档将介绍sunxi 平台Display Engine 模块中LCD 的调试方法. LCD 调试方法,调试手段. LCD 驱动编写. lcd0 节点下各个属性的解释. 典型LCD ...

  4. MIPI DSI之DBI DPI含义和区别(3-1)

    一.MIPI MIPI(Mobile Industry Processor Interface/移动工业处理器接口)是2003年由ARM.Nokia.ST 等公司成立联盟并为移动应用处理器制定的一个开 ...

  5. Linux的lcd的mipi接口,LCD MIPI DSI简析系列之二【转】

    MIPI DSI 协议标准支持两种模式:Command模式和Video模式. 1 Command 模式 只有当LCD面板带有显示控制器和帧缓冲区的时候才能使用Command模式.数据传送的格式一般是在 ...

  6. MIPI DSI转LVDS东芝TC358775XBG视频解码芯片,RK3399点LVDS屏必备

    TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200. 特征: MIPI接口: (1).支持1/2/3/4 ...

  7. TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200

    TC358775XBG 功能:TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200,其应用图如下: 产品特征 ...

  8. TC358775XBG转换芯片:MIPI DSI转LVDS(单路/双路)

    功能:TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200,其应用图如下: 产品特征: MIPI接口: (1 ...

  9. TOSHIBA,TC358775XBG,MIPI DSI转LVDS,视频解码器,RK3399点LVDS屏必备

    1   功能:TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200,其应用图如下 2产品特征: MIPI接口 ...

  10. MIPI DSI转LVDS TC358775XBG转换芯片

    原厂:Toshiba 型号:TC358775XBG 功能:TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x120 ...

最新文章

  1. 从空间数据库中删除所有拓扑对象
  2. SAP WM初阶根据Group Number来查询与之有关的TO单
  3. codeforces 785D D. Anton and School - 2
  4. python把nan值去掉_python – Keras Neural Nets,如何删除输出中的NaN值?
  5. 一张照片攻破人脸识别系统:能点头摇头张嘴
  6. 【☘️C语言の单链表是否有环问题☘️】
  7. Apache Druid Console 远程命令执行漏洞
  8. 快速乘 防爆乘 快速幂
  9. dqpsk的matlab,基于MATLAB的理想_4_DQPSK系统仿真.pdf
  10. 自动驾驶 6-3 几何横向控制 - Stanley Geometric Lateral Control - Stanley
  11. **海量搜索解决方案_Spring Data Solr [篇3/共3篇]*
  12. 单个索引和组合索引(联合索引)谁效率高
  13. GitHub、Apache 等平台开源项目,受美国出口管制么?
  14. Linux鼠标回报率修改,技术编辑帮您鼠标怎么调回报率
  15. 态度和态度改变:影响思维和情绪
  16. Opencv实战——OCR文档扫描
  17. 论文解读:Generated Knowledge Prompting for Commonsense Reasoning
  18. 网络爬虫全解析(JAVA)--目录
  19. OpenGL学习笔记(一)绘制点线面及多面体
  20. Android 插件化之—— 加载插件中的资源

热门文章

  1. 肖特基二极管工作原理
  2. 【图像算法朝圣之路二】虹膜识别1(K-means算法)
  3. html5制作涂鸦板,HTML5实现涂鸦板
  4. 不懂域名系统,何谈网络编程
  5. 哈利波特信息站web网页课设报告(html+css)
  6. 带头节点 (非头指针) 双向链表 (doubly linked list)
  7. [《与闲适共处》偶感小记]2012年8月28日
  8. 恒指2.25日预测及操作建议
  9. Keil uVision5开发一个基于LPC17XX系列芯片的工程文件
  10. HTML——使用表格制作个人简历