casaroli commented on code in PR #19041: URL: https://github.com/apache/nuttx/pull/19041#discussion_r4392390198
########## tools/ci/testlist/tricore-01.dat: ########## @@ -0,0 +1 @@ +/tricore/* Review Comment: CI never uses this file: `tricore-01` is not in the board list of `.github/workflows/build.yml`, and the CI image has no tricore-elf-gcc. Fix: add `tricore-01` to the Linux boards and the toolchain to the CI image, or remove the file. ########## Documentation/platforms/tricore/tc4x/index.rst: ########## @@ -0,0 +1,17 @@ +========== +AURIX TC4X +========== + +NuttX support for the Infineon AURIX TC4X (TriCore TC1.8) family. + +The TC4X port covers SCU clock tree bring-up (PLL, CCU dividers, +SafetyEndInit/CpuEndInit unlock), the IR/SRC interrupt routing +(SRPN equals the IRQ number), the System Timer (STM) oneshot and +ASCLIN-based UART. Boards select a particular TC4X variant through +``CONFIG_TC4X_CHIP_*``. + +.. toctree:: + :maxdepth: 1 + :glob: + + */* Review Comment: The `*/*` glob matches no document until #21040 adds the first TC4X board, and the docs build uses `-W`. Fix: add this toctree in #21040. ########## Documentation/platforms/tricore/index.rst: ########## @@ -2,37 +2,311 @@ TriCore ======= -All TriCore source reside in lower-level common, chip-specific, and architecture-specific -directories. +NuttX runs on Infineon AURIX TriCore microcontrollers in flat 32-bit +supervisor mode on CPU0. The port is implemented entirely with direct +SFR access; there is no dependency on Infineon's iLLD SDK, and the +low-level startup, trap handling and interrupt routing are provided by +NuttX itself. -arch/tricore/src/common/ Directory -================================== +The port covers two AURIX SoC families: -This directory holds source files common to all TriCore architectures. +- `AURIX TC3X <https://www.infineon.com/products/microcontroller/32-bit-tricore/aurix-tc3xx>`_ + using the TC1.6.2P ISA +- `AURIX TC4X <https://www.infineon.com/products/microcontroller/32-bit-tricore/aurix-tc4x>`_ + using the TC1.8P ISA -Architecture-Specific Directories -================================= +Key supported features +====================== -Architecture-specific directories hold common source files shared for by -implementations of specific TriCore architectures. +The table below summarises the state of the kernel-relevant features +across both AURIX SoC families. -``TriCore`` - This directory holds logic appropriate for any instantiation of the 32-bit - TriCore architecture. +================================ ======== ======== +Feature TC3X TC4X +================================ ======== ======== +ISA version TC1.6.2P TC1.8P +Single-CPU NSH kernel Yes Yes +SMP / AMP No No +Hardware MPU (DPR/CPR) No No +MPU stack guard No No +System Timer (STM) tick Yes Yes +Single-precision FPU Yes Yes +Double-precision FPU No Yes +ASCLIN UART (NSH console) Yes Yes +GPIO pinmuxing Yes Yes +Instruction/data cache control Yes No Review Comment: The table says cache control is Yes on TC3X and No on TC4X, but `arch/tricore/Kconfig:50-51` selects the caches only for TC4X. Fix: correct the table. ########## arch/tricore/src/aurix/tricore_serial.c: ########## @@ -0,0 +1,904 @@ +/**************************************************************************** + * arch/tricore/src/aurix/tricore_serial.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/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/irq.h> +#include <nuttx/arch.h> +#include <nuttx/spinlock.h> +#include <nuttx/serial/serial.h> + +#include "tricore_internal.h" +#include "tricore_asclin.h" + +#ifndef CONFIG_TRICORE_ASCLINF_FREQUENCY +# if defined(CONFIG_ARCH_CHIP_FAMILY_TC4X) +# define CONFIG_TRICORE_ASCLINF_FREQUENCY 200000000 +# elif defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) +# define CONFIG_TRICORE_ASCLINF_FREQUENCY 100000000 +# endif +#endif + +/* Default ASCLIN clock source selection */ +#ifndef CONFIG_TRICORE_ASCLIN_CLK_SRC +# define CONFIG_TRICORE_ASCLIN_CLK_SRC ASCLIN_CSR_CLKSEL_FASCLINF +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_OVERSAMPLING +# define CONFIG_TRICORE_ASCLIN_OVERSAMPLING 16u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_SAMPLEPOINT +# define CONFIG_TRICORE_ASCLIN_SAMPLEPOINT 8u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_PRESCALER +# define CONFIG_TRICORE_ASCLIN_PRESCALER 1u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER +# define CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER 1u +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ASCLIN_CLK_TIMEOUT 100000u + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) && defined(CONFIG_TRICORE_UART0) +# define HAVE_SERIAL_CONSOLE 1 +# define CONSOLE_DEV g_uart0port +# define TTYS0_DEV g_uart0port +# ifdef CONFIG_TRICORE_UART1 +# define TTYS1_DEV g_uart1port +# endif +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_TRICORE_UART1) +# define HAVE_SERIAL_CONSOLE 1 +# define CONSOLE_DEV g_uart1port +# define TTYS0_DEV g_uart1port +# ifdef CONFIG_TRICORE_UART0 +# define TTYS1_DEV g_uart0port +# endif +#elif defined(CONFIG_TRICORE_UART0) +# define TTYS0_DEV g_uart0port +# ifdef CONFIG_TRICORE_UART1 +# define TTYS1_DEV g_uart1port +# endif +#elif defined(CONFIG_TRICORE_UART1) +# define TTYS0_DEV g_uart1port +#endif + +struct aurix_uart_config_s +{ + uintptr_t base; + uint32_t fclk; + uint32_t baud; + uint8_t clk_src; + uint8_t oversampling; + uint8_t samplepoint; + uint8_t prescaler_val; + uint8_t median_filter; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t parity; + uint8_t rxirq; + uint8_t txirq; + uint8_t erirq; + uint8_t rx_alti; +}; + +struct aurix_uart_priv_s +{ + struct aurix_uart_config_s *config; + bool txint_enabled; + bool rxint_enabled; +}; + +static int aurix_setup(struct uart_dev_s *dev); +static void aurix_shutdown(struct uart_dev_s *dev); +static int aurix_attach(struct uart_dev_s *dev); +static void aurix_detach(struct uart_dev_s *dev); +static int aurix_interrupt(int irq, void *context, void *arg); +static int aurix_ioctl(struct file *filep, int cmd, unsigned long arg); +static int aurix_receive(struct uart_dev_s *dev, unsigned int *status); +static void aurix_rxint(struct uart_dev_s *dev, bool enable); +static bool aurix_rxavailable(struct uart_dev_s *dev); +static void aurix_send(struct uart_dev_s *dev, int ch); +static void aurix_txint(struct uart_dev_s *dev, bool enable); +static bool aurix_txready(struct uart_dev_s *dev); +static bool aurix_txempty(struct uart_dev_s *dev); + +static const struct uart_ops_s g_uart_ops = +{ + .setup = aurix_setup, + .shutdown = aurix_shutdown, + .attach = aurix_attach, + .detach = aurix_detach, + .ioctl = aurix_ioctl, + .receive = aurix_receive, + .rxint = aurix_rxint, + .rxavailable = aurix_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = aurix_send, + .txint = aurix_txint, + .txready = aurix_txready, + .txempty = aurix_txempty, +}; + +#ifdef CONFIG_TRICORE_UART0 + +static struct aurix_uart_config_s g_uart0_config = +{ + .base = TRICORE_ASCLIN_BASE(0), + .fclk = CONFIG_TRICORE_ASCLINF_FREQUENCY, + .baud = CONFIG_UART0_BAUD, + .clk_src = CONFIG_TRICORE_ASCLIN_CLK_SRC, + .oversampling = CONFIG_TRICORE_ASCLIN_OVERSAMPLING, + .samplepoint = CONFIG_TRICORE_ASCLIN_SAMPLEPOINT, + .prescaler_val = CONFIG_TRICORE_ASCLIN_PRESCALER, + .median_filter = CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER, + .data_bits = CONFIG_UART0_BITS, + .stop_bits = CONFIG_UART0_2STOP ? 2 : 1, +#if defined(CONFIG_UART0_PARITY) && CONFIG_UART0_PARITY == 1 + .parity = 2, +#elif defined(CONFIG_UART0_PARITY) && CONFIG_UART0_PARITY == 2 + .parity = 1, +#else + .parity = 0, +#endif + .rxirq = CONFIG_TRICORE_UART0_RXIRQ, + .txirq = CONFIG_TRICORE_UART0_TXIRQ, + .erirq = CONFIG_TRICORE_UART0_ERIRQ, + + .rx_alti = ASCLIN_IOCR_ALTI_A, +}; + +static struct aurix_uart_priv_s g_uart0_priv = +{ + .config = &g_uart0_config, + .txint_enabled = false, + .rxint_enabled = false, +}; + +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; + +static uart_dev_t g_uart0port = +{ +#ifdef HAVE_SERIAL_CONSOLE + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0_priv, +}; + +#endif /* CONFIG_TRICORE_UART0 */ + +#ifdef CONFIG_TRICORE_UART1 + +static struct aurix_uart_config_s g_uart1_config = +{ + .base = TRICORE_ASCLIN_BASE(1), + .fclk = CONFIG_TRICORE_ASCLINF_FREQUENCY, + .baud = CONFIG_UART1_BAUD, + .clk_src = CONFIG_TRICORE_ASCLIN_CLK_SRC, + .oversampling = CONFIG_TRICORE_ASCLIN_OVERSAMPLING, + .samplepoint = CONFIG_TRICORE_ASCLIN_SAMPLEPOINT, + .prescaler_val = CONFIG_TRICORE_ASCLIN_PRESCALER, + .median_filter = CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER, + .data_bits = CONFIG_UART1_BITS, + .stop_bits = CONFIG_UART1_2STOP ? 2 : 1, +#if defined(CONFIG_UART1_PARITY) && CONFIG_UART1_PARITY == 1 + .parity = 2, +#elif defined(CONFIG_UART1_PARITY) && CONFIG_UART1_PARITY == 2 + .parity = 1, +#else + .parity = 0, +#endif + .rxirq = CONFIG_TRICORE_UART1_RXIRQ, + .txirq = CONFIG_TRICORE_UART1_TXIRQ, + .erirq = CONFIG_TRICORE_UART1_ERIRQ, + + .rx_alti = ASCLIN_IOCR_ALTI_A, +}; + +static struct aurix_uart_priv_s g_uart1_priv = +{ + .config = &g_uart1_config, + .txint_enabled = false, + .rxint_enabled = false, +}; + +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +static uart_dev_t g_uart1port = +{ +#if defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(HAVE_SERIAL_CONSOLE) + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1_priv, +}; + +#endif /* CONFIG_TRICORE_UART1 */ + +static inline uintptr_t aurix_serialreg( + const struct aurix_uart_config_s *cfg, uint32_t offset) +{ + return cfg->base + offset; +} + +static inline uint32_t aurix_serialin( + const struct aurix_uart_config_s *cfg, uint32_t offset) +{ + return getreg32(aurix_serialreg(cfg, offset)); +} + +static inline void aurix_serialout( + const struct aurix_uart_config_s *cfg, uint32_t offset, uint32_t value) +{ + putreg32(value, aurix_serialreg(cfg, offset)); +} + +static inline void aurix_serialmod( + const struct aurix_uart_config_s *cfg, uint32_t offset, + uint32_t setbits, uint32_t clrbits) +{ + modreg32(setbits, setbits | clrbits, aurix_serialreg(cfg, offset)); +} + +static int aurix_asclin_wait_clk( + const struct aurix_uart_config_s *cfg, bool on) +{ + uint32_t timeout = ASCLIN_CLK_TIMEOUT; + + while (timeout--) + { + uint32_t csr = aurix_serialin(cfg, ASCLIN_CSR_OFFSET); + bool con = !!(csr & ASCLIN_CSR_CON); + if (con == on) + { + return OK; + } + } + + return -ETIMEDOUT; +} + +static int aurix_asclin_set_clk( + const struct aurix_uart_config_s *cfg, uint8_t clksel) +{ + aurix_serialout(cfg, ASCLIN_CSR_OFFSET, clksel); + return aurix_asclin_wait_clk(cfg, clksel != ASCLIN_CSR_CLKSEL_NONE); +} + +static void aurix_asclin_set_baudrate( + const struct aurix_uart_config_s *cfg) +{ + uint32_t fovs = cfg->baud * cfg->oversampling; + uint32_t fpd = cfg->fclk / cfg->prescaler_val; + + uint32_t n = fovs; + uint32_t d = fpd; + uint32_t h0 = 0; + uint32_t h1 = 1; + uint32_t k0 = 1; + uint32_t k1 = 0; + + while (d != 0) + { + uint32_t a = n / d; + uint32_t r = n - a * d; + uint32_t h2 = a * h1 + h0; + uint32_t k2 = a * k1 + k0; + + if (k2 > 4095u) + { + break; + } + + h0 = h1; + h1 = h2; + k0 = k1; + k1 = k2; + + n = d; + d = r; + } + + if (h1 == 0) + { + h1 = 1; + } + + if (k1 == 0) + { + k1 = 1; + } + + aurix_serialout(cfg, ASCLIN_BRG_OFFSET, ASCLIN_BRG_VAL(h1, k1)); +} + +static void aurix_asclin_set_bittime( + const struct aurix_uart_config_s *cfg) +{ + uint32_t val = 0; + + val |= ((cfg->prescaler_val - 1u) & 0xfffu) + << ASCLIN_BITCON_PRESCALER_SHIFT; + + val |= (((uint32_t)(cfg->oversampling - 1u)) & 0xfu) + << ASCLIN_BITCON_OVERSAMPLING_SHIFT; + + val |= ((uint32_t)cfg->samplepoint & 0xfu) + << ASCLIN_BITCON_SAMPLEPOINT_SHIFT; + + if (cfg->median_filter) + { + val |= ASCLIN_BITCON_SM; + } + + aurix_serialout(cfg, ASCLIN_BITCON_OFFSET, val); +} + +static void aurix_asclin_set_frame( + const struct aurix_uart_config_s *cfg) +{ + uint32_t framecon; + uint32_t datcon; + uint32_t txfifocon; + uint32_t rxfifocon; + + framecon = ASCLIN_FRAMECON_MODE_ASC; + + framecon |= ((uint32_t)cfg->stop_bits & 0x7u) + << ASCLIN_FRAMECON_STOP_SHIFT; + + if (cfg->parity != 0) + { + framecon |= ASCLIN_FRAMECON_PEN; + if (cfg->parity == 2) + { + framecon |= ASCLIN_FRAMECON_ODD; + } + } + + aurix_serialout(cfg, ASCLIN_FRAMECON_OFFSET, framecon); + + datcon = ASCLIN_DATCON_DATLEN(cfg->data_bits); + aurix_serialout(cfg, ASCLIN_DATCON_OFFSET, datcon); + + txfifocon = ASCLIN_TXFIFOCON_FLUSH + | ASCLIN_TXFIFOCON_ENO + | ASCLIN_TXFIFOCON_FM_COMBINED + | ASCLIN_TXFIFOCON_INW_1; + + aurix_serialout(cfg, ASCLIN_TXFIFOCON_OFFSET, txfifocon); + + rxfifocon = ASCLIN_RXFIFOCON_FLUSH + | ASCLIN_RXFIFOCON_ENI + | ASCLIN_RXFIFOCON_OUTW_1; + + aurix_serialout(cfg, ASCLIN_RXFIFOCON_OFFSET, rxfifocon); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +static int aurix_asclin_index(const struct aurix_uart_config_s *cfg) +{ + return (int)((cfg->base - TRICORE_ASCLIN_BASE(0)) / TRICORE_ASCLIN_STRIDE); +} + +static int aurix_asclin_init(const struct aurix_uart_config_s *cfg) +{ + int ret; + uint32_t val; + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(false); +#endif + + val = aurix_serialin(cfg, ASCLIN_CLC_OFFSET); + val &= ~ASCLIN_CLC_DISR; + aurix_serialout(cfg, ASCLIN_CLC_OFFSET, val); + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(true); +#endif + + uint32_t timeout = ASCLIN_CLK_TIMEOUT; + + while ((aurix_serialin(cfg, ASCLIN_CLC_OFFSET) & ASCLIN_CLC_DISS) && + timeout--); + + if (timeout == 0) + { + return -ETIMEDOUT; + } + + board_aurix_setup_serial_pin(aurix_asclin_index(cfg)); + + ret = aurix_asclin_set_clk(cfg, ASCLIN_CSR_CLKSEL_NONE); + if (ret < 0) + { + return ret; + } + + aurix_serialout(cfg, ASCLIN_FRAMECON_OFFSET, 0); + + aurix_asclin_set_bittime(cfg); + aurix_asclin_set_baudrate(cfg); + + val = (uint32_t)cfg->rx_alti & ASCLIN_IOCR_ALTI_MASK; + aurix_serialout(cfg, ASCLIN_IOCR_OFFSET, val); + + aurix_asclin_set_frame(cfg); + + aurix_serialout(cfg, ASCLIN_FLAGSENABLE_OFFSET, 0); + aurix_serialout(cfg, ASCLIN_FLAGSCLEAR_OFFSET, ASCLIN_FLAGSCLEAR_ALL); + + val = ASCLIN_FLAGSENABLE_PEE + | ASCLIN_FLAGSENABLE_FEE + | ASCLIN_FLAGSENABLE_RFOE + | ASCLIN_FLAGSENABLE_RFUE + | ASCLIN_FLAGSENABLE_TFOE; + aurix_serialout(cfg, ASCLIN_FLAGSENABLE_OFFSET, val); + + ret = aurix_asclin_set_clk(cfg, cfg->clk_src); + if (ret < 0) + { + return ret; + } + + return OK; +} + +static int aurix_setup(struct uart_dev_s *dev) +{ + struct aurix_uart_priv_s *priv = dev->priv; + + return aurix_asclin_init(priv->config); +} + +static void aurix_shutdown(struct uart_dev_s *dev) +{ + struct aurix_uart_priv_s *priv = dev->priv; + const struct aurix_uart_config_s *cfg = priv->config; + + aurix_serialout(cfg, ASCLIN_FLAGSENABLE_OFFSET, 0); + + aurix_asclin_set_clk(cfg, ASCLIN_CSR_CLKSEL_NONE); + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(false); +#endif + + aurix_serialmod(cfg, ASCLIN_CLC_OFFSET, ASCLIN_CLC_DISR, 0); + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(true); +#endif +} + +static int aurix_attach(struct uart_dev_s *dev) +{ + struct aurix_uart_priv_s *priv = dev->priv; + const struct aurix_uart_config_s *cfg = priv->config; + int ret; + + ret = irq_attach(cfg->rxirq, aurix_interrupt, dev); + if (ret != OK) + { + return ret; + } + + ret = irq_attach(cfg->txirq, aurix_interrupt, dev); + if (ret != OK) + { + irq_detach(cfg->rxirq); + return ret; + } + + ret = irq_attach(cfg->erirq, aurix_interrupt, dev); + if (ret != OK) + { + irq_detach(cfg->rxirq); + irq_detach(cfg->txirq); + return ret; + } + + up_enable_irq(cfg->rxirq); + up_enable_irq(cfg->txirq); + up_enable_irq(cfg->erirq); + + return OK; +} + +static void aurix_detach(struct uart_dev_s *dev) +{ + struct aurix_uart_priv_s *priv = dev->priv; + const struct aurix_uart_config_s *cfg = priv->config; + + up_disable_irq(cfg->rxirq); + up_disable_irq(cfg->txirq); + up_disable_irq(cfg->erirq); + + irq_detach(cfg->rxirq); + irq_detach(cfg->txirq); + irq_detach(cfg->erirq); +} + +static int aurix_interrupt(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct aurix_uart_priv_s *priv = dev->priv; + const struct aurix_uart_config_s *cfg = priv->config; + uint32_t flags; + + flags = aurix_serialin(cfg, ASCLIN_FLAGS_OFFSET); + + if (flags & ASCLIN_FLAGS_RFL) + { + aurix_serialout(cfg, ASCLIN_FLAGSCLEAR_OFFSET, + ASCLIN_FLAGSCLEAR_RFLC); + + uart_recvchars(dev); + } + + if (flags & ASCLIN_FLAGS_TFL) + { + aurix_serialout(cfg, ASCLIN_FLAGSCLEAR_OFFSET, + ASCLIN_FLAGSCLEAR_TFLC); + + uart_xmitchars(dev); + } + + if (flags & (ASCLIN_FLAGS_PE | ASCLIN_FLAGS_FE | ASCLIN_FLAGS_CE | + ASCLIN_FLAGS_RFO | ASCLIN_FLAGS_RFU)) + { + aurix_serialout(cfg, ASCLIN_FLAGSCLEAR_OFFSET, + ASCLIN_FLAGSCLEAR_ALL_ERRS); + } + + return OK; +} + +static int aurix_ioctl(struct file *filep, int cmd, unsigned long arg) +{ + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; + struct aurix_uart_priv_s *priv = dev->priv; + struct aurix_uart_config_s *cfg = + (struct aurix_uart_config_s *)priv->config; + int ret = OK; + + switch (cmd) + { + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + return -EINVAL; + } + + memset(termiosp, 0, sizeof(struct termios)); + + cfsetispeed(termiosp, cfg->baud); + cfsetospeed(termiosp, cfg->baud); + + switch (cfg->data_bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + case 6: + termiosp->c_cflag |= CS6; + break; + case 7: + termiosp->c_cflag |= CS7; + break; + default: + termiosp->c_cflag |= CS8; + break; + } + + if (cfg->parity == 1) + { + termiosp->c_cflag |= PARENB; + } + else if (cfg->parity == 2) + { + termiosp->c_cflag |= PARENB | PARODD; + } + + if (cfg->stop_bits >= 2) + { + termiosp->c_cflag |= CSTOPB; + } + } + break; + + case TCSETS: + case TCSETSW: + case TCSETSF: + { + struct termios *termiosp = (struct termios *)arg; + + if (!termiosp) + { + return -EINVAL; + } + + cfg->baud = cfgetospeed(termiosp); + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + cfg->data_bits = 5; + break; + case CS6: + cfg->data_bits = 6; + break; + case CS7: + cfg->data_bits = 7; + break; + default: + cfg->data_bits = 8; + break; + } + + if (termiosp->c_cflag & PARENB) + { + cfg->parity = (termiosp->c_cflag & PARODD) ? 2 : 1; + } + else + { + cfg->parity = 0; + } + + cfg->stop_bits = (termiosp->c_cflag & CSTOPB) ? 2 : 1; + + aurix_shutdown(dev); Review Comment: After TCSETS, `aurix_asclin_init()` writes FLAGSENABLE with the error flags only (lines 497-502), so RFLE and TFLE are cleared and the port stops receiving. Fix: restore RFLE/TFLE from `priv->rxint_enabled` and `priv->txint_enabled` after `aurix_setup()`. ########## boards/tricore/tc3x/a2g-tc375-lite/scripts/tricore.lsl: ########## @@ -0,0 +1,180 @@ +#include <nuttx/config.h> Review Comment: This new file has no license header. Fix: add the Apache-2.0 header with the SPDX line, as in `tricore.ld`. ########## arch/tricore/src/tc3x/Toolchain.defs: ########## @@ -20,18 +20,22 @@ # ############################################################################ -ifeq ($(CONFIG_ARCH_CHIP_TC397),y) - ifeq ($(CONFIG_TRICORE_TOOLCHAIN_TASKING),y) - ARCHCPUFLAGS += --cpu=tc39xb - LDFLAGS += -Ctc39xb - else - ARCHCPUFLAGS += -mcpu=tc39xx - ARCHCPUFLAGS += -mtc162 - endif +ifeq ($(CONFIG_TRICORE_TOOLCHAIN_LLVM),y) +ARCHCPUFLAGS += -march=tc162 -mcpu=tc3xx +ARCHCPUFLAGS += -Wno-error=implicit-function-declaration Review Comment: `-Wno-error=implicit-function-declaration` hides missing prototypes in every LLVM build (also `tc4x/Toolchain.defs:25` and `cmake/chip.cmake:28,43`). Fix: remove the flag and add the missing declarations. ########## arch/tricore/src/aurix/tricore_serial.c: ########## @@ -0,0 +1,904 @@ +/**************************************************************************** + * arch/tricore/src/aurix/tricore_serial.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/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/irq.h> +#include <nuttx/arch.h> +#include <nuttx/spinlock.h> +#include <nuttx/serial/serial.h> + +#include "tricore_internal.h" +#include "tricore_asclin.h" + +#ifndef CONFIG_TRICORE_ASCLINF_FREQUENCY +# if defined(CONFIG_ARCH_CHIP_FAMILY_TC4X) +# define CONFIG_TRICORE_ASCLINF_FREQUENCY 200000000 +# elif defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) +# define CONFIG_TRICORE_ASCLINF_FREQUENCY 100000000 +# endif +#endif + +/* Default ASCLIN clock source selection */ +#ifndef CONFIG_TRICORE_ASCLIN_CLK_SRC +# define CONFIG_TRICORE_ASCLIN_CLK_SRC ASCLIN_CSR_CLKSEL_FASCLINF +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_OVERSAMPLING +# define CONFIG_TRICORE_ASCLIN_OVERSAMPLING 16u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_SAMPLEPOINT +# define CONFIG_TRICORE_ASCLIN_SAMPLEPOINT 8u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_PRESCALER +# define CONFIG_TRICORE_ASCLIN_PRESCALER 1u +#endif + +#ifndef CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER +# define CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER 1u +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ASCLIN_CLK_TIMEOUT 100000u + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) && defined(CONFIG_TRICORE_UART0) +# define HAVE_SERIAL_CONSOLE 1 +# define CONSOLE_DEV g_uart0port +# define TTYS0_DEV g_uart0port +# ifdef CONFIG_TRICORE_UART1 +# define TTYS1_DEV g_uart1port +# endif +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_TRICORE_UART1) +# define HAVE_SERIAL_CONSOLE 1 +# define CONSOLE_DEV g_uart1port +# define TTYS0_DEV g_uart1port +# ifdef CONFIG_TRICORE_UART0 +# define TTYS1_DEV g_uart0port +# endif +#elif defined(CONFIG_TRICORE_UART0) +# define TTYS0_DEV g_uart0port +# ifdef CONFIG_TRICORE_UART1 +# define TTYS1_DEV g_uart1port +# endif +#elif defined(CONFIG_TRICORE_UART1) +# define TTYS0_DEV g_uart1port +#endif + +struct aurix_uart_config_s +{ + uintptr_t base; + uint32_t fclk; + uint32_t baud; + uint8_t clk_src; + uint8_t oversampling; + uint8_t samplepoint; + uint8_t prescaler_val; + uint8_t median_filter; + uint8_t data_bits; + uint8_t stop_bits; + uint8_t parity; + uint8_t rxirq; + uint8_t txirq; + uint8_t erirq; + uint8_t rx_alti; +}; + +struct aurix_uart_priv_s +{ + struct aurix_uart_config_s *config; + bool txint_enabled; + bool rxint_enabled; +}; + +static int aurix_setup(struct uart_dev_s *dev); +static void aurix_shutdown(struct uart_dev_s *dev); +static int aurix_attach(struct uart_dev_s *dev); +static void aurix_detach(struct uart_dev_s *dev); +static int aurix_interrupt(int irq, void *context, void *arg); +static int aurix_ioctl(struct file *filep, int cmd, unsigned long arg); +static int aurix_receive(struct uart_dev_s *dev, unsigned int *status); +static void aurix_rxint(struct uart_dev_s *dev, bool enable); +static bool aurix_rxavailable(struct uart_dev_s *dev); +static void aurix_send(struct uart_dev_s *dev, int ch); +static void aurix_txint(struct uart_dev_s *dev, bool enable); +static bool aurix_txready(struct uart_dev_s *dev); +static bool aurix_txempty(struct uart_dev_s *dev); + +static const struct uart_ops_s g_uart_ops = +{ + .setup = aurix_setup, + .shutdown = aurix_shutdown, + .attach = aurix_attach, + .detach = aurix_detach, + .ioctl = aurix_ioctl, + .receive = aurix_receive, + .rxint = aurix_rxint, + .rxavailable = aurix_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = NULL, +#endif + .send = aurix_send, + .txint = aurix_txint, + .txready = aurix_txready, + .txempty = aurix_txempty, +}; + +#ifdef CONFIG_TRICORE_UART0 + +static struct aurix_uart_config_s g_uart0_config = +{ + .base = TRICORE_ASCLIN_BASE(0), + .fclk = CONFIG_TRICORE_ASCLINF_FREQUENCY, + .baud = CONFIG_UART0_BAUD, + .clk_src = CONFIG_TRICORE_ASCLIN_CLK_SRC, + .oversampling = CONFIG_TRICORE_ASCLIN_OVERSAMPLING, + .samplepoint = CONFIG_TRICORE_ASCLIN_SAMPLEPOINT, + .prescaler_val = CONFIG_TRICORE_ASCLIN_PRESCALER, + .median_filter = CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER, + .data_bits = CONFIG_UART0_BITS, + .stop_bits = CONFIG_UART0_2STOP ? 2 : 1, +#if defined(CONFIG_UART0_PARITY) && CONFIG_UART0_PARITY == 1 + .parity = 2, +#elif defined(CONFIG_UART0_PARITY) && CONFIG_UART0_PARITY == 2 + .parity = 1, +#else + .parity = 0, +#endif + .rxirq = CONFIG_TRICORE_UART0_RXIRQ, + .txirq = CONFIG_TRICORE_UART0_TXIRQ, + .erirq = CONFIG_TRICORE_UART0_ERIRQ, + + .rx_alti = ASCLIN_IOCR_ALTI_A, +}; + +static struct aurix_uart_priv_s g_uart0_priv = +{ + .config = &g_uart0_config, + .txint_enabled = false, + .rxint_enabled = false, +}; + +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; + +static uart_dev_t g_uart0port = +{ +#ifdef HAVE_SERIAL_CONSOLE + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0_priv, +}; + +#endif /* CONFIG_TRICORE_UART0 */ + +#ifdef CONFIG_TRICORE_UART1 + +static struct aurix_uart_config_s g_uart1_config = +{ + .base = TRICORE_ASCLIN_BASE(1), + .fclk = CONFIG_TRICORE_ASCLINF_FREQUENCY, + .baud = CONFIG_UART1_BAUD, + .clk_src = CONFIG_TRICORE_ASCLIN_CLK_SRC, + .oversampling = CONFIG_TRICORE_ASCLIN_OVERSAMPLING, + .samplepoint = CONFIG_TRICORE_ASCLIN_SAMPLEPOINT, + .prescaler_val = CONFIG_TRICORE_ASCLIN_PRESCALER, + .median_filter = CONFIG_TRICORE_ASCLIN_MEDIAN_FILTER, + .data_bits = CONFIG_UART1_BITS, + .stop_bits = CONFIG_UART1_2STOP ? 2 : 1, +#if defined(CONFIG_UART1_PARITY) && CONFIG_UART1_PARITY == 1 + .parity = 2, +#elif defined(CONFIG_UART1_PARITY) && CONFIG_UART1_PARITY == 2 + .parity = 1, +#else + .parity = 0, +#endif + .rxirq = CONFIG_TRICORE_UART1_RXIRQ, + .txirq = CONFIG_TRICORE_UART1_TXIRQ, + .erirq = CONFIG_TRICORE_UART1_ERIRQ, + + .rx_alti = ASCLIN_IOCR_ALTI_A, +}; + +static struct aurix_uart_priv_s g_uart1_priv = +{ + .config = &g_uart1_config, + .txint_enabled = false, + .rxint_enabled = false, +}; + +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +static uart_dev_t g_uart1port = +{ +#if defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(HAVE_SERIAL_CONSOLE) + .isconsole = true, +#endif + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1_priv, +}; + +#endif /* CONFIG_TRICORE_UART1 */ + +static inline uintptr_t aurix_serialreg( + const struct aurix_uart_config_s *cfg, uint32_t offset) +{ + return cfg->base + offset; +} + +static inline uint32_t aurix_serialin( + const struct aurix_uart_config_s *cfg, uint32_t offset) +{ + return getreg32(aurix_serialreg(cfg, offset)); +} + +static inline void aurix_serialout( + const struct aurix_uart_config_s *cfg, uint32_t offset, uint32_t value) +{ + putreg32(value, aurix_serialreg(cfg, offset)); +} + +static inline void aurix_serialmod( + const struct aurix_uart_config_s *cfg, uint32_t offset, + uint32_t setbits, uint32_t clrbits) +{ + modreg32(setbits, setbits | clrbits, aurix_serialreg(cfg, offset)); +} + +static int aurix_asclin_wait_clk( + const struct aurix_uart_config_s *cfg, bool on) +{ + uint32_t timeout = ASCLIN_CLK_TIMEOUT; + + while (timeout--) + { + uint32_t csr = aurix_serialin(cfg, ASCLIN_CSR_OFFSET); + bool con = !!(csr & ASCLIN_CSR_CON); + if (con == on) + { + return OK; + } + } + + return -ETIMEDOUT; +} + +static int aurix_asclin_set_clk( + const struct aurix_uart_config_s *cfg, uint8_t clksel) +{ + aurix_serialout(cfg, ASCLIN_CSR_OFFSET, clksel); + return aurix_asclin_wait_clk(cfg, clksel != ASCLIN_CSR_CLKSEL_NONE); +} + +static void aurix_asclin_set_baudrate( + const struct aurix_uart_config_s *cfg) +{ + uint32_t fovs = cfg->baud * cfg->oversampling; + uint32_t fpd = cfg->fclk / cfg->prescaler_val; + + uint32_t n = fovs; + uint32_t d = fpd; + uint32_t h0 = 0; + uint32_t h1 = 1; + uint32_t k0 = 1; + uint32_t k1 = 0; + + while (d != 0) + { + uint32_t a = n / d; + uint32_t r = n - a * d; + uint32_t h2 = a * h1 + h0; + uint32_t k2 = a * k1 + k0; + + if (k2 > 4095u) + { + break; + } + + h0 = h1; + h1 = h2; + k0 = k1; + k1 = k2; + + n = d; + d = r; + } + + if (h1 == 0) + { + h1 = 1; + } + + if (k1 == 0) + { + k1 = 1; + } + + aurix_serialout(cfg, ASCLIN_BRG_OFFSET, ASCLIN_BRG_VAL(h1, k1)); +} + +static void aurix_asclin_set_bittime( + const struct aurix_uart_config_s *cfg) +{ + uint32_t val = 0; + + val |= ((cfg->prescaler_val - 1u) & 0xfffu) + << ASCLIN_BITCON_PRESCALER_SHIFT; + + val |= (((uint32_t)(cfg->oversampling - 1u)) & 0xfu) + << ASCLIN_BITCON_OVERSAMPLING_SHIFT; + + val |= ((uint32_t)cfg->samplepoint & 0xfu) + << ASCLIN_BITCON_SAMPLEPOINT_SHIFT; + + if (cfg->median_filter) + { + val |= ASCLIN_BITCON_SM; + } + + aurix_serialout(cfg, ASCLIN_BITCON_OFFSET, val); +} + +static void aurix_asclin_set_frame( + const struct aurix_uart_config_s *cfg) +{ + uint32_t framecon; + uint32_t datcon; + uint32_t txfifocon; + uint32_t rxfifocon; + + framecon = ASCLIN_FRAMECON_MODE_ASC; + + framecon |= ((uint32_t)cfg->stop_bits & 0x7u) + << ASCLIN_FRAMECON_STOP_SHIFT; + + if (cfg->parity != 0) + { + framecon |= ASCLIN_FRAMECON_PEN; + if (cfg->parity == 2) + { + framecon |= ASCLIN_FRAMECON_ODD; + } + } + + aurix_serialout(cfg, ASCLIN_FRAMECON_OFFSET, framecon); + + datcon = ASCLIN_DATCON_DATLEN(cfg->data_bits); + aurix_serialout(cfg, ASCLIN_DATCON_OFFSET, datcon); + + txfifocon = ASCLIN_TXFIFOCON_FLUSH + | ASCLIN_TXFIFOCON_ENO + | ASCLIN_TXFIFOCON_FM_COMBINED + | ASCLIN_TXFIFOCON_INW_1; + + aurix_serialout(cfg, ASCLIN_TXFIFOCON_OFFSET, txfifocon); + + rxfifocon = ASCLIN_RXFIFOCON_FLUSH + | ASCLIN_RXFIFOCON_ENI + | ASCLIN_RXFIFOCON_OUTW_1; + + aurix_serialout(cfg, ASCLIN_RXFIFOCON_OFFSET, rxfifocon); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +static int aurix_asclin_index(const struct aurix_uart_config_s *cfg) +{ + return (int)((cfg->base - TRICORE_ASCLIN_BASE(0)) / TRICORE_ASCLIN_STRIDE); +} + +static int aurix_asclin_init(const struct aurix_uart_config_s *cfg) +{ + int ret; + uint32_t val; + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(false); +#endif + + val = aurix_serialin(cfg, ASCLIN_CLC_OFFSET); + val &= ~ASCLIN_CLC_DISR; + aurix_serialout(cfg, ASCLIN_CLC_OFFSET, val); + +#if defined(CONFIG_ARCH_CHIP_FAMILY_TC3X) + aurix_cpu_endinit_enable(true); +#endif + + uint32_t timeout = ASCLIN_CLK_TIMEOUT; + + while ((aurix_serialin(cfg, ASCLIN_CLC_OFFSET) & ASCLIN_CLC_DISS) && + timeout--); + + if (timeout == 0) Review Comment: `timeout--` in the loop condition wraps to `UINT32_MAX`, so `if (timeout == 0)` never sees the timeout. Fix: after the loop, test `ASCLIN_CLC_DISS` again and return `-ETIMEDOUT` if it is still set. ########## boards/tricore/tc3x/a2g-tc375-lite/scripts/Make.defs: ########## @@ -22,23 +22,50 @@ include $(TOPDIR)/.config include $(TOPDIR)/tools/Config.mk -include $(TOPDIR)/arch/tricore/src/tc4xx/Toolchain.defs +include $(TOPDIR)/arch/tricore/src/tc3x/Toolchain.defs -ifeq ($(CONFIG_TRICORE_TOOLCHAIN_TASKING),y) - TRICORE_TOOLCHAIN := Tasking +ifeq ($(CONFIG_TRICORE_TOOLCHAIN_LLVM),y) +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)tricore-llvm.ld +else ifeq ($(CONFIG_TRICORE_TOOLCHAIN_TASKING),y) +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)tricore.lsl else - TRICORE_TOOLCHAIN := Gnuc -endif - -ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)Lcf_$(TRICORE_TOOLCHAIN)_Tricore_Tc.lsl.kernel - -ifeq ($(CONFIG_BUILD_PROTECTED),y) - ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)Lcf_$(TRICORE_TOOLCHAIN)_Tricore_Tc.lsl.user +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)tricore.ld endif CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 + +ifneq ($(CONFIG_TRICORE_TOOLCHAIN_TASKING),y) +LDFLAGS += --gc-sections +endif + +OPENOCD ?= /opt/tooling/tricore-openocd/bin/openocd +OPENOCD_SCRIPTS ?= /opt/tooling/tricore-openocd/share/openocd/scripts/ +OPENOCD_BOARD ?= board/infineon/kit_a2g_tc375_lite.cfg +OPENOCD_SERIAL ?= AURIX LITE KIT V2.0 (TC375) LKAS28QS Review Comment: `OPENOCD_SERIAL` defaults to one specific kit, so `make flash` fails on every other TC375 Lite Kit. Fix: make the default empty. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
