我是靠谱客的博主 单身小蚂蚁,最近开发中收集的这篇文章主要介绍idea2020.2.2 license server_i.MX6 MIPI DSI: 低功耗LCD时钟配置出现显示闪烁和抖动的问题...,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

    I.MX适配不同屏:

https://boundarydev2.wpengine.com/i-mx6-kernel-3-10-53/

https://boundarydevices.com/configuring-i-mx6-machines-different-screens-nitrogen6x-sabre-lite/

    平台 Android 5.0,使用 MIPI LCD,偶尔 LCD 会出现闪烁情况。LCD使用 HX8379 480RGB x 864 dot, 16.7M color。MIPI LCD 有两个模式一个是 LP 模式( 低功耗模式), 另一个是HS模式( 高速模式),当前配置HS模式为 800M,会超过 MIPI 指标, 因此 LCD 会闪烁。

kernel_imx/drivers/video/mxc$vi mxcfb_hx8369_wvga.c

#define HX8369_MAX_DPHY_CLK                                     (800)

    将其修改为 500M:

#define HX8369_MAX_DPHY_CLK                                     (500)

    修改后LCD闪烁不会出现,会带来另外的问题,有些设备会出现LCD初始化失败的情况。设置 HS 时钟为 800M,  LP 时钟为 7.1M。

    MIPI LCD 厂家需要配置如下:LP:6-8M;HS:小于 500M。需要设置 MIPI DSI 在低功耗模式下,如何设置 MIPI DSI低功耗时钟模式?

/kernel_imx/drivers/video/mxc$ vi mipi_dsi.c
/* enable LP mode when TX DCS cmd and enable DSI command mode */
mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG,
                        MIPI_DSI_CMD_MODE_CFG_EN_LOWPOWER);

    LCD屏有时候有轻微的抖动。测量数据线,屏幕抖动时每一帧的Vporch都会多一个,多在VS里 。代码里设置的是2+5+8=15,正常的时候,示波器上测出来的就是15个,当抖动的时候,示波器上测出来的多一个为16个。可能是板极硬件问题。禁止DVFS ,增大CAP电压。正常的波形如下:

a4a3dee086dff9b62432917be1e928fd.png

异常的波形如下:

052818563861766b2eec218d6728de5d.png

    IPU 时钟设置如下:

pll5_video     1   1    1101184008
pll5_post_div   1   1    275296002 

pll5_video_div  1   1    68824000  
ipu1_di1_pre_sel 1   1    68824000

ipu1_di1_pre 1   1    34412000 
ipu1_di1_sel 1   1    34412000  
ipu1_di1 1   1    34412000  
ipu1_pclk1_sel 1   1    34412000  
ipu1_pclk1_div 1     1   34412000  
ipu1_pclk_1 1     1   34412000 

 dump 时钟树:$ cat /sys/kernel/debug/clock/clk_summary

    I.MX6DL, MIPI 像素时钟来自于 270MHz IPU 时钟,因此,建议设置像素时钟为30MHz。IPU不能准确的分频到精确的频率,只能尽可能的接近,因此会导致一些小抖动。

    更改mipi接口接收时的LP频率。

#define       DSI_CLKMGR_CFG_CLK_DIV          (0x107)  to  (0x104)

    更新mipi接口的HS频率。

#define HX8369_MAX_DPHY_CLK                     (800)  to (500)  

    更新pixclock像素时钟37880为29059(同时帧频率也从45Hz提升到 60Hz) 。     

static struct fb_videomode truly_lcd_modedb[] = {

        {

        "TRULY-WVGA", 60, 480, 854, 29059,

         60, 60,

         2, 5,

         60, 8,

         FB_SYNC_OE_LOW_ACT,

         FB_VMODE_NONINTERLACED,

         0,

        },

};

    在做如上更新后闪屏现象和无法初始化,以及读取芯片IC ID的问题已经解决,但还是有LCD 偶尔出现画面抖动的现象。

    电源供电:VCC=2.8V IOVCC=1.8V 硬件复位;

  接口:MIPI DSI Video 2Lanes, 420Mbps/Lane, Column inversion, Frame Freq= 60Hz。
#define VBPD 2
#define VFPD 5
#define VSPW 8
#define HBPD 60
#define HFPD 60
#define HSPW 60

需要仔细查看 LCD手册,HSYNC 和VSYNC是低有效,DE是高有效:

        { "TRULY-WVGA", 60, 480, 854, 29059,  60, 60,         2, 5,  60, 8,         0,         FB_VMODE_NONINTERLACED,         0,        },

或者

        { "TRULY-WVGA", 60, 480, 854, 29059,  60, 60,         2, 5,  60, 8,         FB_SYNC_CLK_LAT_FALL,         FB_VMODE_NONINTERLACED,         0,        },

  TX_ESC时钟和MIPI的LP时钟是一样的,因此,DSI_CLKMGR_CFG_CLK_DIV 用于控制LP时钟频率。

TX_ESC 时钟= PHY byte 时钟/ DSI_CLKMGR_CFG_CLK_DIV,在文件mipi_dsi.c中, DSI_CLKMGR_CFG_CLK_DIV用于调整 TX_ESC时钟,可以调整这个数值来测量 LP的时钟。默认500Mbps PHY的时钟数值是0x107,通过修改 DSI_CLKMGR_CFG_CLK_DIV 数值(0x106或者0x105)解决 LCD抖动问题。

/*
 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
 * 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.

 * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc.,* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "mipi_dsi.h"

#define DISPDRV_MIPI   "mipi_dsi"
#define ROUND_UP(x)   ((x)+1)
#define NS2PS_RATIO   (1000)
#define NUMBER_OF_CHUNKS  (0x8)
#define NULL_PKT_SIZE   (0x8)
#define PHY_BTA_MAXTIME   (0xd00)
#define PHY_LP2HS_MAXTIME  (0x40)
#define PHY_HS2LP_MAXTIME  (0x40)
#define PHY_STOP_WAIT_TIME  (0x20)
//#define DSI_CLKMGR_CFG_CLK_DIV  (0x107)
#define       DSI_CLKMGR_CFG_CLK_DIV          (0x104)
#define DSI_GEN_PLD_DATA_BUF_ENTRY (0x10)
#define MIPI_MUX_CTRL(v)  (((v) & 0x3) << 4)
#define MIPI_LCD_SLEEP_MODE_DELAY (120)
#define MIPI_DSI_REG_RW_TIMEOUT  (20)
#define MIPI_DSI_PHY_TIMEOUT  (10)

//unsigned char gReportPowerKey = 0;

static int bl_pwn_gpio;

static struct mipi_dsi_match_lcd mipi_dsi_lcd_db[] = {
#ifdef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
 {
  "TRULY-WVGA",
  {mipid_hx8369_get_lcd_videomode, mipid_hx8369_lcd_setup}
 },
#endif
 {
 "", {NULL, NULL}
 }
};

struct _mipi_dsi_phy_pll_clk {
 u32  max_phy_clk;
 u32  config;
};

/* configure data for DPHY PLL 27M reference clk out */
static const struct _mipi_dsi_phy_pll_clk mipi_dsi_phy_pll_clk_table[] = {
 {1000, 0x74}, /*  950-1000MHz */
 {950,  0x54}, /*  900-950Mhz */
 {900,  0x34}, /*  850-900Mhz */
 {850,  0x14}, /*  800-850MHz */
 {800,  0x32}, /*  750-800MHz */
 {750,  0x12}, /*  700-750Mhz */
 {700,  0x30}, /*  650-700Mhz */
 {650,  0x10}, /*  600-650MHz */
 {600,  0x2e}, /*  550-600MHz */
 {550,  0x0e}, /*  500-550Mhz */
 {500,  0x2c}, /*  450-500Mhz */
 {450,  0x0c}, /*  400-450MHz */
 {400,  0x4a}, /*  360-400MHz */
 {360,  0x2a}, /*  330-360Mhz */
 {330,  0x48}, /*  300-330Mhz */
 {300,  0x28}, /*  270-300MHz */
 {270,  0x08}, /*  250-270MHz */
 {250,  0x46}, /*  240-250Mhz */
 {240,  0x26}, /*  210-240Mhz */
 {210,  0x06}, /*  200-210MHz */
 {200,  0x44}, /*  180-200MHz */
 {180,  0x24}, /*  160-180MHz */
 {160,  0x04}, /*  150-160MHz */
};

static int valid_mode(int pixel_fmt)
{
 return ((pixel_fmt == IPU_PIX_FMT_RGB24)  ||
   (pixel_fmt == IPU_PIX_FMT_BGR24)  ||
   (pixel_fmt == IPU_PIX_FMT_RGB666) ||
   (pixel_fmt == IPU_PIX_FMT_RGB565) ||
   (pixel_fmt == IPU_PIX_FMT_BGR666) ||
   (pixel_fmt == IPU_PIX_FMT_RGB332));
}

static inline void mipi_dsi_read_register(struct mipi_dsi_info *mipi_dsi,
    u32 reg, u32 *val)
{
 *val = ioread32(mipi_dsi->mmio_base + reg);

 dev_dbg(&mipi_dsi->pdev->dev, "read_reg:0x%02x, val:0x%08x.n",
   reg, *val);
}

static inline void mipi_dsi_write_register(struct mipi_dsi_info *mipi_dsi,
    u32 reg, u32 val)
{
 iowrite32(val, mipi_dsi->mmio_base + reg);
 dev_dbg(&mipi_dsi->pdev->dev, "ttwrite_reg:0x%02x, val:0x%08x.n",
   reg, val);
}

int mipi_dsi_pkt_write(struct mipi_dsi_info *mipi_dsi,
    u8 data_type, const u32 *buf, int len)
{
 u32 val;
 u32 status = 0;
 int write_len = len;
 uint32_t timeout = 0;

 if (len) {
  /* generic long write command */
  while (len / DSI_GEN_PLD_DATA_BUF_SIZE) {
   mipi_dsi_write_register(mipi_dsi,
    MIPI_DSI_GEN_PLD_DATA, *buf);
   buf++;
   len -= DSI_GEN_PLD_DATA_BUF_SIZE;
   mipi_dsi_read_register(mipi_dsi,
    MIPI_DSI_CMD_PKT_STATUS, &status);
   while ((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) ==
      DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) {
    msleep(1);
    timeout++;
    if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
     return -EIO;
    mipi_dsi_read_register(mipi_dsi,
     MIPI_DSI_CMD_PKT_STATUS, &status);
   }
  }
  /* write the remainder bytes */
  if (len > 0) {
   while ((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) ==
      DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) {
    msleep(1);
    timeout++;
    if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
     return -EIO;
    mipi_dsi_read_register(mipi_dsi,
     MIPI_DSI_CMD_PKT_STATUS, &status);
   }
   mipi_dsi_write_register(mipi_dsi,
    MIPI_DSI_GEN_PLD_DATA, *buf);
  }

  val = data_type | ((write_len & DSI_GEN_HDR_DATA_MASK)
   << DSI_GEN_HDR_DATA_SHIFT);
 } else {
  /* generic short write command */
  val = data_type | ((*buf & DSI_GEN_HDR_DATA_MASK)
   << DSI_GEN_HDR_DATA_SHIFT);
 }

 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &status);
 while ((status & DSI_CMD_PKT_STATUS_GEN_CMD_FULL) ==
    DSI_CMD_PKT_STATUS_GEN_CMD_FULL) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
   return -EIO;
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
    &status);
 }
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_GEN_HDR, val);

 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &status);
 while (!((status & DSI_CMD_PKT_STATUS_GEN_CMD_EMPTY) ==
    DSI_CMD_PKT_STATUS_GEN_CMD_EMPTY) ||
   !((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_EMPTY) ==
   DSI_CMD_PKT_STATUS_GEN_PLD_W_EMPTY)) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
   return -EIO;
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
    &status);
 }

 return 0;
}

int mipi_dsi_pkt_read(struct mipi_dsi_info *mipi_dsi,
    u8 data_type, u32 *buf, int len)
{
 u32  val;
 int  read_len = 0;
 uint32_t timeout = 0;

 if (!len) {
  mipi_dbg("%s, len = 0 invalid error!n", __func__);
  return -EINVAL;
 }

 val = data_type | ((*buf & DSI_GEN_HDR_DATA_MASK)
  << DSI_GEN_HDR_DATA_SHIFT);
 memset(buf, 0, len);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_GEN_HDR, val);

 /* wait for cmd to sent out */
 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &val);
 while ((val & DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) !=
    DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
   return -EIO;
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
   &val);
 }
 /* wait for entire response stroed in FIFO */
 while ((val & DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) ==
    DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
   return -EIO;
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
   &val);
 }

 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &val);
 while (!(val & DSI_CMD_PKT_STATUS_GEN_PLD_R_EMPTY)) {
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_GEN_PLD_DATA, buf);
  read_len += DSI_GEN_PLD_DATA_BUF_SIZE;
  buf++;
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
   &val);
  if (read_len == (DSI_GEN_PLD_DATA_BUF_ENTRY *
     DSI_GEN_PLD_DATA_BUF_SIZE))
   break;
 }

 if ((len <= read_len) &&
  ((len + DSI_GEN_PLD_DATA_BUF_SIZE) >= read_len))
  return 0;
 else {
  dev_err(&mipi_dsi->pdev->dev,
   "actually read_len:%d != len:%d.n", read_len, len);
  return -ERANGE;
 }
}

int mipi_dsi_dcs_cmd(struct mipi_dsi_info *mipi_dsi,
    u8 cmd, const u32 *param, int num)
{
 int err = 0;
 u32 buf[DSI_CMD_BUF_MAXSIZE];

 switch (cmd) {
 case MIPI_DCS_EXIT_SLEEP_MODE:
 case MIPI_DCS_ENTER_SLEEP_MODE:
 case MIPI_DCS_SET_DISPLAY_ON:
 case MIPI_DCS_SET_DISPLAY_OFF:
  buf[0] = cmd;
  err = mipi_dsi_pkt_write(mipi_dsi,
    MIPI_DSI_DCS_SHORT_WRITE, buf, 0);
  break;

 default:
 dev_err(&mipi_dsi->pdev->dev,
   "MIPI DSI DCS Command:0x%x Not supported!n", cmd);
  break;
 }

 return err;
}

static void mipi_dsi_dphy_init(struct mipi_dsi_info *mipi_dsi,
      u32 cmd, u32 data)
{
 u32 val;
 u32 timeout = 0;

 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
   DSI_PHY_IF_CTRL_RESET);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP, DSI_PWRUP_POWERUP);

 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL1,
  (0x10000 | cmd));
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 2);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL1, (0 | data));
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 2);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
 val = DSI_PHY_RSTZ_EN_CLK | DSI_PHY_RSTZ_DISABLE_RST |
   DSI_PHY_RSTZ_DISABLE_SHUTDOWN;
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ, val);

 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
 while ((val & DSI_PHY_STATUS_LOCK) != DSI_PHY_STATUS_LOCK) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_PHY_TIMEOUT) {
   dev_err(&mipi_dsi->pdev->dev,
    "Error: phy lock timeout!n");
   break;
  }
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
 }
 timeout = 0;
 while ((val & DSI_PHY_STATUS_STOPSTATE_CLK_LANE) !=
   DSI_PHY_STATUS_STOPSTATE_CLK_LANE) {
  msleep(1);
  timeout++;
  if (timeout == MIPI_DSI_PHY_TIMEOUT) {
   dev_err(&mipi_dsi->pdev->dev,
    "Error: phy lock lane timeout!n");
   break;
  }
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
 }
}

static void mipi_dsi_enable_controller(struct mipi_dsi_info *mipi_dsi,
    bool init)
{
 u32  val;
 u32  lane_byte_clk_period;
 struct  fb_videomode *mode = mipi_dsi->mode;
 struct  mipi_lcd_config *lcd_config = mipi_dsi->lcd_config;

 if (init) {
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
   DSI_PWRUP_RESET);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ,
   DSI_PHY_RSTZ_RST);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CLKMGR_CFG,
   DSI_CLKMGR_CFG_CLK_DIV);

  if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
   val = DSI_DPI_CFG_VSYNC_ACT_LOW;
  if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
   val |= DSI_DPI_CFG_HSYNC_ACT_LOW;
  if ((mode->sync & FB_SYNC_OE_LOW_ACT))
   val |= DSI_DPI_CFG_DATAEN_ACT_LOW;
  if (MIPI_RGB666_LOOSELY == lcd_config->dpi_fmt)
   val |= DSI_DPI_CFG_EN18LOOSELY;
  val |= (lcd_config->dpi_fmt & DSI_DPI_CFG_COLORCODE_MASK)
    << DSI_DPI_CFG_COLORCODE_SHIFT;
  val |= (lcd_config->virtual_ch & DSI_DPI_CFG_VID_MASK)
    << DSI_DPI_CFG_VID_SHIFT;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_DPI_CFG, val);

  val = DSI_PCKHDL_CFG_EN_BTA |
    DSI_PCKHDL_CFG_EN_ECC_RX |
    DSI_PCKHDL_CFG_EN_CRC_RX;

  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PCKHDL_CFG, val);

  val = (mode->xres & DSI_VID_PKT_CFG_VID_PKT_SZ_MASK)
    << DSI_VID_PKT_CFG_VID_PKT_SZ_SHIFT;
  val |= (NUMBER_OF_CHUNKS & DSI_VID_PKT_CFG_NUM_CHUNKS_MASK)
    << DSI_VID_PKT_CFG_NUM_CHUNKS_SHIFT;
  val |= (NULL_PKT_SIZE & DSI_VID_PKT_CFG_NULL_PKT_SZ_MASK)
    << DSI_VID_PKT_CFG_NULL_PKT_SZ_SHIFT;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_PKT_CFG, val);

  /* enable LP mode when TX DCS cmd and enable DSI command mode */
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG,
    MIPI_DSI_CMD_MODE_CFG_EN_LOWPOWER);

   /* mipi lane byte clk period in ns unit */
  lane_byte_clk_period = NS2PS_RATIO /
    (lcd_config->max_phy_clk / BITS_PER_BYTE);
  val  = ROUND_UP(mode->hsync_len * mode->pixclock /
    NS2PS_RATIO / lane_byte_clk_period)
    << DSI_TME_LINE_CFG_HSA_TIME_SHIFT;
  val |= ROUND_UP(mode->left_margin * mode->pixclock /
    NS2PS_RATIO / lane_byte_clk_period)
    << DSI_TME_LINE_CFG_HBP_TIME_SHIFT;
  val |= ROUND_UP((mode->left_margin + mode->right_margin +
    mode->hsync_len + mode->xres) * mode->pixclock
    / NS2PS_RATIO / lane_byte_clk_period)
    << DSI_TME_LINE_CFG_HLINE_TIME_SHIFT;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_TMR_LINE_CFG, val);

  val = ((mode->vsync_len & DSI_VTIMING_CFG_VSA_LINES_MASK)
     << DSI_VTIMING_CFG_VSA_LINES_SHIFT);
  val |= ((mode->upper_margin & DSI_VTIMING_CFG_VBP_LINES_MASK)
    << DSI_VTIMING_CFG_VBP_LINES_SHIFT);
  val |= ((mode->lower_margin & DSI_VTIMING_CFG_VFP_LINES_MASK)
    << DSI_VTIMING_CFG_VFP_LINES_SHIFT);
  val |= ((mode->yres & DSI_VTIMING_CFG_V_ACT_LINES_MASK)
    << DSI_VTIMING_CFG_V_ACT_LINES_SHIFT);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VTIMING_CFG, val);

  val = ((PHY_BTA_MAXTIME & DSI_PHY_TMR_CFG_BTA_TIME_MASK)
    << DSI_PHY_TMR_CFG_BTA_TIME_SHIFT);
  val |= ((PHY_LP2HS_MAXTIME & DSI_PHY_TMR_CFG_LP2HS_TIME_MASK)
    << DSI_PHY_TMR_CFG_LP2HS_TIME_SHIFT);
  val |= ((PHY_HS2LP_MAXTIME & DSI_PHY_TMR_CFG_HS2LP_TIME_MASK)
    << DSI_PHY_TMR_CFG_HS2LP_TIME_SHIFT);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TMR_CFG, val);

  val = (((lcd_config->data_lane_num - 1) &
   DSI_PHY_IF_CFG_N_LANES_MASK)
   << DSI_PHY_IF_CFG_N_LANES_SHIFT);
  val |= ((PHY_STOP_WAIT_TIME & DSI_PHY_IF_CFG_WAIT_TIME_MASK)
    << DSI_PHY_IF_CFG_WAIT_TIME_SHIFT);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CFG, val);

  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST0, &val);
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST1, &val);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_ERROR_MSK0, 0);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_ERROR_MSK1, 0);

  mipi_dsi_dphy_init(mipi_dsi, DSI_PHY_CLK_INIT_COMMAND,
     mipi_dsi->dphy_pll_config);
 } else {
  mipi_dsi_dphy_init(mipi_dsi, DSI_PHY_CLK_INIT_COMMAND,
     mipi_dsi->dphy_pll_config);
 }
}

static void mipi_dsi_disable_controller(struct mipi_dsi_info *mipi_dsi)
{
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
   DSI_PHY_IF_CTRL_RESET);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP, DSI_PWRUP_RESET);
 mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ, DSI_PHY_RSTZ_RST);
}

static irqreturn_t mipi_dsi_irq_handler(int irq, void *data)
{
 u32  mask0;
 u32  mask1;
 u32  status0;
 u32  status1;
 struct mipi_dsi_info *mipi_dsi;

 mipi_dsi = (struct mipi_dsi_info *)data;
 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST0,  &status0);
 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST1,  &status1);
 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_MSK0, &mask0);
 mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_MSK1, &mask1);

 if ((status0 & (~mask0)) || (status1 & (~mask1))) {
  dev_err(&mipi_dsi->pdev->dev,
  "mipi_dsi IRQ status0:0x%x, status1:0x%x!n",
  status0, status1);
 }

 return IRQ_HANDLED;
}

static inline void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
 bool cmd_mode)
{
 u32 val;

 if (cmd_mode) {
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
   DSI_PWRUP_RESET);
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, &val);
  val |= MIPI_DSI_CMD_MODE_CFG_EN_CMD_MODE;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, val);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_MODE_CFG, 0);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
   DSI_PWRUP_POWERUP);
 } else {
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
   DSI_PWRUP_RESET);
   /* Disable Command mode when tranfering video data */
  mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, &val);
  val &= ~MIPI_DSI_CMD_MODE_CFG_EN_CMD_MODE;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, val);
  val = DSI_VID_MODE_CFG_EN | DSI_VID_MODE_CFG_EN_BURSTMODE |
    DSI_VID_MODE_CFG_EN_LP_MODE;
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_MODE_CFG, val);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
   DSI_PWRUP_POWERUP);
  mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
    DSI_PHY_IF_CTRL_TX_REQ_CLK_HS);
 }
}

static int mipi_dsi_power_on(struct mxc_dispdrv_handle *disp)
{
 int err;
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);

 if (!mipi_dsi->dsi_power_on) {
  clk_prepare_enable(mipi_dsi->dphy_clk);
  clk_prepare_enable(mipi_dsi->cfg_clk);
  mipi_dsi_enable_controller(mipi_dsi, false);
  mipi_dsi_set_mode(mipi_dsi, false);
  /* host send pclk/hsync/vsync for two frames before sleep-out */
  msleep((1000/mipi_dsi->mode->refresh + 1) << 1);
  mipi_dsi_set_mode(mipi_dsi, true);
  err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_EXIT_SLEEP_MODE,
   NULL, 0);
  if (err) {
   printk("n==============sleep out error=============n");
   dev_err(&mipi_dsi->pdev->dev,
    "MIPI DSI DCS Command sleep-in error!n");
  }
  msleep(MIPI_LCD_SLEEP_MODE_DELAY);
  mipi_dsi_set_mode(mipi_dsi, false);
  mipi_dsi->dsi_power_on = 1;
 }
 //power on backlight
 gpio_set_value(bl_pwn_gpio,1);

 return 0;
}

void mipi_dsi_power_off(struct mxc_dispdrv_handle *disp)
{
 int err;
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);

 if (mipi_dsi->dsi_power_on) {
  mipi_dsi_set_mode(mipi_dsi, true);
  err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_ENTER_SLEEP_MODE,
   NULL, 0);
  if (err) {
   dev_err(&mipi_dsi->pdev->dev,
    "MIPI DSI DCS Command display on error!n");
  }
  /* To allow time for the supply voltages
   * and clock circuits to stabilize.
   */
  msleep(5);
  /* video stream timing on */
  mipi_dsi_set_mode(mipi_dsi, false);
  msleep(MIPI_LCD_SLEEP_MODE_DELAY);

  mipi_dsi_set_mode(mipi_dsi, true);
  mipi_dsi_disable_controller(mipi_dsi);
  mipi_dsi->dsi_power_on = 0;
  clk_disable_unprepare(mipi_dsi->dphy_clk);
  clk_disable_unprepare(mipi_dsi->cfg_clk);
 }
 //power off backlight
        gpio_set_value(bl_pwn_gpio,0);
 //gReportPowerKey = 1;
}

static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
 struct mxc_dispdrv_setting *setting)
{
 int  err;
 int  size;
 int  i;
 struct  fb_videomode *mipi_lcd_modedb;
 struct  fb_videomode mode;
 struct  device   *dev = &mipi_dsi->pdev->dev;

 for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) {
  if (!strcmp(mipi_dsi->lcd_panel,
   mipi_dsi_lcd_db[i].lcd_panel)) {
   mipi_dsi->lcd_callback =
    &mipi_dsi_lcd_db[i].lcd_callback;
   break;
  }
 }
 if (i == ARRAY_SIZE(mipi_dsi_lcd_db)) {
  dev_err(dev, "failed to find supported lcd panel.n");
  return -EINVAL;
 }
 /* get the videomode in the order: cmdline->platform data->driver */
 mipi_dsi->lcd_callback->get_mipi_lcd_videomode(&mipi_lcd_modedb, &size,
     &mipi_dsi->lcd_config);
 err = fb_find_mode(&setting->fbi->var, setting->fbi,
    setting->dft_mode_str,
    mipi_lcd_modedb, size, NULL,
    setting->default_bpp);
 if (err != 1)
  fb_videomode_to_var(&setting->fbi->var, mipi_lcd_modedb);

 INIT_LIST_HEAD(&setting->fbi->modelist);
 for (i = 0; i < size; i++) {
  fb_var_to_videomode(&mode, &setting->fbi->var);
  if (fb_mode_is_equal(&mode, mipi_lcd_modedb + i)) {
   err = fb_add_videomode(mipi_lcd_modedb + i,
     &setting->fbi->modelist);
    /* Note: only support fb mode from driver */
   mipi_dsi->mode = mipi_lcd_modedb + i;
   break;
  }
 }
 if ((err < 0) || (size == i)) {
  dev_err(dev, "failed to add videomode.n");
  return err;
 }

 for (i = 0; i < ARRAY_SIZE(mipi_dsi_phy_pll_clk_table); i++) {
  if (mipi_dsi_phy_pll_clk_table[i].max_phy_clk <
    mipi_dsi->lcd_config->max_phy_clk)
   break;
 }
 if ((i == ARRAY_SIZE(mipi_dsi_phy_pll_clk_table)) ||
  (mipi_dsi->lcd_config->max_phy_clk >
   mipi_dsi_phy_pll_clk_table[0].max_phy_clk)) {
  dev_err(dev, "failed to find data in"
    "mipi_dsi_phy_pll_clk_table.n");
  return -EINVAL;
 }
 mipi_dsi->dphy_pll_config = mipi_dsi_phy_pll_clk_table[--i].config;
 dev_dbg(dev, "dphy_pll_config:0x%x.n", mipi_dsi->dphy_pll_config);
 return 0;
}

static int mipi_dsi_enable(struct mxc_dispdrv_handle *disp,
      struct fb_info *fbi)
{
 int err;
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);

 if (!mipi_dsi->lcd_inited) {
  err = clk_prepare_enable(mipi_dsi->dphy_clk);
  err |= clk_prepare_enable(mipi_dsi->cfg_clk);
  if (err)
   dev_err(&mipi_dsi->pdev->dev,
    "clk enable error:%d!n", err);
  mipi_dsi_enable_controller(mipi_dsi, true);
  err = mipi_dsi->lcd_callback->mipi_lcd_setup(
   mipi_dsi);
  if (err < 0) {
   dev_err(&mipi_dsi->pdev->dev,
    "failed to init mipi lcd.");
   clk_disable_unprepare(mipi_dsi->dphy_clk);
   clk_disable_unprepare(mipi_dsi->cfg_clk);
   return err;
  }
  mipi_dsi_set_mode(mipi_dsi, false);
  mipi_dsi->dsi_power_on = 1;
  mipi_dsi->lcd_inited = 1;
 }
 mipi_dsi_power_on(mipi_dsi->disp_mipi);

 return 0;
}

static void mipi_dsi_disable(struct mxc_dispdrv_handle *disp,
       struct fb_info *fbi)
{
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);

 mipi_dsi_power_off(mipi_dsi->disp_mipi);
}

static int mipi_dsi_disp_init(struct mxc_dispdrv_handle *disp,
 struct mxc_dispdrv_setting *setting)
{
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
 struct device *dev = &mipi_dsi->pdev->dev;
 int ret = 0;

 if (!valid_mode(setting->if_fmt)) {
  dev_warn(dev, "Input pixel format not valid"
   "use default RGB24n");
  setting->if_fmt = IPU_PIX_FMT_RGB24;
 }
 ret = ipu_di_to_crtc(dev, mipi_dsi->dev_id,
        mipi_dsi->disp_id, &setting->crtc);
 if (ret < 0)
 {
  return ret;
 }
 ret = mipi_dsi_lcd_init(mipi_dsi, setting);
 if (ret) {
  dev_err(dev, "failed to init mipi dsi lcdn");
  return ret;
 }

 dev_dbg(dev, "MIPI DSI dispdrv inited!n");
 return ret;
}

static void mipi_dsi_disp_deinit(struct mxc_dispdrv_handle *disp)
{
 struct mipi_dsi_info    *mipi_dsi;

 mipi_dsi = mxc_dispdrv_getdata(disp);

 mipi_dsi_power_off(mipi_dsi->disp_mipi);
 if (mipi_dsi->bl)
  backlight_device_unregister(mipi_dsi->bl);
}

static int mipi_dsi_setup(struct mxc_dispdrv_handle *disp,
     struct fb_info *fbi)
{
 struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
 int xres_virtual = fbi->var.xres_virtual;
 int yres_virtual = fbi->var.yres_virtual;
 int xoffset = fbi->var.xoffset;
 int yoffset = fbi->var.yoffset;
 int pixclock = fbi->var.pixclock;

 if (!mipi_dsi->mode)
  return 0;

 /* set the mode back to var in case userspace changes it */
 fb_videomode_to_var(&fbi->var, mipi_dsi->mode);

 /* restore some var entries cached */
 fbi->var.xres_virtual = xres_virtual;
 fbi->var.yres_virtual = yres_virtual;
 fbi->var.xoffset = xoffset;
 fbi->var.yoffset = yoffset;
 fbi->var.pixclock = pixclock;
 return 0;
}

static struct mxc_dispdrv_driver mipi_dsi_drv = {
 .name = DISPDRV_MIPI,
 .init = mipi_dsi_disp_init,
 .deinit = mipi_dsi_disp_deinit,
 .enable = mipi_dsi_enable,
 .disable = mipi_dsi_disable,
 .setup = mipi_dsi_setup,
};

static int imx6q_mipi_dsi_get_mux(int dev_id, int disp_id)
{
 if (dev_id > 1 || disp_id > 1)
  return -EINVAL;

 return (dev_id << 5) | (disp_id << 4);
}

static struct mipi_dsi_bus_mux imx6q_mipi_dsi_mux[] = {
 {
  .reg = IOMUXC_GPR3,
  .mask = IMX6Q_GPR3_MIPI_MUX_CTL_MASK,
  .get_mux = imx6q_mipi_dsi_get_mux,
 },
};

static int imx6dl_mipi_dsi_get_mux(int dev_id, int disp_id)
{
 if (dev_id > 1 || disp_id > 1)
  return -EINVAL;

 /* MIPI DSI source is LCDIF */
 if (dev_id)
  disp_id = 0;

 return (dev_id << 5) | (disp_id << 4);
}

static struct mipi_dsi_bus_mux imx6dl_mipi_dsi_mux[] = {
 {
  .reg = IOMUXC_GPR3,
  .mask = IMX6Q_GPR3_MIPI_MUX_CTL_MASK,
  .get_mux = imx6dl_mipi_dsi_get_mux,
 },
};

static const struct of_device_id imx_mipi_dsi_dt_ids[] = {
 { .compatible = "fsl,imx6q-mipi-dsi", .data = imx6q_mipi_dsi_mux, },
 { .compatible = "fsl,imx6dl-mipi-dsi", .data = imx6dl_mipi_dsi_mux, },
 { }
};
MODULE_DEVICE_TABLE(of, imx_mipi_dsi_dt_ids);

/**
 * This function is called by the driver framework to initialize the MIPI DSI
 * device.
 *
 * @param pdev The device structure for the MIPI DSI passed in by the
 *   driver framework.
 *
 * @return      Returns 0 on success or negative error code on error
 */
static int mipi_dsi_probe(struct platform_device *pdev)
{
 struct device_node *np = pdev->dev.of_node;
 const struct of_device_id *of_id =
   of_match_device(of_match_ptr(imx_mipi_dsi_dt_ids),
     &pdev->dev);
 struct mipi_dsi_info *mipi_dsi;
 struct resource *res;
 u32 dev_id, disp_id;
 const char *lcd_panel;
 unsigned int mux;
 int ret = 0;

 mipi_dsi = devm_kzalloc(&pdev->dev, sizeof(*mipi_dsi), GFP_KERNEL);
 if (!mipi_dsi)
  return -ENOMEM;

 ret = of_property_read_string(np, "lcd_panel", &lcd_panel);
 if (ret) {
  dev_err(&pdev->dev, "failed to read of property lcd_paneln");
  return ret;
 }

 ret = of_property_read_u32(np, "dev_id", &dev_id);
 if (ret) {
  dev_err(&pdev->dev, "failed to read of property dev_idn");
  return ret;
 }
 ret = of_property_read_u32(np, "disp_id", &disp_id);
 if (ret) {
  dev_err(&pdev->dev, "failed to read of property disp_idn");
  return ret;
 }
 mipi_dsi->dev_id = dev_id;
 mipi_dsi->disp_id = disp_id;

 /*get and set the backlight power on gpio*/
/* bl_pwn_gpio = of_get_named_gpio(np, "bl-pwn-gpios", 0);
 if (!gpio_is_valid(bl_pwn_gpio))
 {
  dev_err(&pdev->dev, "backlight power on gpio is invalidn");
  return -ENODEV;
 } 
 printk("bl_pwn_gpio = %dn",bl_pwn_gpio);
 ret = gpio_request(bl_pwn_gpio, "bl_pwn");
        if (ret) {
  dev_err(&pdev->dev, "failed to request backlight pwn gpion");
                return ret;
 }
 gpio_direction_output(bl_pwn_gpio, 1); 
*/

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 if (!res) {
  dev_err(&pdev->dev, "failed to get platform resource 0n");
  return -ENODEV;
 }

 if (!devm_request_mem_region(&pdev->dev, res->start,
    resource_size(res), pdev->name))
  return -EBUSY;

 mipi_dsi->mmio_base = devm_ioremap(&pdev->dev, res->start,
       resource_size(res));
 if (!mipi_dsi->mmio_base)
  return -EBUSY;

 mipi_dsi->irq = platform_get_irq(pdev, 0);
 if (mipi_dsi->irq < 0) {
  dev_err(&pdev->dev, "failed get device irqn");
  return -ENODEV;
 }

 ret = devm_request_irq(&pdev->dev, mipi_dsi->irq,
    mipi_dsi_irq_handler,
    0, "mipi_dsi", mipi_dsi);
 if (ret) {
  dev_err(&pdev->dev, "failed to request irqn");
  return ret;
 }

 mipi_dsi->dphy_clk = devm_clk_get(&pdev->dev, "mipi_pllref_clk");
 if (IS_ERR(mipi_dsi->dphy_clk)) {
  dev_err(&pdev->dev, "failed to get dphy pll_ref_clkn");
  return PTR_ERR(mipi_dsi->dphy_clk);
 }

 mipi_dsi->cfg_clk = devm_clk_get(&pdev->dev, "mipi_cfg_clk");
 if (IS_ERR(mipi_dsi->cfg_clk)) {
  dev_err(&pdev->dev, "failed to get cfg_clkn");
  return PTR_ERR(mipi_dsi->cfg_clk);
 }

 mipi_dsi->disp_power_on = devm_regulator_get(&pdev->dev,
       "disp-power-on");
 if (!IS_ERR(mipi_dsi->disp_power_on)) {
  ret = regulator_enable(mipi_dsi->disp_power_on);
  if (ret) {
   dev_err(&pdev->dev, "failed to enable display "
    "power regulator, err=%dn", ret);
   return ret;
  }
 } else {
  mipi_dsi->disp_power_on = NULL;
 }

 ret = device_reset(&pdev->dev);
 printk("=============MIPI LCD Reset==============");
 if (ret) {
  dev_err(&pdev->dev, "failed to reset: %dn", ret);
  goto dev_reset_fail;
 }

 if (of_id)
  mipi_dsi->bus_mux = of_id->data;

 mipi_dsi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
 if (IS_ERR(mipi_dsi->regmap)) {
  dev_err(&pdev->dev, "failed to get parent regmapn");
  ret = PTR_ERR(mipi_dsi->regmap);
  goto get_parent_regmap_fail;
 }

 mux = mipi_dsi->bus_mux->get_mux(dev_id, disp_id);
 if (mux >= 0)
  regmap_update_bits(mipi_dsi->regmap, mipi_dsi->bus_mux->reg,
       mipi_dsi->bus_mux->mask, mux);
 else
  dev_warn(&pdev->dev, "invalid dev_id or disp_id muxingn");

 mipi_dsi->lcd_panel = kstrdup(lcd_panel, GFP_KERNEL);
 if (!mipi_dsi->lcd_panel) {
  dev_err(&pdev->dev, "failed to allocate lcd panel namen");
  ret = -ENOMEM;
  goto kstrdup_fail;
 }

 mipi_dsi->pdev = pdev;
 mipi_dsi->disp_mipi = mxc_dispdrv_register(&mipi_dsi_drv);
 if (IS_ERR(mipi_dsi->disp_mipi)) {
  dev_err(&pdev->dev, "mxc_dispdrv_register errorn");
  ret = PTR_ERR(mipi_dsi->disp_mipi);
  goto dispdrv_reg_fail;
 }

 mxc_dispdrv_setdata(mipi_dsi->disp_mipi, mipi_dsi);
 dev_set_drvdata(&pdev->dev, mipi_dsi);
 mxc_dispdrv_setdev(mipi_dsi->disp_mipi, &pdev->dev);

 dev_info(&pdev->dev, "i.MX MIPI DSI driver probedn");
 return ret;

dispdrv_reg_fail:
 kfree(mipi_dsi->lcd_panel);
kstrdup_fail:
get_parent_regmap_fail:
dev_reset_fail:
 if (mipi_dsi->disp_power_on)
  regulator_disable(mipi_dsi->disp_power_on);
 return ret;
}

static void mipi_dsi_shutdown(struct platform_device *pdev)
{
 struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);

 mipi_dsi_power_off(mipi_dsi->disp_mipi);
}

static int mipi_dsi_remove(struct platform_device *pdev)
{
 struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);

 mxc_dispdrv_puthandle(mipi_dsi->disp_mipi);
 mxc_dispdrv_unregister(mipi_dsi->disp_mipi);

 if (mipi_dsi->disp_power_on)
  regulator_disable(mipi_dsi->disp_power_on);

 kfree(mipi_dsi->lcd_panel);
 dev_set_drvdata(&pdev->dev, NULL);

 return 0;
}

static struct platform_driver mipi_dsi_driver = {
 .driver = {
     .of_match_table = imx_mipi_dsi_dt_ids,
     .name = "mxc_mipi_dsi",
 },
 .probe = mipi_dsi_probe,
 .remove = mipi_dsi_remove,
 .shutdown = mipi_dsi_shutdown,
};

static int __init mipi_dsi_init(void)
{
 int err;

 err = platform_driver_register(&mipi_dsi_driver);
 if (err) {
  pr_err("mipi_dsi_driver register failedn");
  return -ENODEV;
 }
 pr_info("MIPI DSI driver module loadedn");
 return 0;
}

static void __exit mipi_dsi_cleanup(void)
{
 platform_driver_unregister(&mipi_dsi_driver);
}

module_init(mipi_dsi_init);
module_exit(mipi_dsi_cleanup);

MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("i.MX MIPI DSI driver");
MODULE_LICENSE("GPL");

最后

以上就是单身小蚂蚁为你收集整理的idea2020.2.2 license server_i.MX6 MIPI DSI: 低功耗LCD时钟配置出现显示闪烁和抖动的问题...的全部内容,希望文章能够帮你解决idea2020.2.2 license server_i.MX6 MIPI DSI: 低功耗LCD时钟配置出现显示闪烁和抖动的问题...所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部