arch/arm/rtl8721dx: add shared Ameba UART driver.

Add a shared Ameba high-speed UART driver on top of the GPIO driver's
common/ameba/ infrastructure, exposing UART0/UART1 through the NuttX
serial upper half.

- arch/arm/src/common/ameba/ameba_uart.c/.h: serial lower-half driver
  built on the SDK fwlib UART register layer (ROM symbol table).  RX/TX
  dispatch through NuttX-native interrupts; TERMIOS get/set supported.
  The pins are muxed to the direction-specific UART crossbar function
  codes (TXD/RXD per controller) required by the amebadplus pinmux, and
  RX is pulled high through the SDK ROM.
- arch/arm/src/common/ameba/Kconfig: AMEBA_UART option (selects SERIAL
  and ARCH_HAVE_SERIAL_TERMIOS) plus RX/TX buffer-size knobs.
- arch/arm/src/rtl8721dx: wire ameba_uart.c into the Make/CMake builds
  and pull the fwlib ram_common UART table into the fwlib link set.
- boards/arm/rtl8721dx/pke8721daf: board UART port table registering
  UART0 at /dev/ttyS1 (PB18/PB19, 115200), bring-up hook, and a uart
  NSH config with the serialrx/serialblaster examples.
- Documentation: describe the driver and the uart board config.

Verified on hardware (PKE8721DAF): pinmux routing, TX/RX and interrupt
paths, and the TERMIOS ioctl path via loopback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: dechao_gong <dechao_gong@realsil.com.cn>
This commit is contained in:
dechao_gong 2026-07-14 16:07:58 +08:00 committed by Alan C. Assis
parent 57c7e47a6b
commit f8d6160022
15 changed files with 1066 additions and 2 deletions

View file

@ -35,6 +35,8 @@ Supported in this NuttX port:
* DHCP client (STA) and DHCP server (SoftAP)
* GPIO pins exposed as ``/dev/gpioN`` character devices (input, output and
interrupt), driven directly on the SDK fwlib register layer
* General-purpose UARTs exposed as ``/dev/ttySN`` serial devices, driven
directly on the SDK fwlib register layer
Buttons and LEDs
================
@ -78,6 +80,26 @@ Pins are encoded with the ``AMEBA_PA()`` / ``AMEBA_PB()`` helpers from
``arch/arm/src/common/ameba/ameba_gpio.h`` (port A/B, pin 0-31), matching the
Ameba SDK ``PinName`` layout.
uart
----
Minimal NSH with the general-purpose UART driver and the ``serialrx`` /
``serialblaster`` examples enabled (no Wi-Fi). The LOG-UART owns the console
and ``/dev/ttyS0``, so the board registers UART0 from its table (see
``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_uart.c``) as ``/dev/ttyS1`` at
115200 8N1. Edit that table -- controller, TX/RX pads and baud -- to match a
board's wiring. The TX/RX pads use the same ``AMEBA_PA()`` / ``AMEBA_PB()``
encoding as the GPIO table; the driver muxes them to the UART function and
pulls RX high through the SDK ROM. Exercise the port with the examples (loop TX
back to RX, or wire it to a host serial adapter)::
nsh> serialblaster # stream a test pattern out /dev/ttyS1
nsh> serialrx # receive and dump bytes from /dev/ttyS1
The line format can be changed at runtime through ``tcsetattr()`` (the config
enables ``CONFIG_SERIAL_TERMIOS``). UART2 is shared with Bluetooth and is not
exposed by the driver.
Wi-Fi
=====

View file

@ -22,4 +22,37 @@ config AMEBA_GPIO
fwlib register layer and dispatches pin interrupts through the ROM
GPIO interrupt handler.
config AMEBA_UART
bool "UART"
default n
select SERIAL
select ARCH_HAVE_SERIAL_TERMIOS
---help---
Expose the Ameba high-speed UARTs (UART0/UART1) through the NuttX
serial upper half. The LOG-UART owns the console and /dev/ttyS0, so
the board registers these general-purpose ports at /dev/ttyS1 and up
in its bring-up code, giving the TX/RX pads and baud for each.
The driver (arch/arm/src/common/ameba/ameba_uart.c) sits on the SDK
fwlib register layer and dispatches RX/TX through NuttX-native
interrupts.
if AMEBA_UART
config AMEBA_UART_RXBUFSIZE
int "UART receive buffer size"
default 256
---help---
Size, in bytes, of the receive buffer allocated for each registered
Ameba UART port.
config AMEBA_UART_TXBUFSIZE
int "UART transmit buffer size"
default 256
---help---
Size, in bytes, of the transmit buffer allocated for each registered
Ameba UART port.
endif # AMEBA_UART
endmenu # Ameba Peripheral Support

View file

@ -83,7 +83,9 @@ extern "C"
*
****************************************************************************/
#ifdef CONFIG_DEV_GPIO
int ameba_gpio_register(int minor, uint8_t pin, enum gpio_pintype_e pintype);
#endif
#undef EXTERN
#ifdef __cplusplus

View file

@ -0,0 +1,700 @@
/****************************************************************************
* arch/arm/src/common/ameba/ameba_uart.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
****************************************************************************/
/* NuttX serial lower half for the Realtek Ameba high-speed UARTs (UART0 and
* UART1; UART2 is shared with Bluetooth and is not wired here). The
* LOG-UART owns the console and /dev/ttyS0 (arch/.../ameba_loguart.c); this
* driver registers the general-purpose UARTs from board bring-up, so they
* appear as /dev/ttyS1 and up.
*
* The controller is programmed through the SDK fwlib UART API. NuttX runs
* on the KM4 core in the SECURE state, so the fwlib routines resolve to the
* secure register aliases via TrustZone_IsSecure() and reach the UART, the
* PINMUX pad mux and the pull control without stall. Every symbol used here
* (UART_Init, UART_SetBaud, UART_CharPut/Get, Pinmux_Config, PAD_PullCtrl,
* RCC_PeriphClockCmd, ...) resolves to the on-chip ROM symbol table; the
* fwlib data tables that ROM code indexes (UART_DEV_TABLE, APBPeriph_UARTx)
* are compiled into libameba_fwlib.a (see AMEBA_FWLIB_SRCS). To keep the
* vendor headers out of the NuttX include world, the few fwlib symbols and
* the UART_InitTypeDef layout used here are declared locally below rather
* than pulled in from <ameba_uart.h>.
*
* Interrupt dispatch stays NuttX-native: each UART's NVIC vector is owned by
* NuttX (irq_attach), and the ISR drains RX / refills TX through the stock
* uart_recvchars()/uart_xmitchars() upper-half helpers.
*/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spinlock.h>
#include <nuttx/serial/serial.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>
#endif
#include "arm_internal.h"
#include "ameba_uart.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Per-controller register base, peripheral clock mask and NuttX IRQ number.
* The driver source is shared by every Ameba ARM chip; each chip's
* <arch/irq.h> (pulled in by <nuttx/irq.h>) names its own vectors, so map
* them onto chip-agnostic aliases here.
*/
#if defined(CONFIG_ARCH_CHIP_RTL8721DX)
# define AMEBA_IRQ_UART0 RTL8721DX_IRQ_UART0
# define AMEBA_IRQ_UART1 RTL8721DX_IRQ_UART1
#else
# error "Ameba UART: controller IRQ numbers not defined for this chip"
#endif
#define AMEBA_UART0_BASE 0x4100c000ul
#define AMEBA_UART1_BASE 0x4100d000ul
/* APBPeriph_UARTx / APBPeriph_UARTx_CLOCK (sysreg_lsys.h). */
#define AMEBA_APBPERIPH_UART0 (((uint32_t)1 << 30) | ((uint32_t)1 << 6))
#define AMEBA_APBPERIPH_UART1 (((uint32_t)1 << 30) | ((uint32_t)1 << 7))
/* Pin mux function (ameba_pinmux.h) and pull control (ameba_gpio.h). RX is
* held high while idle so a floating line is not read as a start bit.
*
* On this SoC (amebadplus) the pad mux is a crossbar: the generic
* PINMUX_FUNCTION_UART code is not enough -- each pad must be routed with a
* direction-specific function code so the crossbar knows which internal UART
* signal to drive onto it (see the SDK's per-chip branch in the raw UART
* example). The codes are indexed by controller in g_uart_txfid/rxfid.
*/
#define AMEBA_PINMUX_UART0_TXD 19 /* PINMUX_FUNCTION_UART0_TXD */
#define AMEBA_PINMUX_UART0_RXD 20 /* PINMUX_FUNCTION_UART0_RXD */
#define AMEBA_PINMUX_UART1_TXD 23 /* PINMUX_FUNCTION_UART1_TXD */
#define AMEBA_PINMUX_UART1_RXD 24 /* PINMUX_FUNCTION_UART1_RXD */
#define AMEBA_GPIO_PUPD_UP 0x2 /* GPIO_PuPd_UP */
/* Mirror of the fwlib UART_InitTypeDef field values (ameba_uart.h). */
#define AMEBA_WLS_7BITS 0x0 /* RUART_WLS_7BITS */
#define AMEBA_WLS_8BITS 0x1 /* RUART_WLS_8BITS */
#define AMEBA_STOP_BIT_1 0x0 /* RUART_STOP_BIT_1 */
#define AMEBA_STOP_BIT_2 0x1 /* RUART_STOP_BIT_2 */
#define AMEBA_PARITY_DISABLE 0x0 /* RUART_PARITY_DISABLE */
#define AMEBA_PARITY_ENABLE 0x1 /* RUART_PARITY_ENABLE */
#define AMEBA_ODD_PARITY 0x0 /* RUART_ODD_PARITY */
#define AMEBA_EVEN_PARITY 0x1 /* RUART_EVEN_PARITY */
#define AMEBA_RX_FIFOTRIG_1 0x0 /* UART_RX_FIFOTRIG_LEVEL_1BYTES */
/* Interrupt enable register (IER) bits. */
#define AMEBA_UART_INT_ERBI ((uint32_t)1 << 0) /* Rx data available */
#define AMEBA_UART_INT_ETBEI ((uint32_t)1 << 1) /* Tx FIFO empty */
#define AMEBA_UART_INT_ETOI ((uint32_t)1 << 5) /* Rx timeout */
/* Line status register (LSR) bits. */
#define AMEBA_UART_LSR_TX_EMPTY ((uint32_t)1 << 5) /* Tx FIFO empty */
/* Second/third argument to fwlib "state" style APIs. */
#define AMEBA_DISABLE 0x0
#define AMEBA_ENABLE 0x1
/* Number of general-purpose controllers this driver can address. */
#define AMEBA_NUART 2
/* Local parity encoding (priv->parity). */
#define AMEBA_PARITY_NONE 0
#define AMEBA_PARITY_ODD 1
#define AMEBA_PARITY_EVEN 2
/****************************************************************************
* Private Types
****************************************************************************/
/* Layout-compatible mirror of the fwlib UART_InitTypeDef (all u32, same
* order); passed by address to UART_Init().
*/
struct ameba_uart_init_s
{
uint32_t dmamodectrl; /* DmaModeCtrl */
uint32_t wordlen; /* WordLen */
uint32_t stopbit; /* StopBit */
uint32_t parity; /* Parity */
uint32_t paritytype; /* ParityType */
uint32_t stickparity; /* StickParity */
uint32_t flowcontrol; /* FlowControl */
uint32_t rxfifotriglevel; /* RxFifoTrigLevel */
uint32_t rxerreportctrl; /* RxErReportCtrl */
uint32_t rxtimeoutcnt; /* RxTimeOutCnt */
};
struct ameba_uart_dev_s
{
struct uart_dev_s dev; /* Serial upper-half device (must be first) */
uintptr_t base; /* UART register base address */
int irq; /* NuttX interrupt vector */
uint32_t clk; /* APBPeriph mask for RCC_PeriphClockCmd() */
uint32_t baud; /* Baud rate */
uint8_t txpin; /* TX pad (AMEBA_PA()/AMEBA_PB() encoding) */
uint8_t rxpin; /* RX pad (AMEBA_PA()/AMEBA_PB() encoding) */
uint8_t txfid; /* Pin mux function code for the TX pad */
uint8_t rxfid; /* Pin mux function code for the RX pad */
uint8_t bits; /* Data bits (7 or 8) */
uint8_t parity; /* AMEBA_PARITY_NONE / _ODD / _EVEN */
bool stop2; /* True: 2 stop bits, false: 1 */
bool txint; /* True while the TX interrupt is unmasked */
spinlock_t lock; /* Serializes IER updates vs the ISR */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* SDK fwlib UART/pin/clock API (all resolve to the ROM symbol table). */
extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t clock,
uint8_t newstate);
extern void Pinmux_Config(uint8_t pin, uint32_t func);
extern void PAD_PullCtrl(uint8_t pin, uint8_t pull);
extern void UART_DeInit(void *uartx);
extern void UART_StructInit(struct ameba_uart_init_s *init);
extern void UART_Init(void *uartx, struct ameba_uart_init_s *init);
extern void UART_SetBaud(void *uartx, uint32_t baud);
extern void UART_RxCmd(void *uartx, uint32_t newstate);
extern uint32_t UART_Writable(void *uartx);
extern uint32_t UART_Readable(void *uartx);
extern void UART_CharPut(void *uartx, uint8_t txdata);
extern void UART_CharGet(void *uartx, uint8_t *rxbyte);
extern void UART_INTConfig(void *uartx, uint32_t uart_it, uint32_t newstate);
extern uint32_t UART_LineStatusGet(void *uartx);
/* Serial lower-half operations. */
static int ameba_uart_setup(struct uart_dev_s *dev);
static void ameba_uart_shutdown(struct uart_dev_s *dev);
static int ameba_uart_attach(struct uart_dev_s *dev);
static void ameba_uart_detach(struct uart_dev_s *dev);
static int ameba_uart_ioctl(struct file *filep, int cmd,
unsigned long arg);
static int ameba_uart_receive(struct uart_dev_s *dev, unsigned int *status);
static void ameba_uart_rxint(struct uart_dev_s *dev, bool enable);
static bool ameba_uart_rxavailable(struct uart_dev_s *dev);
static void ameba_uart_send(struct uart_dev_s *dev, int ch);
static void ameba_uart_txint(struct uart_dev_s *dev, bool enable);
static bool ameba_uart_txready(struct uart_dev_s *dev);
static bool ameba_uart_txempty(struct uart_dev_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct uart_ops_s g_ameba_uart_ops =
{
.setup = ameba_uart_setup,
.shutdown = ameba_uart_shutdown,
.attach = ameba_uart_attach,
.detach = ameba_uart_detach,
.ioctl = ameba_uart_ioctl,
.receive = ameba_uart_receive,
.rxint = ameba_uart_rxint,
.rxavailable = ameba_uart_rxavailable,
.send = ameba_uart_send,
.txint = ameba_uart_txint,
.txready = ameba_uart_txready,
.txempty = ameba_uart_txempty,
};
/* Per-controller register base, peripheral clock and IRQ, indexed by the
* AMEBA_UART0/AMEBA_UART1 controller number.
*/
static const uintptr_t g_uart_base[AMEBA_NUART] =
{
AMEBA_UART0_BASE,
AMEBA_UART1_BASE,
};
static const uint32_t g_uart_clk[AMEBA_NUART] =
{
AMEBA_APBPERIPH_UART0,
AMEBA_APBPERIPH_UART1,
};
static const int g_uart_irq[AMEBA_NUART] =
{
AMEBA_IRQ_UART0,
AMEBA_IRQ_UART1,
};
/* Direction-specific pad mux function codes, indexed by controller. */
static const uint8_t g_uart_txfid[AMEBA_NUART] =
{
AMEBA_PINMUX_UART0_TXD,
AMEBA_PINMUX_UART1_TXD,
};
static const uint8_t g_uart_rxfid[AMEBA_NUART] =
{
AMEBA_PINMUX_UART0_RXD,
AMEBA_PINMUX_UART1_RXD,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ameba_uart_configure
*
* Description:
* Gate the peripheral clock, route the TX/RX pads to the UART function and
* program the line format and baud through fwlib UART_Init()/SetBaud(),
* then enable the receiver. Called from setup() and on a termios change.
*
****************************************************************************/
static void ameba_uart_configure(struct ameba_uart_dev_s *priv)
{
struct ameba_uart_init_s init;
void *uartx = (void *)priv->base;
/* Gate on the UART peripheral clock (idempotent). */
RCC_PeriphClockCmd(priv->clk, priv->clk, AMEBA_ENABLE);
/* Route the pads to this controller's TX/RX signals through the crossbar;
* hold RX high while idle.
*/
Pinmux_Config(priv->txpin, priv->txfid);
Pinmux_Config(priv->rxpin, priv->rxfid);
PAD_PullCtrl(priv->rxpin, AMEBA_GPIO_PUPD_UP);
/* Start from the fwlib defaults, then apply the requested line format. */
UART_StructInit(&init);
init.wordlen = (priv->bits == 7) ?
AMEBA_WLS_7BITS : AMEBA_WLS_8BITS;
init.stopbit = priv->stop2 ? AMEBA_STOP_BIT_2 : AMEBA_STOP_BIT_1;
init.flowcontrol = AMEBA_DISABLE;
init.rxfifotriglevel = AMEBA_RX_FIFOTRIG_1;
if (priv->parity == AMEBA_PARITY_NONE)
{
init.parity = AMEBA_PARITY_DISABLE;
}
else
{
init.parity = AMEBA_PARITY_ENABLE;
init.paritytype = (priv->parity == AMEBA_PARITY_ODD) ?
AMEBA_ODD_PARITY : AMEBA_EVEN_PARITY;
}
UART_Init(uartx, &init);
UART_SetBaud(uartx, priv->baud);
UART_RxCmd(uartx, AMEBA_ENABLE);
}
/****************************************************************************
* Name: ameba_uart_interrupt
*
* Description:
* Common UART interrupt handler. Drains the RX FIFO into the receive
* buffer and, while the TX interrupt is unmasked, refills the TX FIFO from
* the transmit buffer.
*
****************************************************************************/
static int ameba_uart_interrupt(int irq, void *context, void *arg)
{
struct uart_dev_s *dev = (struct uart_dev_s *)arg;
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
void *uartx = (void *)priv->base;
UNUSED(irq);
UNUSED(context);
/* Reading the line status register clears any latched RX error bits. */
UART_LineStatusGet(uartx);
if (UART_Readable(uartx))
{
uart_recvchars(dev);
}
if (priv->txint && UART_Writable(uartx))
{
uart_xmitchars(dev);
}
return OK;
}
/****************************************************************************
* Name: ameba_uart_setup
****************************************************************************/
static int ameba_uart_setup(struct uart_dev_s *dev)
{
ameba_uart_configure((struct ameba_uart_dev_s *)dev);
return OK;
}
/****************************************************************************
* Name: ameba_uart_shutdown
****************************************************************************/
static void ameba_uart_shutdown(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
ameba_uart_rxint(dev, false);
ameba_uart_txint(dev, false);
UART_DeInit((void *)priv->base);
}
/****************************************************************************
* Name: ameba_uart_attach
****************************************************************************/
static int ameba_uart_attach(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
int ret;
ret = irq_attach(priv->irq, ameba_uart_interrupt, dev);
if (ret == OK)
{
up_enable_irq(priv->irq);
}
return ret;
}
/****************************************************************************
* Name: ameba_uart_detach
****************************************************************************/
static void ameba_uart_detach(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
up_disable_irq(priv->irq);
irq_detach(priv->irq);
}
/****************************************************************************
* Name: ameba_uart_ioctl
****************************************************************************/
static int ameba_uart_ioctl(struct file *filep, int cmd, unsigned long arg)
{
#ifdef CONFIG_SERIAL_TERMIOS
struct inode *inode = filep->f_inode;
struct uart_dev_s *dev = inode->i_private;
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
switch (cmd)
{
case TCGETS:
{
struct termios *termiosp = (struct termios *)(uintptr_t)arg;
tcflag_t ccflag;
if (termiosp == NULL)
{
return -EINVAL;
}
ccflag = (priv->bits == 7) ? CS7 : CS8;
if (priv->parity != AMEBA_PARITY_NONE)
{
ccflag |= PARENB;
if (priv->parity == AMEBA_PARITY_ODD)
{
ccflag |= PARODD;
}
}
if (priv->stop2)
{
ccflag |= CSTOPB;
}
termiosp->c_cflag = ccflag;
cfsetispeed(termiosp, priv->baud);
cfsetospeed(termiosp, priv->baud);
return OK;
}
case TCSETS:
{
struct termios *termiosp = (struct termios *)(uintptr_t)arg;
irqstate_t flags;
if (termiosp == NULL)
{
return -EINVAL;
}
flags = spin_lock_irqsave(&priv->lock);
priv->bits = ((termiosp->c_cflag & CSIZE) == CS7) ? 7 : 8;
priv->stop2 = (termiosp->c_cflag & CSTOPB) != 0;
if ((termiosp->c_cflag & PARENB) == 0)
{
priv->parity = AMEBA_PARITY_NONE;
}
else if ((termiosp->c_cflag & PARODD) != 0)
{
priv->parity = AMEBA_PARITY_ODD;
}
else
{
priv->parity = AMEBA_PARITY_EVEN;
}
priv->baud = cfgetispeed(termiosp);
ameba_uart_configure(priv);
spin_unlock_irqrestore(&priv->lock, flags);
return OK;
}
default:
return -ENOTTY;
}
#else
UNUSED(filep);
UNUSED(cmd);
UNUSED(arg);
return -ENOTTY;
#endif
}
/****************************************************************************
* Name: ameba_uart_receive
****************************************************************************/
static int ameba_uart_receive(struct uart_dev_s *dev, unsigned int *status)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
uint8_t rxbyte = 0;
*status = 0;
UART_CharGet((void *)priv->base, &rxbyte);
return rxbyte;
}
/****************************************************************************
* Name: ameba_uart_rxint
****************************************************************************/
static void ameba_uart_rxint(struct uart_dev_s *dev, bool enable)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
/* Enable both the RX-trigger and RX-timeout sources so that bytes still
* held below the FIFO trigger level are delivered promptly.
*/
UART_INTConfig((void *)priv->base,
AMEBA_UART_INT_ERBI | AMEBA_UART_INT_ETOI,
enable ? AMEBA_ENABLE : AMEBA_DISABLE);
spin_unlock_irqrestore(&priv->lock, flags);
}
/****************************************************************************
* Name: ameba_uart_rxavailable
****************************************************************************/
static bool ameba_uart_rxavailable(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
return UART_Readable((void *)priv->base) != 0;
}
/****************************************************************************
* Name: ameba_uart_send
****************************************************************************/
static void ameba_uart_send(struct uart_dev_s *dev, int ch)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
UART_CharPut((void *)priv->base, (uint8_t)ch);
}
/****************************************************************************
* Name: ameba_uart_txint
*
* Description:
* Unmask/mask the TX-FIFO-empty interrupt. Enabling it while the FIFO is
* already empty asserts the interrupt at once, so the ISR pumps the first
* bytes; uart_xmitchars() re-disables it once the transmit buffer drains.
*
****************************************************************************/
static void ameba_uart_txint(struct uart_dev_s *dev, bool enable)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
irqstate_t flags;
flags = spin_lock_irqsave(&priv->lock);
priv->txint = enable;
UART_INTConfig((void *)priv->base, AMEBA_UART_INT_ETBEI,
enable ? AMEBA_ENABLE : AMEBA_DISABLE);
spin_unlock_irqrestore(&priv->lock, flags);
}
/****************************************************************************
* Name: ameba_uart_txready
****************************************************************************/
static bool ameba_uart_txready(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
return UART_Writable((void *)priv->base) != 0;
}
/****************************************************************************
* Name: ameba_uart_txempty
****************************************************************************/
static bool ameba_uart_txempty(struct uart_dev_s *dev)
{
struct ameba_uart_dev_s *priv = (struct ameba_uart_dev_s *)dev;
return (UART_LineStatusGet((void *)priv->base) &
AMEBA_UART_LSR_TX_EMPTY) != 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ameba_uart_register
*
* Description:
* See ameba_uart.h.
*
****************************************************************************/
int ameba_uart_register(const char *path, int uart, uint8_t txpin,
uint8_t rxpin, uint32_t baud)
{
struct ameba_uart_dev_s *priv;
char *rxbuffer;
char *txbuffer;
int ret;
if (uart < 0 || uart >= AMEBA_NUART || path == NULL || baud == 0)
{
return -EINVAL;
}
priv = kmm_zalloc(sizeof(struct ameba_uart_dev_s));
if (priv == NULL)
{
return -ENOMEM;
}
rxbuffer = kmm_malloc(CONFIG_AMEBA_UART_RXBUFSIZE);
txbuffer = kmm_malloc(CONFIG_AMEBA_UART_TXBUFSIZE);
if (rxbuffer == NULL || txbuffer == NULL)
{
ret = -ENOMEM;
goto errout;
}
priv->base = g_uart_base[uart];
priv->clk = g_uart_clk[uart];
priv->irq = g_uart_irq[uart];
priv->txpin = txpin;
priv->rxpin = rxpin;
priv->txfid = g_uart_txfid[uart];
priv->rxfid = g_uart_rxfid[uart];
priv->baud = baud;
priv->bits = 8;
priv->parity = AMEBA_PARITY_NONE;
priv->stop2 = false;
spin_lock_init(&priv->lock);
priv->dev.recv.size = CONFIG_AMEBA_UART_RXBUFSIZE;
priv->dev.recv.buffer = rxbuffer;
priv->dev.xmit.size = CONFIG_AMEBA_UART_TXBUFSIZE;
priv->dev.xmit.buffer = txbuffer;
priv->dev.ops = &g_ameba_uart_ops;
ret = uart_register(path, &priv->dev);
if (ret < 0)
{
_err("ERROR: uart_register(%s) failed: %d\n", path, ret);
goto errout;
}
return OK;
errout:
kmm_free(rxbuffer);
kmm_free(txbuffer);
kmm_free(priv);
return ret;
}

View file

@ -0,0 +1,90 @@
/****************************************************************************
* arch/arm/src/common/ameba/ameba_uart.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_ARM_SRC_COMMON_AMEBA_AMEBA_UART_H
#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_UART_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* The Ameba high-speed UART controllers exposed to NuttX. UART2 is shared
* with Bluetooth on this family and is not wired for general serial use, so
* only UART0 and UART1 are registered by boards. TX/RX pins are given with
* the same AMEBA_PA()/AMEBA_PB() PinName encoding used by the GPIO driver
* (see ameba_gpio.h); any pad can be routed to a UART through the pin mux.
*/
#define AMEBA_UART0 0
#define AMEBA_UART1 1
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: ameba_uart_register
*
* Description:
* Configure one Ameba high-speed UART and register it with the NuttX
* serial upper half at the given device path (e.g. "/dev/ttyS1"). The
* LOG-UART console is owned separately (arch/.../ameba_loguart.c) and
* already occupies /dev/ttyS0, so boards register the general-purpose
* UARTs starting at /dev/ttyS1.
*
* Input Parameters:
* path - The serial device path to register (e.g. "/dev/ttyS1").
* uart - The controller index, AMEBA_UART0 or AMEBA_UART1.
* txpin - The TX pad, encoded with AMEBA_PA()/AMEBA_PB().
* rxpin - The RX pad, encoded with AMEBA_PA()/AMEBA_PB().
* baud - The initial baud rate.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int ameba_uart_register(const char *path, int uart, uint8_t txpin,
uint8_t rxpin, uint32_t baud);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_UART_H */

View file

@ -44,6 +44,10 @@ if(CONFIG_AMEBA_GPIO)
list(APPEND SRCS ${AMEBA_COMMON}/ameba_gpio.c)
endif()
if(CONFIG_AMEBA_UART)
list(APPEND SRCS ${AMEBA_COMMON}/ameba_uart.c)
endif()
target_include_directories(arch PRIVATE ${AMEBA_COMMON})
target_sources(arch PRIVATE ${SRCS})

View file

@ -54,6 +54,10 @@ ifeq ($(CONFIG_AMEBA_GPIO),y)
CHIP_CSRCS += ameba_gpio.c
endif
ifeq ($(CONFIG_AMEBA_UART),y)
CHIP_CSRCS += ameba_uart.c
endif
############################################################################
# Realtek RTL8721Dx SDK integration
#

View file

@ -128,6 +128,15 @@ ifeq ($(CONFIG_AMEBA_GPIO),y)
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_gpio.c
endif
# UART register layer. The UART driver (arch/.../common/ameba/ameba_uart.c)
# calls the fwlib UART API, all of which resolves to the ROM symbol table; but
# the ROM routines index the fwlib data tables (UART_DEV_TABLE, APBPeriph_UARTx)
# which live in this RAM source and must be compiled in (--gc-sections drops
# the unused DMA/monitor helpers).
ifeq ($(CONFIG_AMEBA_UART),y)
AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_uart.c
endif
# -Wno-int-conversion: the vendored SDK passes NULL to irq_register()'s u32
# "Data" (interrupt context) argument in many places -- an intentional
# NULL-as-context idiom. Silence -Wint-conversion for the SDK fwlib sources

View file

@ -0,0 +1,55 @@
#
# 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_DEBUG_WARN is not set
CONFIG_AMEBA_UART=y
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="pke8721daf"
CONFIG_ARCH_BOARD_PKE8721DAF=y
CONFIG_ARCH_CHIP="rtl8721dx"
CONFIG_ARCH_CHIP_RTL8721DX=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARMV8M_SYSTICK=y
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEFAULT_TASK_STACKSIZE=4096
CONFIG_EXAMPLES_HELLO=y
CONFIG_EXAMPLES_SERIALBLASTER=y
CONFIG_EXAMPLES_SERIALBLASTER_DEVPATH="/dev/ttyS1"
CONFIG_EXAMPLES_SERIALRX=y
CONFIG_EXAMPLES_SERIALRX_DEVPATH="/dev/ttyS1"
CONFIG_FS_PROCFS=y
CONFIG_FS_TMPFS=y
CONFIG_IDLETHREAD_STACKSIZE=4096
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_LIBC_MEMFD_ERROR=y
CONFIG_MM_DEFAULT_ALIGNMENT=32
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=294912
CONFIG_RAM_START=0x20020000
CONFIG_RR_INTERVAL=200
CONFIG_RTL8721DX_FLASH_FS=y
CONFIG_SCHED_HPWORK=y
CONFIG_SCHED_HPWORKPRIORITY=192
CONFIG_SCHED_LPWORK=y
CONFIG_SERIAL_TERMIOS=y
CONFIG_STACK_COLORATION=y
CONFIG_START_DAY=16
CONFIG_START_MONTH=6
CONFIG_START_YEAR=2026
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_NSH_STACKSIZE=2500
CONFIG_TIMER=y
CONFIG_TIMER_ARCH=y
CONFIG_USEC_PER_TICK=1000

View file

@ -26,10 +26,14 @@ if(CONFIG_AMEBA_GPIO)
list(APPEND SRCS rtl8721dx_gpio.c)
endif()
if(CONFIG_AMEBA_UART)
list(APPEND SRCS rtl8721dx_uart.c)
endif()
target_sources(board PRIVATE ${SRCS})
if(CONFIG_AMEBA_GPIO)
# The board pin table pulls in the shared driver's public header from
if(CONFIG_AMEBA_GPIO OR CONFIG_AMEBA_UART)
# The board pin/UART tables pull in the shared driver's public headers from
# arch/arm/src/common/ameba/, not on the default board include path.
target_include_directories(board
PRIVATE ${NUTTX_DIR}/arch/arm/src/common/ameba)

View file

@ -33,4 +33,13 @@ CSRCS += rtl8721dx_gpio.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
endif
ifeq ($(CONFIG_AMEBA_UART),y)
CSRCS += rtl8721dx_uart.c
# The board UART table pulls in the shared driver's public header from
# arch/arm/src/common/ameba/, which is not on the default board include path.
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba
endif
include $(TOPDIR)/boards/Board.mk

View file

@ -118,6 +118,16 @@ int rtl8721dx_bringup(void)
}
#endif
#ifdef CONFIG_AMEBA_UART
/* Register the board's general-purpose UART ports at /dev/ttySN. */
ret = rtl8721dx_uart_initialize();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: rtl8721dx_uart_initialize failed: %d\n", ret);
}
#endif
/* Install the inter-core HW IPC-semaphore RTOS hooks LAST -- after all the
* flash / WHC bring-up above, and just before this (board_late_initialize)
* path returns and nx_start() hands off to the init task.

View file

@ -81,6 +81,20 @@ int rtl8721dx_wifi_initialize(void);
int rtl8721dx_gpio_initialize(void);
#endif
#ifdef CONFIG_AMEBA_UART
/****************************************************************************
* Name: rtl8721dx_uart_initialize
*
* Description:
* Register the board's general-purpose UART ports with the NuttX serial
* upper half
* (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_uart.c).
*
****************************************************************************/
int rtl8721dx_uart_initialize(void);
#endif
#ifdef CONFIG_RTL8721DX_FLASH_FS
/****************************************************************************
* Name: ameba_flash_fs_initialize

View file

@ -0,0 +1,105 @@
/****************************************************************************
* boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_uart.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 <sys/param.h>
#include <syslog.h>
#include "ameba_gpio.h"
#include "ameba_uart.h"
#include "rtl8721dx_pke8721daf.h"
#ifdef CONFIG_AMEBA_UART
/****************************************************************************
* Private Types
****************************************************************************/
/* One entry per general-purpose UART exposed to NuttX. The LOG-UART owns
* the console and /dev/ttyS0, so these ports are registered starting at
* /dev/ttyS1 in the order listed below. The TX/RX pads are examples used by
* the `uart` config (examples/serialrx / serialblaster) -- any pad can be
* routed to a UART through the pin mux, so adjust them to match your board's
* wiring.
*/
struct rtl8721dx_uart_s
{
const char *path; /* Device path (/dev/ttyS1, ...) */
int uart; /* Controller index (AMEBA_UART0/AMEBA_UART1) */
uint8_t txpin; /* TX pad (AMEBA_PA()/AMEBA_PB() encoding) */
uint8_t rxpin; /* RX pad (AMEBA_PA()/AMEBA_PB() encoding) */
uint32_t baud; /* Initial baud rate */
};
/****************************************************************************
* Private Data
****************************************************************************/
static const struct rtl8721dx_uart_s g_uart_ports[] =
{
{
"/dev/ttyS1", AMEBA_UART0, AMEBA_PB(18), AMEBA_PB(19), 115200
},
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: rtl8721dx_uart_initialize
*
* Description:
* Register the board's general-purpose UART ports with the NuttX serial
* upper half.
*
****************************************************************************/
int rtl8721dx_uart_initialize(void)
{
int ret;
size_t i;
for (i = 0; i < nitems(g_uart_ports); i++)
{
ret = ameba_uart_register(g_uart_ports[i].path, g_uart_ports[i].uart,
g_uart_ports[i].txpin, g_uart_ports[i].rxpin,
g_uart_ports[i].baud);
if (ret < 0)
{
syslog(LOG_ERR,
"ERROR: ameba_uart_register(%s) failed: %d\n",
g_uart_ports[i].path, ret);
return ret;
}
}
return OK;
}
#endif /* CONFIG_AMEBA_UART */

View file

@ -278,10 +278,13 @@ static const char *g_white_prefix[] =
"OSC2M_",
"OSC4M_",
"OSC131K_",
"PAD_",
"Pinmux_",
"RCC_",
"RTCIO_",
"SYSCFG_",
"SYSTIMER_",
"UART_",
"SystemCoreClock", /* SystemCoreClock, SystemCoreClockUpdate */
"cmse_", /* ARM CMSE TrustZone intrinsics (arm_cmse.h) */
"MQTTErrors", /* apps/tools/netutils/mqttc/MQTT-C/include/mqtt.h */