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 <piyushpatle228@gmail.com>
This commit is contained in:
Piyush Patle 2026-05-31 18:33:58 +05:30
parent 2cb7b7c03e
commit c82a48d45b
31 changed files with 3268 additions and 59 deletions

View file

@ -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``.

View file

@ -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``.

View file

@ -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
================

View file

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

View file

@ -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)

View file

@ -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

View file

@ -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).

View file

@ -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;
}

View file

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

View file

@ -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;
}

View file

@ -0,0 +1,40 @@
/****************************************************************************
* arch/arm64/src/am62x/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_AM62X_I2C_H
#define __ARCH_ARM64_SRC_AM62X_AM62X_I2C_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/i2c/i2c_master.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct i2c_master_s *am62x_i2cbus_initialize(int port);
int am62x_i2cbus_uninitialize(struct i2c_master_s *dev);
#endif /* __ARCH_ARM64_SRC_AM62X_AM62X_I2C_H */

View file

@ -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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,69 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
CONFIG_16550_ADDRWIDTH=0
CONFIG_16550_POLLING=y
CONFIG_16550_SET_MCR_OUT2=y
CONFIG_16550_SUPRESS_INITIAL_CONFIG=y
CONFIG_16550_UART0=y
CONFIG_16550_UART0_BASE=0x02800000
CONFIG_16550_UART0_CLOCK=48000000
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"
CONFIG_ARCH_BOARD_BEAGLEPLAY=y
CONFIG_ARCH_CHIP="am62x"
CONFIG_ARCH_CHIP_AM62X=y
CONFIG_ARCH_EARLY_PRINT=y
CONFIG_ARCH_INTERRUPTSTACK=4096
CONFIG_ARCH_IRQPRIO=y
CONFIG_BOARD_LOOPSPERMSEC=100000
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SCHED=y
CONFIG_DEBUG_SCHED_ERROR=y
CONFIG_DEBUG_SCHED_WARN=y
CONFIG_DEBUG_SYMBOLS=y
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
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_PTHREAD_STACK_MIN=8192
CONFIG_RAMLOG=y
CONFIG_RAM_SIZE=536870912
CONFIG_RAM_START=0x80000000
CONFIG_RAW_BINARY=y
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SCHED_WAITPID=y
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

View file

@ -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"

View file

@ -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.

View file

@ -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

View file

@ -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;
}

View file

@ -0,0 +1,71 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
CONFIG_16550_ADDRWIDTH=0
CONFIG_16550_POLLING=y
CONFIG_16550_REGWIDTH=32
CONFIG_16550_SET_MCR_OUT2=y
CONFIG_16550_SUPRESS_INITIAL_CONFIG=y
CONFIG_16550_UART0=y
CONFIG_16550_UART0_BASE=0x02860000
CONFIG_16550_UART0_CLOCK=48000000
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"
CONFIG_ARCH_BOARD_POCKETBEAGLE2=y
CONFIG_ARCH_CHIP="am62x"
CONFIG_ARCH_CHIP_AM62X=y
CONFIG_ARCH_EARLY_PRINT=y
CONFIG_ARCH_INTERRUPTSTACK=4096
CONFIG_ARCH_IRQPRIO=y
CONFIG_BOARD_LOOPSPERMSEC=100000
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SCHED=y
CONFIG_DEBUG_SCHED_ERROR=y
CONFIG_DEBUG_SCHED_WARN=y
CONFIG_DEBUG_SYMBOLS=y
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
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_PTHREAD_STACK_MIN=8192
CONFIG_RAMLOG=y
CONFIG_RAM_SIZE=536870912
CONFIG_RAM_START=0x80000000
CONFIG_RAM_VSTART=0x80000000
CONFIG_RAW_BINARY=y
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SCHED_WAITPID=y
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

View file

@ -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"

View file

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

View file

@ -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})

View file

@ -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

View file

@ -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)
}

View file

@ -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;
}

View file

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