text: /****************************************************************************
   * arch/arm/src/imxrt/imxrt_lcd.c
   *
   *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
   *   Copyright (C) 2017, NXP Semiconductors, Inc.
   *   Author: Johannes Schock (Port)
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   * 3. Neither the name NuttX nor the names of its contributors may be
   *    used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGE.
   *
   ****************************************************************************/
  
  /****************************************************************************
   * Included Files
   ****************************************************************************/
  
  #include <nuttx/config.h>
  
  #include "imxrt_lcd.h"
  #include "imxrt_periphclks.h"
  
  #include <stdint.h>
  #include <string.h>
  #include <errno.h>
  #include <debug.h>
  
  #include <nuttx/video/fb.h>
  
  #include "arm_arch.h"
  
  #include <nuttx/board.h>
  
  #include "imxrt_gpio.h"
  #include "imxrt_iomuxc.h"
  
  #include "hardware/imxrt_pinmux.h"
  
  #include <arch/board/board.h>
  
  /****************************************************************************
   * Pre-processor Definitions
   ****************************************************************************/
  
  #define IMXRT_LCD_CLK_PER_LINE \
    (CONFIG_IMXRT_LCD_HWIDTH + CONFIG_IMXRT_LCD_HPULSE + \
     CONFIG_IMXRT_LCD_HFRONTPORCH + CONFIG_IMXRT_LCD_HBACKPORCH)
  #define IMXRT_LCD_LINES_PER_FRAME \
    (CONFIG_IMXRT_LCD_VHEIGHT + CONFIG_IMXRT_LCD_VPULSE + \
     CONFIG_IMXRT_LCD_VFRONTPORCH + CONFIG_IMXRT_LCD_VBACKPORCH)
  #define IMXRT_LCD_PIXEL_CLOCK \
    (IMXRT_LCD_CLK_PER_LINE * IMXRT_LCD_LINES_PER_FRAME * \
     CONFIG_IMXRT_LCD_REFRESH_FREQ)
  
  /* Framebuffer characteristics in bytes */
  
  #define IMXRT_STRIDE ((CONFIG_IMXRT_LCD_HWIDTH * IMXRT_BPP + 7) / 8)
  #define IMXRT_FBSIZE (IMXRT_STRIDE * CONFIG_IMXRT_LCD_VHEIGHT)
  
  /* Delays */
  
  #define IMXRT_LCD_RESET_DELAY (0x100)
  
  /****************************************************************************
   * Private Function Prototypes
   ****************************************************************************/
  
  /* Get information about the video controller configuration and the
   * configuration of each color plane.
   */
  
  static int imxrt_getvideoinfo(FAR struct fb_vtable_s *vtable,
               FAR struct fb_videoinfo_s *vinfo);
  static int imxrt_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
               FAR struct fb_planeinfo_s *pinfo);
  
  /* The following is provided only if the video hardware supports RGB color
   * mapping
   */
  
  #ifdef CONFIG_FB_CMAP
  static int imxrt_getcmap(FAR struct fb_vtable_s *vtable,
               FAR struct fb_cmap_s *cmap);
  static int imxrt_putcmap(FAR struct fb_vtable_s *vtable,
               FAR const struct fb_cmap_s *cmap);
  #endif
  
  #ifdef CONFIG_FB_HWCURSOR
  #  error "Cursor control not supported by this driver"
  #endif
  
  /****************************************************************************
   * Private Data
   ****************************************************************************/
  
  /* This structure describes the video controller */
  
  static const struct fb_videoinfo_s g_videoinfo =
  {
    .fmt      = IMXRT_COLOR_FMT,
    .xres     = CONFIG_IMXRT_LCD_HWIDTH,
    .yres     = CONFIG_IMXRT_LCD_VHEIGHT,
    .nplanes  = 1,
  };
  
  /* This structure describes the single color plane */
  
  static const struct fb_planeinfo_s g_planeinfo =
  {
    .fbmem    = (FAR void *)CONFIG_IMXRT_LCD_VRAMBASE,
    .fblen    = IMXRT_FBSIZE,
    .stride   = IMXRT_STRIDE,
    .display  = 0,
    .bpp      = IMXRT_BPP,
  };
  
  struct pixel_format_reg
  {
      uint32_t regCtrl;  /* Value of register CTRL. */
      uint32_t regCtrl1; /* Value of register CTRL1. */
  };
  
  #if defined (CONFIG_IMXRT_LCD_INPUT_BPP8) || defined (CONFIG_IMXRT_LCD_INPUT_BPP8_LUT)
    static const struct pixel_format_reg pixelFormat =
    {
      /* Register CTRL. */
  
      LCDIF_CTRL_WORD_LENGTH(1U),
  
      /* Register CTRL1. */
  
      LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0fU)
    };
    const uint32_t dataBus = LCDIF_CTRL_LCD_DATABUS_WIDTH(1);
  
  #else
  
  #  if defined (CONFIG_IMXRT_LCD_INPUT_BPP15)
    static const struct pixel_format_reg pixelFormat =
    {
      /* Register CTRL. */
  
      LCDIF_CTRL_WORD_LENGTH(0U) | LCDIF_CTRL_SET_DATA_FORMAT_16_BIT_MASK,
  
      /* Register CTRL1. */
  
      LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0fU)
    };
  #  elif defined (CONFIG_IMXRT_LCD_INPUT_BPP16)
    static const struct pixel_format_reg pixelFormat =
    {
      /* Register CTRL. */
  
      LCDIF_CTRL_WORD_LENGTH(0U),
  
      /* Register CTRL1. */
  
      LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0fU)
    };
  #  elif defined (CONFIG_IMXRT_LCD_INPUT_BPP24)
    static const struct pixel_format_reg pixelFormat =
    {
      /* Register CTRL. 24-bit. */
  
      LCDIF_CTRL_WORD_LENGTH(3U),
  
      /* Register CTRL1. */
  
      LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0fU)
    };
  #  elif defined (CONFIG_IMXRT_LCD_INPUT_BPP32)
    static const struct pixel_format_reg pixelFormat =
    {
      /* Register CTRL. 24-bit. */
  
      LCDIF_CTRL_WORD_LENGTH(3U),
  
      /* Register CTRL1. */
  
      LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)
    };
  #  endif
  
  #  if defined (CONFIG_IMXRT_LCD_OUTPUT_8)
    const uint32_t dataBus = LCDIF_CTRL_LCD_DATABUS_WIDTH(1);
  #  elif defined (CONFIG_IMXRT_LCD_OUTPUT_16)
    const uint32_t dataBus = LCDIF_CTRL_LCD_DATABUS_WIDTH(0);
  #  elif defined (CONFIG_IMXRT_LCD_OUTPUT_18)
    const uint32_t dataBus = LCDIF_CTRL_LCD_DATABUS_WIDTH(2);
  #  elif defined (CONFIG_IMXRT_LCD_OUTPUT_24)
    const uint32_t dataBus = LCDIF_CTRL_LCD_DATABUS_WIDTH(3);
  #  endif
  
  #endif
  
  /* The framebuffer object -- There is no private state information in this
   * framebuffer driver.
   */
  
  struct fb_vtable_s g_fbobject =
  {
    .getvideoinfo  = imxrt_getvideoinfo,
    .getplaneinfo  = imxrt_getplaneinfo,
  #ifdef CONFIG_FB_CMAP
    .getcmap       = imxrt_getcmap,
    .putcmap       = imxrt_putcmap,
  #endif
  };
  
  /****************************************************************************
   * Private Functions
   ****************************************************************************/
  
  /****************************************************************************
   * Name: imxrt_getvideoinfo
   ****************************************************************************/
  
  static int imxrt_getvideoinfo(FAR struct fb_vtable_s *vtable,
                                FAR struct fb_videoinfo_s *vinfo)
  {
    lcdinfo("vtable=%p vinfo=%p\n", vtable, vinfo);
    if (vtable && vinfo)
      {
        memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
        return OK;
      }
  
    lcderr("ERROR: Returning EINVAL\n");
    return -EINVAL;
  }
  
  /****************************************************************************
   * Name: imxrt_getplaneinfo
   ****************************************************************************/
  
  static int imxrt_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
                                FAR struct fb_planeinfo_s *pinfo)
  {
    lcdinfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
    if (vtable && planeno == 0 && pinfo)
      {
        memcpy(pinfo, &g_planeinfo, sizeof(struct fb_planeinfo_s));
        return OK;
      }
  
    lcderr("ERROR: Returning EINVAL\n");
    return -EINVAL;
  }
  
  /****************************************************************************
   * Name: imxrt_getcmap
   ****************************************************************************/
  
  #ifdef CONFIG_FB_CMAP
  static int imxrt_getcmap(FAR struct fb_vtable_s *vtable,
                           FAR struct fb_cmap_s *cmap)
  {
    uint32_t n;
    uint32_t reg;
  
    lcdinfo("vtable=%p cmap=%p first=%d len=%d\n",
        vtable, cmap, cmap->first, cmap->len);
  
    DEBUGASSERT(vtable && cmap);
  
    /* Only has 256 entries. */
  
    if (cmap->first + cmap->len > IMXRT_LCDIF_LUT_ENTRY_NUM)
      {
        return ERROR;
      }
  
    putreg32(cmap->first, IMXRT_LCDIF_LUT0_ADDR);
  
    for (n = 0; n < cmap->len; n++)
      {
        reg = getreg32(IMXRT_LCDIF_LUT0_DATA);
  
  #if defined (CONFIG_IMXRT_LCD_OUTPUT_24)
        cmap->red[n] =   (reg >> 16) & 0xff;
        cmap->green[n] = (reg >>  8) & 0xff;
        cmap->blue[n] =  (reg >>  0) & 0xff;
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_18)
        cmap->red[n] =   (reg >> 10) & 0xfc;
        cmap->green[n] = (reg >>  4) & 0xfc;
        cmap->blue[n] =  (reg <<  2) & 0xfc;
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_16)
        cmap->red[n] =   (reg >>  8) & 0xf8;
        cmap->green[n] = (reg >>  3) & 0xfc;
        cmap->blue[n] =  (reg <<  3) & 0xf8;
  #endif
      }
  
    return OK;
  }
  #endif
  
  /****************************************************************************
   * Name: imxrt_putcmap
   ****************************************************************************/
  
  #ifdef CONFIG_FB_CMAP
  static int imxrt_putcmap(FAR struct fb_vtable_s *vtable,
      FAR const struct fb_cmap_s *cmap)
  {
    uint32_t n;
  
    lcdinfo("vtable=%p cmap=%p first=%d len=%d\n",
            vtable, cmap, cmap->first, cmap->len);
  
    DEBUGASSERT(vtable && cmap);
  
    /* Only has 256 entries. */
  
    if (cmap->first + cmap->len > IMXRT_LCDIF_LUT_ENTRY_NUM)
      {
        return ERROR;
      }
  
    putreg32(cmap->first, IMXRT_LCDIF_LUT0_ADDR);
  
    for (n = 0; n < cmap->len; n++)
      {
  
  #if defined (CONFIG_IMXRT_LCD_OUTPUT_24)
        putreg32((uint32_t)0xff000000             |
                 ((uint32_t)cmap->red[n]   << 16) |
                 ((uint32_t)cmap->green[n] <<  8) |
                 ((uint32_t)cmap->blue[n]  <<  0),
                 IMXRT_LCDIF_LUT0_DATA);
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_18)
        putreg32((uint32_t)0xfffc0000                      |
                 (((uint32_t)cmap->red[n] & 0xfc)   << 10) |
                 (((uint32_t)cmap->green[n] & 0xfc) <<  4) |
                 (((uint32_t)cmap->blue[n] & 0xfc)  >>  2),
                 IMXRT_LCDIF_LUT0_DATA);
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_16)
        putreg32((uint32_t)0xffff0000                      |
                 (((uint32_t)cmap->red[n] & 0xf8)   <<  8) |
                 (((uint32_t)cmap->green[n] & 0xfc) <<  3) |
                 (((uint32_t)cmap->blue[n] & 0xf8)  >>  3),
                 IMXRT_LCDIF_LUT0_DATA);
  #endif
      }
  
    return OK;
  }
  #endif
  
  /****************************************************************************
   * Name: imxrt_lcd_reset
   ****************************************************************************/
  
  static void imxrt_lcdreset(void)
  {
    volatile uint32_t i = IMXRT_LCD_RESET_DELAY;
  
    /* Disable the clock gate. */
  
    putreg32(LCDIF_CTRL_CLKGATE_MASK, IMXRT_LCDIF_CTRL_CLR);
  
    /* Confirm the clock gate is disabled. */
  
    while ((getreg32(IMXRT_LCDIF_CTRL) & LCDIF_CTRL_CLKGATE_MASK) != 0)
      {
      }
  
    /* Reset the block. */
  
    putreg32(LCDIF_CTRL_SFTRST_MASK, IMXRT_LCDIF_CTRL_SET);
  
    /* Confirm the reset bit is set. */
  
    while ((getreg32(IMXRT_LCDIF_CTRL) & LCDIF_CTRL_SFTRST_MASK) == 0)
      {
      }
  
    /* Delay for the reset. */
  
    while (i--)
      {
      }
  
    /* Bring the module out of reset. */
  
    putreg32(LCDIF_CTRL_SFTRST_MASK, IMXRT_LCDIF_CTRL_CLR);
  
    /* Disable the clock gate. */
  
    putreg32(LCDIF_CTRL_CLKGATE_MASK, IMXRT_LCDIF_CTRL_CLR);
  }
  
  /****************************************************************************
   * Public Functions
   ****************************************************************************/
  
  /****************************************************************************
   * Name: up_fbinitialize
   *
   * Description:
   *   Initialize the framebuffer video hardware associated with the display.
   *
   * Input Parameters:
   *   display - In the case of hardware with multiple displays, this
   *     specifies the display.  Normally this is zero.
   *
   * Returned Value:
   *   Zero is returned on success; a negated errno value is returned on any
   *   failure.
   *
   ****************************************************************************/
  
  int up_fbinitialize(int display)
  {
  
  #if defined (CONFIG_IMXRT_LCD_INPUT_BPP8_LUT) || defined (CONFIG_IMXRT_LCD_INPUT_BPP8)
    uint32_t n;
  #endif
  
    /* Configure pins
     *
     * LCD panel data. Pins used depend on the panel configuration:
     */
  
    lcdinfo("Configuring pins\n");
  
  #if defined(CONFIG_IMXRT_LCD_OUTPUT_24)
  
    imxrt_config_gpio(GPIO_LCD_DATA23);
    imxrt_config_gpio(GPIO_LCD_DATA22);
    imxrt_config_gpio(GPIO_LCD_DATA21);
    imxrt_config_gpio(GPIO_LCD_DATA20);
    imxrt_config_gpio(GPIO_LCD_DATA19);
    imxrt_config_gpio(GPIO_LCD_DATA18);
  
  #endif
  #if defined(CONFIG_IMXRT_LCD_OUTPUT_24) || \
      defined(CONFIG_IMXRT_LCD_OUTPUT_18)
  
    imxrt_config_gpio(GPIO_LCD_DATA17);
    imxrt_config_gpio(GPIO_LCD_DATA16);
  
  #endif
  #if defined(CONFIG_IMXRT_LCD_OUTPUT_24) || \
      defined(CONFIG_IMXRT_LCD_OUTPUT_18) || \
      defined(CONFIG_IMXRT_LCD_OUTPUT_16)
  
    imxrt_config_gpio(GPIO_LCD_DATA15);
    imxrt_config_gpio(GPIO_LCD_DATA14);
    imxrt_config_gpio(GPIO_LCD_DATA13);
    imxrt_config_gpio(GPIO_LCD_DATA12);
    imxrt_config_gpio(GPIO_LCD_DATA11);
    imxrt_config_gpio(GPIO_LCD_DATA10);
    imxrt_config_gpio(GPIO_LCD_DATA09);
    imxrt_config_gpio(GPIO_LCD_DATA08);
  
  #endif
  
    imxrt_config_gpio(GPIO_LCD_DATA07);
    imxrt_config_gpio(GPIO_LCD_DATA06);
    imxrt_config_gpio(GPIO_LCD_DATA05);
    imxrt_config_gpio(GPIO_LCD_DATA04);
    imxrt_config_gpio(GPIO_LCD_DATA03);
    imxrt_config_gpio(GPIO_LCD_DATA02);
    imxrt_config_gpio(GPIO_LCD_DATA01);
    imxrt_config_gpio(GPIO_LCD_DATA00);
  
    /* Other pins */
  
    imxrt_config_gpio(GPIO_LCD_ENABLE);
    imxrt_config_gpio(GPIO_LCD_HSYNC);
    imxrt_config_gpio(GPIO_LCD_VSYNC);
    imxrt_config_gpio(GPIO_LCD_CLK);
  
    lcdinfo("Enable clocking to the LCD controller\n");
  
    /* Enable clocking to the LCD peripheral */
  
    imxrt_clockall_pxp();
  
    imxrt_clockall_lcd();
  
    imxrt_clockall_lcdif_pix();
  
    /* Reset the LCD */
  
    imxrt_lcd_initialize();
  
    imxrt_lcdreset();
  
    lcdinfo("Configuring the LCD controller\n");
  
    putreg32(pixelFormat.regCtrl | dataBus |
        LCDIF_CTRL_DOTCLK_MODE_MASK |
        LCDIF_CTRL_BYPASS_COUNT_MASK |
        LCDIF_CTRL_MASTER_MASK, IMXRT_LCDIF_CTRL);
  
    putreg32(pixelFormat.regCtrl1, IMXRT_LCDIF_CTRL1);
  
    putreg32((CONFIG_IMXRT_LCD_VHEIGHT << LCDIF_TRANSFER_COUNT_V_COUNT_SHIFT) |
        (CONFIG_IMXRT_LCD_HWIDTH << LCDIF_TRANSFER_COUNT_H_COUNT_SHIFT),
        IMXRT_LCDIF_TRANSFER_COUNT);
  
    putreg32(LCDIF_VDCTRL0_ENABLE_PRESENT_MASK |
        LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT_MASK |
        LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT_MASK |
        VSYNC_POL | HSYNC_POL | DATAEN_POL | DATA_EDGE |
        CONFIG_IMXRT_LCD_VPULSE,
        IMXRT_LCDIF_VDCTRL0);
  
    putreg32(CONFIG_IMXRT_LCD_VPULSE + CONFIG_IMXRT_LCD_VHEIGHT +
        CONFIG_IMXRT_LCD_VFRONTPORCH + CONFIG_IMXRT_LCD_VBACKPORCH,
        IMXRT_LCDIF_VDCTRL1);
  
    putreg32((CONFIG_IMXRT_LCD_HPULSE << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_SHIFT) |
        ((CONFIG_IMXRT_LCD_HFRONTPORCH + CONFIG_IMXRT_LCD_HBACKPORCH +
          CONFIG_IMXRT_LCD_HWIDTH + CONFIG_IMXRT_LCD_HPULSE)
            << LCDIF_VDCTRL2_HSYNC_PERIOD_SHIFT),
        IMXRT_LCDIF_VDCTRL2);
  
    putreg32(((CONFIG_IMXRT_LCD_HBACKPORCH + CONFIG_IMXRT_LCD_HPULSE)
          << LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_SHIFT) |
        ((CONFIG_IMXRT_LCD_VBACKPORCH + CONFIG_IMXRT_LCD_VPULSE)
          << LCDIF_VDCTRL3_VERTICAL_WAIT_CNT_SHIFT),
        IMXRT_LCDIF_VDCTRL3);
  
    putreg32(LCDIF_VDCTRL4_SYNC_SIGNALS_ON_MASK |
        (CONFIG_IMXRT_LCD_HWIDTH << LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT_SHIFT),
        IMXRT_LCDIF_VDCTRL4);
  
  #ifdef CONFIG_IMXRT_LCD_BGR
    /* Swap red and blue.  The colors will be 0x00RRGGBB, not 0x00bbGGRR. */
  
    /* TODO */
  #endif
  
  #if defined (CONFIG_IMXRT_LCD_INPUT_BPP8_LUT) || defined (CONFIG_IMXRT_LCD_INPUT_BPP8)
  
    putreg32(0, IMXRT_LCDIF_LUT0_ADDR);
  
    for (n = 0; n < IMXRT_LCDIF_LUT_ENTRY_NUM; n++)
      {
        uint8_t  red;
        uint8_t  green;
        uint8_t  blue;
  
        red = (n << 0) & 0xe0;
        green = (n << 3) & 0xe0;
        blue = (n << 6) & 0xc0;
  
  #if defined (CONFIG_IMXRT_LCD_OUTPUT_24)
        putreg32((uint32_t)0xff000000    |
                 ((uint32_t)red   << 16) |
                 ((uint32_t)green <<  8) |
                 ((uint32_t)blue  <<  0),
                 IMXRT_LCDIF_LUT0_DATA);
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_18)
        putreg32((uint32_t)0xfffc0000             |
                 (((uint32_t)red & 0xfc)   << 10) |
                 (((uint32_t)green & 0xfc) <<  4) |
                 (((uint32_t)blue & 0xfc)  >>  2),
                 IMXRT_LCDIF_LUT0_DATA);
  #elif defined (CONFIG_IMXRT_LCD_OUTPUT_16)
        putreg32((uint32_t)0xffff0000             |
                 (((uint32_t)red & 0xf8)   <<  8) |
                 (((uint32_t)green & 0xfc) <<  3) |
                 (((uint32_t)blue & 0xf8)  >>  3),
                 IMXRT_LCDIF_LUT0_DATA);
  #endif
      }
  
    putreg32(0, IMXRT_LCDIF_LUT_CTRL);
  
  #endif
  
    putreg32(CONFIG_IMXRT_LCD_VRAMBASE, IMXRT_LCDIF_CUR_BUF);
    putreg32(CONFIG_IMXRT_LCD_VRAMBASE, IMXRT_LCDIF_NEXT_BUF);
  
    /* Clear the display */
  
    imxrt_lcdclear(CONFIG_IMXRT_LCD_BACKCOLOR);
  
  #ifdef CONFIG_IMXRT_LCD_BACKLIGHT
  
    /* Turn on the back light */
  
    imxrt_backlight(true);
  
  #endif
  
    putreg32(LCDIF_CTRL_RUN_MASK | LCDIF_CTRL_DOTCLK_MODE_MASK,
        IMXRT_LCDIF_CTRL_SET);
  
    return OK;
  }
  
  /****************************************************************************
   * Name: up_fbgetvplane
   *
   * Description:
   *   Return a a reference to the framebuffer object for the specified video
   *   plane of the specified plane.  Many OSDs support multiple planes of
   *   video.
   *
   * Input Parameters:
   *   display - In the case of hardware with multiple displays, this
   *     specifies the display.  Normally this is zero.
   *   vplane - Identifies the plane being queried.
   *
   * Returned Value:
   *   A non-NULL pointer to the frame buffer access structure is returned on
   *   success; NULL is returned on any failure.
   *
   ****************************************************************************/
  
  FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
  {
    lcdinfo("vplane: %d\n", vplane);
    if (vplane == 0)
      {
        return &g_fbobject;
      }
    else
      {
        return NULL;
      }
  }
  
  /****************************************************************************
   * Name: up_fbuninitialize
   *
   * Description:
   *   Uninitialize the framebuffer support for the specified display.
   *
   * Input Parameters:
   *   display - In the case of hardware with multiple displays, this
   *     specifies the display.  Normally this is zero.
   *
   * Returned Value:
   *   None
   *
   ****************************************************************************/
  
  void up_fbuninitialize(int display)
  {
    /* We assume there is only one use of the LCD and so we do not need to
     * worry about mutually exclusive access to the LCD hardware.
     */
  
  #ifdef CONFIG_IMXRT_LCD_BACKLIGHT
    /* Turn off the back light */
  
    imxrt_backlight(false);
  #endif
  
    /* Disable the clock gate. */
  
    putreg32(LCDIF_CTRL_CLKGATE_MASK, IMXRT_LCDIF_CTRL_CLR);
  
    /* Disable clocking to the LCD peripheral */
  
    imxrt_clockoff_lcdif_pix();
  
    imxrt_clockoff_lcd();
  
  }
  
  /****************************************************************************
   * Name:  imxrt_lcdclear
   *
   * Description:
   *   This is a non-standard LCD interface just for the IMXRT.  Clearing
   *   the display in the normal way by writing a sequences of runs that
   *   covers the entire display can be slow.  Here the display is cleared by
   *   simply setting all VRAM memory to the specified color.
   *
   ****************************************************************************/
  
  void imxrt_lcdclear(nxgl_mxpixel_t color)
  {
    int i;
    int size;
  
    size = CONFIG_IMXRT_LCD_HWIDTH * CONFIG_IMXRT_LCD_VHEIGHT;
  
    #if IMXRT_BPP > 24
    uint32_t *dest = (uint32_t *)CONFIG_IMXRT_LCD_VRAMBASE;
  
    lcdinfo("Clearing display: color=%08x VRAM=%08x size=%d\n",
            color, CONFIG_IMXRT_LCD_VRAMBASE,
            size * sizeof(uint32_t));
  
  #elif IMXRT_BPP > 16
    uint32_t *dest = (uint32_t *)CONFIG_IMXRT_LCD_VRAMBASE;
  
    size = (size * 3) >> 2;
  
    lcdinfo("Clearing display: color=%06x VRAM=%08x size=%d\n",
            color, CONFIG_IMXRT_LCD_VRAMBASE,
            size * sizeof(uint32_t));
  
  #elif IMXRT_BPP > 8
    uint16_t *dest = (uint16_t *)CONFIG_IMXRT_LCD_VRAMBASE;
  
    lcdinfo("Clearing display: color=%04x VRAM=%08x size=%d\n",
            color, CONFIG_IMXRT_LCD_VRAMBASE,
            size * sizeof(uint16_t));
  #else
    uint8_t *dest = (uint8_t *)CONFIG_IMXRT_LCD_VRAMBASE;
  
    lcdinfo("Clearing display: color=%02x VRAM=%08x size=%d\n",
            color, CONFIG_IMXRT_LCD_VRAMBASE,
            size * sizeof(uint8_t));
  #endif
  
    for (i = 0; i < size; i++)
      {
        *dest++ = color;
      }
  }
  