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) */