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

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

commit 89ac35cc550700840e92ea4cffd40b7c5e052f00
Author: Jorge Guzman <[email protected]>
AuthorDate: Mon Aug 31 01:23:30 2026 -0300

    boards/esp32p4-tab5: add the ILI9881C and GT911 hardware variant
    
    The Tab5 ships in two hardware variants and the board supported only
    one of them.  The earlier units carry an ILI9881C panel and a GT911
    touch controller, the later ones a ST7121/ST7123 panel and a ST7123
    touch controller, and the two always come as a pair.  On an earlier
    unit the panel stays lit but black, and the touch bring-up fails with
    "failed to register ST7123: -5".
    
    Add the ILI9881C initialization table, taken from the Espressif BSP,
    along with the display timings it needs, which differ from the ST7123
    ones in the DPI clock (60 MHz instead of 70 MHz) and in every porch.
    The panel identification lives on command page 1 and is read and
    logged during bring-up, so the boot log says which panel answered.
    
    Add the GT911 to the touch controller choice.  These units have a
    pull-up to 3V3 on the touch interrupt line that keeps the controller
    from scanning, so the line is driven low instead of being used as an
    interrupt, and contacts are picked up when the device is read.  The
    controller identification is logged the same way.
    
    Split esp32p4_touch.c into one file per controller, which is how the
    panels are already handled, and document both variants together with
    the I2C scan that tells which one is fitted.  The defaults are
    unchanged, so an existing configuration still selects the ST7121
    panel and the ST7123 touch controller.
    
    Signed-off-by: Jorge Guzman <[email protected]>
---
 .../risc-v/esp32p4/boards/esp32p4-tab5/index.rst   |  47 +-
 boards/risc-v/esp32p4/esp32p4-tab5/Kconfig         |  42 +-
 boards/risc-v/esp32p4/esp32p4-tab5/include/board.h |  27 +-
 .../risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt |   8 +-
 boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs   |   8 +-
 .../esp32p4/esp32p4-tab5/src/esp32p4_display.c     |   5 +-
 .../esp32p4-tab5/src/esp32p4_lcd_ili9881c.c        | 493 +++++++++++++++++++++
 .../esp32p4-tab5/src/esp32p4_lcd_ili9881c.h        |  81 ++++
 .../esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c | 232 ++++++++++
 .../{esp32p4_touch.c => esp32p4_touch_st7123.c}    |   3 +-
 10 files changed, 930 insertions(+), 16 deletions(-)

diff --git 
a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst 
b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst
index 8a78b2fa0a1..60710556b7d 100644
--- a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst
+++ b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst
@@ -140,6 +140,45 @@ The Tab5 ships with ESP32-P4 **revision v1.0**.  The 
``nsh`` defconfig sets
 ``CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y`` accordingly.  A harmless boot warning
 is printed because the upstream default targets rev >= 3.0.
 
+Display panel and touch controller
+==================================
+
+The Tab5 ships in two hardware variants, and they always come as a pair:
+
+======================= ============================ ==========================
+Variant                 Panel                        Touch controller
+======================= ============================ ==========================
+Earlier units           ILI9881C                     GT911 (I2C ``0x14``)
+Later units             ST7121 / ST7123              ST7123 (I2C ``0x55``)
+======================= ============================ ==========================
+
+The panels need different initialization tables and different display
+timings, so the wrong selection leaves the panel lit but black, and the wrong
+touch selection fails the bring-up with::
+
+    ERROR: failed to register ST7123: -5
+
+Identify the board by scanning I2C0 with the ``nsh`` configuration. The
+address that answers tells which variant is fitted, and therefore which
+panel to select as well::
+
+    nsh> i2c dev -b 0 0x03 0x77
+
+Select the panel with ``ESP32P4_TAB5_LCD_ST7121`` (the default),
+``ESP32P4_TAB5_LCD_ST7123`` or ``ESP32P4_TAB5_LCD_ILI9881C``, and the touch
+controller with ``ESP32P4_TAB5_TOUCH_ST7123`` (the default) or
+``ESP32P4_TAB5_TOUCH_GT911``, both under the board menu.
+
+Both panels report their identification at boot, which confirms the
+selection. The ILI9881C answers ``98 81`` in the first two ID registers::
+
+    ili9881c: panel ID 98 81 5c
+    gt911: product "911" (39 31 31 00) fw 1060
+
+On the GT911 units the touch interrupt line has a pull-up to 3V3 that keeps
+the controller from scanning, so the board drives it low instead of using it
+as an interrupt. Contacts are picked up when the device is read.
+
 Configurations
 ==============
 
@@ -165,7 +204,6 @@ lvgl_demo
 ---------
 
 LVGL demo configuration with touch support.
-Requires the ST7123 touch controller version.
 
 .. note::
    This configuration redirects the console to UART0 instead of the USB 
Serial/JTAG port
@@ -181,11 +219,12 @@ lvgl_term
 ---------
 
 LVGL terminal configuration with touch support.
-Requires the ST7123 touch controller version.
 
 .. note::
-   This configuration redirects the console to UART0 instead of the USB 
Serial/JTAG port
-   and sets a custom entry point to open LVGL terminal on screen.
+   This configuration starts the LVGL terminal on the panel as its entry
+   point, and it runs its own NSH on a pseudo-terminal. The console is kept
+   on the USB Serial/JTAG port (exposed as ``ttyACM`` on the host), which
+   carries the system log.
 
 .. code-block:: console
 
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig 
b/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig
index 44a9ed1c838..87c4df21537 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig
@@ -96,15 +96,53 @@ config ESP32P4_TAB5_LCD_ST7123
        ---help---
                Use the ST7123 initialization table and display timings.
 
+config ESP32P4_TAB5_LCD_ILI9881C
+       bool "ILI9881C"
+       ---help---
+               Use the ILI9881C initialization table and display timings.  
This is
+               the panel fitted to the earlier Tab5 units, the ones that also 
carry
+               the GT911 touch controller.
+
 endchoice
 
 config ESP32P4_TAB5_TOUCHSCREEN
        bool "Touch Screen Controller"
        default n
        select INPUT
-       select INPUT_ST7123
        select ESP32P4_TAB5_HMI_POWER
        ---help---
-               Initialize the ST7123 touch screen controller.
+               Initialize the touch screen controller.
+
+if ESP32P4_TAB5_TOUCHSCREEN
+
+choice
+       prompt "Touch screen controller"
+       default ESP32P4_TAB5_TOUCH_ST7123
+
+config ESP32P4_TAB5_TOUCH_ST7123
+       bool "ST7123"
+       select INPUT_ST7123
+       ---help---
+               Sitronix ST7123, fitted to the Tab5 units that ship with the
+               ST7121/ST7123 panel.  Answers on I2C address 0x55.
+
+config ESP32P4_TAB5_TOUCH_GT911
+       bool "GT911"
+       select INPUT_GT9XX
+       ---help---
+               Goodix GT911, fitted to the earlier Tab5 units.
+
+endchoice
+
+config ESP32P4_TAB5_TOUCH_GT911_ADDR
+       hex "GT911 I2C address"
+       depends on ESP32P4_TAB5_TOUCH_GT911
+       default 0x14
+       ---help---
+               The GT911 latches its I2C address from the INT pin while it is
+               held in reset: either 0x14 or 0x5d.  Scan the bus with
+               "i2c dev -b 0 0x03 0x77" if unsure.
+
+endif # ESP32P4_TAB5_TOUCHSCREEN
 
 endif # ARCH_BOARD_ESP32P4_TAB5
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h 
b/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h
index 9758200e99f..75b2d9c740c 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h
@@ -63,27 +63,42 @@
  *
  * Enable /dev/fb0 with CONFIG_ESP32P4_TAB5_LCD (see configs/lcd), which
  * selects power + MIPI host + VIDEO_FB.  Select the matching panel with
- * CONFIG_ESP32P4_TAB5_LCD_ST7121 or CONFIG_ESP32P4_TAB5_LCD_ST7123.
+ * CONFIG_ESP32P4_TAB5_LCD_ST7121, CONFIG_ESP32P4_TAB5_LCD_ST7123 or
+ * CONFIG_ESP32P4_TAB5_LCD_ILI9881C (board version 1, paired with GT911).
  */
 
 #define TAB5_GPIO_LCD_BL_EN    22  /* Backlight enable -> ME2212 boost EN */
 
 #define TAB5_MIPI_DSI_H_RES              720
 #define TAB5_MIPI_DSI_V_RES              1280
-#define TAB5_MIPI_DSI_DPI_CLK_MHZ        70
-#define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH  2
-#define TAB5_MIPI_DSI_HSYNC_BACK_PORCH   40
-#define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH  40
 #define TAB5_MIPI_DSI_LANES              2
 
-#ifdef CONFIG_ESP32P4_TAB5_LCD_ST7123
+#if defined(CONFIG_ESP32P4_TAB5_LCD_ILI9881C)
+#  define TAB5_LCD_PANEL_NAME             "ILI9881C"
+#  define TAB5_MIPI_DSI_DPI_CLK_MHZ        60
+#  define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH  40
+#  define TAB5_MIPI_DSI_HSYNC_BACK_PORCH   140
+#  define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH  40
+#  define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH  4
+#  define TAB5_MIPI_DSI_VSYNC_BACK_PORCH   20
+#  define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH  20
+#  define TAB5_MIPI_DSI_LANE_BITRATE_MBPS  1000
+#elif defined(CONFIG_ESP32P4_TAB5_LCD_ST7123)
 #  define TAB5_LCD_PANEL_NAME             "ST7123"
+#  define TAB5_MIPI_DSI_DPI_CLK_MHZ        70
+#  define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH  2
+#  define TAB5_MIPI_DSI_HSYNC_BACK_PORCH   40
+#  define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH  40
 #  define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH  2
 #  define TAB5_MIPI_DSI_VSYNC_BACK_PORCH   8
 #  define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH  220
 #  define TAB5_MIPI_DSI_LANE_BITRATE_MBPS  1000
 #else
 #  define TAB5_LCD_PANEL_NAME             "ST7121"
+#  define TAB5_MIPI_DSI_DPI_CLK_MHZ        70
+#  define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH  2
+#  define TAB5_MIPI_DSI_HSYNC_BACK_PORCH   40
+#  define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH  40
 #  define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH  20
 #  define TAB5_MIPI_DSI_VSYNC_BACK_PORCH   24
 #  define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH  200
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt
index 7635e1315ed..4504f73ec9f 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt
@@ -36,11 +36,17 @@ if(CONFIG_ESP32P4_TAB5_LCD)
     list(APPEND SRCS esp32p4_lcd_st7121.c)
   elseif(CONFIG_ESP32P4_TAB5_LCD_ST7123)
     list(APPEND SRCS esp32p4_lcd_st7123.c)
+  elseif(CONFIG_ESP32P4_TAB5_LCD_ILI9881C)
+    list(APPEND SRCS esp32p4_lcd_ili9881c.c)
   endif()
 endif()
 
 if(CONFIG_ESP32P4_TAB5_TOUCHSCREEN)
-  list(APPEND SRCS esp32p4_touch.c)
+  if(CONFIG_ESP32P4_TAB5_TOUCH_ST7123)
+    list(APPEND SRCS esp32p4_touch_st7123.c)
+  elseif(CONFIG_ESP32P4_TAB5_TOUCH_GT911)
+    list(APPEND SRCS esp32p4_touch_gt911.c)
+  endif()
 endif()
 
 if(CONFIG_BOARDCTL)
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs
index b1537ba3531..5d5e02d3842 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs
@@ -42,11 +42,17 @@ ifeq ($(CONFIG_ESP32P4_TAB5_LCD),y)
     CSRCS += esp32p4_lcd_st7121.c
   else ifeq ($(CONFIG_ESP32P4_TAB5_LCD_ST7123),y)
     CSRCS += esp32p4_lcd_st7123.c
+  else ifeq ($(CONFIG_ESP32P4_TAB5_LCD_ILI9881C),y)
+    CSRCS += esp32p4_lcd_ili9881c.c
   endif
 endif
 
 ifeq ($(CONFIG_ESP32P4_TAB5_TOUCHSCREEN),y)
-  CSRCS += esp32p4_touch.c
+  ifeq ($(CONFIG_ESP32P4_TAB5_TOUCH_ST7123),y)
+    CSRCS += esp32p4_touch_st7123.c
+  else ifeq ($(CONFIG_ESP32P4_TAB5_TOUCH_GT911),y)
+    CSRCS += esp32p4_touch_gt911.c
+  endif
 endif
 
 ifeq ($(CONFIG_BOARDCTL),y)
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c
index 7225b722d06..0f4d104cf27 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c
@@ -54,7 +54,10 @@
 
 #include "esp32p4-tab5.h"
 
-#ifdef CONFIG_ESP32P4_TAB5_LCD_ST7123
+#if defined(CONFIG_ESP32P4_TAB5_LCD_ILI9881C)
+#  include "esp32p4_lcd_ili9881c.h"
+#  define tab5_panel_initialize tab5_ili9881c_initialize
+#elif defined(CONFIG_ESP32P4_TAB5_LCD_ST7123)
 #  include "esp32p4_lcd_st7123.h"
 #  define tab5_panel_initialize tab5_st7123_initialize
 #else
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c
new file mode 100644
index 00000000000..bf94bdd2369
--- /dev/null
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c
@@ -0,0 +1,493 @@
+/****************************************************************************
+ * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/* ILI9881C panel bring-up for M5Stack Tab5, fitted to the units that also
+ * carry the GT911 touch controller.  Init table sourced from
+ * https://github.com/espressif/esp-bsp under
+ * bsp/m5stack_tab5/priv_include/disp_init_data.h.
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <syslog.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/video/mipi_display.h>
+#include <nuttx/video/mipi_dsi.h>
+
+#include <arch/board/board.h>
+
+#include "esp32p4-tab5.h"
+#include "esp32p4_lcd_ili9881c.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ILI9881C_NAME           "ili9881c"
+
+/* Command page selection: 0xff 0x98 0x81 <page> */
+
+#define ILI9881C_CMD_PAGE       0xff
+#define ILI9881C_PAGE_BYTE0     0x98
+#define ILI9881C_PAGE_BYTE1     0x81
+#define ILI9881C_PAGE0          0x00
+#define ILI9881C_PAGE1          0x01
+
+/* On command page 1, registers 0x00..0x02 hold the panel identification */
+
+#define ILI9881C_REG_ID1        0x00
+#define ILI9881C_ID1_ILITEK     0x98
+#define ILI9881C_ID2_ILITEK     0x81
+
+/* Time the panel needs after leaving sleep mode */
+
+#define ILI9881C_SLEEP_OUT_MS   120
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Vendor initialization table, as a flat byte stream: DCS command, payload
+ * length, payload.  It walks the panel through its command pages, so the
+ * order matters, and ends back on page 0 with display on (0x29).
+ */
+
+static const uint8_t g_ili9881c_init[] =
+{
+  0xff, 3, 0x98, 0x81, 0x01,
+  0xb7, 1, 0x03,
+  0xff, 3, 0x98, 0x81, 0x03,
+  0x01, 1, 0x00,
+  0x02, 1, 0x00,
+  0x03, 1, 0x73,
+  0x04, 1, 0x00,
+  0x05, 1, 0x00,
+  0x06, 1, 0x08,
+  0x07, 1, 0x00,
+  0x08, 1, 0x00,
+  0x09, 1, 0x1b,
+  0x0a, 1, 0x01,
+  0x0b, 1, 0x01,
+  0x0c, 1, 0x0d,
+  0x0d, 1, 0x01,
+  0x0e, 1, 0x01,
+  0x0f, 1, 0x26,
+  0x10, 1, 0x26,
+  0x11, 1, 0x00,
+  0x12, 1, 0x00,
+  0x13, 1, 0x02,
+  0x14, 1, 0x00,
+  0x15, 1, 0x00,
+  0x16, 1, 0x00,
+  0x17, 1, 0x00,
+  0x18, 1, 0x00,
+  0x19, 1, 0x00,
+  0x1a, 1, 0x00,
+  0x1b, 1, 0x00,
+  0x1c, 1, 0x00,
+  0x1d, 1, 0x00,
+  0x1e, 1, 0x40,
+  0x1f, 1, 0x00,
+  0x20, 1, 0x06,
+  0x21, 1, 0x01,
+  0x22, 1, 0x00,
+  0x23, 1, 0x00,
+  0x24, 1, 0x00,
+  0x25, 1, 0x00,
+  0x26, 1, 0x00,
+  0x27, 1, 0x00,
+  0x28, 1, 0x33,
+  0x29, 1, 0x03,
+  0x2a, 1, 0x00,
+  0x2b, 1, 0x00,
+  0x2c, 1, 0x00,
+  0x2d, 1, 0x00,
+  0x2e, 1, 0x00,
+  0x2f, 1, 0x00,
+  0x30, 1, 0x00,
+  0x31, 1, 0x00,
+  0x32, 1, 0x00,
+  0x33, 1, 0x00,
+  0x34, 1, 0x00,
+  0x35, 1, 0x00,
+  0x36, 1, 0x00,
+  0x37, 1, 0x00,
+  0x38, 1, 0x00,
+  0x39, 1, 0x00,
+  0x3a, 1, 0x00,
+  0x3b, 1, 0x00,
+  0x3c, 1, 0x00,
+  0x3d, 1, 0x00,
+  0x3e, 1, 0x00,
+  0x3f, 1, 0x00,
+  0x40, 1, 0x00,
+  0x41, 1, 0x00,
+  0x42, 1, 0x00,
+  0x43, 1, 0x00,
+  0x44, 1, 0x00,
+  0x50, 1, 0x01,
+  0x51, 1, 0x23,
+  0x52, 1, 0x45,
+  0x53, 1, 0x67,
+  0x54, 1, 0x89,
+  0x55, 1, 0xab,
+  0x56, 1, 0x01,
+  0x57, 1, 0x23,
+  0x58, 1, 0x45,
+  0x59, 1, 0x67,
+  0x5a, 1, 0x89,
+  0x5b, 1, 0xab,
+  0x5c, 1, 0xcd,
+  0x5d, 1, 0xef,
+  0x5e, 1, 0x11,
+  0x5f, 1, 0x02,
+  0x60, 1, 0x00,
+  0x61, 1, 0x07,
+  0x62, 1, 0x06,
+  0x63, 1, 0x0e,
+  0x64, 1, 0x0f,
+  0x65, 1, 0x0c,
+  0x66, 1, 0x0d,
+  0x67, 1, 0x02,
+  0x68, 1, 0x02,
+  0x69, 1, 0x02,
+  0x6a, 1, 0x02,
+  0x6b, 1, 0x02,
+  0x6c, 1, 0x02,
+  0x6d, 1, 0x02,
+  0x6e, 1, 0x02,
+  0x6f, 1, 0x02,
+  0x70, 1, 0x02,
+  0x71, 1, 0x02,
+  0x72, 1, 0x02,
+  0x73, 1, 0x05,
+  0x74, 1, 0x01,
+  0x75, 1, 0x02,
+  0x76, 1, 0x00,
+  0x77, 1, 0x07,
+  0x78, 1, 0x06,
+  0x79, 1, 0x0e,
+  0x7a, 1, 0x0f,
+  0x7b, 1, 0x0c,
+  0x7c, 1, 0x0d,
+  0x7d, 1, 0x02,
+  0x7e, 1, 0x02,
+  0x7f, 1, 0x02,
+  0x80, 1, 0x02,
+  0x81, 1, 0x02,
+  0x82, 1, 0x02,
+  0x83, 1, 0x02,
+  0x84, 1, 0x02,
+  0x85, 1, 0x02,
+  0x86, 1, 0x02,
+  0x87, 1, 0x02,
+  0x88, 1, 0x02,
+  0x89, 1, 0x05,
+  0x8a, 1, 0x01,
+  0xff, 3, 0x98, 0x81, 0x04,
+  0x38, 1, 0x01,
+  0x39, 1, 0x00,
+  0x6c, 1, 0x15,
+  0x6e, 1, 0x1a,
+  0x6f, 1, 0x25,
+  0x3a, 1, 0xa4,
+  0x8d, 1, 0x20,
+  0x87, 1, 0xba,
+  0x3b, 1, 0x98,
+  0xff, 3, 0x98, 0x81, 0x01,
+  0x22, 1, 0x0a,
+  0x31, 1, 0x00,
+  0x50, 1, 0x6b,
+  0x51, 1, 0x66,
+  0x53, 1, 0x73,
+  0x55, 1, 0x8b,
+  0x60, 1, 0x1b,
+  0x61, 1, 0x01,
+  0x62, 1, 0x0c,
+  0x63, 1, 0x00,
+  0xa0, 1, 0x00,
+  0xa1, 1, 0x15,
+  0xa2, 1, 0x1f,
+  0xa3, 1, 0x13,
+  0xa4, 1, 0x11,
+  0xa5, 1, 0x21,
+  0xa6, 1, 0x17,
+  0xa7, 1, 0x1b,
+  0xa8, 1, 0x6b,
+  0xa9, 1, 0x1e,
+  0xaa, 1, 0x2b,
+  0xab, 1, 0x5d,
+  0xac, 1, 0x19,
+  0xad, 1, 0x14,
+  0xae, 1, 0x4b,
+  0xaf, 1, 0x1d,
+  0xb0, 1, 0x27,
+  0xb1, 1, 0x49,
+  0xb2, 1, 0x5d,
+  0xb3, 1, 0x39,
+  0xc0, 1, 0x00,
+  0xc1, 1, 0x01,
+  0xc2, 1, 0x0c,
+  0xc3, 1, 0x11,
+  0xc4, 1, 0x15,
+  0xc5, 1, 0x28,
+  0xc6, 1, 0x1b,
+  0xc7, 1, 0x1c,
+  0xc8, 1, 0x62,
+  0xc9, 1, 0x1c,
+  0xca, 1, 0x29,
+  0xcb, 1, 0x60,
+  0xcc, 1, 0x16,
+  0xcd, 1, 0x17,
+  0xce, 1, 0x4a,
+  0xcf, 1, 0x23,
+  0xd0, 1, 0x24,
+  0xd1, 1, 0x4f,
+  0xd2, 1, 0x5f,
+  0xd3, 1, 0x39,
+  0xff, 3, 0x98, 0x81, 0x00,
+  0x35, 0,
+  0xfe, 0,
+  0x29, 0,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ili9881c_select_page
+ *
+ * Description:
+ *   Select one of the ILI9881C command pages.
+ *
+ * Input Parameters:
+ *   device - The MIPI DSI device.
+ *   page - The command page to select.
+ *
+ * Returned Value:
+ *   Zero on success, a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int ili9881c_select_page(FAR struct mipi_dsi_device *device,
+                                uint8_t page)
+{
+  const uint8_t sel[3] =
+    {
+      ILI9881C_PAGE_BYTE0, ILI9881C_PAGE_BYTE1, page
+    };
+
+  ssize_t n = mipi_dsi_dcs_write(device, ILI9881C_CMD_PAGE, sel,
+                                 sizeof(sel));
+
+  return n < 0 ? (int)n : OK;
+}
+
+/****************************************************************************
+ * Name: ili9881c_report_id
+ *
+ * Description:
+ *   Read and log the panel identification from registers 0x00..0x02 of
+ *   command page 1, which must already be selected.  An Ilitek panel
+ *   answers 0x98 0x81 in the first two.  A failed read is not fatal.
+ *
+ * Input Parameters:
+ *   device - The MIPI DSI device.
+ *
+ ****************************************************************************/
+
+static void ili9881c_report_id(FAR struct mipi_dsi_device *device)
+{
+  uint8_t id[3] =
+    {
+      0, 0, 0
+    };
+
+  ssize_t n;
+  int i;
+
+  for (i = 0; i < 3; i++)
+    {
+      n = mipi_dsi_dcs_read(device, ILI9881C_REG_ID1 + i, &id[i], 1);
+      if (n < 0)
+        {
+          syslog(LOG_WARNING, "ili9881c: ID read %d failed: %d\n",
+                 i, (int)n);
+          return;
+        }
+    }
+
+  syslog(LOG_INFO, "ili9881c: panel ID %02x %02x %02x%s\n",
+         id[0], id[1], id[2],
+         (id[0] == ILI9881C_ID1_ILITEK && id[1] == ILI9881C_ID2_ILITEK) ?
+         "" : " (unexpected: not an Ilitek panel?)");
+}
+
+/****************************************************************************
+ * Name: ili9881c_send_init
+ *
+ * Description:
+ *   Send the vendor initialization table.
+ *
+ * Input Parameters:
+ *   device - The MIPI DSI device.
+ *
+ * Returned Value:
+ *   Zero on success, a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int ili9881c_send_init(FAR struct mipi_dsi_device *device)
+{
+  size_t i = 0;
+  uint8_t cmd;
+  uint8_t len;
+  ssize_t n;
+
+  while (i + 1 < nitems(g_ili9881c_init))
+    {
+      cmd = g_ili9881c_init[i];
+      len = g_ili9881c_init[i + 1];
+      i += 2;
+
+      n = mipi_dsi_dcs_write(device, cmd,
+                             len > 0 ? &g_ili9881c_init[i] : NULL, len);
+      if (n < 0)
+        {
+          syslog(LOG_ERR, "ili9881c: cmd %02x failed: %d\n",
+                 cmd, (int)n);
+          return (int)n;
+        }
+
+      i += len;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tab5_ili9881c_initialize
+ *
+ * Description:
+ *   Register the ILI9881C as a mipi_dsi_device, attach it to the Espressif
+ *   host, report the panel identification and send the vendor DCS
+ *   initialization table.  Does not start video.
+ *
+ * Input Parameters:
+ *   host - Registered MIPI-DSI host (esp_mipi_dsi_host_get())
+ *
+ * Returned Value:
+ *   Pointer to the registered device on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+FAR struct mipi_dsi_device *tab5_ili9881c_initialize(
+      FAR struct mipi_dsi_host *host)
+{
+  FAR struct mipi_dsi_device *device;
+  const uint8_t colmod = MIPI_DCS_PIXEL_FMT_16BIT;
+  const uint8_t madctl = 0x00;
+  int ret;
+
+  if (host == NULL)
+    {
+      return NULL;
+    }
+
+  device = mipi_dsi_device_register(host, ILI9881C_NAME, 0);
+  if (device == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: mipi_dsi_device_register failed\n");
+      return NULL;
+    }
+
+  device->lanes = TAB5_MIPI_DSI_LANES;
+  device->format = MIPI_DSI_FMT_RGB565;
+  device->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+                       MIPI_DSI_MODE_LPM;
+  device->hs_rate = TAB5_MIPI_DSI_LANE_BITRATE_MBPS * 1000000UL;
+  device->lp_rate = 0;
+
+  ret = mipi_dsi_attach(device);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: attach failed: %d\n", ret);
+      return NULL;
+    }
+
+  /* The identification registers live on command page 1 */
+
+  ret = ili9881c_select_page(device, ILI9881C_PAGE1);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: page 1 select failed: %d\n", ret);
+      return NULL;
+    }
+
+  ili9881c_report_id(device);
+
+  ret = ili9881c_select_page(device, ILI9881C_PAGE0);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: page 0 select failed: %d\n", ret);
+      return NULL;
+    }
+
+  ret = mipi_dsi_dcs_exit_sleep_mode(device);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: exit sleep mode failed: %d\n", ret);
+      return NULL;
+    }
+
+  up_mdelay(ILI9881C_SLEEP_OUT_MS);
+
+  if (mipi_dsi_dcs_write(device, MIPI_DCS_SET_ADDRESS_MODE, &madctl, 1) < 0
+      || mipi_dsi_dcs_write(device, MIPI_DCS_SET_PIXEL_FORMAT,
+                            &colmod, 1) < 0)
+    {
+      syslog(LOG_ERR, "ERROR: address/pixel format setup failed\n");
+      return NULL;
+    }
+
+  ret = ili9881c_send_init(device);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: DCS init failed: %d\n", ret);
+      return NULL;
+    }
+
+  return device;
+}
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h
new file mode 100644
index 00000000000..7dd4c54e1cb
--- /dev/null
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/* ST7121 panel bring-up for M5Stack Tab5.
+ *
+ * Init init table sourced from https://github.com/espressif/esp-iot-solution
+ * under components/display/lcd/esp_lcd_st7121/esp_lcd_st7121.c.
+ */
+#ifndef __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H
+#define __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/video/mipi_dsi.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: tab5_ili9881c_initialize
+ *
+ * Description:
+ *   Register the ILI9881C as a mipi_dsi_device, attach to the Espressif
+ *   host, report the panel identification and send the M5Stack Tab5
+ *   ILI9881C vendor DCS initialization table.  Does not start video; board
+ *   code starts it afterwards.
+ *
+ * Input Parameters:
+ *   host - Registered MIPI-DSI host (esp_mipi_dsi_host_get())
+ *
+ * Returned Value:
+ *   Pointer to the registered device on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ESP32P4_TAB5_LCD_ILI9881C
+FAR struct mipi_dsi_device *tab5_ili9881c_initialize(
+      FAR struct mipi_dsi_host *host);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H */
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c
new file mode 100644
index 00000000000..f2a0f5df6b6
--- /dev/null
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c
@@ -0,0 +1,232 @@
+/****************************************************************************
+ * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/input/gt9xx.h>
+
+#include <arch/board/board.h>
+
+#include "espressif/esp_gpio.h"
+#include "espressif/esp_i2c.h"
+
+#include "esp32p4-tab5.h"
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int board_gt911_attach(FAR const struct gt9xx_board_s *state,
+                              xcpt_t isr, FAR void *arg);
+static void board_gt911_enable(FAR const struct gt9xx_board_s *state,
+                               bool enable);
+static int board_gt911_power(FAR const struct gt9xx_board_s *state, bool on);
+static void board_gt911_report_id(FAR struct i2c_master_s *i2c);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct gt9xx_board_s g_gt911_config =
+{
+  .irq_attach = board_gt911_attach,
+  .irq_enable = board_gt911_enable,
+  .set_power  = board_gt911_power,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_gt911_attach
+ *
+ * Description:
+ *   Drive TAB5_GPIO_TP_INT low.  These units have a pull-up to 3V3 on the
+ *   touch interrupt line that stops the GT911 from scanning, so the pin is
+ *   held low and no interrupt is used; contacts are picked up on read.
+ *
+ * Input Parameters:
+ *   state - Pointer to the GT9XX board configuration structure.
+ *   isr - The interrupt service routine (unused).
+ *   arg - The argument for the interrupt service routine (unused).
+ *
+ * Returned Value:
+ *   Zero on success.
+ *
+ ****************************************************************************/
+
+static int board_gt911_attach(FAR const struct gt9xx_board_s *state,
+                              xcpt_t isr, FAR void *arg)
+{
+  UNUSED(state);
+  UNUSED(isr);
+  UNUSED(arg);
+
+  esp_configgpio(TAB5_GPIO_TP_INT, OUTPUT_FUNCTION_2);
+  esp_gpiowrite(TAB5_GPIO_TP_INT, false);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: board_gt911_enable
+ *
+ * Description:
+ *   No interrupt is used on this board (see board_gt911_attach).
+ *
+ * Input Parameters:
+ *   state - Pointer to the GT9XX board configuration structure.
+ *   enable - True to enable the interrupt, false to disable it.
+ *
+ ****************************************************************************/
+
+static void board_gt911_enable(FAR const struct gt9xx_board_s *state,
+                               bool enable)
+{
+  UNUSED(state);
+  UNUSED(enable);
+}
+
+/****************************************************************************
+ * Name: board_gt911_power
+ *
+ * Description:
+ *   Nothing to do: the rails and the reset line are driven earlier, by
+ *   tab5_hmi_power_init().
+ *
+ * Input Parameters:
+ *   state - Pointer to the GT9XX board configuration structure.
+ *   on - True to power on, false to power off.
+ *
+ * Returned Value:
+ *   Zero on success.
+ *
+ ****************************************************************************/
+
+static int board_gt911_power(FAR const struct gt9xx_board_s *state, bool on)
+{
+  UNUSED(state);
+  UNUSED(on);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: board_gt911_report_id
+ *
+ * Description:
+ *   Read and log the controller identification: product ID (ASCII, "911"
+ *   for the GT911), firmware version and maximum coordinates, from
+ *   register 0x8140.  A failed read is logged but is not fatal.
+ *
+ * Input Parameters:
+ *   i2c - The I2C bus the controller is attached to.
+ *
+ ****************************************************************************/
+
+static void board_gt911_report_id(FAR struct i2c_master_s *i2c)
+{
+  struct i2c_config_s config;
+  uint8_t reg[2];
+  uint8_t buf[10];
+  char product[5];
+  int ret;
+
+  config.frequency = CONFIG_INPUT_GT9XX_I2C_FREQUENCY;
+  config.address   = CONFIG_ESP32P4_TAB5_TOUCH_GT911_ADDR;
+  config.addrlen   = 7;
+
+  /* 0x8140: product ID (4) + firmware version (2) + x max (2) + y max (2) */
+
+  reg[0] = 0x81;
+  reg[1] = 0x40;
+
+  ret = i2c_writeread(i2c, &config, reg, sizeof(reg), buf, sizeof(buf));
+  if (ret < 0)
+    {
+      syslog(LOG_WARNING, "gt911: ID read failed: %d\n", ret);
+      return;
+    }
+
+  memcpy(product, buf, 4);
+  product[4] = '\0';
+
+  syslog(LOG_INFO,
+         "gt911: product \"%s\" (%02x %02x %02x %02x) fw %02x%02x "
+         "res %dx%d\n",
+         product, buf[0], buf[1], buf[2], buf[3], buf[5], buf[4],
+         buf[6] | (buf[7] << 8), buf[8] | (buf[9] << 8));
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tab5_touchscreen_init
+ *
+ * Description:
+ *   Initialize the touch screen controller.
+ *
+ * Returned Value:
+ *   Zero on success, -1 on failure.
+ *
+ ****************************************************************************/
+
+int tab5_touchscreen_init(void)
+{
+  FAR struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = esp_i2cbus_initialize(ESPRESSIF_I2C0);
+  if (i2c == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: failed to get I2C0 bus\n");
+      return -ENODEV;
+    }
+
+  board_gt911_report_id(i2c);
+
+  ret = gt9xx_register("/dev/input0", i2c,
+                       CONFIG_ESP32P4_TAB5_TOUCH_GT911_ADDR,
+                       &g_gt911_config);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: failed to register GT911: %d\n", ret);
+      return ret;
+    }
+
+  syslog(LOG_INFO, "GT911 touchscreen controller initialized!\n");
+
+  return OK;
+}
diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c 
b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c
similarity index 98%
rename from boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c
rename to boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c
index 0de9e51e22f..c62022bd3fe 100644
--- a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c
+++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c
+ * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -134,5 +134,6 @@ int tab5_touchscreen_init(void)
     }
 
   syslog(LOG_INFO, "ST7123 touchscreen controller initialized!\n");
+
   return OK;
 }

Reply via email to