当前位置:   article > 正文

RK3566恢复显示屏异常显示的方法_rk3566 屏幕不亮 排查

rk3566 屏幕不亮 排查

 设备进行EMI静电测试时,LCD显示屏异常之后不能恢复,需要在软件上检测LCD是否处于工作状态,如果没有处于工作状态,则需要重启LCD。

如何确定LCD是否处于工作状态?

参照SDK docs/Common/DISPLAY路径下的Rockchip_DRM_Panel_Porting_Guide_V1.6_20190228.pdf》文档,其中3.4章节提到了如何判断MIPI-DSI外设有正常工作?瑞芯微也为此申请了专利。

drivers/gpu/drm/drm_mipi_dsi.c

kernel/include/drm/drm_mipi_dsi.h

提供了对 MIPI-DSI 外设通信的相关 API。

支持 DCS 标准 MIPI_DCS_GET_POWER_MODE(0x0A)命令的外设,可以通过读取 power_mode 来判断,函数mipi_dsi_dcs_get_power_mode() - query the display module's current power mode。mode=0x08 说 明 设 备 目 前 是 OFF 状 态,mode=0x9c,说明设备目前是 ON 状态。

驱动说明文档<rockchip_drm_integration_helper-zh.pdf>

  1. # echo off > /sys/class/drm/card0-DSI-1/status
  2. # echo on > /sys/class/drm/card0-DSI-1/status

修改驱动,启动时获取power_mode
..\x3566_linux_v1.2.0\kernel\drivers\gpu\drm\panel\panel-simple.c文件,在static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)函数中增加读取液晶状态的函数:

  1. static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
  2. {
  3. struct panel_simple *panel;
  4. struct device *dev = &dsi->dev;
  5. const struct panel_desc_dsi *desc;
  6. struct panel_desc_dsi *d;
  7. const struct of_device_id *id;
  8. int err;
  9. u8 mode;
  10. id = of_match_node(dsi_of_match, dsi->dev.of_node);
  11. if (!id)
  12. return -ENODEV;
  13. dev_info(dev, "panel_simple_dsi_probe\n");
  14. if (!id->data) {
  15. d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
  16. if (!d)
  17. return -ENOMEM;
  18. err = panel_simple_dsi_of_get_desc_data(dev, d);
  19. if (err) {
  20. dev_err(dev, "failed to get desc data: %d\n", err);
  21. return err;
  22. }
  23. }
  24. desc = id->data ? id->data : d;
  25. err = panel_simple_probe(&dsi->dev, &desc->desc);
  26. if (err < 0)
  27. return err;
  28. panel = dev_get_drvdata(dev);
  29. panel->dsi = dsi;
  30. dsi->mode_flags = desc->flags;
  31. dsi->format = desc->format;
  32. dsi->lanes = desc->lanes;
  33. ++ /* user add begin */
  34. ++ if(dsi)
  35. ++ {
  36. ++ err = mipi_dsi_dcs_get_power_mode( dsi, &mode);
  37. ++ dev_info( dev, "get_power_mode err=%d, mode=%02x\n", err, mode );
  38. ++ }
  39. ++ /* user add end */
  40. err = mipi_dsi_attach(dsi);
  41. if (err) {
  42. struct panel_simple *panel = dev_get_drvdata(&dsi->dev);
  43. drm_panel_remove(&panel->base);
  44. }
  45. return err;
  46. }

启动时没有连接屏幕,打印如下:

  1. [root@RK356X:/]# dmesg | grep get_power_mode
  2. [ 0.267272] panel-simple-dsi fe060000.dsi.0: get_power_mode err=-110, mode=02

启动时连接了屏幕,打印如下:

  1. [root@RK356X:/]# dmesg | grep get_power_mode
  2. [ 0.268318] panel-simple-dsi fe060000.dsi.0: get_power_mode err=0, mode=9c

设备运行过程中定时查询屏幕状态

在panel-simple.c文件中增加一个内核线程函数,每5s读取一次power_mode:

  1. static int kthread_checkLCDstatus_func(void * data)
  2. {
  3. struct mipi_dsi_device *dsi = (struct mipi_dsi_device *)data;
  4. int err;
  5. u8 mode;
  6. while (!kthread_should_stop())
  7. {
  8. err = mipi_dsi_dcs_get_power_mode( dsi, &mode);
  9. dev_info( &dsi->dev, "get_power_mode err=%d, mode=%02x\n", err, mode );
  10. msleep(5000);
  11. }
  12. return 0;
  13. }

在panel_simple_dsi_probe()函数中创建并运行checkLCDstatus_kthread线程:

  1. static struct task_struct *checkLCDstatus_kthread = NULL;
  2. static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
  3. {
  4. struct panel_simple *panel;
  5. struct device *dev = &dsi->dev;
  6. const struct panel_desc_dsi *desc;
  7. struct panel_desc_dsi *d;
  8. const struct of_device_id *id;
  9. int err;
  10. u8 mode;
  11. id = of_match_node(dsi_of_match, dsi->dev.of_node);
  12. if (!id)
  13. return -ENODEV;
  14. if (!id->data) {
  15. d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
  16. if (!d)
  17. return -ENOMEM;
  18. err = panel_simple_dsi_of_get_desc_data(dev, d);
  19. if (err) {
  20. dev_err(dev, "failed to get desc data: %d\n", err);
  21. return err;
  22. }
  23. }
  24. desc = id->data ? id->data : d;
  25. err = panel_simple_probe(&dsi->dev, &desc->desc);
  26. if (err < 0)
  27. return err;
  28. panel = dev_get_drvdata(dev);
  29. panel->dsi = dsi;
  30. dsi->mode_flags = desc->flags;
  31. dsi->format = desc->format;
  32. dsi->lanes = desc->lanes;
  33. ++ /* user add begin */
  34. ++ if(dsi)
  35. ++ {
  36. ++ err = mipi_dsi_dcs_get_power_mode( dsi, &mode);
  37. ++ dev_info( dev, "get_power_mode err=%d, mode=%02x\n", err, mode );
  38. ++ checkLCDstatus_kthread = kthread_run(kthread_checkLCDstatus_func, dsi, "test_task");
  39. ++ }
  40. ++ /* user add end */
  41. err = mipi_dsi_attach(dsi);
  42. if (err) {
  43. struct panel_simple *panel = dev_get_drvdata(&dsi->dev);
  44. drm_panel_remove(&panel->base);
  45. }
  46. return err;
  47. }

设备运行过程中,手动复位触发LCD复位,读取的mode重9c变为了08,日志如下: 

  1. [ 118.415228] kthread is running
  2. [ 118.418300] panel-simple-dsi fe060000.dsi.0: get_power_mode err=0, mode=9c
  3. [ 123.535187] kthread is running
  4. [ 123.541131] panel-simple-dsi fe060000.dsi.0: get_power_mode err=0, mode=9c
  5. [ 128.655245] kthread is running
  6. [ 128.664003] panel-simple-dsi fe060000.dsi.0: get_power_mode err=0, mode=08
  7. [ 133.775156] kthread is running
  8. [ 133.786790] panel-simple-dsi fe060000.dsi.0: get_power_mode err=0, mode=08

设备运行过程中读取到power_mode为OFF状态时,重启内核

本应该只重启LCD即可,但没有合适的方法,所以直接重启系统,修改kthread_checkLCDstatus_func()函数:

  1. static int kthread_checkLCDstatus_func(void * data)
  2. {
  3. struct mipi_dsi_device *dsi = (struct mipi_dsi_device *)data;
  4. int err;
  5. u8 mode;
  6. while (!kthread_should_stop())
  7. {
  8. err = mipi_dsi_dcs_get_power_mode( dsi, &mode);
  9. dev_info( &dsi->dev, "get_power_mode err=%d, mode=%02x\n", err, mode );
  10. msleep(5000);
  11. printk("panel-simple restart kernel\n");
  12. kernel_restart(NULL); //linux kernel restart.
  13. }
  14. return 0;
  15. }
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号