This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new f3805fb222d arch/mips/jz4780: Add HDMI EDID parsing and dynamic 
display modes
f3805fb222d is described below

commit f3805fb222d1413cb824ee17aa238e5434b1f7a9
Author: Lwazi Dube <[email protected]>
AuthorDate: Fri Aug 21 23:12:16 2026 -0400

    arch/mips/jz4780: Add HDMI EDID parsing and dynamic display modes
    
    This commit introduces EDID reading and parsing to the JZ4780 display
    driver, replacing hardcoded resolution limits with dynamic mode selection
    based on the connected display's capabilities.
    
    Specific changes include:
      - Implemented I2C DDC master communication for the HDMI controller to
        read EDID blocks from monitors.
      - Added dynamic mode selection to calculate bandwidth and pick the best
        supported resolution, prioritizing the EDID preferred mode.
      - Dynamically allocated framebuffer bounds (g_planeinfo and g_videoinfo)
        based on parsed EDID dimensions.
      - Configured GPIO pin multiplexing for HDMI power, DDC, and control pins
        (POWER_EN, CEC, SCL, SDA) to enable display power and communication
        on the CI20 board.
    
    Signed-off-by: Lwazi Dube <[email protected]>
---
 .../mips/jz4780/boards/mips-creator-ci20/index.rst |   2 +-
 arch/mips/include/jz4780/chip.h                    |  17 +-
 arch/mips/src/jz4780/jz4780_lcd.c                  | 422 ++++++++++++++++-----
 boards/mips/jz4780/ci20/configs/jumbo/defconfig    |   2 +
 boards/mips/jz4780/ci20/src/jz4780_bringup.c       |  15 +
 5 files changed, 368 insertions(+), 90 deletions(-)

diff --git 
a/Documentation/platforms/mips/jz4780/boards/mips-creator-ci20/index.rst 
b/Documentation/platforms/mips/jz4780/boards/mips-creator-ci20/index.rst
index db7115435de..0488c29c258 100644
--- a/Documentation/platforms/mips/jz4780/boards/mips-creator-ci20/index.rst
+++ b/Documentation/platforms/mips/jz4780/boards/mips-creator-ci20/index.rst
@@ -21,7 +21,7 @@ CPU1         No     1.2GHz MIPS32 processor
 RAM          Yes    256MiB
 ADC          No
 Audio        No
-Display      Yes    HDMI (EDID not yet supported)
+Display      Yes    HDMI
 DMA          No
 Ethernet     Yes    Fast Ethernet (DM9000)
 GPIO         Yes
diff --git a/arch/mips/include/jz4780/chip.h b/arch/mips/include/jz4780/chip.h
index 6a15381b786..74d8ff6f99a 100644
--- a/arch/mips/include/jz4780/chip.h
+++ b/arch/mips/include/jz4780/chip.h
@@ -89,6 +89,15 @@
 
 #define JZPMC_BASE          0xb0000000
 
+#define JZ_EXTCLK           48000000U
+
+#define PCR_PLLM(r)         ((r >> 19) & 0x1FFF)
+#define PCR_PLLN(r)         ((r >> 13) & 0x3F)
+#define PCR_PLLOD(r)        ((r >> 9) & 0xF)
+
+#define CPMPCR_REG          (JZPMC_BASE + 0x14)
+#define CPVPCR_REG          (JZPMC_BASE + 0x1c)
+
 #define CLKGR0_REG          (JZPMC_BASE + 0x20)
 #  define CLKGR0_OTG0       (1 << 2)
 #  define CLKGR0_UHC        (1 << 24)
@@ -111,11 +120,17 @@
 
 #define LP1CDR_REG          (JZPMC_BASE + 0x54)
 #  define LPCDR_VAL         0x15
-#  define LPCS_VPLL         0X80000000
+#  define LPCS_MPLL         0x40000000
+#  define LPCS_VPLL         0x80000000
 #  define CE_LCD            (1 << 28)
 #  define LCD_BUSY          (1 << 27)
 
 #define HDMICDR_REG         (JZPMC_BASE + 0x8c)
+#  define HPCS_SCLK_A       0x00000000
+#  define HPCS_MPLL         0x40000000
+#  define HPCS_VPLL         0x80000000
+#  define CE_HDMI           (1 << 29)
+#  define HDMI_BUSY         (1 << 28)
 
 #define SRBC_REG            (JZPMC_BASE + 0xc4)
 #  define SRBC_UHC_SR       (1 << 14)
diff --git a/arch/mips/src/jz4780/jz4780_lcd.c 
b/arch/mips/src/jz4780/jz4780_lcd.c
index 4ed30e3d4ef..d59025e1ddc 100644
--- a/arch/mips/src/jz4780/jz4780_lcd.c
+++ b/arch/mips/src/jz4780/jz4780_lcd.c
@@ -42,6 +42,7 @@
 #include <errno.h>
 #include <debug.h>
 
+#include <nuttx/video/edid.h>
 #include <nuttx/video/fb.h>
 
 #include "mips_internal.h"
@@ -55,26 +56,25 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define JZ4780_COLOR_FMT    FB_FMT_RGB16_565
+#define JZ4780_BPP          16
+
+#define FB_MAX_BW           (1920 * 1080 * 60)
+#define FB_MAX_W            2048
+#define FB_MAX_H            2048
+#define FB_DIVIDE(x, y)     (((x) + ((y) / 2)) / (y))
+#define FB_MAX_SIZE         (FB_MAX_W * FB_MAX_H * (JZ4780_BPP / 2))
+
+#define DOT_CLOCK_TO_HZ(c)  ((c) * 1000)
+
 #define JZ4780_LCD_VRAMBASE                               0xAF800000
-#define JZ4780_LCD_HWIDTH                                 1360
-#define JZ4780_LCD_VHEIGHT                                768
 
 #define PCFG_MAGIC                                        0xc7ff2100
 
 #define FOREGROUND_OFFSET                                 0x400000
 
-#define VID_PHSYNC                                        0x0001
-#define VID_PVSYNC                                        0x0004
-#define VID_INTERLACE                                     0x0010
-
 #define JZ_REG_SHIFT                                      2
 
-#define JZ4780_COLOR_FMT                                  FB_FMT_RGB16_565
-#define JZ4780_BPP                                        16
-
-#define JZ4780_STRIDE ((JZ4780_LCD_HWIDTH * JZ4780_BPP + 7) / 8)
-#define JZ4780_FBSIZE (JZ4780_STRIDE * JZ4780_LCD_VHEIGHT)
-
 /* HDMI controller registers */
 
 #define HDMI_DESIGN_ID                                    0x0000
@@ -85,6 +85,11 @@
 /* Interrupt Registers */
 #define HDMI_IH_PHY_STAT0                                 0x0104
 #  define HDMI_IH_PHY_STAT0_HPD                           (1 << 0)
+
+#define HDMI_IH_I2CM_STAT0                                0x0105
+#  define HDMI_IH_I2CM_STAT0_DONE                         (1 << 1)
+#  define HDMI_IH_I2CM_STAT0_ERROR                        (1 << 0)
+
 #define HDMI_IH_I2CMPHY_STAT0                             0x0108
 #  define HDMI_IH_I2CMPHY_STAT0_DONE                      (1 << 1)
 #  define HDMI_IH_I2CMPHY_STAT0_ERROR                     (1 << 0)
@@ -238,7 +243,7 @@
 
 /* I2C Master Registers (E-DDC) */
 #define HDMI_I2CM_SLAVE                                   0x7E00
-#define HDMI_I2CMESS                                      0x7E01
+#define HDMI_I2CM_ADDRESS                                 0x7E01
 #define HDMI_I2CM_DATAO                                   0x7E02
 #define HDMI_I2CM_DATAI                                   0x7E03
 #define HDMI_I2CM_OPERATION                               0x7E04
@@ -247,6 +252,7 @@
 #define HDMI_I2CM_INT                                     0x7E05
 #define HDMI_I2CM_CTLINT                                  0x7E06
 #define HDMI_I2CM_DIV                                     0x7E07
+#define  HDMI_I2CM_DIV_MODE_MASK                          0xF7
 #define HDMI_I2CM_SEGADDR                                 0x7E08
 #define HDMI_I2CM_SOFTRSTZ                                0x7E09
 #define HDMI_I2CM_SEGPTR                                  0x7E0A
@@ -340,6 +346,35 @@
 #define LCDDESSIZE_HEIGHT_SHIFT                           12
 #define LCDDESSIZE_WIDTH_SHIFT                            0
 
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct lcd_frame_descriptor
+{
+  uint32_t next;
+  uint32_t physaddr;
+  uint32_t id;
+  uint32_t cmd;
+  uint32_t offs;
+  uint32_t pw;
+  uint32_t cnum_pos;
+  uint32_t dessize;
+} __packed;
+
+struct display_s
+{
+  uint32_t fbsize;
+  uint32_t paddr;
+  uint32_t vaddr;
+
+  uint32_t fdesc_paddr;
+  struct lcd_frame_descriptor *fdesc;
+
+  struct videomode_s sc_mode;
+  struct edid_info_s ei;
+};
+
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
@@ -375,6 +410,12 @@ static int jz_setcursor(struct fb_vtable_s *vtable,
              struct fb_setcursor_s *settings);
 #endif
 
+static int dwc_hdmi_wait_i2cm_done(int msec);
+static int get_edid(uint8_t *buf, uint8_t block);
+static int jzlcd_get_bandwidth(const struct videomode_s *mode);
+static int jzlcd_mode_supported(const struct videomode_s *mode);
+static int jzlcd_find_mode(struct display_s *sc);
+
 static uint8_t hdmi_rd1(uint32_t off);
 static void hdmi_wr1(uint32_t off, uint8_t val);
 static void dwc_hdmi_init(void);
@@ -385,21 +426,21 @@ static void dwc_hdmi_init(void);
 
 /* This structure describes the video controller */
 
-static const struct fb_videoinfo_s g_videoinfo =
+static struct fb_videoinfo_s g_videoinfo =
 {
   .fmt      = JZ4780_COLOR_FMT,
-  .xres     = JZ4780_LCD_HWIDTH,
-  .yres     = JZ4780_LCD_VHEIGHT,
+  .xres     = 0,
+  .yres     = 0,
   .nplanes  = 1,
 };
 
 /* This structure describes the single color plane */
 
-static const struct fb_planeinfo_s g_planeinfo =
+static struct fb_planeinfo_s g_planeinfo =
 {
   .fbmem    = (void *)JZ4780_LCD_VRAMBASE,
-  .fblen    = JZ4780_FBSIZE,
-  .stride   = JZ4780_STRIDE,
+  .fblen    = 0,
+  .stride   = 0,
   .display  = 0,
   .bpp      = JZ4780_BPP,
 };
@@ -434,44 +475,6 @@ struct fb_vtable_s g_fbobject =
 #endif
 };
 
-struct lcd_frame_descriptor
-{
-  uint32_t next;
-  uint32_t physaddr;
-  uint32_t id;
-  uint32_t cmd;
-  uint32_t offs;
-  uint32_t pw;
-  uint32_t cnum_pos;
-  uint32_t dessize;
-} __packed;
-
-struct videomode_s
-{
-  int dot_clock;    /* Dot clock frequency in kHz. */
-  int hdisplay;
-  int hsync_start;
-  int hsync_end;
-  int htotal;
-  int vdisplay;
-  int vsync_start;
-  int vsync_end;
-  int vtotal;
-  int flags;         /* Video mode flags; see below. */
-};
-
-struct display_s
-{
-  uint32_t fbsize;
-  uint32_t paddr;
-  uint32_t vaddr;
-
-  uint32_t fdesc_paddr;
-  struct lcd_frame_descriptor *fdesc;
-
-  struct videomode_s sc_mode;
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -496,6 +499,29 @@ static void lcd_write(struct display_s *sc, uint32_t reg, 
uint32_t val)
   putreg32(val, 0xb3050000 + reg);
 }
 
+static int dwc_hdmi_wait_i2cm_done(int msec)
+{
+  uint8_t val;
+
+  val = hdmi_rd1(HDMI_IH_I2CM_STAT0) &
+      (HDMI_IH_I2CM_STAT0_DONE | HDMI_IH_I2CM_STAT0_ERROR);
+
+  while ((val & HDMI_IH_I2CM_STAT0_DONE) == 0)
+    {
+      up_mdelay(10);
+      msec -= 10;
+      if (msec <= 0)
+        {
+          return -ETIMEDOUT;
+        }
+
+      val = hdmi_rd1(HDMI_IH_I2CM_STAT0) &
+          (HDMI_IH_I2CM_STAT0_DONE | HDMI_IH_I2CM_STAT0_ERROR);
+    }
+
+  return 0;
+}
+
 static void
 dwc_hdmi_phy_wait_i2c_done(int msec)
 {
@@ -508,7 +534,10 @@ dwc_hdmi_phy_wait_i2c_done(int msec)
       up_mdelay(10);
       msec -= 10;
       if (msec <= 0)
-        return;
+        {
+          return;
+        }
+
       val = hdmi_rd1(HDMI_IH_I2CMPHY_STAT0) &
           (HDMI_IH_I2CMPHY_STAT0_DONE | HDMI_IH_I2CMPHY_STAT0_ERROR);
     }
@@ -706,7 +735,9 @@ static void dwc_hdmi_clear_overflow(void)
   val = hdmi_rd1(HDMI_FC_INVIDCONF);
 
   for (count = 0 ; count < 4 ; count++)
-    hdmi_wr1(HDMI_FC_INVIDCONF, val);
+    {
+      hdmi_wr1(HDMI_FC_INVIDCONF, val);
+    }
 }
 
 static int
@@ -768,17 +799,29 @@ dwc_hdmi_phy_configure(int dot_clock)
    */
 
   if (dot_clock * 1000 <= 54000000)
-    dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    }
   else if (dot_clock * 1000 <= 58400000)
-    dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    }
   else if (dot_clock * 1000 <= 72000000)
-    dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    }
   else if (dot_clock * 1000 <= 74250000)
-    dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    }
   else if (dot_clock * 1000 <= 118800000)
-    dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x091c, HDMI_PHY_I2C_CURRCTRL);
+    }
   else if (dot_clock * 1000 <= 216000000)
-    dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    {
+      dwc_hdmi_phy_i2c_write(0x06dc, HDMI_PHY_I2C_CURRCTRL);
+    }
   else
     {
       /* Unsupported mode */
@@ -835,7 +878,7 @@ dwc_hdmi_phy_configure(int dot_clock)
       up_mdelay(1);
       if (msec-- == 0)
         {
-          lcderr("PHY PLL not locked\n");
+          gerr("PHY PLL not locked\n");
           return -1;
         }
 
@@ -1050,7 +1093,7 @@ dwc_hdmi_set_mode(struct display_s *sc)
 
   dwc_hdmi_disable_overflow_interrupts();
   dwc_hdmi_av_composer(sc);
-  ret = dwc_hdmi_phy_init(sc->sc_mode.dot_clock);
+  ret = dwc_hdmi_phy_init(sc->sc_mode.dotclock);
   if (ret != OK)
     {
       return ret;
@@ -1066,10 +1109,162 @@ dwc_hdmi_set_mode(struct display_s *sc)
   return 0;
 }
 
+/****************************************************************************
+ * Name: get_edid
+ *
+ * Description:
+ *   Read the EDID block from the attached monitor.
+ *
+ * Input Parameters:
+ *   buf   - The buffer into which the data is copied.
+ *   block - Identifies the block being read.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is return on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+static int get_edid(uint8_t *buf, uint8_t block)
+{
+  uint8_t val = hdmi_rd1(HDMI_I2CM_DIV);
+  uint8_t segment = block / 2;
+  uint8_t offset = (block % 2) * 128;
+  int i;
+  int ret;
+
+  if (segment > 0)
+    {
+      return -EINVAL;
+    }
+
+  hdmi_wr1(HDMI_I2CM_DIV, val & HDMI_I2CM_DIV_MODE_MASK);
+  hdmi_wr1(HDMI_I2CM_SLAVE, 0x50);
+
+  hdmi_wr1(HDMI_I2CM_SEGADDR, 0x00);
+  hdmi_wr1(HDMI_I2CM_SEGPTR, segment);
+
+  for (i = 0; i < EDID_LENGTH; i++)
+    {
+      hdmi_wr1(HDMI_IH_I2CM_STAT0, HDMI_IH_I2CM_STAT0_DONE);
+      hdmi_wr1(HDMI_IH_I2CM_STAT0, HDMI_IH_I2CM_STAT0_ERROR);
+
+      hdmi_wr1(HDMI_I2CM_ADDRESS, offset + i);
+
+      hdmi_wr1(HDMI_I2CM_OPERATION, 0x01);
+
+      ret = dwc_hdmi_wait_i2cm_done(1000);
+      if (ret)
+        {
+          return ret;
+        }
+
+      buf[i] = hdmi_rd1(HDMI_I2CM_DATAI);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: jzlcd_get_bandwidth
+ ****************************************************************************/
+
+static int jzlcd_get_bandwidth(const struct videomode_s *mode)
+{
+  int refresh;
+
+  refresh = FB_DIVIDE(FB_DIVIDE(DOT_CLOCK_TO_HZ(mode->dotclock),
+      mode->htotal), mode->vtotal);
+
+  return mode->hdisplay * mode->vdisplay * refresh;
+}
+
+/****************************************************************************
+ * Name: jzlcd_mode_supported
+ ****************************************************************************/
+
+static int jzlcd_mode_supported(const struct videomode_s *mode)
+{
+  if (mode->hdisplay > FB_MAX_W || mode->vdisplay > FB_MAX_H)
+    {
+      return -EINVAL;
+    }
+
+  /* Bandwidth check */
+
+  if (jzlcd_get_bandwidth(mode) > FB_MAX_BW)
+    {
+      return -EINVAL;
+    }
+
+  /* Interlace modes not yet supported by the driver */
+
+  if ((mode->flags & VID_INTERLACE) != 0)
+    {
+      return -EINVAL;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: jzlcd_find_mode
+ ****************************************************************************/
+
+static int jzlcd_find_mode(struct display_s *sc)
+{
+  const struct videomode_s *best;
+  int n;
+  int bw;
+  int best_bw;
+
+  /* If the preferred mode is OK, just use it */
+
+  if (jzlcd_mode_supported(sc->ei.edid_preferred_mode) == OK)
+    {
+      sc->sc_mode = *sc->ei.edid_preferred_mode;
+      return OK;
+    }
+
+  /* Pick the mode with the highest bandwidth requirements */
+
+  best = NULL;
+  best_bw = 0;
+  for (n = 0; n < sc->ei.edid_nmodes; n++)
+    {
+      if (jzlcd_mode_supported(&sc->ei.edid_modes[n]) != OK)
+        {
+          continue;
+        }
+
+      bw = jzlcd_get_bandwidth(&sc->ei.edid_modes[n]);
+      if (bw > FB_MAX_BW)
+        {
+          continue;
+        }
+
+      if (best == NULL || bw > best_bw)
+        {
+          best = &sc->ei.edid_modes[n];
+          best_bw = bw;
+        }
+    }
+
+  if (best)
+    {
+      sc->sc_mode = *best;
+      return OK;
+    }
+  else
+    {
+      return -EINVAL;
+    }
+}
+
 void
 dwc_hdmi_init(void)
 {
-  lcdinfo("HDMI controller %02x:%02x:%02x:%02x\n",
+  ginfo("HDMI controller %02x:%02x:%02x:%02x\n",
       hdmi_rd1(HDMI_DESIGN_ID), hdmi_rd1(HDMI_REVISION_ID),
       hdmi_rd1(HDMI_PRODUCT_ID0), hdmi_rd1(HDMI_PRODUCT_ID1));
 
@@ -1077,6 +1272,15 @@ dwc_hdmi_init(void)
   hdmi_wr1(HDMI_IH_PHY_STAT0, HDMI_IH_PHY_STAT0_HPD);
 }
 
+static uint32_t get_sclk_khz(uint32_t v)
+{
+  uint32_t pllm = PCR_PLLM(v) + 1;
+  uint32_t plln = PCR_PLLN(v) + 1;
+  uint32_t pllod = PCR_PLLOD(v) + 1;
+
+  return ((JZ_EXTCLK / 1000) * pllm / plln) / pllod;
+}
+
 static void
 jzlcd_start(struct display_s *sc)
 {
@@ -1130,16 +1334,18 @@ jzlcd_setup_descriptor(struct display_s *sc, const 
struct videomode_s *mode,
   uint32_t f0height = mode->vdisplay;
   uint32_t f1width  = mode->hdisplay;
   uint32_t f1height = mode->vdisplay;
-
   uint32_t bpp;
+
   bpp = JZ4780_BPP == 16 ? LCDPOS_BPP01_15_16 : LCDPOS_BPP01_24_COMP;
 
   /* Frame size is specified in # words */
 
   int line_sz = ((desno ? f1width : f0width) * JZ4780_BPP) >> 3;
+
   line_sz = ((line_sz + 3) & ~3) / 4;
 
   struct lcd_frame_descriptor *fdesc = sc->fdesc + desno;
+
   fdesc->id = desno;
   fdesc->offs = 0;
   fdesc->pw = 0;
@@ -1229,9 +1435,12 @@ jzlcd_set_videomode(struct display_s *sc, const struct 
videomode_s *mode)
       + sizeof(struct lcd_frame_descriptor));
   lcd_write(sc, LCDDA1, sc->fdesc_paddr);
 
+  uint32_t sclk = get_sclk_khz(getreg32(CPVPCR_REG));
+  uint32_t lcdiv = sclk / mode->dotclock;
+
   /* Set display clock */
 
-  putreg32(LPCS_VPLL | CE_LCD | LPCDR_VAL, LP1CDR_REG);
+  putreg32(LPCS_VPLL | CE_LCD | (lcdiv - 1), LP1CDR_REG);
   while (getreg32(LP1CDR_REG) & LCD_BUSY)
     {
     }
@@ -1242,9 +1451,10 @@ jzlcd_set_videomode(struct display_s *sc, const struct 
videomode_s *mode)
 static int
 jzlcd_configure(struct display_s *sc, const struct videomode_s *mode)
 {
+  int ret;
   uint32_t vaddr0 = (uint32_t)JZ4780_LCD_VRAMBASE;
 
-  sc->fbsize = 0x00300000;
+  sc->fbsize = FB_MAX_SIZE - 2*sizeof(struct lcd_frame_descriptor);
   sc->vaddr  = vaddr0;
   sc->paddr  = jz_physramaddr(vaddr0);
   sc->fdesc  = (struct lcd_frame_descriptor *)(sc->vaddr + sc->fbsize);
@@ -1252,10 +1462,10 @@ jzlcd_configure(struct display_s *sc, const struct 
videomode_s *mode)
 
   /* Setup video mode */
 
-  int error = jzlcd_set_videomode(sc, mode);
-  if (error != 0)
+  ret = jzlcd_set_videomode(sc, mode);
+  if (ret != 0)
     {
-      return error;
+      return ret;
     }
 
   return 0;
@@ -1264,23 +1474,25 @@ jzlcd_configure(struct display_s *sc, const struct 
videomode_s *mode)
 static void
 jzlcd_hdmi_event(struct display_s *sc)
 {
+  int ret;
+
   /* Stop the controller */
 
   jzlcd_stop(sc);
 
   /* Configure LCD controller */
 
-  int error = jzlcd_configure(sc, &sc->sc_mode);
-  if (error != 0)
+  ret = jzlcd_configure(sc, &sc->sc_mode);
+  if (ret != 0)
     {
-      lcderr("failed to configure FB: %d\n", error);
+      gerr("failed to configure FB: %d\n", ret);
       return;
     }
 
-  error = dwc_hdmi_set_mode(sc);
-  if (error != 0)
+  ret = dwc_hdmi_set_mode(sc);
+  if (ret != 0)
     {
-      lcderr("hdmi error: %d\n", error);
+      gerr("hdmi error: %d\n", ret);
       return;
     }
 
@@ -1302,7 +1514,13 @@ void jzlcd_clocks(void)
 
 int jzlcd_attach(void)
 {
+  int ret;
   uint32_t val;
+  uint8_t edid[EDID_LENGTH] =
+  {
+    0
+  };
+
   static struct display_s sc_obj = {
     .fbsize = 0,
     .paddr = 0,
@@ -1311,7 +1529,7 @@ int jzlcd_attach(void)
     .fdesc = NULL,
 
     .sc_mode = {
-      .dot_clock = 85500,
+      .dotclock = 85500,
       .hdisplay = 1360,
       .hsync_start = 1424,
       .hsync_end = 1536,
@@ -1329,8 +1547,36 @@ int jzlcd_attach(void)
   val &= ~CLKGR0_TVE;
   putreg32(val, CLKGR0_REG);
 
+  ret = get_edid(edid, 0);
+  if (ret == OK)
+    {
+      ret = edid_parse(edid, &sc_obj.ei);
+      if (ret != OK)
+        {
+          gerr("ERROR: Failed to parse EDID\n");
+        }
+      else
+        {
+#ifdef CONFIG_DEBUG_INFO
+          edid_dump(&sc_obj.ei);
+#endif
+          ret = jzlcd_find_mode(&sc_obj);
+        }
+    }
+
+  if (ret != OK)
+    {
+      gerr("EDID error. Falling back to %s.\n", sc_obj.sc_mode.name);
+    }
+
+  g_planeinfo.stride = ((sc_obj.sc_mode.hdisplay * JZ4780_BPP + 7) / 8);
+  g_planeinfo.fblen  = g_planeinfo.stride * sc_obj.sc_mode.vdisplay;
+
+  g_videoinfo.xres   = sc_obj.sc_mode.hdisplay;
+  g_videoinfo.yres   = sc_obj.sc_mode.vdisplay;
+
   jzlcd_hdmi_event(&sc_obj);
-  return 1;
+  return OK;
 }
 
 /****************************************************************************
@@ -1340,14 +1586,14 @@ int jzlcd_attach(void)
 static int jz_getvideoinfo(struct fb_vtable_s *vtable,
                               struct fb_videoinfo_s *vinfo)
 {
-  lcdinfo("vtable=%p vinfo=%p\n", vtable, vinfo);
+  ginfo("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");
+  gerr("ERROR: Returning EINVAL\n");
   return -EINVAL;
 }
 
@@ -1358,14 +1604,14 @@ static int jz_getvideoinfo(struct fb_vtable_s *vtable,
 static int jz_getplaneinfo(struct fb_vtable_s *vtable, int planeno,
                               struct fb_planeinfo_s *pinfo)
 {
-  lcdinfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
+  ginfo("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");
+  gerr("ERROR: Returning EINVAL\n");
   return -EINVAL;
 }
 
@@ -1413,7 +1659,7 @@ static int jz_getcursor(struct fb_vtable_s *vtable,
 static int jz_setcursor(struct fb_vtable_s *vtable,
                            struct fb_setcursor_s *settings)
 {
-  lcderr("ERROR: Returning EINVAL\n");
+  gerr("ERROR: Returning EINVAL\n");
   return -EINVAL;
 }
 #endif
@@ -1470,7 +1716,7 @@ int up_fbinitialize(int display)
 
 struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
 {
-  lcdinfo("vplane: %d\n", vplane);
+  ginfo("vplane: %d\n", vplane);
   if (vplane == 0)
     {
       return &g_fbobject;
diff --git a/boards/mips/jz4780/ci20/configs/jumbo/defconfig 
b/boards/mips/jz4780/ci20/configs/jumbo/defconfig
index 6f2605a938f..7f90259efc6 100644
--- a/boards/mips/jz4780/ci20/configs/jumbo/defconfig
+++ b/boards/mips/jz4780/ci20/configs/jumbo/defconfig
@@ -93,5 +93,7 @@ CONFIG_USBHOST_HUB=y
 CONFIG_USBHOST_HUB_POLLMSEC=100
 CONFIG_USBHOST_MSC=y
 CONFIG_USBHOST_NPREALLOC=8
+CONFIG_VIDEO=y
+CONFIG_VIDEO_EDID=y
 CONFIG_VIDEO_FB=y
 CONFIG_WQUEUE_NOTIFIER=y
diff --git a/boards/mips/jz4780/ci20/src/jz4780_bringup.c 
b/boards/mips/jz4780/ci20/src/jz4780_bringup.c
index 4ad3167598d..c40754604a2 100644
--- a/boards/mips/jz4780/ci20/src/jz4780_bringup.c
+++ b/boards/mips/jz4780/ci20/src/jz4780_bringup.c
@@ -41,11 +41,18 @@
 #endif
 
 #include "ci20.h"
+#include "jz4780_gpio.h"
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define HDMI_CEC      (GPIO_MODE_DEVICE0 | GPIO_PORTF | GPIO_PIN23)
+#define HDMI_SCL      (GPIO_MODE_DEVICE0 | GPIO_PORTF | GPIO_PIN24)
+#define HDMI_SDA      (GPIO_MODE_DEVICE0 | GPIO_PORTF | GPIO_PIN25)
+
+#define HDMI_POWER_EN (GPIO_MODE_OUTPUT1 | GPIO_PORTA | GPIO_PIN25)
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
@@ -92,6 +99,14 @@ int jz4780_bringup(void)
 #endif
 
 #ifdef CONFIG_VIDEO_FB
+
+  /* Configure the DDC pins */
+
+  jz4780_configgpio(HDMI_POWER_EN);
+  jz4780_configgpio(HDMI_CEC);
+  jz4780_configgpio(HDMI_SDA);
+  jz4780_configgpio(HDMI_SCL);
+
   /* Initialize and register the framebuffer driver */
 
   ret = fb_register(0, 0);

Reply via email to