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


The following commit(s) were added to refs/heads/master by this push:
     new da99c2eba54 arm64/am62x: Add TISCI client, GPIO and I2C drivers
da99c2eba54 is described below

commit da99c2eba5411339c39ab9cd5a54a23335b15648
Author: Piyush Patle <[email protected]>
AuthorDate: Sun May 31 18:33:58 2026 +0530

    arm64/am62x: Add TISCI client, GPIO and I2C drivers
    
    On K3 SoCs the A53 cluster does not own device power, clocks, resets or
    interrupt routing; these are managed by the DM/TIFS firmware and requested
    over TISCI through the secure-proxy mailbox.  Add:
    
      - a TISCI client (secure-proxy transport plus device/clock/reset helpers)
      - a GPIO driver for banks 0/1 with pad mux and TISCI power-on
      - an OMAP-I2C driver for the main-domain I2C controllers
    
    and wire them into the PocketBeagle2 and BeaglePlay bring-up.
    
    Tested on PocketBeagle2 (SYSFW 11.2.5) with the TechLab cape attached:
    
      nsh> i2c bus
      nsh> i2c dev -b 0 0x03 0x77   # I2C0 detects onboard 0x20 and 0x50
      nsh> gpio -o 1 /dev/gpio3     # drives a user LED; read back with:
      nsh> gpio /dev/gpio3
    
    Signed-off-by: Piyush Patle <[email protected]>
---
 .../arm64/am62x/boards/beagleplay/index.rst        |  40 +-
 .../arm64/am62x/boards/pocketbeagle2/index.rst     |  39 +-
 Documentation/platforms/arm64/am62x/index.rst      |   2 +
 arch/arm64/include/am62x/irq.h                     |  12 +
 arch/arm64/src/am62x/CMakeLists.txt                |  15 +
 arch/arm64/src/am62x/Kconfig                       |  85 ++-
 arch/arm64/src/am62x/Make.defs                     |  18 +
 arch/arm64/src/am62x/am62x_gpio.c                  | 368 ++++++++++
 arch/arm64/src/am62x/am62x_gpio.h                  |  98 +++
 arch/arm64/src/am62x/am62x_i2c.c                   | 767 +++++++++++++++++++++
 .../arm64/src/am62x/am62x_i2c.h                    |  56 +-
 arch/arm64/src/am62x/am62x_tisci.c                 | 528 ++++++++++++++
 arch/arm64/src/am62x/am62x_tisci.h                 | 189 +++++
 arch/arm64/src/am62x/hardware/am62x_gpio.h         |  79 +++
 arch/arm64/src/am62x/hardware/am62x_i2c.h          | 107 +++
 arch/arm64/src/am62x/hardware/am62x_memorymap.h    |  19 +-
 arch/arm64/src/am62x/hardware/am62x_secure_proxy.h |  88 +++
 arch/arm64/src/am62x/hardware/am62x_tisci_proto.h  | 225 ++++++
 .../beagleplay/configs/{nsh => i2c}/defconfig      |   6 +
 .../arm64/am62x/beagleplay/configs/nsh/defconfig   |   2 +
 .../am62x/beagleplay/include/board_memorymap.h     |  15 +
 boards/arm64/am62x/beagleplay/scripts/dramboot.ld  |  15 +
 .../am62x/beagleplay/src/beagleplay_bringup.c      |  84 ++-
 .../pocketbeagle2/configs/{nsh => i2c}/defconfig   |   6 +
 .../am62x/pocketbeagle2/configs/nsh/defconfig      |   2 +
 boards/arm64/am62x/pocketbeagle2/include/board.h   |  19 +-
 .../arm64/am62x/pocketbeagle2/src/CMakeLists.txt   |   4 +
 boards/arm64/am62x/pocketbeagle2/src/Makefile      |   4 +
 .../arm64/am62x/pocketbeagle2/src/pocketbeagle2.h  |  12 +
 .../pocketbeagle2/src/pocketbeagle2_bringup.c      | 146 +++-
 .../am62x/pocketbeagle2/src/pocketbeagle2_gpio.c   | 165 +++++
 31 files changed, 3108 insertions(+), 107 deletions(-)

diff --git a/Documentation/platforms/arm64/am62x/boards/beagleplay/index.rst 
b/Documentation/platforms/arm64/am62x/boards/beagleplay/index.rst
index 7b87f6b3628..d3347eb7b94 100644
--- a/Documentation/platforms/arm64/am62x/boards/beagleplay/index.rst
+++ b/Documentation/platforms/arm64/am62x/boards/beagleplay/index.rst
@@ -18,10 +18,11 @@ Features
 * Four user LEDs
 * Gigabit Ethernet, USB, Wi-Fi, and Bluetooth hardware on the board
 
-Current NuttX support is limited to early boot, the 16550 serial console,
-interactive NSH, and ``procfs`` mount during board bring-up. GPIO, LEDs,
-I2C, SPI, MMC/SD, Ethernet, Wi-Fi, Bluetooth, and USB runtime support are
-not implemented yet.
+Current NuttX support includes early boot, the 16550 serial console,
+interactive NSH, ``procfs`` mount during board bring-up, AM62x TISCI
+initialization, main-domain GPIO, and I2C0/I2C1 controller support in the
+``beagleplay:i2c`` configuration. SPI, MMC/SD, Ethernet, Wi-Fi, Bluetooth,
+and USB runtime support are not implemented yet.
 
 Buttons and LEDs
 ================
@@ -37,8 +38,8 @@ USR2    GPIO1_24  Red user LED
 USR3    GPIO1_25  Blue user LED
 ======  ========  ==================
 
-The current NuttX port does not yet provide functional GPIO-backed LED
-control. The ``CONFIG_ARCH_LEDS`` hooks are present as placeholders only.
+The current NuttX port initializes the AM62x GPIO controller. Automatic
+``CONFIG_ARCH_LEDS`` LED hooks remain placeholders only.
 
 Serial Console
 ==============
@@ -57,7 +58,9 @@ Interface    SoC signal              Notes
 ===========  ======================  =======================================
 DEBUG USB-C  UART0                   Default NuttX serial console
 microSD      MMC1                    Validated boot media for ``nuttx.bin``
-USR0-3       GPIO1_22 through 1_25   User LEDs, not yet driven by NuttX
+USR0-3       GPIO1_22 through 1_25   User LEDs on the main GPIO block
+I2C0         I2C0                    Available in ``beagleplay:i2c``
+I2C1         I2C1                    Available in ``beagleplay:i2c``
 ===========  ======================  =======================================
 
 Power Supply
@@ -113,8 +116,23 @@ microSD using the BeaglePlay U-Boot prompt.
 Configurations
 ==============
 
-``beagleplay:nsh``
-  Interactive NSH configuration for serial bring-up and shell access.
+Configure NuttX with ``beagleplay:<config-name>``.
 
-``beagleplay:ostest``
-  Hardware validation configuration that boots directly into ``ostest_main``.
+.. code:: console
+
+   $ ./tools/configure.sh beagleplay:nsh
+
+nsh
+---
+
+Interactive NSH configuration for serial bring-up and shell access.
+
+i2c
+---
+
+NSH configuration with AM62x I2C0/I2C1 and the ``i2c`` tool enabled.
+
+ostest
+------
+
+Hardware validation configuration that boots directly into ``ostest_main``.
diff --git a/Documentation/platforms/arm64/am62x/boards/pocketbeagle2/index.rst 
b/Documentation/platforms/arm64/am62x/boards/pocketbeagle2/index.rst
index 85941e44214..06579633852 100644
--- a/Documentation/platforms/arm64/am62x/boards/pocketbeagle2/index.rst
+++ b/Documentation/platforms/arm64/am62x/boards/pocketbeagle2/index.rst
@@ -17,10 +17,11 @@ Features
 * Expansion headers for GPIO, I2C, SPI, UART, PWM, and ADC
 * User LEDs exposed by the board port
 
-Current NuttX support is limited to early boot, the 16550 serial console,
-interactive NSH, and ``procfs`` mount during board bring-up. GPIO, functional
-LED control, I2C, SPI, MMC/SD runtime support, Ethernet, and USB runtime
-support are not implemented yet.
+Current NuttX support includes early boot, the 16550 serial console,
+interactive NSH, ``procfs`` mount during board bring-up, AM62x TISCI
+initialization, main-domain GPIO, and I2C0/I2C2 controller support in the
+``pocketbeagle2:i2c`` configuration. SPI, MMC/SD runtime support, Ethernet,
+and USB runtime support are not implemented yet.
 
 Buttons and LEDs
 ================
@@ -35,7 +36,8 @@ USR1    Amber     ``CONFIG_ARCH_LEDS`` placeholder
 USR2    Red       ``CONFIG_ARCH_LEDS`` placeholder
 ======  ========  =====================
 
-These LEDs are not driven yet because AM62x GPIO support has not been added.
+The AM62x GPIO controller is initialized by the board port. Automatic
+``CONFIG_ARCH_LEDS`` LED hooks remain placeholders only.
 
 Serial Console
 ==============
@@ -54,7 +56,9 @@ Interface    SoC signal              Notes
 ===========  ======================  =======================================
 USB-C debug  UART6                   Default NuttX serial console
 microSD      MMC1                    Validated boot media for ``nuttx.bin``
-USR0-2       Board user LEDs         Not yet driven by NuttX GPIO support
+USR0-2       Board user LEDs         Available through the main GPIO block
+I2C0         I2C0                    Available in ``pocketbeagle2:i2c``
+I2C2         Header I2C2             Available in ``pocketbeagle2:i2c``
 ===========  ======================  =======================================
 
 Power Supply
@@ -103,8 +107,23 @@ present in on-board flash.
 Configurations
 ==============
 
-``pocketbeagle2:nsh``
-  Interactive NSH configuration for serial bring-up and shell access.
+Configure NuttX with ``pocketbeagle2:<config-name>``.
 
-``pocketbeagle2:ostest``
-  Hardware validation configuration that boots directly into ``ostest_main``.
+.. code:: console
+
+   $ ./tools/configure.sh pocketbeagle2:nsh
+
+nsh
+---
+
+Interactive NSH configuration for serial bring-up and shell access.
+
+i2c
+---
+
+NSH configuration with AM62x I2C0/I2C2 and the ``i2c`` tool enabled.
+
+ostest
+------
+
+Hardware validation configuration that boots directly into ``ostest_main``.
diff --git a/Documentation/platforms/arm64/am62x/index.rst 
b/Documentation/platforms/arm64/am62x/index.rst
index acb2457aee2..1849d995786 100644
--- a/Documentation/platforms/arm64/am62x/index.rst
+++ b/Documentation/platforms/arm64/am62x/index.rst
@@ -10,6 +10,8 @@ Texas Instruments featuring:
 - **Boot:** ROM → R5 SYSFW (TIFS) → U-Boot SPL → U-Boot → NuttX
 - **Memory:** External DDR4/LPDDR4 (512 MB – 2 GB depending on board)
 - **UART:** Seven 16550-compatible UARTs (48 MHz clock)
+- **GPIO:** Main-domain GPIO controller support
+- **I2C:** Main-domain I2C controller support
 
 Supported Boards
 ================
diff --git a/arch/arm64/include/am62x/irq.h b/arch/arm64/include/am62x/irq.h
index ca643a65f46..7f6349fbbc8 100644
--- a/arch/arm64/include/am62x/irq.h
+++ b/arch/arm64/include/am62x/irq.h
@@ -102,4 +102,16 @@
 #define AM62X_IRQ_UART5           215   /* GIC_SPI 183                    */
 #define AM62X_IRQ_UART6           216   /* GIC_SPI 184                    */
 
+/* GPIO */
+
+#define AM62X_IRQ_GPIO0            57
+#define AM62X_IRQ_GPIO1            58
+
+/* I2C */
+
+#define AM62X_IRQ_I2C0            193   /* GIC_SPI 161 */
+#define AM62X_IRQ_I2C1            194   /* GIC_SPI 162 */
+#define AM62X_IRQ_I2C2            195   /* GIC_SPI 163 */
+#define AM62X_IRQ_I2C3            196   /* GIC_SPI 164 */
+
 #endif /* __ARCH_ARM64_INCLUDE_AM62X_IRQ_H */
diff --git a/arch/arm64/src/am62x/CMakeLists.txt 
b/arch/arm64/src/am62x/CMakeLists.txt
index 9ff3612e594..beeba7c7209 100644
--- a/arch/arm64/src/am62x/CMakeLists.txt
+++ b/arch/arm64/src/am62x/CMakeLists.txt
@@ -24,6 +24,21 @@
 
 list(APPEND SRCS am62x_boot.c am62x_16550serial.c)
 
+if(CONFIG_AM62X_GPIO)
+  list(APPEND SRCS am62x_gpio.c)
+endif()
+
+if(CONFIG_AM62X_I2C0
+   OR CONFIG_AM62X_I2C1
+   OR CONFIG_AM62X_I2C2
+   OR CONFIG_AM62X_I2C3)
+  list(APPEND SRCS am62x_i2c.c)
+endif()
+
+if(CONFIG_AM62X_TISCI)
+  list(APPEND SRCS am62x_tisci.c)
+endif()
+
 # Early UART assembly (needed for CONFIG_ARCH_EARLY_PRINT / semihosting console
 # before the full serial driver is up)
 
diff --git a/arch/arm64/src/am62x/Kconfig b/arch/arm64/src/am62x/Kconfig
index 3a0618e5a14..6fe752b2b65 100644
--- a/arch/arm64/src/am62x/Kconfig
+++ b/arch/arm64/src/am62x/Kconfig
@@ -7,6 +7,89 @@
 
 if ARCH_CHIP_AM62X
 
-comment "AM62x peripheral selection is provided by board defconfig for now."
+menu "AM62x peripheral support"
+
+config AM62X_TISCI
+       bool "TISCI system controller (DM/TIFS) client"
+       default n
+       ---help---
+               Enable the AM62x TISCI client.  On K3 SoCs the A53 does not own
+               device power, clocks, resets, or interrupt routing; those are
+               requested from the DM/TIFS firmware over the TISCI protocol via 
the
+               secure-proxy mailbox.  This driver provides the request helpers 
used
+               by peripheral drivers to power on a block, enable its functional
+               clock, release resets, and route its interrupt to the GIC.
+
+if AM62X_TISCI
+
+config AM62X_TISCI_HOST_ID
+       int "TISCI host ID"
+       default 12
+       ---help---
+               Host ID this core presents to the DM/TIFS firmware.  Must match 
the
+               host allocation in the firmware boardcfg.  12 is the standard 
A53
+               HLOS host on AM62x.
+
+config AM62X_TISCI_RX_THREAD
+       int "Secure proxy RX (response) thread"
+       default 12
+       ---help---
+               Secure-proxy thread the firmware uses to send responses back to 
this
+               host.
+
+config AM62X_TISCI_TX_THREAD
+       int "Secure proxy TX (request) thread"
+       default 13
+       ---help---
+               Secure-proxy thread this host uses to send requests to the 
firmware.
+
+endif # AM62X_TISCI
+
+config AM62X_GPIO
+       bool "GPIO support"
+       default n
+       ---help---
+               Enable the AM62x main-domain GPIO controller driver, including
+               basic GPIO input/output operations, pad-mux helper support, and
+               per-pin interrupt callback dispatch for GPIO0/GPIO1.
+
+config AM62X_GPIO_IRQ
+       bool "GPIO interrupt (GIC) delivery"
+       depends on AM62X_GPIO
+       default n
+       ---help---
+               Enable per-bank GPIO interrupt delivery through the GIC.  On 
AM62x
+               the GPIO bank interrupts are routed through the main GPIO 
interrupt
+               router, which must be programmed over TISCI (RM_IRQ_SET) before 
the
+               GIC input line is valid.  Until that routing is implemented, 
leave
+               this disabled: enabling an unrouted GIC line faults at boot.  
GPIO
+               input/output and the callback API still work without it.
+
+config AM62X_I2C0
+       bool "I2C0 support"
+       depends on I2C
+       default n
+
+config AM62X_I2C1
+       bool "I2C1 support"
+       depends on I2C
+       default n
+
+config AM62X_I2C2
+       bool "I2C2 support"
+       depends on I2C
+       default n
+
+config AM62X_I2C3
+       bool "I2C3 support"
+       depends on I2C
+       default n
+
+config AM62X_I2CTIMEOMS
+       int "I2C transfer timeout milliseconds"
+       default 500
+       depends on AM62X_I2C0 || AM62X_I2C1 || AM62X_I2C2 || AM62X_I2C3
+
+endmenu
 
 endif # ARCH_CHIP_AM62X
diff --git a/arch/arm64/src/am62x/Make.defs b/arch/arm64/src/am62x/Make.defs
index 6f849b82ad4..477ca0a5bdb 100644
--- a/arch/arm64/src/am62x/Make.defs
+++ b/arch/arm64/src/am62x/Make.defs
@@ -30,6 +30,24 @@ include common/Make.defs
 CHIP_CSRCS  = am62x_boot.c
 CHIP_CSRCS += am62x_16550serial.c
 
+ifeq ($(CONFIG_AM62X_GPIO),y)
+CHIP_CSRCS += am62x_gpio.c
+endif
+
+AM62X_I2C_CONFIGS := $(CONFIG_AM62X_I2C0)
+AM62X_I2C_CONFIGS += $(CONFIG_AM62X_I2C1)
+AM62X_I2C_CONFIGS += $(CONFIG_AM62X_I2C2)
+AM62X_I2C_CONFIGS += $(CONFIG_AM62X_I2C3)
+
+ifneq ($(AM62X_I2C_CONFIGS),)
+CHIP_CSRCS += am62x_i2c.c
+endif
+
+ifeq ($(CONFIG_AM62X_TISCI),y)
+CHIP_CSRCS += am62x_tisci.c
+endif
+
+
 # Early UART assembly (only when CONFIG_ARCH_EARLY_PRINT is set, which
 # is selected automatically when CONFIG_ARCH_HAVE_LOWPUTC is enabled
 # and the common arch layer needs early console output).
diff --git a/arch/arm64/src/am62x/am62x_gpio.c 
b/arch/arm64/src/am62x/am62x_gpio.c
new file mode 100644
index 00000000000..fe06182140a
--- /dev/null
+++ b/arch/arm64/src/am62x/am62x_gpio.c
@@ -0,0 +1,368 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/am62x_gpio.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 <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "hardware/am62x_gpio.h"
+#include "hardware/am62x_memorymap.h"
+#include "am62x_gpio.h"
+#include "am62x_tisci.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct am62x_gpio_callback_s
+{
+  xcpt_t handler;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const uintptr_t g_gpiobase[AM62X_GPIO_NBANKS] =
+{
+  AM62X_GPIO0_BASE,
+  AM62X_GPIO1_BASE,
+};
+
+static const int g_gpioirq[AM62X_GPIO_NBANKS] =
+{
+  AM62X_IRQ_GPIO0,
+  AM62X_IRQ_GPIO1,
+};
+
+#ifdef CONFIG_AM62X_TISCI
+/* TISCI power-domain / device id for each GPIO bank.  The bank must be
+ * powered on through the system firmware before its registers are touched.
+ */
+
+static const uint32_t g_gpiopd[AM62X_GPIO_NBANKS] =
+{
+  AM62X_DEV_GPIO0,
+  AM62X_DEV_GPIO1,
+};
+
+static const uint32_t g_gpioclk[AM62X_GPIO_NBANKS] =
+{
+  0,
+  0,
+};
+#endif
+
+static struct am62x_gpio_callback_s
+  g_callbacks[AM62X_GPIO_NBANKS][AM62X_GPIO_NPINS];
+
+static bool g_gpio_initialized;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int am62x_gpio_decode(gpio_pinset_t pinset, unsigned int *bank,
+                             unsigned int *line)
+{
+  *bank = AM62X_GPIO_BANK(pinset);
+  *line = AM62X_GPIO_LINE(pinset);
+
+  if (*bank >= AM62X_GPIO_NBANKS || *line >= AM62X_GPIO_NPINS)
+    {
+      return -EINVAL;
+    }
+
+  return OK;
+}
+
+static int am62x_gpio_interrupt(int irq, void *context, void *arg)
+{
+  unsigned int bank = (uintptr_t)arg;
+  uintptr_t base = g_gpiobase[bank];
+  uint32_t pending;
+  unsigned int line;
+
+  pending = getreg32(AM62X_GPIO_INTSTAT(base, 0));
+  putreg32(pending, AM62X_GPIO_INTSTAT(base, 0));
+
+  for (line = 0; line < AM62X_GPIO_NPINS; line++)
+    {
+      if ((pending & AM62X_GPIO_BIT(line)) != 0 &&
+          g_callbacks[bank][line].handler != NULL)
+        {
+          g_callbacks[bank][line].handler(irq, context,
+                                          g_callbacks[bank][line].arg);
+        }
+    }
+
+  putreg32(0, AM62X_GPIO_BINTEN(base));
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int am62x_gpio_initialize(void)
+{
+  unsigned int bank;
+  int ret;
+
+  if (g_gpio_initialized)
+    {
+      return OK;
+    }
+
+  for (bank = 0; bank < AM62X_GPIO_NBANKS; bank++)
+    {
+      uintptr_t base = g_gpiobase[bank];
+
+#ifdef CONFIG_AM62X_TISCI
+      /* Power, release reset, and clock the GPIO bank before any register
+       * access.  On K3 an access to a gated block faults the bus.
+       */
+
+      ret = am62x_tisci_module_enable(g_gpiopd[bank], g_gpioclk[bank]);
+      if (ret < 0)
+        {
+          return ret;
+        }
+#endif
+
+      putreg32(0xffffffff, AM62X_GPIO_CLR_RIS_TRIG(base, 0));
+      putreg32(0xffffffff, AM62X_GPIO_CLR_FAL_TRIG(base, 0));
+      putreg32(0xffffffff, AM62X_GPIO_INTSTAT(base, 0));
+      putreg32(0, AM62X_GPIO_BINTEN(base));
+
+      ret = irq_attach(g_gpioirq[bank], am62x_gpio_interrupt,
+                       (void *)(uintptr_t)bank);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      /* GPIO bank interrupts on AM62x are not delivered directly to the GIC:
+       * they pass through the main GPIO interrupt router, which must be
+       * programmed via TISCI (RM_IRQ_SET) before the GIC input is valid.
+       * Until that routing is wired up, enabling the GIC line delivers a
+       * spurious/unrouted interrupt and faults.  GPIO input/output works
+       * without it; gate the enable behind CONFIG_AM62X_GPIO_IRQ.
+       */
+
+#ifdef CONFIG_AM62X_GPIO_IRQ
+#ifdef CONFIG_ARCH_IRQPRIO
+      (void)up_prioritize_irq(g_gpioirq[bank], 0);
+#endif
+#ifdef CONFIG_ARCH_HAVE_IRQTRIGGER
+      (void)up_set_irq_type(g_gpioirq[bank], IRQ_HIGH_LEVEL);
+#endif
+      up_enable_irq(g_gpioirq[bank]);
+#endif
+    }
+
+  g_gpio_initialized = true;
+  return OK;
+}
+
+int am62x_configgpio(gpio_pinset_t cfgset)
+{
+  irqstate_t flags;
+  uintptr_t base;
+  uint32_t bit;
+  uint32_t regval;
+  unsigned int bank;
+  unsigned int line;
+  int ret;
+
+  ret = am62x_gpio_decode(cfgset, &bank, &line);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  base = g_gpiobase[bank];
+  bit = AM62X_GPIO_BIT(line);
+
+  flags = enter_critical_section();
+
+  if (!AM62X_GPIO_IS_INPUT(cfgset))
+    {
+      putreg32(bit, AM62X_GPIO_INITVAL(cfgset) ?
+                    AM62X_GPIO_SET_DATA(base, 0) :
+                    AM62X_GPIO_CLR_DATA(base, 0));
+    }
+
+  regval = getreg32(AM62X_GPIO_DIR(base, 0));
+  if (AM62X_GPIO_IS_INPUT(cfgset))
+    {
+      regval |= bit;
+    }
+  else
+    {
+      regval &= ~bit;
+    }
+
+  putreg32(regval, AM62X_GPIO_DIR(base, 0));
+
+  putreg32(bit, AM62X_GPIO_CLR_RIS_TRIG(base, 0));
+  putreg32(bit, AM62X_GPIO_CLR_FAL_TRIG(base, 0));
+
+  if (AM62X_GPIO_IRQMODE(cfgset) == AM62X_GPIO_IRQ_RISING ||
+      AM62X_GPIO_IRQMODE(cfgset) == AM62X_GPIO_IRQ_BOTH)
+    {
+      putreg32(bit, AM62X_GPIO_SET_RIS_TRIG(base, 0));
+    }
+
+  if (AM62X_GPIO_IRQMODE(cfgset) == AM62X_GPIO_IRQ_FALLING ||
+      AM62X_GPIO_IRQMODE(cfgset) == AM62X_GPIO_IRQ_BOTH)
+    {
+      putreg32(bit, AM62X_GPIO_SET_FAL_TRIG(base, 0));
+    }
+
+  putreg32(bit, AM62X_GPIO_INTSTAT(base, 0));
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+void am62x_gpiowrite(gpio_pinset_t pinset, bool value)
+{
+  irqstate_t flags;
+  uintptr_t base;
+  unsigned int bank;
+  unsigned int line;
+
+  if (am62x_gpio_decode(pinset, &bank, &line) < 0)
+    {
+      return;
+    }
+
+  base = g_gpiobase[bank];
+  flags = enter_critical_section();
+  putreg32(AM62X_GPIO_BIT(line), value ? AM62X_GPIO_SET_DATA(base, 0) :
+                                    AM62X_GPIO_CLR_DATA(base, 0));
+  leave_critical_section(flags);
+}
+
+bool am62x_gpioread(gpio_pinset_t pinset)
+{
+  irqstate_t flags;
+  uintptr_t base;
+  bool value;
+  unsigned int bank;
+  unsigned int line;
+
+  if (am62x_gpio_decode(pinset, &bank, &line) < 0)
+    {
+      return false;
+    }
+
+  base = g_gpiobase[bank];
+  flags = enter_critical_section();
+  value = (getreg32(AM62X_GPIO_IN_DATA(base, 0)) &
+           AM62X_GPIO_BIT(line)) != 0;
+  leave_critical_section(flags);
+  return value;
+}
+
+bool am62x_gpiooutread(gpio_pinset_t pinset)
+{
+  irqstate_t flags;
+  uintptr_t base;
+  bool value;
+  unsigned int bank;
+  unsigned int line;
+
+  if (am62x_gpio_decode(pinset, &bank, &line) < 0)
+    {
+      return false;
+    }
+
+  base = g_gpiobase[bank];
+  flags = enter_critical_section();
+  value = (getreg32(AM62X_GPIO_OUT_DATA(base, 0)) &
+           AM62X_GPIO_BIT(line)) != 0;
+  leave_critical_section(flags);
+  return value;
+}
+
+int am62x_gpio_irq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg)
+{
+  irqstate_t flags;
+  unsigned int bank;
+  unsigned int line;
+  int ret;
+
+  ret = am62x_gpio_decode(pinset, &bank, &line);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = am62x_gpio_initialize();
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  flags = enter_critical_section();
+  g_callbacks[bank][line].handler = isr;
+  g_callbacks[bank][line].arg = arg;
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+void am62x_gpio_irq_detach(gpio_pinset_t pinset)
+{
+  irqstate_t flags;
+  unsigned int bank;
+  unsigned int line;
+
+  if (am62x_gpio_decode(pinset, &bank, &line) < 0)
+    {
+      return;
+    }
+
+  flags = enter_critical_section();
+  g_callbacks[bank][line].handler = NULL;
+  g_callbacks[bank][line].arg = NULL;
+  leave_critical_section(flags);
+}
+
+int am62x_pinmux_configure(uintptr_t offset, uint32_t value)
+{
+  putreg32(value, AM62X_PADCFG_BASE + offset);
+  return OK;
+}
diff --git a/arch/arm64/src/am62x/am62x_gpio.h 
b/arch/arm64/src/am62x/am62x_gpio.h
new file mode 100644
index 00000000000..34ccbdd979f
--- /dev/null
+++ b/arch/arm64/src/am62x/am62x_gpio.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/am62x_gpio.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.
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM64_SRC_AM62X_AM62X_GPIO_H
+#define __ARCH_ARM64_SRC_AM62X_AM62X_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+typedef uint32_t gpio_pinset_t;
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define AM62X_GPIO_LINE_SHIFT       0
+#define AM62X_GPIO_LINE_MASK        (0xffu << AM62X_GPIO_LINE_SHIFT)
+#define AM62X_GPIO_BANK_SHIFT       8
+#define AM62X_GPIO_BANK_MASK        (0x03u << AM62X_GPIO_BANK_SHIFT)
+#define AM62X_GPIO_INPUT            (1u << 10)
+#define AM62X_GPIO_OUTPUT_ONE       (1u << 11)
+#define AM62X_GPIO_PULL_SHIFT       12
+#define AM62X_GPIO_PULL_MASK        (0x03u << AM62X_GPIO_PULL_SHIFT)
+#  define AM62X_GPIO_PULL_NONE      (0u << AM62X_GPIO_PULL_SHIFT)
+#  define AM62X_GPIO_PULL_UP        (1u << AM62X_GPIO_PULL_SHIFT)
+#  define AM62X_GPIO_PULL_DOWN      (2u << AM62X_GPIO_PULL_SHIFT)
+#define AM62X_GPIO_IRQ_SHIFT        14
+#define AM62X_GPIO_IRQ_MASK         (0x07u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_NONE       (0u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_RISING     (1u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_FALLING    (2u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_BOTH       (3u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_HIGH       (4u << AM62X_GPIO_IRQ_SHIFT)
+#  define AM62X_GPIO_IRQ_LOW        (5u << AM62X_GPIO_IRQ_SHIFT)
+
+#define AM62X_GPIO_OUTPUT           0u
+
+#define AM62X_GPIO_PIN(b,l)         ((((uint32_t)(b) << AM62X_GPIO_BANK_SHIFT) 
& \
+                                      AM62X_GPIO_BANK_MASK) | \
+                                     (((uint32_t)(l) << AM62X_GPIO_LINE_SHIFT) 
& \
+                                      AM62X_GPIO_LINE_MASK))
+#define AM62X_GPIO_BANK(p)          (((p) & AM62X_GPIO_BANK_MASK) >> \
+                                     AM62X_GPIO_BANK_SHIFT)
+#define AM62X_GPIO_LINE(p)          (((p) & AM62X_GPIO_LINE_MASK) >> \
+                                     AM62X_GPIO_LINE_SHIFT)
+#define AM62X_GPIO_IS_INPUT(p)      (((p) & AM62X_GPIO_INPUT) != 0)
+#define AM62X_GPIO_INITVAL(p)       (((p) & AM62X_GPIO_OUTPUT_ONE) != 0)
+#define AM62X_GPIO_IRQMODE(p)       ((p) & AM62X_GPIO_IRQ_MASK)
+
+#define AM62X_PADCFG_RXACTIVE       (1 << 18)
+#define AM62X_PADCFG_PULL_DISABLE   (1 << 16)
+#define AM62X_PADCFG_PULL_UP        (1 << 17)
+#define AM62X_PADCFG_MUXMODE(n)     ((n) & 0x0f)
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int am62x_gpio_initialize(void);
+int am62x_configgpio(gpio_pinset_t cfgset);
+void am62x_gpiowrite(gpio_pinset_t pinset, bool value);
+bool am62x_gpioread(gpio_pinset_t pinset);
+bool am62x_gpiooutread(gpio_pinset_t pinset);
+int am62x_gpio_irq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg);
+void am62x_gpio_irq_detach(gpio_pinset_t pinset);
+int am62x_pinmux_configure(uintptr_t offset, uint32_t value);
+
+#endif /* __ARCH_ARM64_SRC_AM62X_AM62X_GPIO_H */
diff --git a/arch/arm64/src/am62x/am62x_i2c.c b/arch/arm64/src/am62x/am62x_i2c.c
new file mode 100644
index 00000000000..ae612922b70
--- /dev/null
+++ b/arch/arm64/src/am62x/am62x_i2c.c
@@ -0,0 +1,767 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/am62x_i2c.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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/clock.h>
+#include <nuttx/debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "hardware/am62x_i2c.h"
+#include "hardware/am62x_memorymap.h"
+#include "am62x_i2c.h"
+#include "am62x_tisci.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define AM62X_I2C_INPUT_CLOCK  96000000
+#define AM62X_I2C_INTERNAL_CLK 12000000
+
+#ifndef CONFIG_AM62X_I2CTIMEOMS
+#  define CONFIG_AM62X_I2CTIMEOMS 500
+#endif
+
+#ifndef CONFIG_AM62X_I2CTIMEOTICKS
+#  define CONFIG_AM62X_I2CTIMEOTICKS MSEC2TICK(CONFIG_AM62X_I2CTIMEOMS)
+#endif
+
+/* The transmit underflow is left masked, the module raises it while it
+ * holds the bus between the messages of a register read.
+ */
+
+#define AM62X_I2C_INTERRUPTS   (I2C_IRQ_AL | I2C_IRQ_NACK | I2C_IRQ_ARDY | \
+                                I2C_IRQ_RRDY | I2C_IRQ_XRDY)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum am62x_i2c_state_e
+{
+  INTSTATE_IDLE = 0,
+  INTSTATE_WAITING,
+  INTSTATE_DONE,
+};
+
+struct am62x_i2c_config_s
+{
+  uintptr_t base;
+  int irq;
+  uint32_t devid;     /* TISCI device id (power/clock domain)              */
+  uint32_t clkid;     /* TISCI functional clock id                         */
+};
+
+struct am62x_i2c_priv_s
+{
+  const struct i2c_ops_s *ops;
+  const struct am62x_i2c_config_s *config;
+  int refs;
+  mutex_t lock;
+#ifndef CONFIG_I2C_POLLED
+  sem_t sem_isr;
+#endif
+  volatile uint8_t intstate;
+  struct i2c_msg_s *msgv;
+  int msgc;
+  int msgidx;
+  uint8_t *ptr;
+  int dcnt;
+  uint16_t flags;
+  uint32_t frequency;
+  uint32_t status;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int am62x_i2c_transfer(struct i2c_master_s *dev,
+                              struct i2c_msg_s *msgs, int count);
+#ifdef CONFIG_I2C_RESET
+static int am62x_i2c_reset(struct i2c_master_s *dev);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct i2c_ops_s g_i2c_ops =
+{
+  .transfer = am62x_i2c_transfer,
+#ifdef CONFIG_I2C_RESET
+  .reset = am62x_i2c_reset,
+#endif
+};
+
+#ifdef CONFIG_AM62X_I2C0
+static const struct am62x_i2c_config_s g_i2c0_config =
+{
+  .base = AM62X_I2C0_BASE,
+  .irq = AM62X_IRQ_I2C0,
+  .devid = AM62X_DEV_I2C0,
+  .clkid = 2,
+};
+
+static struct am62x_i2c_priv_s g_i2c0_priv =
+{
+  .ops = &g_i2c_ops,
+  .config = &g_i2c0_config,
+  .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+#endif
+};
+#endif
+
+#ifdef CONFIG_AM62X_I2C1
+static const struct am62x_i2c_config_s g_i2c1_config =
+{
+  .base = AM62X_I2C1_BASE,
+  .irq = AM62X_IRQ_I2C1,
+  .devid = AM62X_DEV_I2C1,
+  .clkid = 2,
+};
+
+static struct am62x_i2c_priv_s g_i2c1_priv =
+{
+  .ops = &g_i2c_ops,
+  .config = &g_i2c1_config,
+  .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+#endif
+};
+#endif
+
+#ifdef CONFIG_AM62X_I2C2
+static const struct am62x_i2c_config_s g_i2c2_config =
+{
+  .base = AM62X_I2C2_BASE,
+  .irq = AM62X_IRQ_I2C2,
+  .devid = AM62X_DEV_I2C2,
+  .clkid = 2,
+};
+
+static struct am62x_i2c_priv_s g_i2c2_priv =
+{
+  .ops = &g_i2c_ops,
+  .config = &g_i2c2_config,
+  .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+#endif
+};
+#endif
+
+#ifdef CONFIG_AM62X_I2C3
+static const struct am62x_i2c_config_s g_i2c3_config =
+{
+  .base = AM62X_I2C3_BASE,
+  .irq = AM62X_IRQ_I2C3,
+  .devid = AM62X_DEV_I2C3,
+  .clkid = 2,
+};
+
+static struct am62x_i2c_priv_s g_i2c3_priv =
+{
+  .ops = &g_i2c_ops,
+  .config = &g_i2c3_config,
+  .lock = NXMUTEX_INITIALIZER,
+#ifndef CONFIG_I2C_POLLED
+  .sem_isr = SEM_INITIALIZER(0),
+#endif
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline uint32_t am62x_i2c_getreg(struct am62x_i2c_priv_s *priv,
+                                        uint16_t offset)
+{
+  return getreg32(priv->config->base + offset);
+}
+
+static inline void am62x_i2c_putreg(struct am62x_i2c_priv_s *priv,
+                                    uint16_t offset, uint32_t value)
+{
+  putreg32(value, priv->config->base + offset);
+}
+
+static inline void am62x_i2c_modifyreg(struct am62x_i2c_priv_s *priv,
+                                       uint16_t offset, uint32_t clearbits,
+                                       uint32_t setbits)
+{
+  modifyreg32(priv->config->base + offset, clearbits, setbits);
+}
+
+static bool am62x_i2c_wait_bus_free(struct am62x_i2c_priv_s *priv)
+{
+  clock_t start = clock_systime_ticks();
+
+  do
+    {
+      if ((am62x_i2c_getreg(priv, AM62X_I2C_IRQSTATUS_RAW_OFFSET) &
+           I2C_IRQ_BB) == 0)
+        {
+          return true;
+        }
+    }
+  while ((clock_systime_ticks() - start) < CONFIG_AM62X_I2CTIMEOTICKS);
+
+  return false;
+}
+
+static void am62x_i2c_flush_fifo(struct am62x_i2c_priv_s *priv)
+{
+  uint32_t buf = am62x_i2c_getreg(priv, AM62X_I2C_BUF_OFFSET);
+
+  /* Pulse the clear bits only, the thresholds must be preserved. */
+
+  buf |= I2C_BUF_RXFIFO_CLR | I2C_BUF_TXFIFO_CLR;
+  am62x_i2c_putreg(priv, AM62X_I2C_BUF_OFFSET, buf);
+}
+
+static int am62x_i2c_softreset(struct am62x_i2c_priv_s *priv)
+{
+  clock_t start;
+
+  /* The module must be enabled for the reset to progress. */
+
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, 0);
+  am62x_i2c_putreg(priv, AM62X_I2C_SYSC_OFFSET, I2C_SYSC_SRST);
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, I2C_CON_EN);
+
+  start = clock_systime_ticks();
+  do
+    {
+      if ((am62x_i2c_getreg(priv, AM62X_I2C_SYSS_OFFSET) &
+           I2C_SYSS_RST_DONE) != 0)
+        {
+          am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, 0);
+          return OK;
+        }
+    }
+  while ((clock_systime_ticks() - start) < CONFIG_AM62X_I2CTIMEOTICKS);
+
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, 0);
+  return -ETIMEDOUT;
+}
+
+static void am62x_i2c_setclock(struct am62x_i2c_priv_s *priv,
+                               uint32_t frequency)
+{
+  uint32_t internal;
+  uint32_t psc;
+  uint32_t divider;
+  uint32_t scll;
+  uint32_t sclh;
+  uint32_t enabled;
+
+  if (frequency == 0)
+    {
+      frequency = 100000;
+    }
+
+  if (frequency == priv->frequency)
+    {
+      return;
+    }
+
+  enabled = am62x_i2c_getreg(priv, AM62X_I2C_CON_OFFSET) & I2C_CON_EN;
+  if (enabled != 0)
+    {
+      am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, I2C_CON_EN, 0);
+    }
+
+  psc = (AM62X_I2C_INPUT_CLOCK / AM62X_I2C_INTERNAL_CLK) - 1;
+  internal = AM62X_I2C_INPUT_CLOCK / (psc + 1);
+  divider = internal / frequency;
+
+  if (divider < 14)
+    {
+      divider = 14;
+    }
+
+  scll = (divider / 2) - 7;
+  sclh = (divider - (divider / 2)) - 5;
+
+  if (scll > 255)
+    {
+      scll = 255;
+    }
+
+  if (sclh > 255)
+    {
+      sclh = 255;
+    }
+
+  am62x_i2c_putreg(priv, AM62X_I2C_PSC_OFFSET, psc);
+  am62x_i2c_putreg(priv, AM62X_I2C_SCLL_OFFSET, scll);
+  am62x_i2c_putreg(priv, AM62X_I2C_SCLH_OFFSET, sclh);
+
+  if (enabled != 0)
+    {
+      am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, 0, I2C_CON_EN);
+    }
+
+  priv->frequency = frequency;
+}
+
+static void am62x_i2c_recover(struct am62x_i2c_priv_s *priv)
+{
+  uint32_t frequency = priv->frequency;
+
+  /* A transfer aborted while the bus was held keeps the lines driven. */
+
+  am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, 0, I2C_CON_STP);
+  am62x_i2c_flush_fifo(priv);
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQSTATUS_OFFSET, I2C_IRQ_CLEARMASK);
+
+  if ((am62x_i2c_getreg(priv, AM62X_I2C_IRQSTATUS_RAW_OFFSET) &
+       I2C_IRQ_BB) == 0)
+    {
+      return;
+    }
+
+  /* The bus is still held, only a soft reset gets the module out. */
+
+  if (am62x_i2c_softreset(priv) == OK)
+    {
+      priv->frequency = 0;
+      am62x_i2c_setclock(priv, frequency);
+      am62x_i2c_flush_fifo(priv);
+      am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, 0, I2C_CON_EN);
+      am62x_i2c_modifyreg(priv, AM62X_I2C_SYSTEST_OFFSET, 0,
+                          I2C_SYSTEST_FREE);
+    }
+}
+
+static void am62x_i2c_start_message(struct am62x_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgidx];
+  uint32_t con = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT;
+  bool last = (priv->msgidx + 1) >= priv->msgc;
+
+  priv->ptr = msg->buffer;
+  priv->dcnt = msg->length;
+  priv->flags = msg->flags;
+
+  if ((msg->flags & I2C_M_READ) == 0)
+    {
+      con |= I2C_CON_TRX;
+    }
+
+  if ((msg->flags & I2C_M_TEN) != 0)
+    {
+      con |= I2C_CON_XSA;
+    }
+
+  if (last && (msg->flags & I2C_M_NOSTOP) == 0)
+    {
+      con |= I2C_CON_STP;
+    }
+
+  am62x_i2c_putreg(priv, AM62X_I2C_SA_OFFSET, msg->addr);
+  am62x_i2c_putreg(priv, AM62X_I2C_CNT_OFFSET, msg->length);
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, con);
+}
+
+static void am62x_i2c_complete(struct am62x_i2c_priv_s *priv)
+{
+#ifndef CONFIG_I2C_POLLED
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQENABLE_CLR_OFFSET,
+                   I2C_IRQ_CLEARMASK);
+  if (priv->intstate == INTSTATE_WAITING)
+    {
+      priv->intstate = INTSTATE_DONE;
+      nxsem_post(&priv->sem_isr);
+    }
+#else
+  priv->intstate = INTSTATE_DONE;
+#endif
+}
+
+static int am62x_i2c_isr_process(struct am62x_i2c_priv_s *priv)
+{
+#ifndef CONFIG_I2C_POLLED
+  uint32_t status = am62x_i2c_getreg(priv, AM62X_I2C_IRQSTATUS_OFFSET);
+#else
+  uint32_t status = am62x_i2c_getreg(priv, AM62X_I2C_IRQSTATUS_RAW_OFFSET);
+#endif
+
+  if (status == 0)
+    {
+      return OK;
+    }
+
+  priv->status = status;
+
+  if ((status & I2C_IRQ_ERRORMASK) != 0)
+    {
+      am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, 0, I2C_CON_STP);
+      am62x_i2c_complete(priv);
+      am62x_i2c_putreg(priv, AM62X_I2C_IRQSTATUS_OFFSET, status);
+      return OK;
+    }
+
+  if ((status & I2C_IRQ_XRDY) != 0 && (priv->flags & I2C_M_READ) == 0)
+    {
+      if (priv->dcnt > 0)
+        {
+          am62x_i2c_putreg(priv, AM62X_I2C_DATA_OFFSET, *priv->ptr++);
+          priv->dcnt--;
+        }
+    }
+
+  if ((status & I2C_IRQ_RRDY) != 0 && (priv->flags & I2C_M_READ) != 0)
+    {
+      if (priv->dcnt > 0)
+        {
+          *priv->ptr++ = am62x_i2c_getreg(priv, AM62X_I2C_DATA_OFFSET) &
+                         I2C_DATA_MASK;
+          priv->dcnt--;
+        }
+      else
+        {
+          (void)am62x_i2c_getreg(priv, AM62X_I2C_DATA_OFFSET);
+        }
+    }
+
+  /* Acknowledge before starting the next message, clearing the status
+   * afterwards would drop the events raised by that message.
+   */
+
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQSTATUS_OFFSET, status);
+
+  if ((status & I2C_IRQ_ARDY) != 0)
+    {
+      if (priv->msgidx + 1 < priv->msgc)
+        {
+          priv->msgidx++;
+          am62x_i2c_start_message(priv);
+        }
+      else
+        {
+          am62x_i2c_complete(priv);
+        }
+    }
+
+  return OK;
+}
+
+#ifndef CONFIG_I2C_POLLED
+static int am62x_i2c_isr(int irq, void *context, void *arg)
+{
+  struct am62x_i2c_priv_s *priv = arg;
+
+  DEBUGASSERT(priv != NULL);
+  return am62x_i2c_isr_process(priv);
+}
+#endif
+
+static int am62x_i2c_waitdone(struct am62x_i2c_priv_s *priv)
+{
+#ifndef CONFIG_I2C_POLLED
+  int ret;
+
+  priv->intstate = INTSTATE_WAITING;
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQENABLE_SET_OFFSET,
+                   AM62X_I2C_INTERRUPTS);
+  am62x_i2c_start_message(priv);
+
+  do
+    {
+      ret = nxsem_tickwait(&priv->sem_isr, CONFIG_AM62X_I2CTIMEOTICKS);
+    }
+  while (ret == -EINTR && priv->intstate != INTSTATE_DONE);
+
+  if (ret < 0)
+    {
+      am62x_i2c_putreg(priv, AM62X_I2C_IRQENABLE_CLR_OFFSET,
+                       I2C_IRQ_CLEARMASK);
+      am62x_i2c_recover(priv);
+      priv->intstate = INTSTATE_IDLE;
+      return ret;
+    }
+
+  priv->intstate = INTSTATE_IDLE;
+  return OK;
+#else
+  clock_t start = clock_systime_ticks();
+
+  priv->intstate = INTSTATE_WAITING;
+  am62x_i2c_start_message(priv);
+
+  while (priv->intstate != INTSTATE_DONE &&
+         (clock_systime_ticks() - start) < CONFIG_AM62X_I2CTIMEOTICKS)
+    {
+      am62x_i2c_isr_process(priv);
+    }
+
+  if (priv->intstate != INTSTATE_DONE)
+    {
+      am62x_i2c_recover(priv);
+      priv->intstate = INTSTATE_IDLE;
+      return -ETIMEDOUT;
+    }
+
+  priv->intstate = INTSTATE_IDLE;
+  return OK;
+#endif
+}
+
+static int am62x_i2c_init(struct am62x_i2c_priv_s *priv)
+{
+#ifdef CONFIG_AM62X_TISCI
+  /* Power, release reset, and clock I2C before any register access. */
+
+  int pret = am62x_tisci_module_enable(priv->config->devid,
+                                       priv->config->clkid);
+  if (pret < 0)
+    {
+      return pret;
+    }
+#endif
+
+  /* The bootloader may have left the module holding the bus. */
+
+  am62x_i2c_softreset(priv);
+
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, 0);
+  am62x_i2c_modifyreg(priv, AM62X_I2C_SYSC_OFFSET, I2C_SYSC_AUTOIDLE, 0);
+  priv->frequency = 0;
+  am62x_i2c_setclock(priv, 100000);
+  am62x_i2c_flush_fifo(priv);
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQSTATUS_OFFSET, I2C_IRQ_CLEARMASK);
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQENABLE_CLR_OFFSET,
+                   I2C_IRQ_CLEARMASK);
+
+#ifndef CONFIG_I2C_POLLED
+  int ret = irq_attach(priv->config->irq, am62x_i2c_isr, priv);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+#ifdef CONFIG_ARCH_IRQPRIO
+  (void)up_prioritize_irq(priv->config->irq, 0);
+#endif
+#ifdef CONFIG_ARCH_HAVE_IRQTRIGGER
+  (void)up_set_irq_type(priv->config->irq, IRQ_HIGH_LEVEL);
+#endif
+  up_enable_irq(priv->config->irq);
+#endif
+
+  am62x_i2c_modifyreg(priv, AM62X_I2C_CON_OFFSET, 0, I2C_CON_EN);
+  am62x_i2c_modifyreg(priv, AM62X_I2C_SYSTEST_OFFSET, 0, I2C_SYSTEST_FREE);
+  return OK;
+}
+
+static int am62x_i2c_deinit(struct am62x_i2c_priv_s *priv)
+{
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQENABLE_CLR_OFFSET,
+                   I2C_IRQ_CLEARMASK);
+  am62x_i2c_putreg(priv, AM62X_I2C_CON_OFFSET, 0);
+
+#ifndef CONFIG_I2C_POLLED
+  up_disable_irq(priv->config->irq);
+  irq_detach(priv->config->irq);
+#endif
+
+  return OK;
+}
+
+static int am62x_i2c_transfer(struct i2c_master_s *dev,
+                              struct i2c_msg_s *msgs, int count)
+{
+  struct am62x_i2c_priv_s *priv = (struct am62x_i2c_priv_s *)dev;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && msgs != NULL && count > 0);
+
+  ret = nxmutex_lock(&priv->lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* A previous transfer may have left the bus held.  Recover instead of
+   * refusing every transfer from now on.
+   */
+
+  if (!am62x_i2c_wait_bus_free(priv))
+    {
+      am62x_i2c_recover(priv);
+
+      if (!am62x_i2c_wait_bus_free(priv))
+        {
+          nxmutex_unlock(&priv->lock);
+          return -EBUSY;
+        }
+    }
+
+  am62x_i2c_putreg(priv, AM62X_I2C_IRQSTATUS_OFFSET, I2C_IRQ_CLEARMASK);
+  am62x_i2c_flush_fifo(priv);
+  am62x_i2c_setclock(priv, msgs[0].frequency);
+
+  priv->msgv = msgs;
+  priv->msgc = count;
+  priv->msgidx = 0;
+  priv->ptr = NULL;
+  priv->dcnt = 0;
+  priv->flags = msgs[0].flags;
+  priv->status = 0;
+
+  ret = am62x_i2c_waitdone(priv);
+  if (ret < 0)
+    {
+      ret = -ETIMEDOUT;
+    }
+  else if ((priv->status & I2C_IRQ_AL) != 0)
+    {
+      ret = -EAGAIN;
+    }
+  else if ((priv->status & I2C_IRQ_NACK) != 0)
+    {
+      ret = -ENXIO;
+    }
+  else if ((priv->status & (I2C_IRQ_AERR | I2C_IRQ_ROVR)) != 0)
+    {
+      ret = -EIO;
+    }
+  else
+    {
+      ret = OK;
+    }
+
+  /* Do not leave the bus held, the next transfer would fail too. */
+
+  if (ret < 0)
+    {
+      am62x_i2c_recover(priv);
+    }
+
+  priv->ptr = NULL;
+  priv->dcnt = 0;
+  nxmutex_unlock(&priv->lock);
+  return ret;
+}
+
+#ifdef CONFIG_I2C_RESET
+static int am62x_i2c_reset(struct i2c_master_s *dev)
+{
+  struct am62x_i2c_priv_s *priv = (struct am62x_i2c_priv_s *)dev;
+
+  DEBUGASSERT(priv != NULL);
+  return am62x_i2c_init(priv);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+struct i2c_master_s *am62x_i2cbus_initialize(int port)
+{
+  struct am62x_i2c_priv_s *priv = NULL;
+
+  switch (port)
+    {
+#ifdef CONFIG_AM62X_I2C0
+      case 0:
+        priv = &g_i2c0_priv;
+        break;
+#endif
+#ifdef CONFIG_AM62X_I2C1
+      case 1:
+        priv = &g_i2c1_priv;
+        break;
+#endif
+#ifdef CONFIG_AM62X_I2C2
+      case 2:
+        priv = &g_i2c2_priv;
+        break;
+#endif
+#ifdef CONFIG_AM62X_I2C3
+      case 3:
+        priv = &g_i2c3_priv;
+        break;
+#endif
+      default:
+        return NULL;
+    }
+
+  nxmutex_lock(&priv->lock);
+  if (priv->refs++ == 0)
+    {
+      if (am62x_i2c_init(priv) < 0)
+        {
+          priv->refs--;
+          nxmutex_unlock(&priv->lock);
+          return NULL;
+        }
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return (struct i2c_master_s *)priv;
+}
+
+int am62x_i2cbus_uninitialize(struct i2c_master_s *dev)
+{
+  struct am62x_i2c_priv_s *priv = (struct am62x_i2c_priv_s *)dev;
+
+  DEBUGASSERT(priv != NULL);
+
+  nxmutex_lock(&priv->lock);
+  if (priv->refs == 0)
+    {
+      nxmutex_unlock(&priv->lock);
+      return -EINVAL;
+    }
+
+  if (--priv->refs == 0)
+    {
+      am62x_i2c_deinit(priv);
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return OK;
+}
+
diff --git a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h 
b/arch/arm64/src/am62x/am62x_i2c.h
similarity index 52%
copy from boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
copy to arch/arm64/src/am62x/am62x_i2c.h
index fe1f462d65d..e80a2635dcf 100644
--- a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
+++ b/arch/arm64/src/am62x/am62x_i2c.h
@@ -1,5 +1,5 @@
 /****************************************************************************
- * boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
+ * arch/arm64/src/am62x/am62x_i2c.h
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -17,64 +17,24 @@
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
  * License for the specific language governing permissions and limitations
  * under the License.
- *
  ****************************************************************************/
 
-#ifndef __BOARDS_ARM64_AM62X_POCKETBEAGLE2_SRC_POCKETBEAGLE2_H
-#define __BOARDS_ARM64_AM62X_POCKETBEAGLE2_SRC_POCKETBEAGLE2_H
+#ifndef __ARCH_ARM64_SRC_AM62X_AM62X_I2C_H
+#define __ARCH_ARM64_SRC_AM62X_AM62X_I2C_H
 
 /****************************************************************************
  * Included Files
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <stdint.h>
-
-/****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
-
-#ifndef __ASSEMBLY__
-
-#undef EXTERN
-#if defined(__cplusplus)
-#define EXTERN extern "C"
-extern "C"
-{
-#else
-#define EXTERN extern
-#endif
-
-/****************************************************************************
- * Name: pocketbeagle2_bringup
- *
- * Description:
- *   Bring up board-level drivers and subsystems.  Called from
- *   board_late_initialize().
- *
- ****************************************************************************/
 
-#ifdef CONFIG_BOARD_LATE_INITIALIZE
-int pocketbeagle2_bringup(void);
-#endif
+#include <nuttx/i2c/i2c_master.h>
 
 /****************************************************************************
- * Name: pocketbeagle2_led_initialize
- *
- * Description:
- *   Configure the user LEDs as GPIO outputs.  Called from
- *   am62x_board_initialize() when CONFIG_ARCH_LEDS is set.
- *
+ * Public Function Prototypes
  ****************************************************************************/
 
-#ifdef CONFIG_ARCH_LEDS
-void pocketbeagle2_led_initialize(void);
-#endif
-
-#undef EXTERN
-#if defined(__cplusplus)
-}
-#endif
+struct i2c_master_s *am62x_i2cbus_initialize(int port);
+int am62x_i2cbus_uninitialize(struct i2c_master_s *dev);
 
-#endif /* __ASSEMBLY__ */
-#endif /* __BOARDS_ARM64_AM62X_POCKETBEAGLE2_SRC_POCKETBEAGLE2_H */
+#endif /* __ARCH_ARM64_SRC_AM62X_AM62X_I2C_H */
diff --git a/arch/arm64/src/am62x/am62x_tisci.c 
b/arch/arm64/src/am62x/am62x_tisci.c
new file mode 100644
index 00000000000..51a9aecdf53
--- /dev/null
+++ b/arch/arm64/src/am62x/am62x_tisci.c
@@ -0,0 +1,528 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/am62x_tisci.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 <nuttx/debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/mutex.h>
+
+#include "arm64_arch.h"
+#include "arm64_internal.h"
+#include "hardware/am62x_memorymap.h"
+#include "hardware/am62x_secure_proxy.h"
+#include "hardware/am62x_tisci_proto.h"
+#include "am62x_tisci.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Host id and secure-proxy thread assignment (Kconfig-tunable; defaults
+ * match the A53 HLOS host on a standard AM62x DM/TIFS boardcfg).
+ */
+
+#define AM62X_TISCI_HOST_ID    CONFIG_AM62X_TISCI_HOST_ID
+#define AM62X_TISCI_RX_THREAD  CONFIG_AM62X_TISCI_RX_THREAD
+#define AM62X_TISCI_TX_THREAD  CONFIG_AM62X_TISCI_TX_THREAD
+
+/* Bounded poll: up to ~1 s waiting on a secure-proxy thread credit */
+
+#define AM62X_TISCI_POLL_US    1
+#define AM62X_TISCI_POLL_MAX   1000000
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Serialises the single outstanding request/response transaction */
+
+static mutex_t g_tisci_lock = NXMUTEX_INITIALIZER;
+
+/* Rolling sequence number used to match responses to requests */
+
+static uint8_t g_tisci_seq;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: am62x_sproxy_wait
+ *
+ * Description:
+ *   Wait until the given secure-proxy thread has a non-zero credit count
+ *   (a free slot for TX, or a pending message for RX), or report a thread
+ *   error / timeout.
+ *
+ ****************************************************************************/
+
+static int am62x_sproxy_wait(uintptr_t status_reg)
+{
+  int retries = AM62X_TISCI_POLL_MAX;
+  uint32_t status;
+
+  do
+    {
+      status = getreg32(status_reg);
+      if ((status & AM62X_SEC_PROXY_RT_ERR) != 0)
+        {
+          return -EIO;
+        }
+
+      if ((status & AM62X_SEC_PROXY_RT_CNT_MASK) != 0)
+        {
+          return OK;
+        }
+
+      up_udelay(AM62X_TISCI_POLL_US);
+    }
+  while (--retries > 0);
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: am62x_sproxy_send
+ *
+ * Description:
+ *   Push a message (up to 60 bytes) onto the TX thread.  The message is
+ *   zero-padded to the full 15-word window; the write to the final word
+ *   (offset 0x3c) commits the transfer to the firmware.
+ *
+ ****************************************************************************/
+
+static int am62x_sproxy_send(const void *msg, size_t len)
+{
+  uintptr_t data = AM62X_SEC_PROXY_DATA(AM62X_TISCI_TX_THREAD);
+  uintptr_t status = AM62X_SEC_PROXY_RT(AM62X_TISCI_TX_THREAD) +
+                     AM62X_SEC_PROXY_RT_STATUS;
+  uint32_t buf[AM62X_SEC_PROXY_MSG_WORDS];
+  int ret;
+  int i;
+
+  if (len > AM62X_SEC_PROXY_MAX_MSG_SIZE)
+    {
+      return -EINVAL;
+    }
+
+  ret = am62x_sproxy_wait(status);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  memset(buf, 0, sizeof(buf));
+  memcpy(buf, msg, len);
+
+  /* Write all 15 words in ascending order; the last (offset 0x3c) commits. */
+
+  for (i = 0; i < AM62X_SEC_PROXY_MSG_WORDS; i++)
+    {
+      putreg32(buf[i], data + AM62X_SEC_PROXY_DATA_START + i * 4);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: am62x_sproxy_recv
+ *
+ * Description:
+ *   Read a response from the RX thread.  All 15 words are read so the
+ *   final-word read marks the message consumed.
+ *
+ ****************************************************************************/
+
+static int am62x_sproxy_recv(void *msg, size_t len)
+{
+  uintptr_t data = AM62X_SEC_PROXY_DATA(AM62X_TISCI_RX_THREAD);
+  uintptr_t status = AM62X_SEC_PROXY_RT(AM62X_TISCI_RX_THREAD) +
+                     AM62X_SEC_PROXY_RT_STATUS;
+  uint32_t buf[AM62X_SEC_PROXY_MSG_WORDS];
+  int ret;
+  int i;
+
+  if (len > AM62X_SEC_PROXY_MAX_MSG_SIZE)
+    {
+      return -EINVAL;
+    }
+
+  ret = am62x_sproxy_wait(status);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  for (i = 0; i < AM62X_SEC_PROXY_MSG_WORDS; i++)
+    {
+      buf[i] = getreg32(data + AM62X_SEC_PROXY_DATA_START + i * 4);
+    }
+
+  memcpy(msg, buf, len);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: am62x_sproxy_drain
+ *
+ * Description:
+ *   Discard any stale message pending on the RX thread before a new
+ *   transaction, so an orphaned response cannot desynchronise sequencing.
+ *
+ ****************************************************************************/
+
+static void am62x_sproxy_drain(void)
+{
+  uintptr_t data = AM62X_SEC_PROXY_DATA(AM62X_TISCI_RX_THREAD);
+  uintptr_t status = AM62X_SEC_PROXY_RT(AM62X_TISCI_RX_THREAD) +
+                     AM62X_SEC_PROXY_RT_STATUS;
+  int guard = AM62X_SEC_PROXY_MSG_WORDS + 1;
+  uint32_t s;
+  int i;
+
+  while (guard-- > 0)
+    {
+      s = getreg32(status);
+      if ((s & AM62X_SEC_PROXY_RT_ERR) != 0 ||
+          (s & AM62X_SEC_PROXY_RT_CNT_MASK) == 0)
+        {
+          break;
+        }
+
+      for (i = 0; i < AM62X_SEC_PROXY_MSG_WORDS; i++)
+        {
+          getreg32(data + AM62X_SEC_PROXY_DATA_START + i * 4);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: am62x_tisci_xfer
+ *
+ * Description:
+ *   Run one synchronous TISCI request/response.  Fills the header host, seq,
+ *   and ACK-on-processed flag, sends the request, reads the response, and
+ *   validates the ACK and matching sequence number.
+ *
+ ****************************************************************************/
+
+static int am62x_tisci_xfer(struct ti_sci_msg_hdr *req, size_t req_sz,
+                            struct ti_sci_msg_hdr *resp, size_t resp_sz)
+{
+  uint8_t seq;
+  int ret;
+
+  ret = nxmutex_lock(&g_tisci_lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  seq = ++g_tisci_seq;
+  req->host  = AM62X_TISCI_HOST_ID;
+  req->seq   = seq;
+  req->flags |= TI_SCI_FLAG_REQ_ACK_ON_PROCESSED;
+
+  am62x_sproxy_drain();
+
+  ret = am62x_sproxy_send(req, req_sz);
+  if (ret == OK)
+    {
+      ret = am62x_sproxy_recv(resp, resp_sz);
+    }
+
+  nxmutex_unlock(&g_tisci_lock);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if ((resp->flags & TI_SCI_FLAG_RESP_GENERIC_ACK) == 0)
+    {
+      return -EIO;   /* firmware NAK */
+    }
+
+  if (resp->seq != seq)
+    {
+      return -EPROTO;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: am62x_tisci_clkid
+ *
+ * Description:
+ *   Encode a clock id into the 8-bit clk_id / 32-bit clk_id_32 pair used by
+ *   the clock messages.
+ *
+ ****************************************************************************/
+
+static void am62x_tisci_clkid(uint32_t clkid, uint8_t *clk_id,
+                              uint32_t *clk_id_32)
+{
+  if (clkid < TI_SCI_CLOCK_ID_INDIRECT)
+    {
+      *clk_id    = (uint8_t)clkid;
+      *clk_id_32 = 0;
+    }
+  else
+    {
+      *clk_id    = TI_SCI_CLOCK_ID_INDIRECT;
+      *clk_id_32 = clkid;
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int am62x_tisci_get_version(struct am62x_tisci_version_s *ver)
+{
+  struct ti_sci_msg_hdr req;
+  struct ti_sci_msg_resp_version resp;
+  int ret;
+
+  memset(&req, 0, sizeof(req));
+  req.type = TI_SCI_MSG_VERSION;
+
+  ret = am62x_tisci_xfer(&req, sizeof(req), &resp.hdr, sizeof(resp));
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (ver != NULL)
+    {
+      ver->firmware_revision = resp.firmware_revision;
+      ver->abi_major = resp.abi_major;
+      ver->abi_minor = resp.abi_minor;
+      memcpy(ver->firmware_description, resp.firmware_description,
+             sizeof(resp.firmware_description));
+      ver->firmware_description[sizeof(resp.firmware_description) - 1] =
+        '\0';
+    }
+
+  return OK;
+}
+
+int am62x_tisci_set_device_state(uint32_t devid, uint8_t state)
+{
+  struct ti_sci_msg_req_set_device_state req;
+  struct ti_sci_msg_hdr resp;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_SET_DEVICE_STATE;
+  req.id = devid;
+  req.state = state;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_get_device_state(uint32_t devid, uint8_t *current_state)
+{
+  struct ti_sci_msg_req_get_device_state req;
+  struct ti_sci_msg_resp_get_device_state resp;
+  int ret;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_GET_DEVICE_STATE;
+  req.id = devid;
+
+  ret = am62x_tisci_xfer(&req.hdr, sizeof(req), &resp.hdr, sizeof(resp));
+  if (ret == OK && current_state != NULL)
+    {
+      *current_state = resp.current_state;
+    }
+
+  return ret;
+}
+
+int am62x_tisci_module_enable(uint32_t devid, uint32_t clkid)
+{
+  int ret;
+
+  ret = am62x_tisci_set_device_state(devid, MSG_DEVICE_SW_STATE_ON);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = am62x_tisci_set_device_resets(devid, 0);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = am62x_tisci_clk_enable(devid, clkid);
+  return ret;
+}
+
+int am62x_tisci_set_device_resets(uint32_t devid, uint32_t resets)
+{
+  struct ti_sci_msg_req_set_device_resets req;
+  struct ti_sci_msg_hdr resp;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_SET_DEVICE_RESETS;
+  req.id = devid;
+  req.resets = resets;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_set_clock_state(uint32_t devid, uint32_t clkid,
+                                uint8_t state)
+{
+  struct ti_sci_msg_req_set_clock_state req;
+  struct ti_sci_msg_hdr resp;
+  uint8_t clk_id;
+  uint32_t clk_id_32;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_SET_CLOCK_STATE;
+  req.dev_id = devid;
+  req.request_state = state;
+  am62x_tisci_clkid(clkid, &clk_id, &clk_id_32);
+  req.clk_id = clk_id;
+  req.clk_id_32 = clk_id_32;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_clk_enable(uint32_t devid, uint32_t clkid)
+{
+  return am62x_tisci_set_clock_state(devid, clkid, MSG_CLOCK_SW_STATE_REQ);
+}
+
+int am62x_tisci_set_clock_freq(uint32_t devid, uint32_t clkid,
+                               uint64_t freq_hz)
+{
+  struct ti_sci_msg_req_set_clock_freq req;
+  struct ti_sci_msg_hdr resp;
+  uint8_t clk_id;
+  uint32_t clk_id_32;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_SET_CLOCK_FREQ;
+  req.dev_id = devid;
+  req.min_freq_hz = freq_hz;
+  req.target_freq_hz = freq_hz;
+  req.max_freq_hz = freq_hz;
+  am62x_tisci_clkid(clkid, &clk_id, &clk_id_32);
+  req.clk_id = clk_id;
+  req.clk_id_32 = clk_id_32;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_get_clock_freq(uint32_t devid, uint32_t clkid,
+                               uint64_t *freq_hz)
+{
+  struct ti_sci_msg_req_get_clock_freq req;
+  struct ti_sci_msg_resp_get_clock_freq resp;
+  uint8_t clk_id;
+  uint32_t clk_id_32;
+  int ret;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_GET_CLOCK_FREQ;
+  req.dev_id = devid;
+  am62x_tisci_clkid(clkid, &clk_id, &clk_id_32);
+  req.clk_id = clk_id;
+  req.clk_id_32 = clk_id_32;
+
+  ret = am62x_tisci_xfer(&req.hdr, sizeof(req), &resp.hdr, sizeof(resp));
+  if (ret == OK && freq_hz != NULL)
+    {
+      *freq_hz = resp.freq_hz;
+    }
+
+  return ret;
+}
+
+int am62x_tisci_irq_set(uint16_t src_id, uint16_t src_index,
+                        uint16_t dst_id, uint16_t dst_host_irq)
+{
+  struct ti_sci_msg_req_manage_irq req;
+  struct ti_sci_msg_hdr resp;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_RM_IRQ_SET;
+  req.valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
+  req.src_id = src_id;
+  req.src_index = src_index;
+  req.dst_id = dst_id;
+  req.dst_host_irq = dst_host_irq;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_irq_release(uint16_t src_id, uint16_t src_index,
+                            uint16_t dst_id, uint16_t dst_host_irq)
+{
+  struct ti_sci_msg_req_manage_irq req;
+  struct ti_sci_msg_hdr resp;
+
+  memset(&req, 0, sizeof(req));
+  req.hdr.type = TI_SCI_MSG_RM_IRQ_RELEASE;
+  req.valid_params = MSG_FLAG_DST_ID_VALID | MSG_FLAG_DST_HOST_IRQ_VALID;
+  req.src_id = src_id;
+  req.src_index = src_index;
+  req.dst_id = dst_id;
+  req.dst_host_irq = dst_host_irq;
+
+  return am62x_tisci_xfer(&req.hdr, sizeof(req), &resp, sizeof(resp));
+}
+
+int am62x_tisci_initialize(void)
+{
+  struct am62x_tisci_version_s ver;
+  int ret;
+
+  ret = am62x_tisci_get_version(&ver);
+
+  if (ret < 0)
+    {
+      _err("ERROR: TISCI version handshake failed: %d\n", ret);
+      return ret;
+    }
+
+  _info("AM62x TISCI: firmware \"%s\" rev %u ABI %u.%u\n",
+        ver.firmware_description, ver.firmware_revision,
+        ver.abi_major, ver.abi_minor);
+
+  return OK;
+}
+
diff --git a/arch/arm64/src/am62x/am62x_tisci.h 
b/arch/arm64/src/am62x/am62x_tisci.h
new file mode 100644
index 00000000000..fb922c1bc12
--- /dev/null
+++ b/arch/arm64/src/am62x/am62x_tisci.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/am62x_tisci.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.
+ *
+ ****************************************************************************/
+
+/* AM62x TISCI system-controller client.
+ *
+ * On K3 SoCs the A53 cluster does not directly own device power, clocks,
+ * resets, or interrupt routing.  Those are managed by the DM/TIFS firmware
+ * on the R5 and requested over the TISCI protocol via the secure-proxy
+ * mailbox.  This client provides the minimal request helpers other AM62x
+ * drivers use to power on a device, enable/set a functional clock, release
+ * resets, and route an interrupt through the interrupt router.
+ */
+
+#ifndef __ARCH_ARM64_SRC_AM62X_AM62X_TISCI_H
+#define __ARCH_ARM64_SRC_AM62X_AM62X_TISCI_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Selected TISCI device IDs (ti,sci-dev-id).
+ * Source: Linux arch/arm64/boot/dts/ti/k3-am62-main.dtsi.  Extend as drivers
+ * are added; the full list is in the TISCI device documentation for AM62x.
+ */
+
+#define AM62X_DEV_GPIOMUX_INTROUTER0  3    /* main_gpiomux_introuter0 */
+#define AM62X_DEV_GPIO0               77   /* main_gpio0 @ 0x00600000 */
+#define AM62X_DEV_GPIO1               78   /* main_gpio1 @ 0x00601000 */
+#define AM62X_DEV_I2C0                102  /* main_i2c0 @ 0x20000000 */
+#define AM62X_DEV_I2C1                103  /* main_i2c1 @ 0x20010000 */
+#define AM62X_DEV_I2C2                104  /* main_i2c2 @ 0x20020000 */
+#define AM62X_DEV_I2C3                105  /* main_i2c3 @ 0x20030000 */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct am62x_tisci_version_s
+{
+  uint16_t firmware_revision;
+  uint8_t  abi_major;
+  uint8_t  abi_minor;
+  char     firmware_description[33];   /* 32 chars + NUL terminator        */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Name: am62x_tisci_initialize
+ *
+ * Description:
+ *   Initialise the TISCI client and verify the secure-proxy link by
+ *   issuing a version handshake with the DM/TIFS firmware.  Must be called
+ *   once, before any other am62x_tisci_* helper, early in board bring-up.
+ *
+ * Returned Value:
+ *   OK on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_initialize(void);
+
+/****************************************************************************
+ * Name: am62x_tisci_get_version
+ *
+ * Description:
+ *   Query the running system firmware ABI version and description.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_get_version(struct am62x_tisci_version_s *ver);
+
+/****************************************************************************
+ * Name: am62x_tisci_set_device_state / am62x_tisci_get_device_state
+ *
+ * Description:
+ *   Set or query the software power state of a device (one of
+ *   MSG_DEVICE_SW_STATE_*).  get returns the current hardware state in
+ *   *current_state (one of MSG_DEVICE_HW_STATE_*).
+ *
+ ****************************************************************************/
+
+int am62x_tisci_set_device_state(uint32_t devid, uint8_t state);
+int am62x_tisci_get_device_state(uint32_t devid, uint8_t *current_state);
+
+/****************************************************************************
+ * Name: am62x_tisci_module_enable
+ *
+ * Description:
+ *   Power on a device, release all device-local resets, and request its
+ *   functional clock.  This is the normal sequence before a driver touches
+ *   AM62x/K3 peripheral registers.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_module_enable(uint32_t devid, uint32_t clkid);
+
+/****************************************************************************
+ * Name: am62x_tisci_set_device_resets
+ *
+ * Description:
+ *   Program the device-local reset lines (bitmask; 0 releases all resets).
+ *
+ ****************************************************************************/
+
+int am62x_tisci_set_device_resets(uint32_t devid, uint32_t resets);
+
+/****************************************************************************
+ * Name: am62x_tisci_set_clock_state / am62x_tisci_clk_enable
+ *
+ * Description:
+ *   Set a clock's software state (one of MSG_CLOCK_SW_STATE_*).
+ *   am62x_tisci_clk_enable is a wrapper that requests the clock on.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_set_clock_state(uint32_t devid, uint32_t clkid,
+                                uint8_t state);
+int am62x_tisci_clk_enable(uint32_t devid, uint32_t clkid);
+
+/****************************************************************************
+ * Name: am62x_tisci_set_clock_freq / am62x_tisci_get_clock_freq
+ *
+ * Description:
+ *   Request a target frequency for a clock, or read its current frequency.
+ *   set accepts the target in Hz and asks the firmware to honour it exactly.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_set_clock_freq(uint32_t devid, uint32_t clkid,
+                               uint64_t freq_hz);
+int am62x_tisci_get_clock_freq(uint32_t devid, uint32_t clkid,
+                               uint64_t *freq_hz);
+
+/****************************************************************************
+ * Name: am62x_tisci_irq_set / am62x_tisci_irq_release
+ *
+ * Description:
+ *   Program (or release) a route through an interrupt router so a peripheral
+ *   output interrupt reaches the A53 GIC.  src_id is the router's device id,
+ *   src_index its input line, dst_id the destination IRQ-controller device
+ *   id (the GIC), and dst_host_irq the destination GIC interrupt input.
+ *
+ ****************************************************************************/
+
+int am62x_tisci_irq_set(uint16_t src_id, uint16_t src_index,
+                        uint16_t dst_id, uint16_t dst_host_irq);
+int am62x_tisci_irq_release(uint16_t src_id, uint16_t src_index,
+                            uint16_t dst_id, uint16_t dst_host_irq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARCH_ARM64_SRC_AM62X_AM62X_TISCI_H */
diff --git a/arch/arm64/src/am62x/hardware/am62x_gpio.h 
b/arch/arm64/src/am62x/hardware/am62x_gpio.h
new file mode 100644
index 00000000000..fce39ff6188
--- /dev/null
+++ b/arch/arm64/src/am62x/hardware/am62x_gpio.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/hardware/am62x_gpio.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.
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_GPIO_H
+#define __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_GPIO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hardware/am62x_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define AM62X_GPIO_NBANKS                  2
+#define AM62X_GPIO_NPINS                   32
+
+#define AM62X_GPIO_BINTEN_OFFSET           0x0008
+
+/* AM62x main GPIO uses the Davinci/Keystone register layout.  The Linux
+ * binding for k3-am62-main.dtsi advertises compatible = "ti,am64-gpio",
+ * "ti,keystone-gpio" and a 0x100-byte register window.
+ */
+
+#define AM62X_GPIO_BANK_STRIDE             0x0028
+#define AM62X_GPIO_BANK_OFFSET(n)          (0x0010 + \
+                                            (n) * AM62X_GPIO_BANK_STRIDE)
+#define AM62X_GPIO_DIR_OFFSET(n)           (AM62X_GPIO_BANK_OFFSET(n) + 0x00)
+#define AM62X_GPIO_OUT_DATA_OFFSET(n)      (AM62X_GPIO_BANK_OFFSET(n) + 0x04)
+#define AM62X_GPIO_SET_DATA_OFFSET(n)      (AM62X_GPIO_BANK_OFFSET(n) + 0x08)
+#define AM62X_GPIO_CLR_DATA_OFFSET(n)      (AM62X_GPIO_BANK_OFFSET(n) + 0x0c)
+#define AM62X_GPIO_IN_DATA_OFFSET(n)       (AM62X_GPIO_BANK_OFFSET(n) + 0x10)
+#define AM62X_GPIO_SET_RIS_TRIG_OFFSET(n)  \
+                                            (AM62X_GPIO_BANK_OFFSET(n) + 0x14)
+#define AM62X_GPIO_CLR_RIS_TRIG_OFFSET(n)  \
+                                            (AM62X_GPIO_BANK_OFFSET(n) + 0x18)
+#define AM62X_GPIO_SET_FAL_TRIG_OFFSET(n)  \
+                                            (AM62X_GPIO_BANK_OFFSET(n) + 0x1c)
+#define AM62X_GPIO_CLR_FAL_TRIG_OFFSET(n)  \
+                                            (AM62X_GPIO_BANK_OFFSET(n) + 0x20)
+#define AM62X_GPIO_INTSTAT_OFFSET(n)       (AM62X_GPIO_BANK_OFFSET(n) + 0x24)
+
+#define AM62X_GPIO_BINTEN(b)               ((b) + AM62X_GPIO_BINTEN_OFFSET)
+#define AM62X_GPIO_DIR(b, n)               ((b) + AM62X_GPIO_DIR_OFFSET(n))
+#define AM62X_GPIO_OUT_DATA(b, n)          ((b) + 
AM62X_GPIO_OUT_DATA_OFFSET(n))
+#define AM62X_GPIO_SET_DATA(b, n)          ((b) + 
AM62X_GPIO_SET_DATA_OFFSET(n))
+#define AM62X_GPIO_CLR_DATA(b, n)          ((b) + 
AM62X_GPIO_CLR_DATA_OFFSET(n))
+#define AM62X_GPIO_IN_DATA(b, n)           ((b) + AM62X_GPIO_IN_DATA_OFFSET(n))
+#define AM62X_GPIO_SET_RIS_TRIG(b, n)      ((b) + 
AM62X_GPIO_SET_RIS_TRIG_OFFSET(n))
+#define AM62X_GPIO_CLR_RIS_TRIG(b, n)      ((b) + 
AM62X_GPIO_CLR_RIS_TRIG_OFFSET(n))
+#define AM62X_GPIO_SET_FAL_TRIG(b, n)      ((b) + 
AM62X_GPIO_SET_FAL_TRIG_OFFSET(n))
+#define AM62X_GPIO_CLR_FAL_TRIG(b, n)      ((b) + 
AM62X_GPIO_CLR_FAL_TRIG_OFFSET(n))
+#define AM62X_GPIO_INTSTAT(b, n)           ((b) + AM62X_GPIO_INTSTAT_OFFSET(n))
+
+#define AM62X_GPIO_BIT(n)                  (1u << ((n) & 31))
+
+#endif /* __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_GPIO_H */
diff --git a/arch/arm64/src/am62x/hardware/am62x_i2c.h 
b/arch/arm64/src/am62x/hardware/am62x_i2c.h
new file mode 100644
index 00000000000..80fb337c8e6
--- /dev/null
+++ b/arch/arm64/src/am62x/hardware/am62x_i2c.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/hardware/am62x_i2c.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.
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_I2C_H
+#define __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hardware/am62x_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define AM62X_I2C_REVNB_LO_OFFSET       0x0000
+#define AM62X_I2C_REVNB_HI_OFFSET       0x0004
+#define AM62X_I2C_SYSC_OFFSET           0x0010
+#define AM62X_I2C_IRQSTATUS_RAW_OFFSET  0x0024
+#define AM62X_I2C_IRQSTATUS_OFFSET      0x0028
+#define AM62X_I2C_IRQENABLE_SET_OFFSET  0x002c
+#define AM62X_I2C_IRQENABLE_CLR_OFFSET  0x0030
+#define AM62X_I2C_WE_OFFSET             0x0034
+#define AM62X_I2C_SYSS_OFFSET           0x0090
+#define AM62X_I2C_BUF_OFFSET            0x0094
+#define AM62X_I2C_CNT_OFFSET            0x0098
+#define AM62X_I2C_DATA_OFFSET           0x009c
+#define AM62X_I2C_CON_OFFSET            0x00a4
+#define AM62X_I2C_OA_OFFSET             0x00a8
+#define AM62X_I2C_SA_OFFSET             0x00ac
+#define AM62X_I2C_PSC_OFFSET            0x00b0
+#define AM62X_I2C_SCLL_OFFSET           0x00b4
+#define AM62X_I2C_SCLH_OFFSET           0x00b8
+#define AM62X_I2C_SYSTEST_OFFSET        0x00bc
+#define AM62X_I2C_BUFSTAT_OFFSET        0x00c0
+
+#define I2C_SYSC_AUTOIDLE               (1 << 0)
+#define I2C_SYSC_SRST                   (1 << 1)
+#define I2C_SYSS_RST_DONE               (1 << 0)
+
+#define I2C_BUF_TXFIFO_CLR              (1 << 6)
+#define I2C_BUF_RXFIFO_CLR              (1 << 14)
+
+#define I2C_IRQ_AL                      (1 << 0)
+#define I2C_IRQ_NACK                    (1 << 1)
+#define I2C_IRQ_ARDY                    (1 << 2)
+#define I2C_IRQ_RRDY                    (1 << 3)
+#define I2C_IRQ_XRDY                    (1 << 4)
+#define I2C_IRQ_GC                      (1 << 5)
+#define I2C_IRQ_STC                     (1 << 6)
+#define I2C_IRQ_AERR                    (1 << 7)
+#define I2C_IRQ_BF                      (1 << 8)
+#define I2C_IRQ_AAS                     (1 << 9)
+#define I2C_IRQ_XUDF                    (1 << 10)
+#define I2C_IRQ_ROVR                    (1 << 11)
+#define I2C_IRQ_BB                      (1 << 12)
+#define I2C_IRQ_RDR                     (1 << 13)
+#define I2C_IRQ_XDR                     (1 << 14)
+
+/* A transmit underflow is not fatal, it is signalled while the module holds
+ * the bus between the messages of a transfer.
+ */
+
+#define I2C_IRQ_ERRORMASK               (I2C_IRQ_AL | I2C_IRQ_NACK | \
+                                         I2C_IRQ_AERR | I2C_IRQ_ROVR)
+
+#define I2C_IRQ_CLEARMASK               (I2C_IRQ_AL | I2C_IRQ_NACK | \
+                                         I2C_IRQ_ARDY | I2C_IRQ_RRDY | \
+                                         I2C_IRQ_XRDY | I2C_IRQ_GC | \
+                                         I2C_IRQ_STC | I2C_IRQ_AERR | \
+                                         I2C_IRQ_BF | I2C_IRQ_AAS | \
+                                         I2C_IRQ_XUDF | I2C_IRQ_ROVR | \
+                                         I2C_IRQ_RDR | I2C_IRQ_XDR)
+
+#define I2C_DATA_MASK                   0xff
+
+#define I2C_CON_STT                     (1 << 0)
+#define I2C_CON_STP                     (1 << 1)
+#define I2C_CON_XSA                     (1 << 8)
+#define I2C_CON_TRX                     (1 << 9)
+#define I2C_CON_MST                     (1 << 10)
+#define I2C_CON_EN                      (1 << 15)
+
+#define I2C_SYSTEST_FREE                (1 << 14)
+
+#endif /* __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_I2C_H */
diff --git a/arch/arm64/src/am62x/hardware/am62x_memorymap.h 
b/arch/arm64/src/am62x/hardware/am62x_memorymap.h
index 4ff25cd3a8c..5189c196ceb 100644
--- a/arch/arm64/src/am62x/hardware/am62x_memorymap.h
+++ b/arch/arm64/src/am62x/hardware/am62x_memorymap.h
@@ -83,6 +83,21 @@
 #define AM62X_SPI1_BASE         0x20110000ul
 #define AM62X_SPI2_BASE         0x20120000ul
 
+/* Secure Proxy (TISCI transport to the DM/TIFS system firmware).
+ * Three 512 KB regions of per-thread 0x1000-stride windows.
+ * Source: Linux k3-am62-main.dtsi (secure_proxy_main).
+ */
+
+#define AM62X_SEC_PROXY_DATA_BASE  0x4d000000ul  /* "target_data" region    */
+#define AM62X_SEC_PROXY_RT_BASE    0x4a600000ul  /* "rt" (status) region    */
+#define AM62X_SEC_PROXY_SCFG_BASE  0x4a400000ul  /* "scfg" (config) region  */
+
+/* DMSC / TIFS system controller (TISCI message target).
+ * Source: Linux k3-am62-main.dtsi (dmsc: system-controller@44043000).
+ */
+
+#define AM62X_DMSC_BASE            0x44043000ul
+
 /* USB */
 
 #define AM62X_USB0_BASE         0x31100000ul
@@ -99,10 +114,10 @@
 #define AM62X_WDT0_BASE         0x23100000ul
 #define AM62X_WDT1_BASE         0x23110000ul
 
-/* CTRL_MMR (Pad config / system control) */
+/* CTRL_MMR (system control) and main-domain pad config */
 
 #define AM62X_CTRLMMR_BASE      0x000f0000ul
-#define AM62X_PADCFG_BASE       0x000f0000ul
+#define AM62X_PADCFG_BASE       0x000f4000ul
 
 /* DDR Base (512 MB on PocketBeagle 2 / BeaglePlay) */
 
diff --git a/arch/arm64/src/am62x/hardware/am62x_secure_proxy.h 
b/arch/arm64/src/am62x/hardware/am62x_secure_proxy.h
new file mode 100644
index 00000000000..3794a32971e
--- /dev/null
+++ b/arch/arm64/src/am62x/hardware/am62x_secure_proxy.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/hardware/am62x_secure_proxy.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.
+ *
+ ****************************************************************************/
+
+/* AM62x Secure Proxy register layout.
+ *
+ * The secure proxy is the mailbox transport used to exchange TISCI messages
+ * between the A53 (running NuttX) and the DM/TIFS system firmware on the R5.
+ * Each "thread" is a unidirectional message queue.  A thread occupies a
+ * 0x1000-stride window in each of two regions used here:
+ *
+ *   - "target_data" : the message payload, 15 data words per thread
+ *                     (registers 0..14 at byte offsets 0x4..0x3c).  Writing
+ *                     the last word (offset 0x3c) commits the message;
+ *                     an RX thread consumes its message by reading it.
+ *   - "rt"          : per-thread status; bits[7:0] hold the credit/message
+ *                     count and bit31 flags a thread error.
+ *
+ * The "scfg" region carries per-thread direction config and is not needed
+ * for fixed-direction synchronous request/response operation, so it is
+ * omitted.
+ *
+ * Source: Linux drivers/mailbox/ti-msgmgr.c (k3_secure_proxy_desc and the
+ *         SPROXY_THREAD_* macros) and U-Boot drivers/mailbox/k3-sec-proxy.c.
+ */
+
+#ifndef __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_SECURE_PROXY_H
+#define __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_SECURE_PROXY_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "hardware/am62x_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Per-thread window stride within each region */
+
+#define AM62X_SEC_PROXY_THREAD_STRIDE  0x1000ul
+
+/* target_data region: 15 message words (registers 0..14).
+ * Word "reg" of thread "tid" lives at:
+ *   AM62X_SEC_PROXY_DATA_BASE + tid*0x1000 + 0x4 + reg*4
+ * giving the data window 0x4 .. 0x3c (60 bytes maximum per message).
+ */
+
+#define AM62X_SEC_PROXY_MSG_WORDS      15
+#define AM62X_SEC_PROXY_MAX_MSG_SIZE   60
+#define AM62X_SEC_PROXY_DATA_START     0x4ul   /* offset of word 0          */
+#define AM62X_SEC_PROXY_DATA_END       0x3cul  /* offset of word 14 (commit)*/
+
+/* rt region: per-thread status register at the thread base */
+
+#define AM62X_SEC_PROXY_RT_STATUS      0x0ul
+#define AM62X_SEC_PROXY_RT_CNT_MASK    0xfful       /* [7:0]  credit count   */
+#define AM62X_SEC_PROXY_RT_ERR         (1ul << 31)  /* [31]   thread error   */
+
+/* Region base for a given thread id */
+
+#define AM62X_SEC_PROXY_DATA(tid)    \
+  (AM62X_SEC_PROXY_DATA_BASE + (uintptr_t)(tid) * 
AM62X_SEC_PROXY_THREAD_STRIDE)
+#define AM62X_SEC_PROXY_RT(tid)      \
+  (AM62X_SEC_PROXY_RT_BASE + (uintptr_t)(tid) * AM62X_SEC_PROXY_THREAD_STRIDE)
+
+#endif /* __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_SECURE_PROXY_H */
diff --git a/arch/arm64/src/am62x/hardware/am62x_tisci_proto.h 
b/arch/arm64/src/am62x/hardware/am62x_tisci_proto.h
new file mode 100644
index 00000000000..b0c413c885f
--- /dev/null
+++ b/arch/arm64/src/am62x/hardware/am62x_tisci_proto.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+ * arch/arm64/src/am62x/hardware/am62x_tisci_proto.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.
+ *
+ ****************************************************************************/
+
+/* TISCI (Texas Instruments System Control Interface) message protocol
+ * definitions for AM62x.  Only the subset used by the NuttX TISCI client is
+ * declared here.  Message IDs, flag bits, and on-the-wire structure layouts
+ * mirror the canonical definitions in Linux drivers/firmware/ti_sci.h.
+ */
+
+#ifndef __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_TISCI_PROTO_H
+#define __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_TISCI_PROTO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* TISCI message type IDs */
+
+#define TI_SCI_MSG_VERSION            0x0002
+#define TI_SCI_MSG_SET_CLOCK_STATE    0x0100
+#define TI_SCI_MSG_GET_CLOCK_STATE    0x0101
+#define TI_SCI_MSG_SET_CLOCK_FREQ     0x010c
+#define TI_SCI_MSG_GET_CLOCK_FREQ     0x010e
+#define TI_SCI_MSG_SET_DEVICE_STATE   0x0200
+#define TI_SCI_MSG_GET_DEVICE_STATE   0x0201
+#define TI_SCI_MSG_SET_DEVICE_RESETS  0x0202
+#define TI_SCI_MSG_RM_IRQ_SET         0x1000
+#define TI_SCI_MSG_RM_IRQ_RELEASE     0x1001
+
+/* Message header flags */
+
+#define TI_SCI_MSG_FLAG(val)              (1u << (val))
+#define TI_SCI_FLAG_REQ_GENERIC_NORESP    0x0
+#define TI_SCI_FLAG_REQ_ACK_ON_RECEIVED   TI_SCI_MSG_FLAG(0)
+#define TI_SCI_FLAG_REQ_ACK_ON_PROCESSED  TI_SCI_MSG_FLAG(1)
+#define TI_SCI_FLAG_RESP_GENERIC_NACK     0x0
+#define TI_SCI_FLAG_RESP_GENERIC_ACK      TI_SCI_MSG_FLAG(1)
+
+/* Device-state request: software state values and header flag options */
+
+#define MSG_DEVICE_SW_STATE_AUTO_OFF      0
+#define MSG_DEVICE_SW_STATE_RETENTION     1
+#define MSG_DEVICE_SW_STATE_ON            2
+
+#define MSG_FLAG_DEVICE_WAKE_ENABLED      TI_SCI_MSG_FLAG(8)
+#define MSG_FLAG_DEVICE_RESET_ISO         TI_SCI_MSG_FLAG(9)
+#define MSG_FLAG_DEVICE_EXCLUSIVE         TI_SCI_MSG_FLAG(10)
+
+/* Device-state response: hardware state values */
+
+#define MSG_DEVICE_HW_STATE_OFF           0
+#define MSG_DEVICE_HW_STATE_ON            1
+#define MSG_DEVICE_HW_STATE_TRANS         2
+
+/* Clock-state request: software state values and header flag options */
+
+#define MSG_CLOCK_SW_STATE_UNREQ          0
+#define MSG_CLOCK_SW_STATE_AUTO           1
+#define MSG_CLOCK_SW_STATE_REQ            2
+
+#define MSG_FLAG_CLOCK_ALLOW_SSC          TI_SCI_MSG_FLAG(8)
+#define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE  TI_SCI_MSG_FLAG(9)
+#define MSG_FLAG_CLOCK_INPUT_TERM         TI_SCI_MSG_FLAG(10)
+
+/* When a clk_id does not fit in the 8-bit clk_id field, it is set to 255 and
+ * the real id is carried in the 32-bit clk_id_32 field.
+ */
+
+#define TI_SCI_CLOCK_ID_INDIRECT          255
+
+/* Resource-management IRQ request: valid_params bit flags */
+
+#define MSG_FLAG_DST_ID_VALID             TI_SCI_MSG_FLAG(0)
+#define MSG_FLAG_DST_HOST_IRQ_VALID       TI_SCI_MSG_FLAG(1)
+#define MSG_FLAG_IA_ID_VALID              TI_SCI_MSG_FLAG(2)
+#define MSG_FLAG_VINT_VALID               TI_SCI_MSG_FLAG(3)
+#define MSG_FLAG_GLB_EVNT_VALID           TI_SCI_MSG_FLAG(4)
+#define MSG_FLAG_VINT_STS_BIT_VALID       TI_SCI_MSG_FLAG(5)
+#define MSG_FLAG_SHOST_VALID              TI_SCI_MSG_FLAG(31)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Common message header (prefixes every request and response) */
+
+begin_packed_struct struct ti_sci_msg_hdr
+{
+  uint16_t type;
+  uint8_t  host;
+  uint8_t  seq;
+  uint32_t flags;
+} end_packed_struct;
+
+/* TI_SCI_MSG_VERSION */
+
+begin_packed_struct struct ti_sci_msg_resp_version
+{
+  struct ti_sci_msg_hdr hdr;
+  char     firmware_description[32];
+  uint16_t firmware_revision;
+  uint8_t  abi_major;
+  uint8_t  abi_minor;
+} end_packed_struct;
+
+/* TI_SCI_MSG_SET_DEVICE_STATE / GET_DEVICE_STATE */
+
+begin_packed_struct struct ti_sci_msg_req_set_device_state
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t id;
+  uint32_t reserved;
+  uint8_t  state;
+} end_packed_struct;
+
+begin_packed_struct struct ti_sci_msg_req_get_device_state
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t id;
+} end_packed_struct;
+
+begin_packed_struct struct ti_sci_msg_resp_get_device_state
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t context_loss_count;
+  uint32_t resets;
+  uint8_t  programmed_state;
+  uint8_t  current_state;
+} end_packed_struct;
+
+/* TI_SCI_MSG_SET_DEVICE_RESETS */
+
+begin_packed_struct struct ti_sci_msg_req_set_device_resets
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t id;
+  uint32_t resets;
+} end_packed_struct;
+
+/* TI_SCI_MSG_SET_CLOCK_STATE */
+
+begin_packed_struct struct ti_sci_msg_req_set_clock_state
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t dev_id;
+  uint8_t  clk_id;
+  uint8_t  request_state;
+  uint32_t clk_id_32;
+} end_packed_struct;
+
+/* TI_SCI_MSG_SET_CLOCK_FREQ */
+
+begin_packed_struct struct ti_sci_msg_req_set_clock_freq
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t dev_id;
+  uint64_t min_freq_hz;
+  uint64_t target_freq_hz;
+  uint64_t max_freq_hz;
+  uint8_t  clk_id;
+  uint32_t clk_id_32;
+} end_packed_struct;
+
+/* TI_SCI_MSG_GET_CLOCK_FREQ */
+
+begin_packed_struct struct ti_sci_msg_req_get_clock_freq
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t dev_id;
+  uint8_t  clk_id;
+  uint32_t clk_id_32;
+} end_packed_struct;
+
+begin_packed_struct struct ti_sci_msg_resp_get_clock_freq
+{
+  struct ti_sci_msg_hdr hdr;
+  uint64_t freq_hz;
+} end_packed_struct;
+
+/* TI_SCI_MSG_RM_IRQ_SET / RM_IRQ_RELEASE */
+
+begin_packed_struct struct ti_sci_msg_req_manage_irq
+{
+  struct ti_sci_msg_hdr hdr;
+  uint32_t valid_params;
+  uint16_t src_id;
+  uint16_t src_index;
+  uint16_t dst_id;
+  uint16_t dst_host_irq;
+  uint16_t ia_id;
+  uint16_t vint;
+  uint16_t global_event;
+  uint8_t  vint_status_bit;
+  uint8_t  secondary_host;
+} end_packed_struct;
+
+#endif /* __ARCH_ARM64_SRC_AM62X_HARDWARE_AM62X_TISCI_PROTO_H */
diff --git a/boards/arm64/am62x/beagleplay/configs/nsh/defconfig 
b/boards/arm64/am62x/beagleplay/configs/i2c/defconfig
similarity index 93%
copy from boards/arm64/am62x/beagleplay/configs/nsh/defconfig
copy to boards/arm64/am62x/beagleplay/configs/i2c/defconfig
index 649e9eefff8..e40bfa7d5c4 100644
--- a/boards/arm64/am62x/beagleplay/configs/nsh/defconfig
+++ b/boards/arm64/am62x/beagleplay/configs/i2c/defconfig
@@ -16,6 +16,10 @@ CONFIG_16550_UART0_IRQ=210
 CONFIG_16550_UART0_RX_TRIGGER=0
 CONFIG_16550_UART0_SERIAL_CONSOLE=y
 CONFIG_16550_UART=y
+CONFIG_AM62X_GPIO=y
+CONFIG_AM62X_I2C0=y
+CONFIG_AM62X_I2C1=y
+CONFIG_AM62X_TISCI=y
 CONFIG_ARCH="arm64"
 CONFIG_ARCH_ARM64=y
 CONFIG_ARCH_BOARD="beagleplay"
@@ -38,6 +42,7 @@ CONFIG_DEFAULT_TASK_STACKSIZE=8192
 CONFIG_FS_PROCFS=y
 CONFIG_HAVE_CXX=y
 CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_I2C=y
 CONFIG_IDLETHREAD_STACKSIZE=8192
 CONFIG_INIT_ENTRYPOINT="nsh_main"
 CONFIG_INTELHEX_BINARY=y
@@ -59,5 +64,6 @@ CONFIG_SERIAL_UART_ARCH_MMIO=y
 CONFIG_SPINLOCK=y
 CONFIG_STACK_COLORATION=y
 CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_I2CTOOL=y
 CONFIG_SYSTEM_NSH=y
 CONFIG_USEC_PER_TICK=1000
diff --git a/boards/arm64/am62x/beagleplay/configs/nsh/defconfig 
b/boards/arm64/am62x/beagleplay/configs/nsh/defconfig
index 649e9eefff8..287af7ace63 100644
--- a/boards/arm64/am62x/beagleplay/configs/nsh/defconfig
+++ b/boards/arm64/am62x/beagleplay/configs/nsh/defconfig
@@ -16,6 +16,8 @@ CONFIG_16550_UART0_IRQ=210
 CONFIG_16550_UART0_RX_TRIGGER=0
 CONFIG_16550_UART0_SERIAL_CONSOLE=y
 CONFIG_16550_UART=y
+CONFIG_AM62X_GPIO=y
+CONFIG_AM62X_TISCI=y
 CONFIG_ARCH="arm64"
 CONFIG_ARCH_ARM64=y
 CONFIG_ARCH_BOARD="beagleplay"
diff --git a/boards/arm64/am62x/beagleplay/include/board_memorymap.h 
b/boards/arm64/am62x/beagleplay/include/board_memorymap.h
index feae2717055..24969085a22 100644
--- a/boards/arm64/am62x/beagleplay/include/board_memorymap.h
+++ b/boards/arm64/am62x/beagleplay/include/board_memorymap.h
@@ -3,6 +3,21 @@
  *
  * 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.
+ *
  * BeaglePlay (AM6254) — 2 GB LPDDR4 at 0x8000_0000.
  * NuttX load address = 0x8200_0000 to avoid the DDR region reserved by
  * the BeagleBoard.org U-Boot environment.
diff --git a/boards/arm64/am62x/beagleplay/scripts/dramboot.ld 
b/boards/arm64/am62x/beagleplay/scripts/dramboot.ld
index 36a47d4aba6..13fa89ada27 100644
--- a/boards/arm64/am62x/beagleplay/scripts/dramboot.ld
+++ b/boards/arm64/am62x/beagleplay/scripts/dramboot.ld
@@ -3,6 +3,21 @@
  *
  * 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.
+ *
  * BeaglePlay (AM6254) linker script.
  * Load address 0x8200_0000 avoids U-Boot reserved region at DDR base.
  * Identical in structure to the PocketBeagle 2 script; kept separate so
diff --git a/boards/arm64/am62x/beagleplay/src/beagleplay_bringup.c 
b/boards/arm64/am62x/beagleplay/src/beagleplay_bringup.c
index 545242ba0b8..5fd5cf54007 100644
--- a/boards/arm64/am62x/beagleplay/src/beagleplay_bringup.c
+++ b/boards/arm64/am62x/beagleplay/src/beagleplay_bringup.c
@@ -25,16 +25,52 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/kmalloc.h>
+
 #include <sys/types.h>
 #include <syslog.h>
 #include <errno.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+#include "am62x_gpio.h"
+#include "am62x_i2c.h"
+#include "am62x_tisci.h"
 #include "beagleplay.h"
 
 #ifdef CONFIG_FS_PROCFS
 #  include <nuttx/fs/fs.h>
 #endif
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if defined(CONFIG_I2C_DRIVER) && \
+    (defined(CONFIG_AM62X_I2C0) || defined(CONFIG_AM62X_I2C1))
+static int am62x_i2cdev_register(int bus)
+{
+  struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = am62x_i2cbus_initialize(bus);
+  if (i2c == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize I2C%d\n", bus);
+      return -ENODEV;
+    }
+
+  ret = i2c_register(i2c, bus);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register /dev/i2c%d: %d\n",
+             bus, ret);
+      am62x_i2cbus_uninitialize(i2c);
+    }
+
+  return ret;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -44,13 +80,7 @@
  *
  * Description:
  *   Bring up board features after the scheduler and device drivers are
- *   initialised.  This is the right place to:
- *     - Mount pseudo file systems (procfs, etc.)
- *     - Register I2C / SPI bus instances
- *     - Attach sensor drivers
- *
- *   Phase 1 only mounts procfs — additional drivers will be added as the
- *   port matures.
+ *   initialised.
  *
  * Returned Value:
  *   Zero (OK) on success; a negated errno on failure.  Non-fatal errors
@@ -63,8 +93,6 @@ int beagleplay_bringup(void)
   int ret = OK;
 
 #ifdef CONFIG_FS_PROCFS
-  /* Mount the process filesystem at /proc */
-
   ret = nx_mount(NULL, "/proc", "procfs", 0, NULL);
   if (ret < 0)
     {
@@ -73,5 +101,41 @@ int beagleplay_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_AM62X_TISCI
+  /* Bring up the TISCI link first: peripheral power, clocks, resets, and
+   * interrupt routing are requested from the DM/TIFS firmware through it.
+   */
+
+  ret = am62x_tisci_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize TISCI: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_AM62X_GPIO
+  ret = am62x_gpio_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize GPIO: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_I2C_DRIVER) && defined(CONFIG_AM62X_I2C0)
+  ret = am62x_i2cdev_register(0);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to bring up I2C0: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_I2C_DRIVER) && defined(CONFIG_AM62X_I2C1)
+  ret = am62x_i2cdev_register(1);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to bring up I2C1: %d\n", ret);
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig 
b/boards/arm64/am62x/pocketbeagle2/configs/i2c/defconfig
similarity index 93%
copy from boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig
copy to boards/arm64/am62x/pocketbeagle2/configs/i2c/defconfig
index 49c8c45affd..be5dc666f8d 100644
--- a/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig
+++ b/boards/arm64/am62x/pocketbeagle2/configs/i2c/defconfig
@@ -17,6 +17,10 @@ CONFIG_16550_UART0_IRQ=216
 CONFIG_16550_UART0_RX_TRIGGER=0
 CONFIG_16550_UART0_SERIAL_CONSOLE=y
 CONFIG_16550_UART=y
+CONFIG_AM62X_GPIO=y
+CONFIG_AM62X_I2C0=y
+CONFIG_AM62X_I2C2=y
+CONFIG_AM62X_TISCI=y
 CONFIG_ARCH="arm64"
 CONFIG_ARCH_ARM64=y
 CONFIG_ARCH_BOARD="pocketbeagle2"
@@ -39,6 +43,7 @@ CONFIG_DEFAULT_TASK_STACKSIZE=8192
 CONFIG_FS_PROCFS=y
 CONFIG_HAVE_CXX=y
 CONFIG_HAVE_CXXINITIALIZE=y
+CONFIG_I2C=y
 CONFIG_IDLETHREAD_STACKSIZE=8192
 CONFIG_INIT_ENTRYPOINT="nsh_main"
 CONFIG_INTELHEX_BINARY=y
@@ -61,5 +66,6 @@ CONFIG_SERIAL_UART_ARCH_MMIO=y
 CONFIG_SPINLOCK=y
 CONFIG_STACK_COLORATION=y
 CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_I2CTOOL=y
 CONFIG_SYSTEM_NSH=y
 CONFIG_USEC_PER_TICK=1000
diff --git a/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig 
b/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig
index 49c8c45affd..d2bcd1603d1 100644
--- a/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig
+++ b/boards/arm64/am62x/pocketbeagle2/configs/nsh/defconfig
@@ -17,6 +17,8 @@ CONFIG_16550_UART0_IRQ=216
 CONFIG_16550_UART0_RX_TRIGGER=0
 CONFIG_16550_UART0_SERIAL_CONSOLE=y
 CONFIG_16550_UART=y
+CONFIG_AM62X_GPIO=y
+CONFIG_AM62X_TISCI=y
 CONFIG_ARCH="arm64"
 CONFIG_ARCH_ARM64=y
 CONFIG_ARCH_BOARD="pocketbeagle2"
diff --git a/boards/arm64/am62x/pocketbeagle2/include/board.h 
b/boards/arm64/am62x/pocketbeagle2/include/board.h
index a89fe5ddc18..ebdd8b54846 100644
--- a/boards/arm64/am62x/pocketbeagle2/include/board.h
+++ b/boards/arm64/am62x/pocketbeagle2/include/board.h
@@ -52,24 +52,25 @@
 
 /* LED definitions *********************************************************
  *
- * PocketBeagle 2 user LEDs are connected to GPIO pins on the AM6254.
- * The exact GPIO numbers will be finalised when the GPIO driver is added;
- * these defines are placeholders so board code can compile now.
- *
- * LED index   Colour   Net name
- *   0          USR0     Green
- *   1          USR1     Yellow/Amber
- *   2          USR2     Red
+ * The PocketBeagle 2 user LEDs are on main GPIO0 lines 3-6.
  */
 
 #define BOARD_LED_USR0      0
 #define BOARD_LED_USR1      1
 #define BOARD_LED_USR2      2
-#define BOARD_NLEDS         3
+#define BOARD_LED_USR3      3
+#define BOARD_NLEDS         4
 
 #define BOARD_LED_USR0_BIT  (1 << BOARD_LED_USR0)
 #define BOARD_LED_USR1_BIT  (1 << BOARD_LED_USR1)
 #define BOARD_LED_USR2_BIT  (1 << BOARD_LED_USR2)
+#define BOARD_LED_USR3_BIT  (1 << BOARD_LED_USR3)
+
+/* GPIO test devices ********************************************************/
+
+#define BOARD_NGPIOOUT      4
+#define BOARD_NGPIOIN       0
+#define BOARD_NGPIOINT      0
 
 /* LED encoded OS states (used when CONFIG_ARCH_LEDS is set) ***************
  *
diff --git a/boards/arm64/am62x/pocketbeagle2/src/CMakeLists.txt 
b/boards/arm64/am62x/pocketbeagle2/src/CMakeLists.txt
index 597a32711ed..836f7071357 100644
--- a/boards/arm64/am62x/pocketbeagle2/src/CMakeLists.txt
+++ b/boards/arm64/am62x/pocketbeagle2/src/CMakeLists.txt
@@ -26,4 +26,8 @@ if(CONFIG_ARCH_LEDS)
   list(APPEND SRCS pocketbeagle2_autoleds.c)
 endif()
 
+if(CONFIG_DEV_GPIO)
+  list(APPEND SRCS pocketbeagle2_gpio.c)
+endif()
+
 target_sources(board PRIVATE ${SRCS})
diff --git a/boards/arm64/am62x/pocketbeagle2/src/Makefile 
b/boards/arm64/am62x/pocketbeagle2/src/Makefile
index 4b1f0e1cb4b..c97327daf4c 100644
--- a/boards/arm64/am62x/pocketbeagle2/src/Makefile
+++ b/boards/arm64/am62x/pocketbeagle2/src/Makefile
@@ -32,4 +32,8 @@ ifeq ($(CONFIG_ARCH_LEDS),y)
 CSRCS += pocketbeagle2_autoleds.c
 endif
 
+ifeq ($(CONFIG_DEV_GPIO),y)
+CSRCS += pocketbeagle2_gpio.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h 
b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
index fe1f462d65d..4d24d8f1829 100644
--- a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
+++ b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2.h
@@ -71,6 +71,18 @@ int pocketbeagle2_bringup(void);
 void pocketbeagle2_led_initialize(void);
 #endif
 
+/****************************************************************************
+ * Name: pocketbeagle2_gpio_initialize
+ *
+ * Description:
+ *   Register board GPIO test devices under /dev/gpioN.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
+int pocketbeagle2_gpio_initialize(void);
+#endif
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_bringup.c 
b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_bringup.c
index 60334ad1566..fce281387fb 100644
--- a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_bringup.c
+++ b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_bringup.c
@@ -25,17 +25,95 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
-#include <nuttx/kmalloc.h>
+
 #include <sys/types.h>
 #include <syslog.h>
 #include <errno.h>
 
+#include <nuttx/i2c/i2c_master.h>
+
+#include "am62x_gpio.h"
+#include "am62x_i2c.h"
+#include "am62x_tisci.h"
 #include "pocketbeagle2.h"
 
 #ifdef CONFIG_FS_PROCFS
 #  include <nuttx/fs/fs.h>
 #endif
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if defined(CONFIG_I2C_DRIVER) && \
+    (defined(CONFIG_AM62X_I2C0) || defined(CONFIG_AM62X_I2C2))
+static int am62x_i2cdev_register(int bus)
+{
+  struct i2c_master_s *i2c;
+  int ret;
+
+  i2c = am62x_i2cbus_initialize(bus);
+  if (i2c == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize I2C%d\n", bus);
+      return -ENODEV;
+    }
+
+  ret = i2c_register(i2c, bus);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register /dev/i2c%d: %d\n",
+             bus, ret);
+      am62x_i2cbus_uninitialize(i2c);
+    }
+
+  return ret;
+}
+#endif
+
+#if defined(CONFIG_AM62X_I2C0) || defined(CONFIG_AM62X_I2C2)
+static int pocketbeagle2_i2c_pinmux(void)
+{
+  int ret;
+
+#ifdef CONFIG_AM62X_I2C0
+  uint32_t i2c0_cfg = AM62X_PADCFG_RXACTIVE | AM62X_PADCFG_PULL_UP |
+                      AM62X_PADCFG_MUXMODE(0);
+
+  ret = am62x_pinmux_configure(0x01e0, i2c0_cfg); /* I2C0_SCL */
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = am62x_pinmux_configure(0x01e4, i2c0_cfg); /* I2C0_SDA */
+  if (ret < 0)
+    {
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_AM62X_I2C2
+  uint32_t i2c2_cfg = AM62X_PADCFG_RXACTIVE | AM62X_PADCFG_PULL_UP |
+                      AM62X_PADCFG_MUXMODE(1);
+
+  ret = am62x_pinmux_configure(0x00b0, i2c2_cfg); /* P1.28 I2C2_SCL */
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = am62x_pinmux_configure(0x00b4, i2c2_cfg); /* P1.26 I2C2_SDA */
+  if (ret < 0)
+    {
+      return ret;
+    }
+#endif
+
+  return OK;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -45,13 +123,7 @@
  *
  * Description:
  *   Bring up board features after the scheduler and device drivers are
- *   initialised.  This is the right place to:
- *     - Mount pseudo file systems (procfs, etc.)
- *     - Register I2C / SPI bus instances
- *     - Attach sensor drivers
- *
- *   Phase 1 only mounts procfs — additional drivers will be added as the
- *   port matures.
+ *   initialised.
  *
  * Returned Value:
  *   Zero (OK) on success; a negated errno on failure.  Non-fatal errors
@@ -64,8 +136,6 @@ int pocketbeagle2_bringup(void)
   int ret = OK;
 
 #ifdef CONFIG_FS_PROCFS
-  /* Mount the process filesystem at /proc */
-
   ret = nx_mount(NULL, "/proc", "procfs", 0, NULL);
   if (ret < 0)
     {
@@ -74,13 +144,57 @@ int pocketbeagle2_bringup(void)
     }
 #endif
 
-  /* TODO Phase 2:
-   *   I2C bus registration (am62x I2C0/I2C1)
-   *   SPI bus registration (am62x SPI0)
-   *   MMC/SD registration (am62x MMCSD0 / MMCSD1)
-   *   GPIO driver registration
-   *   USB device/host registration
+#ifdef CONFIG_AM62X_TISCI
+  /* Bring up the TISCI link first: peripheral power, clocks, resets, and
+   * interrupt routing are requested from the DM/TIFS firmware through it.
    */
 
+  ret = am62x_tisci_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize TISCI: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_AM62X_GPIO
+  ret = am62x_gpio_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize GPIO: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
+  ret = pocketbeagle2_gpio_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register GPIO devices: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_AM62X_I2C0) || defined(CONFIG_AM62X_I2C2)
+  ret = pocketbeagle2_i2c_pinmux();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to configure I2C pinmux: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_I2C_DRIVER) && defined(CONFIG_AM62X_I2C0)
+  ret = am62x_i2cdev_register(0);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to bring up I2C0: %d\n", ret);
+    }
+#endif
+
+#if defined(CONFIG_I2C_DRIVER) && defined(CONFIG_AM62X_I2C2)
+  ret = am62x_i2cdev_register(2);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to bring up I2C2: %d\n", ret);
+    }
+#endif
+
   return ret;
 }
diff --git a/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_gpio.c 
b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_gpio.c
new file mode 100644
index 00000000000..db72e528507
--- /dev/null
+++ b/boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_gpio.c
@@ -0,0 +1,165 @@
+/****************************************************************************
+ * boards/arm64/am62x/pocketbeagle2/src/pocketbeagle2_gpio.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 <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <nuttx/ioexpander/gpio.h>
+
+#include <arch/board/board.h>
+
+#include "am62x_gpio.h"
+#include "pocketbeagle2.h"
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define PB2_GPIO_OUT_FLAGS       (AM62X_GPIO_OUTPUT | AM62X_GPIO_PULL_NONE)
+#define PB2_LED_PADCFG           (AM62X_PADCFG_PULL_DISABLE | \
+                                  AM62X_PADCFG_MUXMODE(7))
+#define PB2_PADCFG_GPIO0_3       0x000c
+#define PB2_PADCFG_GPIO0_4       0x0010
+#define PB2_PADCFG_GPIO0_5       0x0014
+#define PB2_PADCFG_GPIO0_6       0x0018
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct pocketbeagle2_gpio_dev_s
+{
+  struct gpio_dev_s gpio;
+  uint8_t id;
+};
+
+struct pocketbeagle2_gpio_pin_s
+{
+  gpio_pinset_t pinset;
+  uintptr_t padcfg;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int gpout_read(struct gpio_dev_s *dev, bool *value);
+static int gpout_write(struct gpio_dev_s *dev, bool value);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct gpio_operations_s gpout_ops =
+{
+  .go_read = gpout_read,
+  .go_write = gpout_write,
+  .go_attach = NULL,
+  .go_enable = NULL,
+};
+
+static const struct pocketbeagle2_gpio_pin_s g_gpiooutputs[BOARD_NGPIOOUT] =
+{
+  { AM62X_GPIO_PIN(0, 3) | PB2_GPIO_OUT_FLAGS, PB2_PADCFG_GPIO0_3 },
+  { AM62X_GPIO_PIN(0, 4) | PB2_GPIO_OUT_FLAGS, PB2_PADCFG_GPIO0_4 },
+  { AM62X_GPIO_PIN(0, 5) | PB2_GPIO_OUT_FLAGS, PB2_PADCFG_GPIO0_5 },
+  { AM62X_GPIO_PIN(0, 6) | PB2_GPIO_OUT_FLAGS, PB2_PADCFG_GPIO0_6 },
+};
+
+static struct pocketbeagle2_gpio_dev_s g_gpout[BOARD_NGPIOOUT];
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int gpout_read(struct gpio_dev_s *dev, bool *value)
+{
+  struct pocketbeagle2_gpio_dev_s *pb2gpio =
+    (struct pocketbeagle2_gpio_dev_s *)dev;
+
+  DEBUGASSERT(pb2gpio != NULL);
+  DEBUGASSERT(value != NULL);
+  DEBUGASSERT(pb2gpio->id < BOARD_NGPIOOUT);
+
+  *value = am62x_gpiooutread(g_gpiooutputs[pb2gpio->id].pinset);
+  return OK;
+}
+
+static int gpout_write(struct gpio_dev_s *dev, bool value)
+{
+  struct pocketbeagle2_gpio_dev_s *pb2gpio =
+    (struct pocketbeagle2_gpio_dev_s *)dev;
+
+  DEBUGASSERT(pb2gpio != NULL);
+  DEBUGASSERT(pb2gpio->id < BOARD_NGPIOOUT);
+
+  am62x_gpiowrite(g_gpiooutputs[pb2gpio->id].pinset, value);
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int pocketbeagle2_gpio_initialize(void)
+{
+  int i;
+  int ret;
+
+  for (i = 0; i < BOARD_NGPIOOUT; i++)
+    {
+      ret = am62x_pinmux_configure(g_gpiooutputs[i].padcfg, PB2_LED_PADCFG);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      ret = am62x_configgpio(g_gpiooutputs[i].pinset);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN;
+      g_gpout[i].gpio.gp_ops = &gpout_ops;
+      g_gpout[i].id = i;
+
+      ret = gpio_pin_register(&g_gpout[i].gpio,
+                              AM62X_GPIO_LINE(g_gpiooutputs[i].pinset));
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  return OK;
+}
+
+#endif /* defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF) */

Reply via email to