diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 698aa21607252..da91fb6c27c0e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,13 +67,13 @@ jobs: # Determine the repo and leave that unset to use the normal checkout behavior # of using the merge commit instead of HEAD case $GITHUB_REPOSITORY in - "apache/nuttx") + "tiiuae/nuttx") # OS echo "Triggered by change in OS" APPS_REF=$REF_NAME ;; - "apache/nuttx-apps" ) + "tiiuae/incubator-nuttx-apps" ) # APPS OS_REF=$REF_NAME echo "Triggered by change in APPS" @@ -89,9 +89,9 @@ jobs: echo "app_ref=$APPS_REF" >> $GITHUB_OUTPUT - name: Checkout nuttx repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: apache/nuttx + repository: tiiuae/nuttx ref: ${{ steps.gittargets.outputs.os_ref }} path: sources/nuttx fetch-depth: 1 @@ -99,9 +99,9 @@ jobs: run: git -C sources/nuttx fetch --tags - name: Checkout apps repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: apache/nuttx-apps + repository: tiiuae/incubator-nuttx-apps ref: ${{ steps.gittargets.outputs.apps_ref }} path: sources/apps fetch-depth: 1 @@ -123,7 +123,7 @@ jobs: strategy: matrix: - boards: [arm-01, arm-02, arm-03, arm-04, arm-05, arm-06, arm-07, arm-08, arm-09, arm-10, arm-11, arm-12, arm-13, other, risc-v, sim-01, sim-02, xtensa, codechecker] + boards: [arm-12, risc-v] steps: - name: Download Source Artifact @@ -173,6 +173,7 @@ jobs: continue-on-error: true macOS: + if: ${{ false }} # disable for now permissions: contents: none runs-on: macos-13 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index b2ce7b9ccd8a4..ca0cd858f63b8 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -30,9 +30,9 @@ jobs: steps: - name: Checkout nuttx repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - repository: apache/nuttx + repository: tiiuae/nuttx path: nuttx fetch-depth: 0 diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 53c6c51825df2..81a16de70d0a0 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -27,7 +27,7 @@ jobs: build-html: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.8' diff --git a/.github/workflows/docker_linux.yml b/.github/workflows/docker_linux.yml index 0494d14e8a1da..75593042f52f3 100644 --- a/.github/workflows/docker_linux.yml +++ b/.github/workflows/docker_linux.yml @@ -46,7 +46,7 @@ jobs: IMAGE_TAG: ghcr.io/${{ github.repository }}/apache-nuttx-ci-linux steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0b0324560e464..b7c1070be4bb5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: name: Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - run: mkdir super-linter.report diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index 92daf09f5d32f..0e14c905b4713 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -3136,7 +3136,9 @@ static inline int stm32_dm9161(struct stm32_ethmac_s *priv) static int stm32_phyinit(struct stm32_ethmac_s *priv) { +#ifdef CONFIG_STM32F7_AUTONEG volatile uint32_t timeout; +#endif uint32_t regval; uint16_t phyval; int ret; diff --git a/arch/risc-v/src/litex/litex_sdio.c b/arch/risc-v/src/litex/litex_sdio.c index eec66ed29589f..13359662a3f13 100644 --- a/arch/risc-v/src/litex/litex_sdio.c +++ b/arch/risc-v/src/litex/litex_sdio.c @@ -860,12 +860,10 @@ static int litex_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, /* flush CPU d-cache */ -#ifndef CONFIG_LITEX_COHERENT_DMA up_invalidate_dcache_all(); -#endif putreg32(0, LITEX_SDBLOCK2MEM_DMA_ENABLE); - putreg32((uintptr_t)(&buffer[4]), LITEX_SDBLOCK2MEM_DMA_BASE); + putreg32((uintptr_t)buffer >> 32, LITEX_SDBLOCK2MEM_DMA_BASE); putreg32((uintptr_t)buffer, LITEX_SDBLOCK2MEM_DMA_BASE + 0x04); putreg32(nbytes, LITEX_SDBLOCK2MEM_DMA_LENGTH); putreg32(1, LITEX_SDBLOCK2MEM_DMA_ENABLE); @@ -905,12 +903,10 @@ static int litex_sendsetup(struct sdio_dev_s *dev, /* flush CPU d-cache */ -#ifndef CONFIG_LITEX_COHERENT_DMA up_invalidate_dcache_all(); -#endif putreg32(0, LITEX_SDMEM2BLOCK_DMA_ENABLE); - putreg32((uintptr_t)(&buffer[4]), LITEX_SDMEM2BLOCK_DMA_BASE); + putreg32((uintptr_t)buffer >> 32, LITEX_SDMEM2BLOCK_DMA_BASE); putreg32((uintptr_t)buffer, LITEX_SDMEM2BLOCK_DMA_BASE + 0x04); putreg32(nbytes, LITEX_SDMEM2BLOCK_DMA_LENGTH); putreg32(1, LITEX_SDMEM2BLOCK_DMA_ENABLE); diff --git a/arch/risc-v/src/mpfs/.gitignore b/arch/risc-v/src/mpfs/.gitignore new file mode 100644 index 0000000000000..b099a95f78380 --- /dev/null +++ b/arch/risc-v/src/mpfs/.gitignore @@ -0,0 +1 @@ +/crypto diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 9245994e36113..a13d98ad3a86d 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -243,15 +243,48 @@ config MPFS_HAVE_UART4 select UART4_SERIALDRIVER select ARCH_HAVE_SERIAL_TERMIOS +config MPFS_HAVE_UART5 + bool + depends on MPFS_FPGA_UART + default n + select UART5_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + +config MPFS_HAVE_UART6 + bool + depends on MPFS_FPGA_UART + default n + select UART6_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + +config MPFS_HAVE_UART7 + bool + depends on MPFS_FPGA_UART + default n + select UART7_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + # These are the peripheral selections proper +config MPFS_SPI + bool + default n + config MPFS_SPI0 bool "SPI 0" default n + select MPFS_SPI config MPFS_SPI1 bool "SPI 1" default n + select MPFS_SPI + +config MPFS_FPGA_UART + bool "FPGA uarts" + default n + ---help--- + Use FPGA UARTs instead of MSS UARTS. config MPFS_UART0 bool "UART 0" @@ -288,6 +321,30 @@ config MPFS_UART4 select ARCH_HAVE_SERIAL_TERMIOS select MPFS_HAVE_UART4 +config MPFS_UART5 + bool "UART 5" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART5 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART5 + +config MPFS_UART6 + bool "UART 6" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART6 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART6 + +config MPFS_UART7 + bool "UART 7" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART7 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART7 + config MPFS_I2C0 bool "I2C 0" select ARCH_HAVE_I2CRESET @@ -398,7 +455,7 @@ config MPFS_IHC_LINUX_ON_HART3 config MPFS_IHC_LINUX_ON_HART4 int "Linux on hart4" depends on MPFS_IHC_CLIENT || MPFS_IHC_SBI - default 1 + default 0 range 0 1 ---help--- Set this to 1 if U-boot / Linux is running on hart4 @@ -451,6 +508,43 @@ config MPFS_IHC_RPMSG_CH2 Use this only if using 2 x RPMSG channels. This makes the NuttX work as the RPMSG channel 2 client. +config MPFS_IHC_WITH_HSS + bool "IHC with HSS" + depends on MPFS_IHC_CLIENT + default n + ---help--- + Set this to true if using IHC with HSS bootloader + +config MPFS_CH1_VRING_SHMEM_ADDR + hex "Channel 1 Vring shared memory start" + default 0xA2410000 + depends on MPFS_IHC_CLIENT + +config MPFS_CH1_VRING0_DESC_ADDR + hex "Channel 1 Vring0 descriptor area" + default 0xA2400000 + depends on MPFS_IHC_CLIENT + +config MPFS_CH1_VRING1_DESC_ADDR + hex "Channel 1 Vring1 descriptor area" + default 0xA2408000 + depends on MPFS_IHC_CLIENT + +config MPFS_CH2_VRING_SHMEM_ADDR + hex "Channel 2 Vring shared memory start" + default 0xA2460000 + depends on MPFS_IHC_CLIENT && MPFS_IHC_RPMSG_CH2 + +config MPFS_CH2_VRING0_DESC_ADDR + hex "Channel 2 Vring0 descriptor area" + default 0xA2450000 + depends on MPFS_IHC_CLIENT && MPFS_IHC_RPMSG_CH2 + +config MPFS_CH2_VRING1_DESC_ADDR + hex "Channel 2 Vring1 descriptor area" + default 0xA2458000 + depends on MPFS_IHC_CLIENT && MPFS_IHC_RPMSG_CH2 + config MPFS_ETHMAC bool default n @@ -528,12 +622,6 @@ config MPFS_COREPWM0_BASE default 0x44000000 depends on MPFS_COREPWM0 -config MPFS_COREPWM0_PWMCLK - int "Clock frequency of the CorePWM0 block (Hz)" - default 25000000 - range 1000000 100000000 - depends on MPFS_COREPWM0 - config MPFS_COREPWM0_REGWIDTH int "Width of the PWM register (8, 16 or 32 bits)" default 32 @@ -557,12 +645,6 @@ config MPFS_COREPWM1_BASE default 0x45000000 depends on MPFS_COREPWM1 -config MPFS_COREPWM1_PWMCLK - int "Clock frequency of the CorePWM1 block (Hz)" - default 25000000 - range 1000000 100000000 - depends on MPFS_COREPWM1 - config MPFS_COREPWM1_REGWIDTH int "Width of the PWM register (8, 16 or 32 bits)" default 32 @@ -575,6 +657,56 @@ config MPFS_COREPWM1_NCHANNELS range 1 16 depends on MPFS_COREPWM1 +comment "CAN-FD Options" + +config MPFS_HAVE_CANFD + bool "CAN FD" + select ARCH_HAVE_CAN_ERRORS + select NET_CAN_HAVE_CANFD + select NET_CAN_EXTID + select NET_CAN_HAVE_TX_DEADLINE + default n + +config MPFS_CANFD0 + bool "MPFS FPGA CANFD0 IP block configured" + default n + depends on MPFS_HAVE_CANFD + +config MPFS_CANFD_BASE0 + hex "Base address for the CANFD0 instance" + default 0x46000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD_ARBI_BITRATE0 + int "CANFD0 Arbitration phase bitrate" + default 1000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD_DATA_BITRATE0 + int "CANFD0 Data phase bitrate" + default 4000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD1 + bool "MPFS FPGA CANFD1 IP block configured" + default n + depends on MPFS_HAVE_CANFD + +config MPFS_CANFD_BASE1 + hex "Base address for the CANFD1 instance" + default 0x47000000 + depends on MPFS_CANFD1 + +config MPFS_CANFD_ARBI_BITRATE1 + int "CANFD1 Arbitration phase bitrate" + default 1000000 + depends on MPFS_CANFD1 + +config MPFS_CANFD_DATA_BITRATE1 + int "CANFD1 Data phase bitrate" + default 4000000 + depends on MPFS_CANFD1 + endmenu config MPFS_DMA @@ -740,3 +872,13 @@ config ARCH_MPU_HAS_NO4 config ARCH_MPU_HAS_NAPOT default y + +config MPFS_CRYPTO + bool "Enable MPFS HW crypto" + default n + +if MPFS_CRYPTO +config MPFS_CRYPTO_DMA + bool "Enable MPFS HW crypto DMA" + default y +endif diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index d4765ba0be8fb..2692647db7a59 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -32,7 +32,7 @@ CHIP_CSRCS += mpfs_irq.c mpfs_irq_dispatch.c CHIP_CSRCS += mpfs_lowputc.c mpfs_serial.c CHIP_CSRCS += mpfs_start.c mpfs_timerisr.c CHIP_CSRCS += mpfs_gpio.c mpfs_systemreset.c -CHIP_CSRCS += mpfs_plic.c +CHIP_CSRCS += mpfs_plic.c mpfs_dsn.c ifeq ($(CONFIG_MPFS_DMA),y) CHIP_CSRCS += mpfs_dma.c @@ -50,7 +50,7 @@ ifeq ($(CONFIG_MM_PGALLOC),y) CHIP_CSRCS += mpfs_pgalloc.c endif -ifeq ($(CONFIG_SPI),y) +ifeq ($(CONFIG_MPFS_SPI),y) CHIP_CSRCS += mpfs_spi.c endif @@ -74,6 +74,10 @@ ifeq (${CONFIG_MPFS_HAVE_COREPWM},y) CHIP_CSRCS += mpfs_corepwm.c endif +ifeq (${CONFIG_MPFS_HAVE_CANFD}, y) +CHIP_CSRCS += mpfs_fpga_canfd.c +endif + ifeq (${CONFIG_MPFS_DDR_INIT},y) CHIP_CSRCS += mpfs_ddr.c endif @@ -84,6 +88,7 @@ endif ifeq (${CONFIG_MPFS_OPENSBI},y) CHIP_ASRCS += mpfs_opensbi_utils.S +CHIP_ASRCS += mpfs_opensbi_trap.S CHIP_CSRCS += mpfs_opensbi.c endif @@ -103,3 +108,6 @@ ifeq ($(CONFIG_MPFS_CORESPI),y) CHIP_CSRCS += mpfs_corespi.c endif +ifeq ($(CONFIG_MPFS_CRYPTO),y) +include mpfs/crypto.defs +endif diff --git a/arch/risc-v/src/mpfs/crypto.defs b/arch/risc-v/src/mpfs/crypto.defs new file mode 100644 index 0000000000000..98f5c330e65c1 --- /dev/null +++ b/arch/risc-v/src/mpfs/crypto.defs @@ -0,0 +1,14 @@ +MPFS_CRYPTO = mpfs/crypto/.git +$(MPFS_CRYPTO): + $(Q) echo "Symlink PolarFire crypto driver submodule" + $(Q) $(DIRLINK) $(CURDIR)/../../../../extern/pf_crypto mpfs/crypto + +context::$(MPFS_CRYPTO) + +distclean:: + $(Q) rm -rf mpfs/crypto + +CHIP_CSRCS += mpfs_crypto.c mpfs_systemservice.c + +DEPPATH += --dep-path mpfs/crypto +VPATH += :mpfs/crypto diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h index a15d849267902..d398cca8dbd71 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h @@ -21,6 +21,12 @@ #ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_CLINT_H #define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_CLINT_H +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "mpfs_memorymap.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h new file mode 100644 index 0000000000000..e883ccef22011 --- /dev/null +++ b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h @@ -0,0 +1,465 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h + * + * 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_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H +#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define MPFS_CANFD_DEVICE_ID_OFFSET (0x00) +#define MPFS_CANFD_VERSION_OFFSET (0x02) + +#define MPFS_CANFD_MODE_OFFSET (0x04) +#define MPFS_CANFD_SETTINGS_OFFSET (0x06) + +#define MPFS_CANFD_STATUS_OFFSET (0x08) + +#define MPFS_CANFD_COMMAND_OFFSET (0x0c) + +#define MPFS_CANFD_INT_STAT_OFFSET (0x10) + +#define MPFS_CANFD_INT_ENA_SET_OFFSET (0x14) + +#define MPFS_CANFD_INT_ENA_CLR_OFFSET (0x18) + +#define MPFS_CANFD_INT_MASK_SET_OFFSET (0x1c) + +#define MPFS_CANFD_INT_MASK_CLR_OFFSET (0x20) + +#define MPFS_CANFD_BTR_OFFSET (0x24) + +#define MPFS_CANFD_BTR_FD_OFFSET (0x28) + +#define MPFS_CANFD_EWL_OFFSET (0x2c) +#define MPFS_CANFD_ERP_OFFSET (0x2d) +#define MPFS_CANFD_FAULT_STATE_OFFSET (0x2e) + +#define MPFS_CANFD_REC_OFFSET (0x30) +#define MPFS_CANFD_TEC_OFFSET (0x32) + +#define MPFS_CANFD_ERR_NORM_OFFSET (0x34) +#define MPFS_CANFD_ERR_FD_OFFSET (0x36) + +#define MPFS_CANFD_CTR_PRES_OFFSET (0x38) + +#define MPFS_CANFD_FILTER_A_MASK_OFFSET (0x3c) + +#define MPFS_CANFD_FILTER_A_VAL_OFFSET (0x40) + +#define MPFS_CANFD_FILTER_B_MASK_OFFSET (0x44) + +#define MPFS_CANFD_FILTER_B_VAL_OFFSET (0x48) + +#define MPFS_CANFD_FILTER_C_MASK_OFFSET (0x4c) + +#define MPFS_CANFD_FILTER_C_VAL_OFFSET (0x50) + +#define MPFS_CANFD_FILTER_RAN_LOW_OFFSET (0x54) + +#define MPFS_CANFD_FILTER_RAN_HIGH_OFFSET (0x58) + +#define MPFS_CANFD_FILTER_CONTROL_OFFSET (0x5c) +#define MPFS_CANFD_FILTER_STATUS_OFFSET (0x5e) + +/* RX registers */ +#define MPFS_CANFD_RX_MEM_INFO_OFFSET (0x60) + +#define MPFS_CANFD_RX_POINTERS_OFFSET (0x64) + +#define MPFS_CANFD_RX_STATUS_OFFSET (0x68) +#define MPFS_CANFD_RX_SETTINGS_OFFSET (0x6a) + +#define MPFS_CANFD_RX_DATA_OFFSET (0x6c) + +/* TX registers */ +#define MPFS_CANFD_TX_STATUS_OFFSET (0x70) + +#define MPFS_CANFD_TX_COMMAND_OFFSET (0x74) +#define MPFS_CANFD_TXTB_INFO_OFFSET (0x76) + +#define MPFS_CANFD_TX_PRIORITY_OFFSET (0x78) + +#define MPFS_CANFD_ERR_CAPT_OFFSET (0x7c) +#define MPFS_CANFD_RETR_CTR_OFFSET (0x7d) +#define MPFS_CANFD_ALC_OFFSET (0x7e) + +#define MPFS_CANFD_TRV_DELAY_OFFSET (0x80) +#define MPFS_CANFD_SSP_CFG_OFFSET (0x82) + +#define MPFS_CANFD_RX_FR_CTR_OFFSET (0x84) + +#define MPFS_CANFD_TX_FR_CTR_OFFSET (0x88) + +#define MPFS_CANFD_DEBUG_REGISTER_OFFSET (0x8c) + +#define MPFS_CANFD_YOLO_OFFSET (0x90) + +#define MPFS_CANFD_TIMESTAMP_LOW_OFFSET (0x94) + +#define MPFS_CANFD_TIMESTAMP_HIGH_OFFSET (0x98) + +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_1 (0x100) +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_2 (0x104) +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_20 (0x14c) + +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_1 (0x200) +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_2 (0x204) +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_20 (0x24c) + +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_1 (0x300) +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_2 (0x304) +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_20 (0x34c) + +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_1 (0x400) +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_2 (0x404) +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_20 (0x44c) + +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_1 (0x500) +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_2 (0x504) +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_20 (0x54c) + +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_1 (0x600) +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_2 (0x604) +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_20 (0x64c) + +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_1 (0x700) +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_2 (0x704) +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_20 (0x74c) + +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_1 (0x800) +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_2 (0x804) +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_20 (0x84c) + +# define MPFS_CANFD_CTUCANFD_TST_CONTROL (0x900) +# define MPFS_CANFD_CTUCANFD_TST_DEST (0x904) +# define MPFS_CANFD_CTUCANFD_TST_WDATA (0x908) +# define MPFS_CANFD_CTUCANFD_TST_RDATA (0x90c) + +/* Control_registers memory region ******************************************/ + +/* DEVICE ID / VERSION registers */ +#define MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT (0) +#define MPFS_CANFD_DEVICE_ID_DEVICE_ID (0xffff << MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT) +#define MPFS_CANFD_DEVICE_ID_VER_MINOR_SHIFT (16) +#define MPFS_CANFD_DEVICE_ID_VER_MINOR (0xff << MPFS_CANFD_DEVICE_ID_VER_MINOR_SHIFT) +#define MPFS_CANFD_DEVICE_ID_VER_MAJOR_SHIFT (24) +#define MPFS_CANFD_DEVICE_ID_VER_MAJOR (0xff << MPFS_CANFD_DEVICE_ID_VER_MAJOR_SHIFT) + +/* MODE / SETTINGS registers */ +#define MPFS_CANFD_MODE_RST (1 << 0) +#define MPFS_CANFD_MODE_BMM (1 << 1) +#define MPFS_CANFD_MODE_STM (1 << 2) +#define MPFS_CANFD_MODE_AFM (1 << 3) +#define MPFS_CANFD_MODE_FDE (1 << 4) +#define MPFS_CANFD_MODE_TTTM (1 << 5) +#define MPFS_CANFD_MODE_ROM (1 << 6) +#define MPFS_CANFD_MODE_ACF (1 << 7) +#define MPFS_CANFD_MODE_TSTM (1 << 8) +#define MPFS_CANFD_MODE_RXBAM (1 << 9) +#define MPFS_CANFD_MODE_RTRLE (1 << 16) +#define MPFS_CANFD_MODE_RTRTH_SHIFT (17) +#define MPFS_CANFD_MODE_RTRTH (0x0f << MPFS_CANFD_MODE_RTRTH_SHIFT) +#define MPFS_CANFD_MODE_ILBP (1 << 21) +#define MPFS_CANFD_MODE_ENA (1 << 22) +#define MPFS_CANFD_MODE_NISOFD (1 << 23) +#define MPFS_CANFD_MODE_PEX (1 << 24) +#define MPFS_CANFD_MODE_TBFBO (1 << 25) +#define MPFS_CANFD_MODE_FDRF (1 << 26) + +/* STATUS registers */ +#define MPFS_CANFD_STATUS_RXNE (1 << 0) +#define MPFS_CANFD_STATUS_DOR (1 << 1) +#define MPFS_CANFD_STATUS_TXNF (1 << 2) +#define MPFS_CANFD_STATUS_EFT (1 << 3) +#define MPFS_CANFD_STATUS_RXS (1 << 4) +#define MPFS_CANFD_STATUS_TXS (1 << 5) +#define MPFS_CANFD_STATUS_EWL (1 << 6) +#define MPFS_CANFD_STATUS_IDLE (1 << 7) +#define MPFS_CANFD_STATUS_PEXS (1 << 8) +#define MPFS_CANFD_STATUS_STCNT (1 << 16) +#define MPFS_CANFD_STATUS_STRGS (1 << 17) + +/* COMMAND registers */ +#define MPFS_CANFD_COMMAND_RXRPMV (1 << 1) +#define MPFS_CANFD_COMMAND_RRB (1 << 2) +#define MPFS_CANFD_COMMAND_CDO (1 << 3) +#define MPFS_CANFD_COMMAND_ERCRST (1 << 4) +#define MPFS_CANFD_COMMAND_RXFCRST (1 << 5) +#define MPFS_CANFD_COMMAND_TXFCRST (1 << 6) +#define MPFS_CANFD_COMMAND_CPEXS (1 << 7) + +/* INT_STAT registers */ +#define MPFS_CANFD_INT_STAT_RXI (1 << 0) +#define MPFS_CANFD_INT_STAT_TXI (1 << 1) +#define MPFS_CANFD_INT_STAT_EWLI (1 << 2) +#define MPFS_CANFD_INT_STAT_DOI (1 << 3) +#define MPFS_CANFD_INT_STAT_FCSI (1 << 4) +#define MPFS_CANFD_INT_STAT_ALI (1 << 5) +#define MPFS_CANFD_INT_STAT_BEI (1 << 6) +#define MPFS_CANFD_INT_STAT_OFI (1 << 7) +#define MPFS_CANFD_INT_STAT_RXFI (1 << 8) +#define MPFS_CANFD_INT_STAT_BSI (1 << 9) +#define MPFS_CANFD_INT_STAT_RBNEI (1 << 10) +#define MPFS_CANFD_INT_STAT_TXBHCI (1 << 11) + +/* INT_ENA_SET registers */ +#define MPFS_CANFD_INT_ENA_SET_INT_ENA_SET (0x0fff << 0) + +/* INT_ENA_CLR registers */ +#define MPFS_CANFD_INT_ENA_CLR_INT_ENA_CLR (0x0fff << 0) + +/* INT_MASK_SET registers */ +#define MPFS_CANFD_INT_MASK_SET_INT_MASK_SET (0x0fff << 0) + +/* INT_MASK_CLR registers */ +#define MPFS_CANFD_INT_MASK_CLR_INT_MASK_CLR (0x0fff << 0) + +/* BTR registers */ +#define MPFS_CANFD_BTR_PROP_SHIFT (0) +#define MPFS_CANFD_BTR_PROP (0x7f << MPFS_CANFD_BTR_PROP_SHIFT) +#define MPFS_CANFD_BTR_PH1_SHIFT (7) +#define MPFS_CANFD_BTR_PH1 (0x3f << MPFS_CANFD_BTR_PH1_SHIFT) +#define MPFS_CANFD_BTR_PH2_SHIFT (13) +#define MPFS_CANFD_BTR_PH2 (0x3f << MPFS_CANFD_BTR_PH2_SHIFT) +#define MPFS_CANFD_BTR_BRP_SHIFT (19) +#define MPFS_CANFD_BTR_BRP (0xff << MPFS_CANFD_BTR_BRP_SHIFT) +#define MPFS_CANFD_BTR_SJW_SHIFT (27) +#define MPFS_CANFD_BTR_SJW (0x1f << MPFS_CANFD_BTR_SJW_SHIFT) + +/* BTR_FD registers */ +#define MPFS_CANFD_BTR_FD_PROP_FD_SHIFT (0) +#define MPFS_CANFD_BTR_FD_PROP_FD (0x3f << MPFS_CANFD_BTR_FD_PROP_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_PH1_FD_SHIFT (7) +#define MPFS_CANFD_BTR_FD_PH1_FD (0x1f << MPFS_CANFD_BTR_FD_PH1_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_PH2_FD_SHIFT (13) +#define MPFS_CANFD_BTR_FD_PH2_FD (0x1f << MPFS_CANFD_BTR_FD_PH2_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_BRP_FD_SHIFT (19) +#define MPFS_CANFD_BTR_FD_BRP_FD (0xff << MPFS_CANFD_BTR_FD_BRP_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_SJW_FD_SHIFT (27) +#define MPFS_CANFD_BTR_FD_SJW_FD (0x1f << MPFS_CANFD_BTR_FD_SJW_FD_SHIFT) + +/* EWL / ERP / FAULT_STATE registers */ +#define MPFS_CANFD_EWL_EW_LIMIT_SHIFT (0) +#define MPFS_CANFD_EWL_EW_LIMIT (0xff << MPFS_CANFD_EWL_EW_LIMIT_SHIFT) +#define MPFS_CANFD_EWL_ERP_LIMIT_SHIFT (8) +#define MPFS_CANFD_EWL_ERP_LIMIT (0xff << MPFS_CANFD_EWL_ERP_LIMIT_SHIFT) +#define MPFS_CANFD_EWL_ERA (1 << 16) +#define MPFS_CANFD_EWL_ERP (1 << 17) +#define MPFS_CANFD_EWL_BOF (1 << 18) + +/* REC / TEC registers */ +#define MPFS_CANFD_REC_REC_VAL_SHIFT (0) +#define MPFS_CANFD_REC_REC_VAL (0x01ff << MPFS_CANFD_REC_REC_VAL_SHIFT) +#define MPFS_CANFD_REC_TEC_VAL_SHIFT (16) +#define MPFS_CANFD_REC_TEC_VAL (0x01ff << MPFS_CANFD_REC_TEC_VAL_SHIFT) + +/* ERR_NORM ERR_FD registers */ +#define MPFS_CANFD_ERR_NORM_ERR_NORM_VAL_SHIFT (0) +#define MPFS_CANFD_ERR_NORM_ERR_NORM_VAL (0xffff << MPFS_CANFD_ERR_NORM_ERR_NORM_VAL_SHIFT) +#define MPFS_CANFD_ERR_NORM_ERR_FD_VAL_SHIFT (16) +#define MPFS_CANFD_ERR_NORM_ERR_FD_VAL (0xffff << MPFS_CANFD_ERR_NORM_ERR_FD_VAL_SHIFT) + +/* CTR_PRES registers */ +#define MPFS_CANFD_CTR_PRES_CTPV_SHIFT (0) +#define MPFS_CANFD_CTR_PRES_CTPV (0x01ff << MPFS_CANFD_CTR_PRES_CTPV_SHIFT) +#define MPFS_CANFD_CTR_PRES_PTX (1 << 9) +#define MPFS_CANFD_CTR_PRES_PRX (1 << 10) +#define MPFS_CANFD_CTR_PRES_ENORM (1 << 11) +#define MPFS_CANFD_CTR_PRES_EFD (1 << 12) + +/* FILTER_A_MASK registers */ +#define MPFS_CANFD_FILTER_A_MASK_BIT_MASK_A_VAL (0x1fffffff << 0) + +/* FILTER_A_VAL registers */ +#define MPFS_CANFD_FILTER_A_VAL_BIT_VAL_A_VAL (0x1fffffff << 0) + +/* FILTER_B_MASK registers */ +#define MPFS_CANFD_FILTER_B_MASK_BIT_MASK_B_VAL (0x1fffffff << 0) + +/* FILTER_B_VAL registers */ +#define MPFS_CANFD_FILTER_B_VAL_BIT_VAL_B_VAL (0x1fffffff << 0) + +/* FILTER_C_MASK registers */ +#define MPFS_CANFD_FILTER_C_MASK_BIT_MASK_C_VAL (0x1fffffff << 0) + +/* FILTER_C_VAL registers */ +#define MPFS_CANFD_FILTER_C_VAL_BIT_VAL_C_VAL (0x1fffffff << 0) + +/* FILTER_RAN_LOW registers */ +#define MPFS_CANFD_FILTER_RAN_LOW_BIT_RAN_LOW_VAL (0x1fffffff << 0) + +/* FILTER_RAN_HIGH registers */ +#define MPFS_CANFD_FILTER_RAN_HIGH_BIT_RAN_HIGH_VAL (0x1fffffff << 0) + +/* FILTER_CONTROL / FILTER_STATUS registers */ +#define MPFS_CANFD_FILTER_CONTROL_FANB (1 << 0) +#define MPFS_CANFD_FILTER_CONTROL_FANE (1 << 1) +#define MPFS_CANFD_FILTER_CONTROL_FAFB (1 << 2) +#define MPFS_CANFD_FILTER_CONTROL_FAFE (1 << 3) +#define MPFS_CANFD_FILTER_CONTROL_FBNB (1 << 4) +#define MPFS_CANFD_FILTER_CONTROL_FBNE (1 << 5) +#define MPFS_CANFD_FILTER_CONTROL_FBFB (1 << 6) +#define MPFS_CANFD_FILTER_CONTROL_FBFE (1 << 7) +#define MPFS_CANFD_FILTER_CONTROL_FCNB (1 << 8) +#define MPFS_CANFD_FILTER_CONTROL_FCNE (1 << 9) +#define MPFS_CANFD_FILTER_CONTROL_FCFB (1 << 10) +#define MPFS_CANFD_FILTER_CONTROL_FCFE (1 << 11) +#define MPFS_CANFD_FILTER_CONTROL_FRNB (1 << 12) +#define MPFS_CANFD_FILTER_CONTROL_FRNE (1 << 13) +#define MPFS_CANFD_FILTER_CONTROL_FRFB (1 << 14) +#define MPFS_CANFD_FILTER_CONTROL_FRFE (1 << 15) +#define MPFS_CANFD_FILTER_CONTROL_SFA (1 << 16) +#define MPFS_CANFD_FILTER_CONTROL_SFB (1 << 17) +#define MPFS_CANFD_FILTER_CONTROL_SFC (1 << 18) +#define MPFS_CANFD_FILTER_CONTROL_SFR (1 << 19) + +/* RX_MEM_INFO registers */ +#define MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE_SHIFT (0) +#define MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE (0x1fff << MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE_SHIFT) +#define MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE_SHIFT (16) +#define MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE (0x1fff << MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE_SHIFT) + +/* RX_POINTERS registers */ +#define MPFS_CANFD_RX_POINTERS_RX_WPP_SHIFT (0) +#define MPFS_CANFD_RX_POINTERS_RX_WPP (0x0fff << MPFS_CANFD_RX_POINTERS_RX_WPP_SHIFT) +#define MPFS_CANFD_RX_POINTERS_RX_RPP_SHIFT (16) +#define MPFS_CANFD_RX_POINTERS_RX_RPP (0x0fff << MPFS_CANFD_RX_POINTERS_RX_RPP_SHIFT) + +/* RX_STATUS / RX_SETTINGS registers */ +#define MPFS_CANFD_RX_STATUS_RXE (1 << 0) +#define MPFS_CANFD_RX_STATUS_RXF (1 << 1) +#define MPFS_CANFD_RX_STATUS_RXMOF (1 << 2) +#define MPFS_CANFD_RX_STATUS_RXFRC_SHIFT (4) +#define MPFS_CANFD_RX_STATUS_RXFRC (0x07ff << MPFS_CANFD_RX_STATUS_RXFRC_SHIFT) +#define MPFS_CANFD_RX_STATUS_RTSOP (1 << 16) + +/* RX_DATA registers */ +#define MPFS_CANFD_RX_DATA_RX_DATA (0xffffffff << 0) + +/* TX_STATUS registers */ +#define MPFS_CANFD_TX_STATUS_TX1S_SHIFT (0) +#define MPFS_CANFD_TX_STATUS_TX1S (0x0f << MPFS_CANFD_TX_STATUS_TX1S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX2S_SHIFT (4) +#define MPFS_CANFD_TX_STATUS_TX2S (0x0f << MPFS_CANFD_TX_STATUS_TX2S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX3S_SHIFT (8) +#define MPFS_CANFD_TX_STATUS_TX3S (0x0f << MPFS_CANFD_TX_STATUS_TX3S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX4S_SHIFT (12) +#define MPFS_CANFD_TX_STATUS_TX4S (0x0f << MPFS_CANFD_TX_STATUS_TX4S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX5S_SHIFT (16) +#define MPFS_CANFD_TX_STATUS_TX5S (0x0f << MPFS_CANFD_TX_STATUS_TX5S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX6S_SHIFT (20) +#define MPFS_CANFD_TX_STATUS_TX6S (0x0f << MPFS_CANFD_TX_STATUS_TX6S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX7S_SHIFT (24) +#define MPFS_CANFD_TX_STATUS_TX7S (0x0f << MPFS_CANFD_TX_STATUS_TX7S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX8S_SHIFT (28) +#define MPFS_CANFD_TX_STATUS_TX8S (0x0f << MPFS_CANFD_TX_STATUS_TX8S_SHIFT) + +/* TX_COMMAND TXTB_INFO registers */ +#define MPFS_CANFD_TX_COMMAND_TXCE (1 << 0) +#define MPFS_CANFD_TX_COMMAND_TXCR (1 << 1) +#define MPFS_CANFD_TX_COMMAND_TXCA (1 << 2) +#define MPFS_CANFD_TX_COMMAND_TXB1 (1 << 8) +#define MPFS_CANFD_TX_COMMAND_TXB2 (1 << 9) +#define MPFS_CANFD_TX_COMMAND_TXB3 (1 << 10) +#define MPFS_CANFD_TX_COMMAND_TXB4 (1 << 11) +#define MPFS_CANFD_TX_COMMAND_TXB5 (1 << 12) +#define MPFS_CANFD_TX_COMMAND_TXB6 (1 << 13) +#define MPFS_CANFD_TX_COMMAND_TXB7 (1 << 14) +#define MPFS_CANFD_TX_COMMAND_TXB8 (1 << 15) +#define MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT_SHIFT (16) +#define MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT (0x0f << MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT_SHIFT) + +/* TX_PRIORITY registers */ +#define MPFS_CANFD_TX_PRIORITY_TXT1P_SHIFT (0) +#define MPFS_CANFD_TX_PRIORITY_TXT1P (0x07 << )MPFS_CANFD_TX_PRIORITY_TXT1P_SHIFT +#define MPFS_CANFD_TX_PRIORITY_TXT2P_SHIFT (4) +#define MPFS_CANFD_TX_PRIORITY_TXT2P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT2P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT3P_SHIFT (8) +#define MPFS_CANFD_TX_PRIORITY_TXT3P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT3P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT4P_SHIFT (12) +#define MPFS_CANFD_TX_PRIORITY_TXT4P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT4P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT5P_SHIFT (16) +#define MPFS_CANFD_TX_PRIORITY_TXT5P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT5P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT6P_SHIFT (20) +#define MPFS_CANFD_TX_PRIORITY_TXT6P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT6P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT7P_SHIFT (24) +#define MPFS_CANFD_TX_PRIORITY_TXT7P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT7P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT8P_SHIFT (28) +#define MPFS_CANFD_TX_PRIORITY_TXT8P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT8P_SHIFT) + +/* ERR_CAPT RETR_CTR ALC registers */ +#define MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT (0) +#define MPFS_CANFD_ERR_CAPT_ERR_POS (0x1f << MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT (5) +#define MPFS_CANFD_ERR_CAPT_ERR_TYPE (0x07 << MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT) +#define MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL_SHIFT (8) +#define MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL (0x0f << MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT (16) +#define MPFS_CANFD_ERR_CAPT_ALC_BIT (0x1f << MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT (21) +#define MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD (0x07 << MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT) + +/* TRV_DELAY SSP_CFG registers */ +#define MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE_SHIFT (0) +#define MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE (0x7f << MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE_SHIFT) +#define MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT (16) +#define MPFS_CANFD_TRV_DELAY_SSP_OFFSET (0xff << MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT) +#define MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT (24) +#define MPFS_CANFD_TRV_DELAY_SSP_SRC (0x03 << MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT) + +/* RX_FR_CTR registers */ +#define MPFS_CANFD_RX_FR_CTR_RX_FR_CTR_VAL (0xffffffff << 0) + +/* TX_FR_CTR registers */ +#define MPFS_CANFD_TX_FR_CTR_TX_FR_CTR_VAL (0xffffffff << 0) + +/* DEBUG_REGISTER registers */ +#define MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT_SHIFT (0) +#define MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT (0x07 << MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT_SHIFT) +#define MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT_SHIFT (3) +#define MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT (0x07 << MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT_SHIFT) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ARB (1 << 6) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CON (1 << 7) +#define MPFS_CANFD_DEBUG_REGISTER_PC_DAT (1 << 8) +#define MPFS_CANFD_DEBUG_REGISTER_PC_STC (1 << 9) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CRC (1 << 10) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CRCD (1 << 11) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ACK (1 << 12) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ACKD (1 << 13) +#define MPFS_CANFD_DEBUG_REGISTER_PC_EOF (1 << 14) +#define MPFS_CANFD_DEBUG_REGISTER_PC_INT (1 << 15) +#define MPFS_CANFD_DEBUG_REGISTER_PC_SUSP (1 << 16) +#define MPFS_CANFD_DEBUG_REGISTER_PC_OVR (1 << 17) +#define MPFS_CANFD_DEBUG_REGISTER_PC_SOF (1 << 18) + +/* YOLO_REG registers */ +#define MPFS_CANFD_YOLO_REG_YOLO_VAL (0xffffffff << 0) + +/* TIMESTAMP_LOW registers */ +#define MPFS_CANFD_TIMESTAMP_LOW_TIMESTAMP_LOW (0xffffffff << 0) + +/* TIMESTAMP_HIGH registers */ +#define MPFS_CANFD_TIMESTAMP_HIGH_TIMESTAMP_HIGH (0xffffffff << 0) + +#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H */ \ No newline at end of file diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h b/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h index af7a081dd949e..9b8bf00571e2a 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_ihc.h @@ -27,8 +27,8 @@ enum mpfs_irq_type_e { - MP_IRQ = 0x0, - ACK_IRQ = 0x1, + MP_IRQ = 0x1, + ACK_IRQ = 0x2, }; #define IHC_MAX_MESSAGE_SIZE 2 diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h index 5d93013734d19..54d9fda0c2d2c 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h @@ -130,4 +130,15 @@ #define MPFS_UART3_BASE MPFS_UART3_LO_BASE #define MPFS_UART4_BASE MPFS_UART4_LO_BASE +/* FPGA UART defines */ + +#define MPFS_FPGA_UART0_BASE 0x4c000000UL +#define MPFS_FPGA_UART1_BASE 0x4c001000UL +#define MPFS_FPGA_UART2_BASE 0x4c002000UL +#define MPFS_FPGA_UART3_BASE 0x4c003000UL +#define MPFS_FPGA_UART4_BASE 0x4c004000UL +#define MPFS_FPGA_UART5_BASE 0x4c005000UL +#define MPFS_FPGA_UART6_BASE 0x4c006000UL +#define MPFS_FPGA_UART7_BASE 0x4c007000UL + #endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_MEMORYMAP_H */ diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_sgmii.h b/arch/risc-v/src/mpfs/hardware/mpfs_sgmii.h index 65959492beef2..126ace313667b 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_sgmii.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_sgmii.h @@ -152,7 +152,7 @@ #define MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DDR_PHY_OFFSET 0x000 #define MPFS_CFG_DDR_SGMII_PHY_DDRPHY_MODE_OFFSET 0x004 #define MPFS_CFG_DDR_SGMII_PHY_STARTUP_OFFSET 0x008 -#define MPFS_CFG_DDR_SGMII_PHY_SPARE_0_OFFSET 0x00c +#define MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0_OFFSET 0x00c #define MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_MAIN_PLL_OFFSET 0x080 #define MPFS_CFG_DDR_SGMII_PHY_PLL_CTRL_MAIN_OFFSET 0x084 #define MPFS_CFG_DDR_SGMII_PHY_PLL_REF_FB_MAIN_OFFSET 0x088 @@ -566,18 +566,19 @@ /* SGMII register definitions */ +#define MPFS_CFG_DDR_SGMII_PHY_SPARE0 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SPARE0_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_DRIVER_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_ODT_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SOFT_RESET_DECODER_IO_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_TRAINING_START (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_TRAINING_START_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_DDRPHY_MODE (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DDRPHY_MODE_OFFSET) +#define MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_DPC_BITS (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DPC_BITS_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC95 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC95_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC96 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC96_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC97 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC97_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC98 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC98_OFFSET) -#define MPFS_CFG_DDR_SGMII_PHY_SPARE_0 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SPARE_0_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_SPIO253 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_SPIO253_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC10_ODT (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC10_ODT_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC11_ODT (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC11_ODT_OFFSET) @@ -605,6 +606,7 @@ #define MPFS_CFG_DDR_SGMII_PHY_RPC166 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC166_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC168 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC168_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC220 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC220_OFFSET) +#define MPFS_CFG_DDR_SGMII_PHY_RPC226 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC226_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC235 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC235_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC236 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC236_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_RPC237 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_RPC237_OFFSET) @@ -654,6 +656,7 @@ #define MPFS_CFG_DDR_SGMII_PHY_GT_ERR_COMB (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_GT_ERR_COMB_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_DQ_DQS_ERR_DONE (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DQ_DQS_ERR_DONE_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1_OFFSET) +#define MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2 (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY_OFFSET) #define MPFS_CFG_DDR_SGMII_PHY_DYN_CNTL (MPFS_CFG_DDR_SGMII_PHY_BASE + MPFS_CFG_DDR_SGMII_PHY_DYN_CNTL_OFFSET) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h index 863044d8ddd9a..bbea409fbdaba 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h @@ -142,6 +142,8 @@ #define MPFS_USB_C_T_HHSRTN_OFFSET 0x346 #define MPFS_USB_C_T_HSBT_OFFSET 0x348 +#define MPFS_USB_DMA_ADDR_UPPER_REG_OFFSET 0x3FC + #define MPFS_USB_POWER (MPFS_USB_BASE + MPFS_USB_POWER_OFFSET) #define MPFS_USB_POWER_ENABLE_SUSPENDM (1 << 0) #define MPFS_USB_POWER_SUSPEND_MODE (1 << 1) @@ -175,6 +177,12 @@ #define MPFS_USB_RX_DPBUF_DIS (MPFS_USB_BASE + MPFS_USB_RX_DPBUF_DIS_OFFSET) #define MPFS_USB_TX_DPBUF_DIS (MPFS_USB_BASE + MPFS_USB_TX_DPBUF_DIS_OFFSET) +/* MPFS_USB_DMA_ADDR_UPPER_REG is used to set the upper 6-bits of + * the Address bus for USB DMA operations. + */ + +#define MPFS_USB_DMA_ADDR_UPPER_REG (MPFS_USB_BASE + MPFS_USB_DMA_ADDR_UPPER_REG_OFFSET) + #define MPFS_USB_DMA_CHANNEL(n) (MPFS_USB_BASE + MPFS_USB_DMA_CHANNEL_OFFSET + MPFS_USB_DMA_CHANNEL_SIZE * n) /**************************************************************************** diff --git a/arch/risc-v/src/mpfs/mpfs_clockconfig.c b/arch/risc-v/src/mpfs/mpfs_clockconfig.c index 320021a27805f..7802560cfa838 100644 --- a/arch/risc-v/src/mpfs/mpfs_clockconfig.c +++ b/arch/risc-v/src/mpfs/mpfs_clockconfig.c @@ -143,6 +143,8 @@ enum part_type_e static uint64_t g_cpu_clock = MPFS_MSS_EXT_SGMII_REF_CLK; +#ifdef CONFIG_MPFS_BOOTLOADER + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -630,6 +632,8 @@ void mpfs_clockconfig(void) mpfs_pll_config(); } +#endif + /**************************************************************************** * Name: mpfs_get_cpuclk ****************************************************************************/ diff --git a/arch/risc-v/src/mpfs/mpfs_config.h b/arch/risc-v/src/mpfs/mpfs_config.h index ce2007d599822..896036b5c6ac9 100644 --- a/arch/risc-v/src/mpfs/mpfs_config.h +++ b/arch/risc-v/src/mpfs/mpfs_config.h @@ -37,7 +37,8 @@ #undef HAVE_UART_DEVICE #if defined(CONFIG_MPFS_UART0) || defined(CONFIG_MPFS_UART1) || \ defined(CONFIG_MPFS_UART2) || defined(CONFIG_MPFS_UART3) || \ - defined(CONFIG_MPFS_UART4) + defined(CONFIG_MPFS_UART4) || defined(CONFIG_MPFS_UART5) || \ + defined(CONFIG_MPFS_UART6) || defined(CONFIG_MPFS_UART7) # define HAVE_UART_DEVICE 1 #endif @@ -46,30 +47,72 @@ # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART1) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART2_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART2) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART3_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART3) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART4) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART5) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART6_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART6) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART7) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #else # undef CONFIG_UART0_SERIAL_CONSOLE diff --git a/arch/risc-v/src/mpfs/mpfs_corepwm.c b/arch/risc-v/src/mpfs/mpfs_corepwm.c index 1734c6d610fc9..408afb7b43f16 100644 --- a/arch/risc-v/src/mpfs/mpfs_corepwm.c +++ b/arch/risc-v/src/mpfs/mpfs_corepwm.c @@ -76,7 +76,6 @@ struct mpfs_pwmtimer_s struct mpfs_pwmchan_s channels[MPFS_MAX_PWM_CHANNELS]; uint32_t frequency; /* Current frequency setting */ uintptr_t base; /* The base address of the pwm block */ - uint32_t pwmclk; /* The frequency of the pwm clock */ }; /**************************************************************************** @@ -187,7 +186,6 @@ static struct mpfs_pwmtimer_s g_pwm0dev = } }, .base = CONFIG_MPFS_COREPWM0_BASE, - .pwmclk = CONFIG_MPFS_COREPWM0_PWMCLK, }; #endif @@ -249,7 +247,6 @@ static struct mpfs_pwmtimer_s g_pwm1dev = } }, .base = CONFIG_MPFS_COREPWM1_BASE, - .pwmclk = CONFIG_MPFS_COREPWM1_PWMCLK, }; #endif @@ -404,12 +401,12 @@ static int pwm_timer(struct mpfs_pwmtimer_s *priv, * PERIOD = pwmclk / frequency = 25,000,000 / 50 = 500,000 */ - pwminfo("PWM%u frequency: %u PWMCLK: %u prescaler: %u\n", - priv->pwmid, info->frequency, priv->pwmclk, prescaler); + pwminfo("PWM%u frequency: %u PWMCLK: %lu prescaler: %u\n", + priv->pwmid, info->frequency, MPFS_FPGA_PERIPHERAL_CLK, prescaler); /* Set the reload and prescaler values */ - period = priv->pwmclk / info->frequency; + period = MPFS_FPGA_PERIPHERAL_CLK / info->frequency; pwm_putreg(priv, MPFS_COREPWM_PERIOD_OFFSET, period); pwm_putreg(priv, MPFS_COREPWM_PRESCALE_OFFSET, prescaler); diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index b2f8b368ec1d4..d4b2f43252ca2 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -192,37 +192,6 @@ enum ddr_access_size_e DDR_64_BIT }; -typedef struct -{ - uint32_t status_lower; - uint32_t status_upper; - uint32_t lower; - uint32_t upper; - uint32_t vref_result; -} mss_ddr_vref_t; - -typedef struct -{ - uint32_t status_lower; - uint32_t lower[MAX_LANES]; - uint32_t lane_calib_result; -} mss_mpfs_ddr_write_calibration_t; - -typedef struct -{ - uint32_t lower[MAX_LANES]; - uint32_t upper[MAX_LANES]; - uint32_t calibration_found[MAX_LANES]; -} mss_lpddr4_dq_calibration_t; - -typedef struct -{ - mss_mpfs_ddr_write_calibration_t write_cal; - mss_lpddr4_dq_calibration_t dq_cal; - mss_ddr_vref_t fpga_vref; - mss_ddr_vref_t mem_vref; -} mss_ddr_calibration_t; - struct mpfs_ddr_priv_s { uint32_t tip_cfg_params; @@ -238,8 +207,6 @@ struct mpfs_ddr_priv_s * Private Data ****************************************************************************/ -static mss_ddr_calibration_t calib_data; - static struct mpfs_ddr_priv_s g_mpfs_ddr_priv = { .en_addcmd0_ovrt9 = true, @@ -306,6 +273,14 @@ static const uint8_t refclk_offsets[][5] = #endif +/* State of the seiran128 PRNG, with initial seed */ + +static uint64_t prng_state[2] = + { + 0x6c64f673ed93b6cc, + 0x97c703d5f6c9d72b + }; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -365,12 +340,12 @@ static void mpfs_ddr_off_mode(void) putreg32(0x07, MPFS_CFG_DDR_SGMII_PHY_RPC97); /* dq */ putreg32(0x07, MPFS_CFG_DDR_SGMII_PHY_RPC98); /* dqs */ - /* SPARE_0: + /* UNUSED_SPACE0: * bits 15:14 connect to ibufmx DQ/DQS/DM * bits 13:12 connect to ibufmx CA/CK */ - putreg32(0, MPFS_CFG_DDR_SGMII_PHY_SPARE_0); + putreg32(0, MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0); /* REG_POWERDOWN_B on PLL turn-off, in case was turned on */ @@ -522,21 +497,21 @@ static void mpfs_set_ddr_rpc_regs(struct mpfs_ddr_priv_s *priv) } putreg32(0x04, MPFS_CFG_DDR_SGMII_PHY_RPC98); - putreg32(0, MPFS_CFG_DDR_SGMII_PHY_SPARE_0); + putreg32(0, MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0); #elif defined(CONFIG_MPFS_DDR_TYPE_DDR4) putreg32(2, MPFS_CFG_DDR_SGMII_PHY_RPC10_ODT); putreg32(2, MPFS_CFG_DDR_SGMII_PHY_RPC11_ODT); putreg32(0x04, MPFS_CFG_DDR_SGMII_PHY_RPC98); - putreg32(0, MPFS_CFG_DDR_SGMII_PHY_SPARE_0); + putreg32(0, MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0); #elif defined(CONFIG_MPFS_DDR_TYPE_LPDDR3) putreg32(2, MPFS_CFG_DDR_SGMII_PHY_RPC10_ODT); putreg32(2, MPFS_CFG_DDR_SGMII_PHY_RPC11_ODT); putreg32(0x04, MPFS_CFG_DDR_SGMII_PHY_RPC98); - putreg32(0, MPFS_CFG_DDR_SGMII_PHY_SPARE_0); + putreg32(0, MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0); #elif defined(CONFIG_MPFS_DDR_TYPE_LPDDR4) @@ -570,8 +545,18 @@ static void mpfs_set_ddr_rpc_regs(struct mpfs_ddr_priv_s *priv) putreg32(1, MPFS_CFG_DDR_SGMII_PHY_SPIO253); } + /* Write ibufmd_dqs. Value is a constant coped from HSS refenrece code */ + putreg32(0x04, MPFS_CFG_DDR_SGMII_PHY_RPC98); - putreg32(0xa000, MPFS_CFG_DDR_SGMII_PHY_SPARE_0); + + /* Write TXDLY offset data. 0x14 is a constant copied from HSS reference + * code, it is unknown whether this needs to be adjustable at the moment + */ + + putreg32(0x14, MPFS_CFG_DDR_SGMII_PHY_RPC226); + + putreg32(0xa000, MPFS_CFG_DDR_SGMII_PHY_UNUSED_SPACE0); + putreg32(0xa000, MPFS_CFG_DDR_SGMII_PHY_SPARE0); #endif @@ -812,6 +797,19 @@ void mpfs_setup_ddr_segments(enum seg_setup_e option) static void mpfs_init_ddrc(void) { + /* Turn on DDRC clock */ + + modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, + SYSREG_SUBBLK_CLOCK_CR_DDRC); + + /* Remove soft reset */ + + modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, 0, + SYSREG_SUBBLK_CLOCK_CR_DDRC); + + modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, + SYSREG_SUBBLK_CLOCK_CR_DDRC, 0); + putreg32(LIBERO_SETTING_CFG_MANUAL_ADDRESS_MAP, MPFS_DDR_CSR_APB_CFG_MANUAL_ADDRESS_MAP); putreg32(LIBERO_SETTING_CFG_CHIPADDR_MAP, @@ -1700,8 +1698,6 @@ static void mpfs_load_dq(uint8_t lane) { modifyreg32(MPFS_CFG_DDR_SGMII_PHY_EXPERT_DLYCNT_LOAD_REG1, 0x0f, 0); } - - putreg32(0x08, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN); } #endif @@ -1722,10 +1718,10 @@ static void mpfs_load_dq(uint8_t lane) * ****************************************************************************/ -static uint8_t mpfs_mtc_test(uint8_t mask, uint64_t start_address, - uint32_t size, - enum mtc_pattern_e data_pattern, - enum mtc_add_pattern_e add_pattern) +static int mpfs_mtc_test(uint8_t mask, uint64_t start_address, + uint32_t size, + enum mtc_pattern_e data_pattern, + enum mtc_add_pattern_e add_pattern) { /* Write calibration: * Configure common memory test interface by writing registers: @@ -1869,12 +1865,6 @@ static uint8_t mpfs_mtc_test(uint8_t mask, uint64_t start_address, modifyreg32(MPFS_DDR_CSR_APB_MT_ERROR_MASK_4, 0x0000f000, 0); } - /* MT_EN - Enables memory test. If asserted at end of memory test, - * will keep going. - */ - - putreg32(0, MPFS_DDR_CSR_APB_MT_EN); - /* MT_EN_SINGLE - Will not repeat if this is set */ putreg32(0, MPFS_DDR_CSR_APB_MT_EN_SINGLE); @@ -1899,47 +1889,63 @@ static uint8_t mpfs_mtc_test(uint8_t mask, uint64_t start_address, } /**************************************************************************** - * Name: mpfs_set_write_calib + * Name: mpfs_mtc_test_all * * Description: - * Sets and stores the calibrated values. + * This performs a memory test with the NWL memory test core + * using all available test patterns. * * Input Parameters: - * priv - Instance of the ddr private state structure + * mask - Test bitmask + * start_address - Test start address + * size - Size of the area to test + * add_pattern - Data modifier pattern * * Returned Value: * Zero (OK) is returned on success. A nonzero value indicates a fail. * ****************************************************************************/ -static void mpfs_set_write_calib(struct mpfs_ddr_priv_s *priv) +static int mpfs_mtc_test_all(uint8_t mask, uint64_t start_address, + uint32_t size, + enum mtc_add_pattern_e add_pattern) { - uint32_t temp = 0; - uint8_t lane_to_set; - uint8_t shift = 0; - uint32_t lanes = priv->number_of_lanes_to_calibrate; + int result; + enum mtc_pattern_e test_pattern; - /* Calculate the calibrated value and write back */ + /* Read once to flush MTC. During write calibration the first MTC + * read must be discarded as it is unreliable after a series of + * bad writes. Only check -ETIMEDOUT; if that occurs, we'll bail out + */ - calib_data.write_cal.lane_calib_result = 0; - for (lane_to_set = 0; lane_to_set < lanes; lane_to_set++) + result = mpfs_mtc_test(mask, start_address, size, + MTC_COUNTING_PATTERN, + add_pattern); + if (result == -ETIMEDOUT) { - temp = calib_data.write_cal.lower[lane_to_set]; - calib_data.write_cal.lane_calib_result = \ - calib_data.write_cal.lane_calib_result | (temp << (shift)); - shift = (uint8_t)(shift + 0x04); + return result; } - /* bit 3 must be set if we want to use the expert_wrcalib - * register. - */ + /* Test all patterns except MTC_USER */ - putreg32(0x08, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN); + result = 0; + for (test_pattern = MTC_COUNTING_PATTERN; + test_pattern <= MTC_PSEUDO_RANDOM_8BIT && result == 0; + test_pattern++) + { + if (test_pattern == MTC_USER) + { + continue; + } + + /* Read using different patterns */ - /* Set the calibrated value */ + result = mpfs_mtc_test(mask, start_address, size, + test_pattern, + add_pattern); + } - putreg32(calib_data.write_cal.lane_calib_result, - MPFS_CFG_DDR_SGMII_PHY_EXPERT_WRCALIB); + return result; } /**************************************************************************** @@ -1962,19 +1968,26 @@ static void mpfs_set_write_calib(struct mpfs_ddr_priv_s *priv) static int mpfs_write_calibration_using_mtc(struct mpfs_ddr_priv_s *priv) { uint64_t start_address = 0x00; - uint32_t size = ONE_MB_MTC; - uint32_t result = 0; - uint8_t lane_to_test; + uint32_t size = ONE_MB_MTC; + int result = 0; + uint8_t done = 0x0; + uint8_t lane; uint32_t cal_data; - uint32_t lanes; + int lanes; + uint8_t offset[MAX_LANES]; + uint8_t done_mask; - calib_data.write_cal.status_lower = 0U; + /* Initialize number of lanes */ + + lanes = priv->number_of_lanes_to_calibrate; /* Bit 3 must be set if we want to use the expert_wrcalib register. */ putreg32(0x08, MPFS_CFG_DDR_SGMII_PHY_EXPERT_MODE_EN); - lanes = priv->number_of_lanes_to_calibrate; + /* mask of as many 1 bits as there are lanes */ + + done_mask = 0xff >> (8 - lanes); /* Training carried out here: sweeping write calibration offset from 0 to F * Explanation: A register, expert_wrcalib, is described in MSS DDR TIP @@ -1983,99 +1996,62 @@ static int mpfs_write_calibration_using_mtc(struct mpfs_ddr_priv_s *priv) * with the respect to the address and command for each lane. */ - for (cal_data = 0x00000; cal_data < 0xfffff; cal_data += 0x11111) + for (cal_data = 0x00000; + cal_data < 0xfffff && done != done_mask && result != -ETIMEDOUT; + cal_data += 0x11111) { putreg32(cal_data, MPFS_CFG_DDR_SGMII_PHY_EXPERT_WRCALIB); - for (lane_to_test = 0x00; lane_to_test < lanes; lane_to_test++) + for (lane = 0; lane < lanes && result != -ETIMEDOUT; lane++) { - /* Read once to flush MTC. During write calibration the first MTC - * read must be discarded as it is unreliable after a series of - * bad writes. - */ + uint8_t cal_value = cal_data & 0xf; + uint8_t mask = (uint8_t)(0x1 << lane); - uint8_t mask = (uint8_t)(1 << lane_to_test); - - result = mpfs_mtc_test(mask, start_address, size, - MTC_COUNTING_PATTERN, MTC_ADD_SEQUENTIAL); - - /* Read using different patterns */ - - result |= mpfs_mtc_test(mask, start_address, size, - MTC_COUNTING_PATTERN, - MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_WALKING_ONE, MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_PSEUDO_RANDOM, MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_NO_REPEATING_PSEUDO_RANDOM, - MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_ALT_ONES_ZEROS, MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_ALT_5_A, MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_PSEUDO_RANDOM_16BIT, - MTC_ADD_SEQUENTIAL); - result |= mpfs_mtc_test(mask, start_address, size, - MTC_PSEUDO_RANDOM_8BIT, - MTC_ADD_SEQUENTIAL); - - if (result == 0) /* if passed for this lane */ - { - if ((calib_data.write_cal.status_lower & - (0x01 << lane_to_test)) == 0) - { - /* Still looking for good value */ - - calib_data.write_cal.lower[lane_to_test] = - (cal_data & 0xf); - calib_data.write_cal.status_lower |= - (0x01 << lane_to_test); - } + /* Check if this lane is not yet done and the test passes */ - /* Check the result */ - - uint32_t lane_to_check; - - for (lane_to_check = 0; lane_to_check < lanes; - lane_to_check++) - { - if (((calib_data.write_cal.status_lower) & - (0x01 << lane_to_check)) == 0) - { - /* not finished, still looking */ - - result = 1; - break; - } - } + if (!(done & (0x1 << lane))) + { + /* First passing value is the offset point, record it */ + result = mpfs_mtc_test_all(mask, start_address, size, + MTC_ADD_SEQUENTIAL); if (result == 0) { - /* We're good for all lanes, can stop */ - - break; + offset[lane] = cal_value; + done |= 1 << lane; } } } + } - if (result == 0) - { - /* if true, we are good for all lanes, can stop searching */ + /* If calibration was successful, calculate and set the value */ - break; + if (done == done_mask) + { + /* Calibration succeeded, set the result */ + + result = 0; + + /* Create cal_data mask from individua lane offsets */ + + cal_data = 0x0; + for (lane = 0; lane < lanes; lane++) + { + cal_data |= offset[lane] << (lane * 4); } - } - /* If calibration successful, calculate and set the value */ + /* Set the write calibration which has been calculated */ - if (result == 0) + putreg32(cal_data, + MPFS_CFG_DDR_SGMII_PHY_EXPERT_WRCALIB); + } + else if (result == 0) { - /* Set the write calibration which has been calculated */ + /* Just in case calibration is not done but last result from lane test + * was OK + */ - mpfs_set_write_calib(priv); + result = 1; } return result; @@ -2085,19 +2061,29 @@ static int mpfs_write_calibration_using_mtc(struct mpfs_ddr_priv_s *priv) * Name: mpfs_ddr_rand * * Description: - * This should return a random value. + * This is adapted from seiran128 + * (https://github.com/andanteyk/prng-seiran) * * Returned Value: - * Always zero at the moment. - * - * Assumptions/Limitations: - * This doesn't return random values at the moment. + * Non-cryptographically secure pseudo random number * ****************************************************************************/ +static inline uint64_t rotl(uint64_t x, int k) +{ + return (x << k) | (x >> (-k & 0x3f)); +} + static int mpfs_ddr_rand(void) { - return 0; + uint64_t s0 = prng_state[0]; + uint64_t s1 = prng_state[1]; + uint64_t result = rotl((s0 + s1) * 9, 29) + s0; + + prng_state[0] = s0 ^ rotl(s1, 29); + prng_state[1] = s0 ^ (s1 << 9); + + return (int)result; } /**************************************************************************** @@ -3002,8 +2988,6 @@ static void mpfs_ddr_sm_init(struct mpfs_ddr_priv_s *priv) priv->refclk_sweep_index = 0xf; priv->number_of_lanes_to_calibrate = mpfs_get_num_lanes(); - - memset(&calib_data, 0, sizeof(calib_data)); } /**************************************************************************** @@ -3020,8 +3004,6 @@ static void mpfs_ddr_sm_init(struct mpfs_ddr_priv_s *priv) static void mpfs_ddr_fail(struct mpfs_ddr_priv_s *priv) { - memset(&calib_data, 0, sizeof(calib_data)); - putreg32(0, MPFS_DDR_CSR_APB_PHY_DFI_INIT_START); /* Reset controller */ @@ -3097,16 +3079,6 @@ static int mpfs_set_mode_vs_bits(struct mpfs_ddr_priv_s *priv) mpfs_setup_ddr_segments(DEFAULT_SEG_SETUP); - /* Turn on DDRC clock */ - - modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, - SYSREG_SUBBLK_CLOCK_CR_DDRC); - - /* Remove soft reset */ - - modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, - SYSREG_SUBBLK_CLOCK_CR_DDRC, 0); - /* Set-up DDRC */ mpfs_init_ddrc(); @@ -3532,7 +3504,7 @@ static int mpfs_training_verify(void) /* Check that DQ/DQS calculated window is above 5 taps. */ - if (getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1) < DQ_DQS_NUM_TAPS) + if (getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2) < DQ_DQS_NUM_TAPS) { t_status |= 0x01; } @@ -3710,29 +3682,35 @@ static int mpfs_training_write_calibration(struct mpfs_ddr_priv_s *priv) /* Now start the write calibration as training has been successful */ #ifdef CONFIG_MPFS_DDR_TYPE_LPDDR4 - uint32_t nr_lanes; uint8_t lane; /* Changed default value to centre dq/dqs on window */ putreg32(0x0c, MPFS_CFG_DDR_SGMII_PHY_RPC220); - nr_lanes = mpfs_get_num_lanes(); - for (lane = 0; lane < nr_lanes; lane++) + for (lane = 0; lane < priv->number_of_lanes_to_calibrate; lane++) { mpfs_load_dq(lane); } #endif - /* Find the proper write latency by using mtc test */ + if (LIBERO_SETTING_CFG_WRITE_LATENCY_SET == 0) + { + /* Find the proper write latency by using mtc test */ - do + do + { + putreg32(write_latency, MPFS_DDR_CSR_APB_CFG_DFI_T_PHY_WRLAT); + error = mpfs_write_calibration_using_mtc(priv); + } + while (error && ++write_latency <= WR_LATENCY_MAX); + } + else { putreg32(write_latency, MPFS_DDR_CSR_APB_CFG_DFI_T_PHY_WRLAT); error = mpfs_write_calibration_using_mtc(priv); } - while (error && ++write_latency <= WR_LATENCY_MAX); /* Return error if mtc test failed on all allowed latency values */ @@ -3758,7 +3736,7 @@ static int mpfs_training_write_calibration(struct mpfs_ddr_priv_s *priv) static int mpfs_training_full_mtc_test(void) { - uint32_t error = 0; + int error = 0; uint8_t mask; if (mpfs_get_num_lanes() <= 3) @@ -3770,48 +3748,16 @@ static int mpfs_training_full_mtc_test(void) mask = 0xf; } - /* Read once to flush MTC. During write calibration the first MTC read - * must be discarded as it is unreliable after a series of bad writes. - */ + /* Test sequential additions */ + + error = mpfs_mtc_test_all(mask, 0x00, ONE_MB_MTC, MTC_ADD_SEQUENTIAL); - mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_COUNTING_PATTERN, - MTC_ADD_SEQUENTIAL); - - /* Read using different patterns */ - - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_COUNTING_PATTERN, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_WALKING_ONE, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, - MTC_NO_REPEATING_PSEUDO_RANDOM, MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_ALT_ONES_ZEROS, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_ALT_5_A, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM_16BIT, - MTC_ADD_SEQUENTIAL); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM_8BIT, - MTC_ADD_SEQUENTIAL); - - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_COUNTING_PATTERN, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_WALKING_ONE, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, - MTC_NO_REPEATING_PSEUDO_RANDOM, MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_ALT_ONES_ZEROS, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_ALT_5_A, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM_16BIT, - MTC_ADD_RANDOM); - error |= mpfs_mtc_test(mask, 0x00, ONE_MB_MTC, MTC_PSEUDO_RANDOM_8BIT, - MTC_ADD_RANDOM); + if (error == 0) + { + /* Test random additions */ + + error = mpfs_mtc_test_all(mask, 0x00, ONE_MB_MTC, MTC_ADD_RANDOM); + } if (error) { diff --git a/arch/risc-v/src/mpfs/mpfs_dsn.c b/arch/risc-v/src/mpfs/mpfs_dsn.c new file mode 100644 index 0000000000000..e745976253b07 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_dsn.c @@ -0,0 +1,154 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_dsn.c + * + * 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 +#include +#include +#include "mpfs_dsn.h" +#include "riscv_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MPFS_SCBCTRL_BASE 0x37020000ul +#define SERVICES_CR_OFFSET 0x50 +#define SERVICES_SR_OFFSET 0x54 + +#define SERVICES_CR (MPFS_SCBCTRL_BASE + SERVICES_CR_OFFSET) +#define SERVICES_SR (MPFS_SCBCTRL_BASE + SERVICES_SR_OFFSET) + +/* Command bits */ + +#define SCBCTRL_SERVICESCR_REQ (1 << 0) + +/* Status bits */ + +#define SCBCTRL_SERVICESSR_BUSY (1 << 1) + +/* 2kB long mailbox. */ + +#define MSS_SCBMAILBOX 0x37020800ul + +/* Retry count */ + +#define RETRIES 500 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_read_dsn + * + * Description: + * Read n bytes of the device serial number. Full serial number is 16 bytes + * + * Parameters: + * dsn - A pointer to the destination buffer + * len - Number of bytes to read + * + * Returned Value: + * Number of bytes read, -ETIMEDOUT on error + * + ****************************************************************************/ + +int mpfs_read_dsn(uint8_t *dsn, size_t len) +{ + uint32_t reg; + uint8_t *p = (uint8_t *)MSS_SCBMAILBOX; + irqstate_t flags = enter_critical_section(); + unsigned retries = RETRIES; + + /* Wait until the system controller is not busy. + * Read the SN inside critical section, just in case someone else is + * using the system controller services + */ + + while ((getreg32(SERVICES_SR) & SCBCTRL_SERVICESSR_BUSY) && --retries > 0) + { + leave_critical_section(flags); + usleep(1000); + flags = enter_critical_section(); + } + + if (retries == 0) + { + goto out; + } + + /* Read at max MPFS_DSN_LENGTH bytes, set the rest to 0 */ + + if (len > MPFS_DSN_LENGTH) + { + len = MPFS_DSN_LENGTH; + } + + /* Command: bits 0 to 6 is the opcode, bits 7 to 15 is the Mailbox + * offset. In this case, opcode == 0 and offset == 0. + */ + + putreg32(SCBCTRL_SERVICESCR_REQ, SERVICES_CR); + + /* Wait until the system controller has started processing the command */ + + retries = RETRIES; + do + { + reg = getreg32(SERVICES_CR); + } + while ((reg & SCBCTRL_SERVICESCR_REQ) && --retries); + + if (retries == 0) + { + goto out; + } + + /* Wait for the completion of the command */ + + retries = RETRIES; + do + { + reg = getreg32(SERVICES_SR); + } + while ((reg & SCBCTRL_SERVICESSR_BUSY) && --retries); + + if (retries == 0) + { + goto out; + } + + /* Read the bytes of serial from service mailbox */ + + for (uint8_t i = 0; i < len; i++) + { + dsn[i] = getreg8(p++); + } + +out: + + leave_critical_section(flags); + + return retries > 0 ? len : -ETIMEDOUT; +} diff --git a/arch/risc-v/src/mpfs/mpfs_dsn.h b/arch/risc-v/src/mpfs/mpfs_dsn.h new file mode 100644 index 0000000000000..825d3019a41a1 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_dsn.h @@ -0,0 +1,81 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_dsn.h + * + * 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 + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_DSN_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_DSN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Pre-Processor Declarations + ****************************************************************************/ + +/* This is the length of the serial number */ + +#define MPFS_DSN_LENGTH 16 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_read_dsn + * + * Description: + * Read n bytes of the device serial number. Full serial number is 16 bytes + * + * Parameters: + * dsn - A pointer to the destination buffer + * len - Number of bytes to read + * + * Returned Value: + * Number of bytes read or negated errno + * + ****************************************************************************/ + +int mpfs_read_dsn(uint8_t *dsn, size_t len); + +#ifdef __cplusplus +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_DSN_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 873fc4ddb09ac..ca4ec4c5ef4c7 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -156,7 +156,7 @@ /* Provide default SD-card 4bit clk if unset at board.h */ #ifndef MPFS_SD_CLOCK_4BIT -# define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_25MHZ +# define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_50MHZ #endif /* Define the Hardware FIFO size */ @@ -782,12 +782,22 @@ static void mpfs_sendfifo(struct mpfs_dev_s *priv) * come back when we're good to write again. */ - if (priv->remaining && (!(getreg32(MPFS_EMMCSD_SRS09) & - MPFS_EMMCSD_SRS09_BWE))) + if (priv->remaining) { - modifyreg32(MPFS_EMMCSD_SRS14, 0, MPFS_EMMCSD_SRS14_BWR_IE); + /* Enable BWR before checking BWE bit */ + putreg32(MPFS_EMMCSD_SRS12_BWR, MPFS_EMMCSD_SRS12); - return; + modifyreg32(MPFS_EMMCSD_SRS14, 0, MPFS_EMMCSD_SRS14_BWR_IE); + if (!(getreg32(MPFS_EMMCSD_SRS09) & MPFS_EMMCSD_SRS09_BWE)) + { + return; + } + + /* There is still room for writing to buffer, + * disable BWR and continue. + */ + + modifyreg32(MPFS_EMMCSD_SRS14, MPFS_EMMCSD_SRS14_BWR_IE, 0); } } @@ -1805,6 +1815,58 @@ static void mpfs_widebus(struct sdio_dev_s *dev, bool wide) } } +/**************************************************************************** + * Name: mpfs_clock + * + ****************************************************************************/ + +static void mpfs_set_hs_8bit(struct sdio_dev_s *dev) +{ + struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; + int ret; + uint32_t r1; + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (6 << 8))) == OK) + { + if ((ret == mpfs_waitresponse(dev, MMCSD_CMD6)) == OK) + { + ret = mpfs_recvshortcrc(dev, MMCSD_CMD6, &r1); + } + } + + if (ret < 0) + { + mcerr("Failed to set high speed mode\n"); + goto err; + } + + modifyreg32(MPFS_EMMCSD_HRS06, 0, priv->bus_mode); + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (2 << 8))) == OK) + { + if ((ret == mpfs_waitresponse(dev, MMCSD_CMD6)) == OK) + { + ret = mpfs_recvshortcrc(dev, MMCSD_CMD6, &r1); + } + } + + if (ret < 0) + { + mcerr("Failed to set 8-bit mode\n"); + goto err; + } + + modifyreg32(MPFS_EMMCSD_SRS10, 0, MPFS_EMMCSD_SRS10_EDTW); + return; + +err: + + /* Reset to 1-bit legacy mode */ + + modifyreg32(MPFS_EMMCSD_HRS06, 0, MPFS_EMMCSD_MODE_LEGACY); + modifyreg32(MPFS_EMMCSD_SRS10, MPFS_EMMCSD_SRS10_EDTW, 0); +} + /**************************************************************************** * Name: mpfs_clock * @@ -1848,7 +1910,8 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) { clckr = MPFS_MMC_CLOCK_200MHZ; } - else if (priv->bus_mode == MPFS_EMMCSD_MODE_SDR) + else if (priv->bus_mode == MPFS_EMMCSD_MODE_SDR || + priv->bus_mode == MPFS_EMMCSD_MODE_DDR) { clckr = MPFS_MMC_CLOCK_50MHZ; } @@ -1869,13 +1932,22 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) /* SD normal operation clocking (narrow 1-bit mode) */ case CLOCK_SD_TRANSFER_1BIT: - clckr = MPFS_MMC_CLOCK_25MHZ; + clckr = MPFS_MMC_CLOCK_50MHZ; break; } /* Set the new clock frequency */ mpfs_setclkrate(priv, clckr); + + /* REVISIT: This should really be a separate configuration procedure */ + + if (rate == CLOCK_MMC_TRANSFER) + { + /* eMMC: Set 8-bit data bus and correct bus mode */ + + mpfs_set_hs_8bit(dev); + } } /**************************************************************************** diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.c b/arch/risc-v/src/mpfs/mpfs_entrypoints.c index 44fe89f7117f0..7847a62aefc09 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.c +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.c @@ -185,4 +185,28 @@ int mpfs_set_use_sbi(uint64_t hartid, bool use_sbi) return ERROR; } +/**************************************************************************** + * Name: mpfs_get_use_sbi + * + * Description: + * Get if hart boots via SBI. + * + * Input Parameters: + * hartid - hart id to check + * + * Returned value: + * true if SBI is used, false otherwise + * + ****************************************************************************/ + +bool mpfs_get_use_sbi(uint64_t hartid) +{ + if (hartid < ENTRYPT_CNT) + { + return (g_hart_use_sbi & (1 << hartid)) != 0; + } + + return false; +} + #endif /* CONFIG_MPFS_BOOTLOADER */ diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.h b/arch/risc-v/src/mpfs/mpfs_entrypoints.h index 949972db74f2c..794b01974a691 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.h +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.h @@ -86,6 +86,22 @@ int mpfs_set_entrypt(uint64_t hartid, uintptr_t entry); int mpfs_set_use_sbi(uint64_t hartid, bool use_sbi); +/**************************************************************************** + * Name: mpfs_get_use_sbi + * + * Description: + * Get if hart boots via SBI. + * + * Input Parameters: + * hartid - hart id to check + * + * Returned value: + * true if SBI is used, false otherwise + * + ****************************************************************************/ + +bool mpfs_get_use_sbi(uint64_t hartid); + #if defined(__cplusplus) } #endif diff --git a/arch/risc-v/src/mpfs/mpfs_ethernet.c b/arch/risc-v/src/mpfs/mpfs_ethernet.c index 7b058d9424445..c72764ebb8c59 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -53,6 +53,7 @@ #include "riscv_internal.h" #include "mpfs_memorymap.h" #include "mpfs_ethernet.h" +#include "mpfs_dsn.h" #if defined(CONFIG_NET) && defined(CONFIG_MPFS_ETHMAC) @@ -155,6 +156,10 @@ #define MPFS_TXTIMEOUT (60 * CLK_TCK) +/* RX timeout = 30s */ + +#define MPFS_RXTIMEOUT (30 * CLK_TCK) + /* PHY reset tim in loop counts */ #define PHY_RESET_WAIT_COUNT (10) @@ -250,6 +255,7 @@ struct mpfs_ethmac_s uint8_t intf; /* Ethernet interface number */ uint8_t phyaddr; /* PHY address */ struct wdog_s txtimeout; /* TX timeout timer */ + struct wdog_s rxtimeout; /* RX timeout timer */ struct work_s irqwork; /* For deferring interrupt work to the work queue */ struct work_s pollwork; /* For deferring poll work to the work queue */ @@ -366,6 +372,7 @@ static void mpfs_ipv6multicast(struct sam_gmac_s *priv); #endif static void mpfs_interrupt_work(void *arg); +static void mpfs_txtimeout_expiry(wdparm_t arg); /**************************************************************************** * Private Functions @@ -447,6 +454,14 @@ static int mpfs_interrupt_0(int irq, void *context, void *arg) wd_cancel(&priv->txtimeout); } + if ((isr & GEM_INT_RECEIVE_COMPLETE) != 0) + { + /* If a RX transfer just completed, restart the timeout */ + + wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT, + mpfs_txtimeout_expiry, (wdparm_t)priv); + } + /* Schedule to perform the interrupt processing on the worker thread. */ work_queue(ETHWORK, &priv->irqwork, mpfs_interrupt_work, priv, 0); @@ -1046,13 +1061,6 @@ static void mpfs_interrupt_work(void *arg) uint32_t rx_error = 0; ninfo("RX: rsr=0x%X\n", rsr); - if ((rsr & RECEIVE_STATUS_FRAME_RECEIVED) != 0) - { - /* Handle the received packet */ - - mpfs_receive(priv, queue); - } - /* Check for Receive Overrun */ if ((rsr & RECEIVE_STATUS_RECEIVE_OVERRUN) != 0) @@ -1094,6 +1102,12 @@ static void mpfs_interrupt_work(void *arg) regval |= NETWORK_CONTROL_ENABLE_RECEIVE; mac_putreg(priv, NETWORK_CONTROL, regval); } + else if ((rsr & RECEIVE_STATUS_FRAME_RECEIVED) != 0) + { + /* Handle the received packet only in case there are no RX errors */ + + mpfs_receive(priv, queue); + } } net_unlock(); @@ -1483,7 +1497,7 @@ static int mpfs_ifup(struct net_driver_s *dev) return ret; } - /* Set the MAC address (should have been configured while we were down) */ + /* Set the MAC address */ mpfs_macaddress(priv); @@ -1528,6 +1542,13 @@ static int mpfs_ifup(struct net_driver_s *dev) up_enable_irq(priv->mac_q_int[2]); up_enable_irq(priv->mac_q_int[3]); + /* Set up the RX timeout. If we don't receive anything in time, try + * to re-initialize + */ + + wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT, + mpfs_txtimeout_expiry, (wdparm_t)priv); + return OK; } @@ -1571,6 +1592,10 @@ static int mpfs_ifdown(struct net_driver_s *dev) wd_cancel(&priv->txtimeout); + /* Cancel the RX timeout timers */ + + wd_cancel(&priv->rxtimeout); + /* Put the MAC in its reset, non-operational state. This should be * a known configuration that will guarantee the mpfs_ifup() always * successfully brings the interface back up. @@ -3543,6 +3568,16 @@ int mpfs_ethinitialize(int intf) priv->queue[2].dma_rxbuf_size = (uint32_t *)(base + DMA_RXBUF_SIZE_Q2); priv->queue[3].dma_rxbuf_size = (uint32_t *)(base + DMA_RXBUF_SIZE_Q3); + /* Generate a locally administrated MAC address for this ethernet if */ + + /* Set first byte to 0x02 or 0x06 acc. to the intf */ + + priv->dev.d_mac.ether.ether_addr_octet[0] = 0x02 | ((intf & 1) << 2); + + /* Read the next 5 bytes from the S/N */ + + mpfs_read_dsn(&priv->dev.d_mac.ether.ether_addr_octet[1], 5); + /* MPU hack for ETH DMA if not enabled by bootloader */ #ifdef CONFIG_MPFS_MPU_DMA_ENABLE diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c new file mode 100644 index 0000000000000..64910be0287eb --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -0,0 +1,3070 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_fpga_canfd.c + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hardware/mpfs_fpga_canfd.h" +#include "riscv_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef OK +# define OK 0 +#endif + +/* This module only compiles if the CANFD IP core instance + * is configured to the FPGA + */ + +#ifndef CONFIG_MPFS_HAVE_CANFD +# error This should not be compiled as CANFD FPGA block is not defined +#endif + +/* This module only compiles if Nuttx socketCAN interface supports CANFD */ + +#ifndef CONFIG_NET_CAN_CANFD +# error This should not be compiled as CANFD driver relies on socket CAN +#endif + +/* Clock reset and enabling */ + +#define MPFS_SYSREG_SOFT_RESET_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SOFT_RESET_CR_OFFSET) +#define MPFS_SYSREG_SUBBLK_CLOCK_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET) + +#define CANWORK HPWORK + +#define MPFS_CANFD_ID 0xCAFD + +/* For allocating the tx and rx CANFD frame buffer */ + +#define POOL_SIZE 1 +#define TIMESTAMP_SIZE sizeof(struct timeval) /* To support + * timestamping frame */ + +/* For bit timing calculation */ + +#define BT_COMPUTE_MAX_ERROR 50 /* 1/10th of % */ +#define BT_COMPUTE_SYNC_SEG 1 + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +/* CAN hw filter support */ + +#define HW_FILTER_A 0 +#define HW_FILTER_B 1 +#define HW_FILTER_C 2 +#define HW_FILTER_RANGE 3 + +#define CAN_STD_ID 0 +#define CAN_EXT_ID 1 +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/* Special address description flags for the CAN_ID */ + +#define CAN_EFF_FLAG 0x80000000 /* EFF/SFF is set in the MSB */ +#define CAN_RTR_FLAG 0x40000000 /* remote transmission request */ +#define CAN_ERR_FLAG 0x20000000 /* error message frame */ + +/* Valid bits in CAN ID for frame formats */ + +#define CAN_SFF_MASK 0x000007FF /* standard frame format (SFF) */ +#define CAN_EFF_MASK 0x1FFFFFFF /* extended frame format (EFF) */ +#define CAN_ERR_MASK 0x1FFFFFFF /* omit EFF, RTR, ERR flags */ + +/* CAN control mode */ + +#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ +#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ +#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ +#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ +#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ +#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ +#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ +#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ +#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ +#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically + * calculates TDCV */ +#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ + +/* TXT buffer */ + +enum mpfs_can_txb_status +{ + TXT_NOT_EXIST = 0x0, + TXT_RDY = 0x1, + TXT_TRAN = 0x2, + TXT_ABTP = 0x3, + TXT_TOK = 0x4, + TXT_ERR = 0x6, + TXT_ABT = 0x7, + TXT_ETY = 0x8, +}; + +enum mpfs_can_txb_command +{ + TXT_CMD_SET_EMPTY = 0x01, + TXT_CMD_SET_READY = 0x02, + TXT_CMD_SET_ABORT = 0x04 +}; + +/**************************************************************************** + * Utility definitions + ****************************************************************************/ + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define clamp(val, lo, hi) min(max(val, lo), hi) + +#define MPFS_CAN_FD_TXNF(priv) \ + (getreg32(priv->base + MPFS_CANFD_STATUS_OFFSET) & MPFS_CANFD_STATUS_TXNF) +#define MPFS_CAN_FD_ENABLED(priv) \ + (getreg32(priv->base + MPFS_CANFD_MODE_OFFSET) & MPFS_CANFD_MODE_ENA) + +#if __GNUC__ >= 3 +# define expect(expr,value) __builtin_expect((expr),(value)) +#else +# define expect(expr,value) (expr) +#endif + +#define expect_false(expr) expect((expr) != 0, 0) +#define expect_true(expr) expect((expr) != 0, 1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CAN operational and error states */ + +/* CAN bit timing parameters */ + +struct mpfs_can_bittiming_s +{ + uint32_t bitrate; /* Bit-rate in bits/second */ + uint32_t sample_point; /* Sample point in one-tenth of a percent */ + uint32_t tq; /* Time quanta (TQ) in nanoseconds */ + uint32_t prop_seg; /* Propagation segment in TQs */ + uint32_t phase_seg1; /* Phase buffer segment 1 in TQs */ + uint32_t phase_seg2; /* Phase buffer segment 2 in TQs */ + uint32_t sjw; /* Synchronisation jump width in TQs */ + uint32_t brp; /* Bitrate prescaler */ +}; + +/* CAN harware dependent bit timing constants + * Used for calculating and checking bit timing parameters + */ + +struct mpfs_can_bittiming_const_s +{ + uint32_t tseg_min; + uint32_t tseg_max; + uint32_t brp_min; + uint32_t brp_max; +}; + +static const struct mpfs_can_bittiming_const_s mpfs_can_bit_timing_range = +{ + .tseg_min = 3, + .tseg_max = 253, + .brp_min = 1, + .brp_max = 8, +}; + +static const struct mpfs_can_bittiming_const_s + mpfs_can_bit_timing_data_range = +{ + .tseg_min = 3, + .tseg_max = 125, + .brp_min = 1, + .brp_max = 2, +}; + +struct mpfs_can_clock_s +{ + uint32_t freq; /* CAN system clock frequency in Hz */ +}; + +enum mpfs_can_state_e +{ + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +struct mpfs_can_ctrlmode_s +{ + uint32_t mask; + uint32_t flags; +}; + +struct mpfs_can_berr_counter_s +{ + uint16_t txerr; + uint16_t rxerr; +}; + +struct mpfs_can_device_stats_s +{ + uint32_t bus_error; /* Bus errors */ + uint32_t error_warning; /* Changes to error warning state */ + uint32_t error_passive; /* Changes to error passive state */ + uint32_t bus_off; /* Changes to bus off state */ + uint32_t arbitration_lost; /* Arbitration lost errors */ + uint32_t restarts; /* CAN controller re-starts */ +}; + +/* CAN common private data */ + +struct mpfs_can_priv_s +{ + struct mpfs_can_device_stats_s can_stats; + struct mpfs_can_bittiming_s bittiming; + struct mpfs_can_bittiming_s data_bittiming; + const struct mpfs_can_bittiming_const_s *bittiming_const; + const struct mpfs_can_bittiming_const_s *data_bittiming_const; + struct mpfs_can_clock_s clock; + + enum mpfs_can_state_e state; + uint32_t ctrlmode; +}; + +/**************************************************************************** + * CANFD Frame Format + ****************************************************************************/ + +/* CAN frame format memory map */ + +enum mpfs_canfd_can_frame_format +{ + MPFS_CANFD_FRAME_FORMAT_W_OFFSET = 0x0, + MPFS_CANFD_IDENTIFIER_W_OFFSET = 0x4, + MPFS_CANFD_TIMESTAMP_L_W_OFFSET = 0x8, + MPFS_CANFD_TIMESTAMP_U_W_OFFSET = 0xc, + MPFS_CANFD_DATA_1_4_W_OFFSET = 0x10, + MPFS_CANFD_DATA_5_8_W_OFFSET = 0x14, + MPFS_CANFD_DATA_61_64_W_OFFSET = 0x4c, +}; + +/* CANFD_Frame_format memory region */ + +/* FRAME_FORMAT_W registers */ + +#define MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT (0) +#define MPFS_CANFD_FRAME_FORMAT_W_DLC (0x0F << \ + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT) +#define MPFS_CANFD_FRAME_FORMAT_W_RTR (1 << 5) +#define MPFS_CANFD_FRAME_FORMAT_W_IDE (1 << 6) +#define MPFS_CANFD_FRAME_FORMAT_W_FDF (1 << 7) +#define MPFS_CANFD_FRAME_FORMAT_W_BRS (1 << 9) +#define MPFS_CANFD_FRAME_FORMAT_W_ESI_RSV (1 << 10) +#define MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT (11) +#define MPFS_CANFD_FRAME_FORMAT_W_RWCNT (0x1F << \ + MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT) + +/* IDENTIFIER_W registers */ + +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT (0) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT (0x03FFFF << \ + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT (18) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE (0x07FF << \ + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT) + +/**************************************************************************** + * CAN controller hardware configuration + ****************************************************************************/ + +struct mpfs_config_s +{ + uint32_t canfd_fpga_irq; /* the only CANFD FPGA IRQ */ +}; + +#ifdef CONFIG_MPFS_CANFD0 +static const struct mpfs_config_s mpfs_fpga_canfd_config0 = +{ + .canfd_fpga_irq = MPFS_IRQ_FABRIC_F2H_0, +}; +#endif +#ifdef CONFIG_MPFS_CANFD1 +static const struct mpfs_config_s mpfs_fpga_canfd_config1 = +{ + .canfd_fpga_irq = MPFS_IRQ_FABRIC_F2H_9, +}; +#endif + +/**************************************************************************** + * The mpfs_driver_s encapsulates all state information for a single + * hw interface + ****************************************************************************/ + +struct mpfs_driver_s +{ + struct mpfs_can_priv_s can; + + const struct mpfs_config_s *config; + + uintptr_t base; /* CANFD FPGA base address */ + bool bifup; /* true:ifup false:ifdown */ + + struct work_s rxwork; /* for deferring rx interrupt work to the wq */ + struct work_s txdwork; /* For deferring tx done interrupt work to the + * wq */ + struct work_s pollwork; /* For deferring poll work to the wq */ + + struct canfd_frame *txdesc; /* A pointer to the list of TX descriptor */ + struct canfd_frame *rxdesc; /* A pointer to the list of RX descriptors */ + + /* rx */ + + uint32_t drv_flags; /* driver flag */ + uint32_t rxfrm_first_word; /* rx frame first word (usually a FFW) */ + + /* tx */ + + unsigned int txb_sent; + unsigned int txb_processed; + uint32_t txb_prio; + unsigned int ntxbufs; + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* hw filter */ + + uint8_t used_bit_filter_number; + bool used_range_filter; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* This holds the information visible to the NuttX network */ + + struct net_driver_s dev; /* Interface understood by the network */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_MPFS_CANFD0 +static struct mpfs_driver_s g_canfd0; + +static uint8_t g_tx_pool0[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +static uint8_t g_rx_pool0[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +#endif + +#ifdef CONFIG_MPFS_CANFD1 +static struct mpfs_driver_s g_canfd1; + +static uint8_t g_tx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +static uint8_t g_rx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* (from interrupt) RX related functions */ + +static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, + struct canfd_frame *cf, + uint32_t ffw); +static void mpfs_receive_work(void *arg); + +/* (from interrupt) TX related functions */ + +static void mpfs_can_update_txb_prio(struct mpfs_driver_s *priv); +static void mpfs_can_send_txb_cmd(struct mpfs_driver_s *priv, + enum mpfs_can_txb_command cmd, + uint8_t buf); +static void mpfs_txdone(struct mpfs_driver_s *priv); +static void mpfs_txdone_work(void *arg); + +/* (from interrupt) Error handling related functions */ + +static enum mpfs_can_state_e + mpfs_can_get_err_state(struct mpfs_driver_s *priv); +static void mpfs_can_get_err_count(struct mpfs_driver_s *priv, + struct mpfs_can_berr_counter_s *bec); +static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr); + +/* Interrupt service routine */ + +static int mpfs_interrupt(int irq, void *context, void *arg); + +/* (Nuttx network driver interface callback when TX packet available) Tx + * related functions + */ + +static enum mpfs_can_txb_status + mpfs_can_get_txb_status(struct mpfs_driver_s *priv, + uint8_t buf); +static bool mpfs_can_is_txb_writable(struct mpfs_driver_s *priv, + uint8_t buf); +static bool mpfs_can_write_txb(struct mpfs_driver_s *priv, + const struct canfd_frame *cf, + uint8_t buf, + bool is_ccf); +static int mpfs_transmit(struct mpfs_driver_s *priv); +static int mpfs_txpoll(struct net_driver_s *dev); +static void mpfs_txavail_work(void *arg); +static int mpfs_txavail(struct net_driver_s *dev); + +/* Bit timing related functions */ + +static int + mpfs_can_btr_compute(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + const struct mpfs_can_bittiming_const_s *btc); + +static int mpfs_can_config_bit_timing(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + bool arbi); +static int mpfs_can_config_arbi_bit_timing(struct mpfs_driver_s *priv); +static int mpfs_can_config_data_bit_timing(struct mpfs_driver_s *priv); + +/* Miscellaneous CAN controller interface functions */ + +static int mpfs_can_config_ssp(struct mpfs_driver_s *priv); +static void + mpfs_can_config_controller_mode(struct mpfs_driver_s *priv, + const struct mpfs_can_ctrlmode_s *mode); + +/* HW filter related functions */ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, + uint8_t filter_type, + uint8_t can_id_type, + uint8_t can_type, + uint32_t fid1, + uint32_t fid2); +static void mpfs_can_reset_hw_filter(struct mpfs_driver_s *priv); +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/* CAN controller life cycle routines */ + +static int mpfs_can_controller_start(struct mpfs_driver_s *priv); +static void mpfs_can_controller_stop(struct mpfs_driver_s *priv); +static int mpfs_reset(struct mpfs_driver_s *priv); + +/* Driver interface to Nuttx network callbacks */ + +static int mpfs_ifup(struct net_driver_s *dev); +static int mpfs_ifdown(struct net_driver_s *dev); +#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); +#endif + +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_can_retrieve_rx_frame + * + * Description: + * Retrieve CAN/CANFD frame from RX Buffer + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cf - Pointer to CANFD frame structure + * ffw - Previously read frame format word + * + * Returned Value: + * None + * + * Assumptions: + * Frame format word is already parsed in advance and provided as 'ffw' arg + * + ****************************************************************************/ + +static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, + struct canfd_frame *cf, + uint32_t ffw) +{ + uint32_t idw; + unsigned int i; + unsigned int data_wc; /* data word count */ + unsigned int data_bc; /* data byte count */ + unsigned int dlc; + unsigned int len; + + /* CAN ID */ + + idw = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + if (MPFS_CANFD_FRAME_FORMAT_W_IDE & ffw) + { + cf->can_id = (idw & CAN_EFF_MASK) | CAN_EFF_FLAG; + } + else + { + cf->can_id = + (idw >> MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT) & + CAN_SFF_MASK; + } + + /* BRS, ESI, RTR Flags */ + + cf->flags = 0; + if (MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw) + { + /* Enable bitrate switch by default if frame is CANFD */ + + cf->flags |= CANFD_BRS; + + if (MPFS_CANFD_FRAME_FORMAT_W_ESI_RSV & ffw) + { + cf->flags |= CANFD_ESI; + } + } + else if (MPFS_CANFD_FRAME_FORMAT_W_RTR & ffw) + { + cf->can_id |= CAN_RTR_FLAG; + } + + /* RWCNT : RX Count of Words without FRAME_FORMAT WORD. Minus the 3 words + * for 1 IDW, 2 timestamp words + */ + + data_wc = ((MPFS_CANFD_FRAME_FORMAT_W_RWCNT & ffw) >> + MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT) - 3; + data_bc = data_wc * 4; + + /* DLC */ + + dlc = (MPFS_CANFD_FRAME_FORMAT_W_DLC & ffw) >> + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT; + if (dlc <= 8) + { + len = dlc; + } + else + { + if (MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw) + { + len = data_wc << 2; + } + else + { + len = 8; + } + } + cf->len = len; + if (expect_false(len > data_bc)) + { + len = data_bc; + } + + /* Timestamp - Read and throw away */ + + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + /* Data */ + + for (i = 0; i < len; i += 4) + { + uint32_t data = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + *(uint32_t *)(cf->data + i) = data; + } + + /* Read and discard exceeding data that does not fit any frame. read + * pointer is automatically increased if RX buffer is not empty. + */ + + while (expect_false(i < data_bc)) + { + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + i += 4; + } +} + +/**************************************************************************** + * Name: mpfs_receive_work + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void mpfs_receive_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + uint32_t status; + uint32_t frame_count; + bool is_classical_can_frame = false; + + frame_count = (getreg32(priv->base + MPFS_CANFD_RX_STATUS_OFFSET) & + MPFS_CANFD_RX_STATUS_RXFRC) >> MPFS_CANFD_RX_STATUS_RXFRC_SHIFT; + while (frame_count) + { + struct canfd_frame *cf = (struct canfd_frame *)priv->rxdesc; + uint32_t ffw; + + ffw = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + if (!(MPFS_CANFD_FRAME_FORMAT_W_RWCNT & ffw)) + { + break; + } + + if (!(MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw)) + { + if (MPFS_CANFD_FRAME_FORMAT_W_RTR & ffw) + { + caninfo("Remote Frame received\n"); + } + else + { + caninfo("Classical CAN Frame received\n"); + } + + is_classical_can_frame = true; + } + else + { + caninfo("CANFD Frame received\n"); + } + + /* Retrieve the classical or CANFD or remote frame */ + + mpfs_can_retrieve_rx_frame(priv, cf, ffw); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = is_classical_can_frame ? + sizeof(struct can_frame) : sizeof(struct canfd_frame); + priv->dev.d_buf = (uint8_t *)cf; + + /* Send to socket interface */ + + NETDEV_RXPACKETS(&priv->dev); + can_input(&priv->dev); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + frame_count = (getreg32(priv->base + MPFS_CANFD_RX_STATUS_OFFSET) & + MPFS_CANFD_RX_STATUS_RXFRC) >> MPFS_CANFD_RX_STATUS_RXFRC_SHIFT; + } + + /* Check for RX FIFO Overflow */ + + status = getreg32(priv->base + MPFS_CANFD_STATUS_OFFSET); + if (MPFS_CANFD_STATUS_DOR & status) + { + /* Notify to socket interface */ + + NETDEV_RXERRORS(&priv->dev); + + /* Clear Data Overrun */ + + putreg32(MPFS_CANFD_COMMAND_CDO, + priv->base + MPFS_CANFD_COMMAND_OFFSET); + } + + /* Clear and re-enable RBNEI */ + + putreg32(MPFS_CANFD_INT_STAT_RBNEI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + putreg32(MPFS_CANFD_INT_STAT_RBNEI, + priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_update_txb_prio + * + * Description: + * Rotates priorities of TXT buffers + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_update_txb_prio(struct mpfs_driver_s *priv) +{ + uint32_t prio = priv->txb_prio; + + /* Rotate TX_PRIORITY register states one step left */ + + prio = (prio << 4) | ((prio >> ((priv->ntxbufs - 1) * 4)) & 0xf); + priv->txb_prio = prio; + putreg32(prio, priv->base + MPFS_CANFD_TX_PRIORITY_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_send_txb_cmd + * + * Description: + * Execute a TXT buffer command + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cmd - Cmd to give + * buf - The TXT buffer index (0-based) + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_send_txb_cmd(struct mpfs_driver_s *priv, + enum mpfs_can_txb_command cmd, + uint8_t buf) +{ + uint32_t txb_cmd = cmd; + + txb_cmd |= 1 << (buf + 8); + putreg32(txb_cmd, priv->base + MPFS_CANFD_TX_COMMAND_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_txdone + * + * Description: + * Tx done interrupt service rountine + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_txdone(struct mpfs_driver_s *priv) +{ + bool first_buffer = true; + bool buffer_processed; + enum mpfs_can_txb_status txb_status; + uint8_t txb_id; + + do + { + buffer_processed = false; + while ((int)(priv->txb_sent - priv->txb_processed) > 0) + { + txb_id = priv->txb_processed % priv->ntxbufs; + txb_status = mpfs_can_get_txb_status(priv, txb_id); + bool other_status = false; + + switch (txb_status) + { + case TXT_TOK: + break; + case TXT_ERR: + canwarn("TXB in Error state\n"); + break; + case TXT_ABT: + canwarn("TXB in Aborted state\n"); + break; + default: + other_status = true; + + if (first_buffer) + { + canerr("TXB#%u not in a finished state (0x%x)!\n", + txb_id, txb_status); + + priv->txb_processed++; + + /* Rotate TXT buffer priority */ + + mpfs_can_update_txb_prio(priv); + + /* Mark current unfinished state TXT buffer as empty */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); + + /* Something is fishy. CLear txb status change interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + return; + } + break; + } + + if (other_status) + { + break; + } + else + { + priv->txb_processed++; + first_buffer = false; + buffer_processed = true; + + /* Rotate TXT buffer priority */ + + mpfs_can_update_txb_prio(priv); + + /* Mark current finished state TXT buffer as empty */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); + } + } + + if (buffer_processed) + { + /* Since there are some buffers processed and the number of TXT + * used now matched the number of processed buffer, we can clear + * the interrupt in order to avoid any erroneous interrupt after + * the last true TXT buffer interrupt is processed. + */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + } + while (buffer_processed); +} + +/**************************************************************************** + * Name: mpfs_txdone_work + * + * Description: + * An interrupt was received indicating that the last TX packet(s) is done + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * We are not in an interrupt context so that we can lock the network. + * + ****************************************************************************/ + +static void mpfs_txdone_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + /* There should be space for a new TX in any event. Poll the network for + * new XMIT data + */ + + net_lock(); + devif_poll(&priv->dev, mpfs_txpoll); + net_unlock(); +} + +/**************************************************************************** + * Name: mpfs_can_get_err_state + * + * Description: + * Reads CAN fault confinement state + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Fault confinement state of controller + * + ****************************************************************************/ + +static enum mpfs_can_state_e + mpfs_can_get_err_state(struct mpfs_driver_s *priv) +{ + u_int32_t ewl_erp_fs_reg, rec_tec_reg, ew_limit, rec_val, tec_val; + + ewl_erp_fs_reg = getreg32(priv->base + MPFS_CANFD_EWL_OFFSET); + rec_tec_reg = getreg32(priv->base + MPFS_CANFD_REC_OFFSET); + + ew_limit = ((ewl_erp_fs_reg & MPFS_CANFD_EWL_EW_LIMIT) >> + MPFS_CANFD_EWL_EW_LIMIT_SHIFT); + rec_val = ((rec_tec_reg & MPFS_CANFD_REC_REC_VAL) >> + MPFS_CANFD_REC_REC_VAL_SHIFT); + tec_val = ((rec_tec_reg & MPFS_CANFD_REC_TEC_VAL) >> + MPFS_CANFD_REC_TEC_VAL_SHIFT); + + if (ewl_erp_fs_reg & MPFS_CANFD_EWL_ERA) + { + if (rec_val < ew_limit && tec_val < ew_limit) + { + return CAN_STATE_ERROR_ACTIVE; + } + else + { + return CAN_STATE_ERROR_WARNING; + } + } + else if (ewl_erp_fs_reg & MPFS_CANFD_EWL_ERP) + { + return CAN_STATE_ERROR_PASSIVE; + } + else if (ewl_erp_fs_reg & MPFS_CANFD_EWL_BOF) + { + return CAN_STATE_BUS_OFF; + } + + canwarn("Invalid FPGA CANFD error state\n"); + return CAN_STATE_ERROR_PASSIVE; +} + +/**************************************************************************** + * Name: mpfs_can_get_err_count + * + * Description: + * Reads CAN RX/TX error counter + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bec - Pointer to Error counter structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mpfs_can_get_err_count(struct mpfs_driver_s *priv, + struct mpfs_can_berr_counter_s *bec) +{ + uint32_t rec_tec_reg = getreg32(priv->base + MPFS_CANFD_REC_OFFSET); + + bec->rxerr = ((rec_tec_reg & MPFS_CANFD_REC_REC_VAL) >> + MPFS_CANFD_REC_REC_VAL_SHIFT); + bec->txerr = ((rec_tec_reg & MPFS_CANFD_REC_TEC_VAL) >> + MPFS_CANFD_REC_TEC_VAL_SHIFT); +} + +/**************************************************************************** + * Name: mpfs_err_interrupt + * + * Description: + * Error frame ISR + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * isr - Interrupt status register value + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) +{ + enum mpfs_can_state_e state; + struct mpfs_can_berr_counter_s bec; + uint32_t err_capt_retr_ctr_alc_reg; + uint32_t err_type; + uint32_t err_pos; + uint32_t alc_id_field; + uint32_t alc_bit; + + mpfs_can_get_err_count(priv, &bec); + state = mpfs_can_get_err_state(priv); + err_capt_retr_ctr_alc_reg = + getreg32(priv->base + MPFS_CANFD_ERR_CAPT_OFFSET); + + err_type = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ERR_TYPE) >> + MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT); + err_pos = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ERR_POS) >> + MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT); + alc_id_field = + ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD) >> + MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT); + alc_bit = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ALC_BIT) >> + MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT); + + caninfo("ISR = 0x%08x, rxerr %d, txerr %d, error type %u, pos %u, ALC " + "id_field %u, bit %u\n", isr, bec.rxerr, bec.txerr, err_type, + err_pos, alc_id_field, alc_bit); + + /* Check for error warning limit and fault confinement state change */ + + if (MPFS_CANFD_INT_STAT_FCSI & isr || MPFS_CANFD_INT_STAT_EWLI & isr) + { + if (priv->can.state == state) + { + canwarn("No state change! Missed interrupt?\n"); + } + + priv->can.state = state; + + switch (state) + { + case CAN_STATE_BUS_OFF: + priv->can.can_stats.bus_off++; + canwarn("Change to BUS_OFF error state\n"); + break; + case CAN_STATE_ERROR_PASSIVE: + priv->can.can_stats.error_passive++; + canwarn("Change to ERROR_PASSIVE error state\n"); + break; + case CAN_STATE_ERROR_WARNING: + priv->can.can_stats.error_warning++; + canwarn("Change to ERROR_WARNING error state\n"); + break; + case CAN_STATE_ERROR_ACTIVE: + caninfo("Change to ERROR_ACTIVE error state\n"); + return; + default: + canwarn("Unhandled error state %d\n", state); + break; + } + } + + if (MPFS_CANFD_INT_STAT_ALI & isr) + { + canerr("Arbitration lost\n"); + priv->can.can_stats.arbitration_lost++; + } + + if (MPFS_CANFD_INT_STAT_BEI & isr) + { + canerr("Bus error\n"); + priv->can.can_stats.bus_error++; + } + + /* Notify to socket interface. */ + + NETDEV_ERRORS(&priv->dev); +} + +/**************************************************************************** + * Name: mpfs_interrupt + * + * Description: + * Three interrupt sources will vector to this function: + * 1. CAN frame transmit interrupt + * 2. CAN frame receive interrupt + * 3. Error interrupt + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + ****************************************************************************/ + +static int mpfs_interrupt(int irq, void *context, void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + uint32_t isr; + uint32_t icr; + uint32_t imask; + int irq_loops; + + for (irq_loops = 0; irq_loops < 10000; irq_loops++) + { + /* Get the interrupt status */ + + isr = getreg32(priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + /* Check and exit interrupt service routine if there is no int flag in + * INT_STAT reg. + */ + + if (!isr) + { + return irq_loops ? OK : -1; + } + + /* Receive Buffer Not Empty Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_RBNEI) + { + /* Mask RBNEI first, then clear interrupt. Even if + * another IRQ fires, RBNEI will always be 0 (masked). + */ + + icr = MPFS_CANFD_INT_STAT_RBNEI; + putreg32(icr, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + /* Schedule work to process RX frame from CAN controller */ + + work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); + } + + /* TXT Buffer HW Command Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_TXBHCI) + { + /* Clear TX interrupt flags */ + + mpfs_txdone(priv); + + /* Schedule work to poll for next available tx frame from the + * network. + */ + + work_queue(CANWORK, &priv->txdwork, mpfs_txdone_work, priv, 0); + } + + /* Error Interrupts */ + + if (isr & MPFS_CANFD_INT_STAT_EWLI || + isr & MPFS_CANFD_INT_STAT_FCSI || + isr & MPFS_CANFD_INT_STAT_ALI || + isr & MPFS_CANFD_INT_STAT_BEI) + { + icr = isr & (MPFS_CANFD_INT_STAT_EWLI | + MPFS_CANFD_INT_STAT_FCSI | + MPFS_CANFD_INT_STAT_ALI | + MPFS_CANFD_INT_STAT_BEI); + canerr("Some error interrupts. Clearing 0x%08x\n", icr); + putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); + mpfs_err_interrupt(priv, isr); + } + } + + /* Now, it seems that there are still some interrupt flags that remain + * stuck in INT_STAT reg. + */ + + canerr("Stuck interrupt (isr=%08x)\n", isr); + + /* Check if any of the stuck one belongs to txb status. */ + + if (isr & MPFS_CANFD_INT_STAT_TXBHCI) + { + canerr("TXBHCI interrupt\n"); + +#ifdef CONFIG_DEBUG_CAN_INFO + caninfo("txb_sent=0x%08x txb_processed=0x%08x\n", priv->txb_sent, + priv->txb_processed); + for (int i = 0; i < priv->ntxbufs; i++) + { + uint32_t status = mpfs_can_get_txb_status(priv, i); + caninfo("txb[%d] txb status=0x%08x\n", i, status); + } +#endif + /* Notify to socket interface */ + + NETDEV_TXERRORS(&priv->dev); + + /* Clear txb status change interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + + /* Check if any of the stuck one belongs to RX buffer data overrun */ + + if (isr & MPFS_CANFD_INT_STAT_DOI) + { + canerr("DOI interrupt\n"); + + /* Notify to socket interface */ + + NETDEV_RXERRORS(&priv->dev); + + /* Clear Data Overrun interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_DOI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + + /* Clear and reset all interrupt. */ + + canwarn("Reset all interrupts...\n"); + imask = 0xffffffff; + putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_CLR_OFFSET); + putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_SET_OFFSET); + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_get_tx_state + * + * Description: + * Get status of txt buffer + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * buf - txt buffer index to get status of (0-based) + * + * Returned Value: + * Status of txt buffer + * + * Assumptions: + * None + * + ****************************************************************************/ + +static enum mpfs_can_txb_status + mpfs_can_get_txb_status(struct mpfs_driver_s *priv, uint8_t buf) +{ + uint32_t tx_status = getreg32(priv->base + MPFS_CANFD_TX_STATUS_OFFSET); + enum mpfs_can_txb_status status = (tx_status >> (buf * 4)) & 0xf; + + return status; +} + +/**************************************************************************** + * Name: mpfs_can_is_txb_writable + * + * Description: + * Precheck txb state if a new frame can be written + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * buf - txt buffer index to get status of (0-based) + * + * Returned Value: + * True - Frame can be inserted to txt buffer + * False - If attempted, frame will not be inserted to txt buffer + * + * Assumptions: + * None + * + ****************************************************************************/ + +static bool mpfs_can_is_txb_writable(struct mpfs_driver_s *priv, + uint8_t buf) +{ + enum mpfs_can_txb_status buf_status; + + buf_status = mpfs_can_get_txb_status(priv, buf); + if (buf_status == TXT_RDY || buf_status == TXT_TRAN || + buf_status == TXT_ABTP) + { + canwarn("TXT buffer status %d\n", buf_status); + return false; + } + + return true; +} + +/**************************************************************************** + * Name: mpfs_can_write_txb + * + * Description: + * Load CAN frame onto txt buffer on the CAN controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cf - Pointer to the CANFD frame to be inserted + * buf - txt buffer index to which the cf frame is inserted (0-based) + * is_ccf- is classical can frame (bool) + * + * Returned Value: + * True - TXT buffer written successfully + * False - Frame was not written to TXT buffer due to: + * 1. TXT buffer is not writable + * 2. Invalid TXT buffer index + * 3. Invalid frame length + * + * Assumptions: + * None + * + ****************************************************************************/ + +static bool mpfs_can_write_txb(struct mpfs_driver_s *priv, + const struct canfd_frame *cf, + uint8_t buf, + bool is_ccf) +{ + uint32_t buf_base; + uint32_t ffw = 0; + uint32_t idw = 0; + unsigned int i; + + /* Check for invalid txt buffer index */ + + if (buf >= priv->ntxbufs) + { + canerr("Invalid txt buffer index...\n"); + return false; + } + + /* Check if it is possible to insert frame to txt buffer */ + + if (!mpfs_can_is_txb_writable(priv, buf)) + { + canwarn("Not possible to insert frame to txt buffer...\n"); + return false; + } + + /* Check for invalid classical CAN / CANFD frame length */ + + if (cf->len > CANFD_MAX_DLEN || (cf->len > CAN_MAX_DLEN && is_ccf)) + { + canerr("Invalid classical / CANFD CAN frame length...\n"); + return false; + } + + /* Populate frame format word */ + + if (cf->can_id & CAN_RTR_FLAG) /* remote transmission request */ + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_RTR; + } + + if (cf->can_id & CAN_EFF_FLAG) /* extended frame format (29 bit long id) */ + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_IDE; + } + + if (!is_ccf) + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_FDF; /* FD Frame */ + if (cf->flags & CANFD_BRS) + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_BRS; /* Bit rate switch */ + } + } + + ffw |= MPFS_CANFD_FRAME_FORMAT_W_DLC & (len_to_can_dlc[cf->len] << + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT); + + /* Populate CAN frame id word */ + + if (cf->can_id & CAN_EFF_FLAG) + { + idw = cf->can_id & CAN_EFF_MASK; + } + else + { + idw = MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + ((cf->can_id & CAN_SFF_MASK) << + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT); + } + + /* Write frame id and frame format word */ + + buf_base = (buf + 1) * 0x100; + putreg32(ffw, priv->base + buf_base + MPFS_CANFD_FRAME_FORMAT_W_OFFSET); + putreg32(idw, priv->base + buf_base + MPFS_CANFD_IDENTIFIER_W_OFFSET); + + /* Write CAN data payload */ + + if (!(cf->can_id & CAN_RTR_FLAG)) + { + for (i = 0; i < cf->len; i += 4) + { + uint32_t data = *(uint32_t *)(cf->data + i); + putreg32(data, + priv->base + buf_base + MPFS_CANFD_DATA_1_4_W_OFFSET + i); + } + } + + return true; +} + +/**************************************************************************** + * Name: mpfs_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int mpfs_transmit(struct mpfs_driver_s *priv) +{ + uint32_t txb_id; + bool ok; + bool is_classical_can_frame; + + /* Retrieve the classical CAN / CANFD frame from network device buffer */ + + is_classical_can_frame = + priv->dev.d_len <= sizeof(struct can_frame) ? true : false; + struct canfd_frame *cf = (struct canfd_frame *)priv->dev.d_buf; + + /* Get the current txt buffer ID */ + + txb_id = priv->txb_sent % priv->ntxbufs; + + /* Insert classical CAN/CANFD frame into controller txt bf at txb_id */ + + ok = mpfs_can_write_txb(priv, cf, txb_id, is_classical_can_frame); + if (!ok) + { + canwarn("TXNF set but cannot insert frame into TXT buffer!\n"); + NETDEV_TXERRORS(&priv->dev); + return OK; + } + + /* Now, write to txt buffer seems ok, use txt command to set buffer state + * to READY for xmit. + */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_READY, txb_id); + priv->txb_sent++; + + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->dev); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int mpfs_txpoll(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + /* Send the packet */ + + mpfs_transmit(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (!MPFS_CAN_FD_TXNF(priv)) + { + return -EBUSY; + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return OK; +} + +/**************************************************************************** + * Name: mpfs_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void mpfs_txavail_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + if (priv->bifup) + { + /* Check if there is room in the controller to hold another outgoing + * packet. + */ + + if (MPFS_CAN_FD_TXNF(priv)) + { + /* Yes, there is, poll the network for new TXT transmit */ + + net_lock(); + devif_poll(&priv->dev, mpfs_txpoll); + net_unlock(); + } + } +} + +/**************************************************************************** + * Name: mpfs_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * 0 - OK + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int mpfs_txavail(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + mpfs_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_btr_compute + * + * Description: + * Calculate bit timing values to be written to bit timing register + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bt - Pointer to the bit timing structure to be set + * btc - Pointer to the constant bit timing structure to be used to set + * the bit timing params + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * Bit timing constants needed to be set in advance on which calculation + * in this function is based + * + ****************************************************************************/ + +static int + mpfs_can_btr_compute(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + const struct mpfs_can_bittiming_const_s *btc) +{ + /* All measured in number of time quanta (Tq = brp / fsys) + * brp : baud rate prescaler as number of system clock periods + * prop_seg : propagation segment (1..8 Tq) + * phase_seg1 : phase segment 1 (1..8 Tq) + * phase_seg2 : phase segment 2 (1..8 Tq) + * + * tseg1 = prop_seg + phase_seg1 + * tseg2 = phase_seg2 + * tseg = tseg1 + tseg2 + * tsegall = BT_COMPUTE_SYNC_SEG + tseg / 2 + * + * sample point = (BT_COMPUTE_SYNC_SEG + tseg1) / + * (BT_COMPUTE_SYNC_SEG + tseg1 + tseg2) * 1000 + * + * CAN bitrate = 1 / (number_of_Tq * Tq) + */ + + unsigned int calc_br; /* current calculated bitrate */ + unsigned int br_err = 0; /* diff between user set bitrate + * and calculated bitrate */ + unsigned int best_br_err = UINT_MAX; /* best bitrate error */ + + unsigned int nominal_sp; /* nominal sample point either set + * by user or inferred from bitrate + * (CiA recommendation) */ + unsigned int calc_sp; /* calculated sample point */ + unsigned int sp_err; /* diff between and nominal sample + * point and currently calculated + * sample point */ + unsigned int best_sp_err = UINT_MAX; /* best sample point error */ + + unsigned int calc_brp; /* currently calculated bitrate + * prescaler */ + unsigned int best_brp = 0; /* currently calculated bitrate + * prescaler */ + unsigned int tseg_double; + unsigned int tseg_sync; + unsigned int tseg1 = 0; + unsigned int tseg2 = 0; + + /* Get sample point nominal */ + + if (bt->sample_point) + { + nominal_sp = bt->sample_point; + } + else + { + if (bt->bitrate <= 500000) + { + nominal_sp = 875; + } + else if (bt->bitrate <= 800000) + { + nominal_sp = 800; + } + else + { + nominal_sp = 750; + } + } + calc_sp = nominal_sp; + + /* Iterate tseg in possible range to find best bit timing values */ + + for (tseg_double = btc->tseg_max * 2 + 1; + tseg_double >= btc->tseg_min * 2; tseg_double--) + { + tseg_sync = tseg_double / 2 + BT_COMPUTE_SYNC_SEG; + + /* Recalculate bitrate prescaler */ + + calc_brp = priv->can.clock.freq / (tseg_sync * bt->bitrate) + + tseg_double % 2; + + if (calc_brp < btc->brp_min || calc_brp > btc->brp_max) + { + continue; + } + + /* Recalculate bitrate and bitrate error */ + + calc_br = priv->can.clock.freq / (calc_brp * tseg_sync); + + br_err = bt->bitrate - calc_br; + if (br_err > best_br_err) + { + continue; + } + else + { + best_sp_err = UINT_MAX; + } + + /* Now, it seems that we have a better bitrate, recalculate sample + * point, tseg1, tseg2 and sample point error + */ + + tseg2 = clamp(tseg_sync - nominal_sp * tseg_sync / 1000, 1, + btc->tseg_max * 249 / 1000); + tseg1 = tseg_double / 2 - tseg2; + calc_sp = 1000 * (tseg_sync - tseg2) / tseg_sync; + + sp_err = nominal_sp - calc_sp; + if (calc_sp > nominal_sp || sp_err > best_sp_err) + { + continue; + } + + /* Update best values and end condition check */ + + best_brp = calc_brp; + best_br_err = br_err; + best_sp_err = sp_err; + + if (best_br_err == 0 && best_sp_err == 0) + { + break; + } + } + + /* Check bitrate error against limit */ + + if ((uint32_t)best_br_err * 1000 > BT_COMPUTE_MAX_ERROR * bt->bitrate) + { + canerr("Bitrate error %d.%d%% is too high\n", br_err / 10, + br_err % 10); + return -EDOM; + } + + /* Retrieve the best calculated sample point */ + + bt->sample_point = calc_sp; + + /* Retrieve bit timing register components */ + + bt->brp = best_brp; + bt->prop_seg = tseg1 / 2; + bt->phase_seg1 = tseg1 - bt->prop_seg; + bt->phase_seg2 = tseg2; + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_bit_timing + * + * Description: + * Set CAN controller arbitration or data bitrate bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bt - Pointer to Bit timing structure + * arbi - True - Arbitration bit timing, False - Data bit timing + * + * Returned Value: + * Zero (OK) on success, -EPERM if CAN controller is not disabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_bit_timing(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + bool arbi) +{ + int max_ph1_len = 31; + uint32_t btr = 0; + + if (MPFS_CAN_FD_ENABLED(priv)) + { + canerr("CAN controller should be disabled to set bit timing\n"); + return -EPERM; + } + + if (arbi) + { + max_ph1_len = 63; + } + + if (bt->phase_seg1 > max_ph1_len) + { + bt->prop_seg += bt->phase_seg1 - max_ph1_len; + bt->phase_seg1 = max_ph1_len; + } + + if (arbi) + { + btr = bt->prop_seg << MPFS_CANFD_BTR_PROP_SHIFT; + btr |= bt->phase_seg1 << MPFS_CANFD_BTR_PH1_SHIFT; + btr |= bt->phase_seg2 << MPFS_CANFD_BTR_PH2_SHIFT; + btr |= bt->brp << MPFS_CANFD_BTR_BRP_SHIFT; + btr |= bt->sjw << MPFS_CANFD_BTR_SJW_SHIFT; + caninfo("Arbitration bitrate: %u, Prop_seg: %u, phase_seg1: %u, " + "phase_seg2: %u, brp: %u, sjw: %u \n", bt->bitrate, + bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->brp, + bt->sjw); + putreg32(btr, priv->base + MPFS_CANFD_BTR_OFFSET); + } + else + { + btr = bt->prop_seg << MPFS_CANFD_BTR_FD_PROP_FD_SHIFT; + btr |= bt->phase_seg1 << MPFS_CANFD_BTR_FD_PH1_FD_SHIFT; + btr |= bt->phase_seg2 << MPFS_CANFD_BTR_FD_PH2_FD_SHIFT; + btr |= bt->brp << MPFS_CANFD_BTR_FD_BRP_FD_SHIFT; + btr |= bt->sjw << MPFS_CANFD_BTR_FD_SJW_FD_SHIFT; + caninfo("Data bitrate: %u, Prop_seg: %u, phase_seg1: %u, " + "phase_seg2: %u, brp: %u, sjw: %u \n", bt->bitrate, + bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->brp, + bt->sjw); + putreg32(btr, priv->base + MPFS_CANFD_BTR_FD_OFFSET); + } + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_arbi_bit_timing + * + * Description: + * Set CAN controller arbitration bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -%EPERM if controller is enabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_arbi_bit_timing(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *arbi_bt = &priv->can.bittiming; + + /* Set bit timing for arbitration bit rate */ + + return mpfs_can_config_bit_timing(priv, arbi_bt, true); +} + +/**************************************************************************** + * Name: mpfs_can_config_data_bit_timing + * + * Description: + * Set CAN controller data bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -%EPERM if controller is enabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_data_bit_timing(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *data_bt = &priv->can.data_bittiming; + + /* Set bit timing for data bit rate */ + + return mpfs_can_config_bit_timing(priv, data_bt, false); +} + +/**************************************************************************** + * Name: mpfs_can_config_ssp + * + * Description: + * Set CAN controller secondary sample point. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -EPERM if CAN controller is not disabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_ssp(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *dbt = &(priv->can.data_bittiming); + int ssp_offset = 0; + uint32_t ssp_cfg = 0; + + if (MPFS_CAN_FD_ENABLED(priv)) + { + canerr("CAN controller should be disabled to set secondary sample " + "point\n"); + return -EPERM; + } + + /* secondary sample point is only used for bitrates > 1 Mbits/s */ + + if (dbt->bitrate > 1000000) + { + ssp_offset = (priv->can.clock.freq / 1000) * + dbt->sample_point / dbt->bitrate; + + if (ssp_offset > 127) + { + canwarn("Secondary sample point offset exceeds 127\n"); + ssp_offset = 127; + } + + ssp_cfg = ssp_offset << MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT; + ssp_cfg |= 0x1 << MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT; + } + + putreg32(ssp_cfg, priv->base + MPFS_CANFD_TRV_DELAY_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_controller_mode + * + * Description: + * Configure CAN controller mode + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * mode - Pointer to controller modes to be set + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void + mpfs_can_config_controller_mode(struct mpfs_driver_s *priv, + const struct mpfs_can_ctrlmode_s *mode) +{ + uint32_t mode_reg = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + + mode_reg = (mode->flags & CAN_CTRLMODE_LOOPBACK) ? + (mode_reg | MPFS_CANFD_MODE_ILBP) : + (mode_reg & ~MPFS_CANFD_MODE_ILBP); + + mode_reg = (mode->flags & CAN_CTRLMODE_LISTENONLY) ? + (mode_reg | MPFS_CANFD_MODE_BMM) : + (mode_reg & ~MPFS_CANFD_MODE_BMM); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD) ? + (mode_reg | MPFS_CANFD_MODE_FDE) : + (mode_reg & ~MPFS_CANFD_MODE_FDE); + + mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ? + (mode_reg | MPFS_CANFD_MODE_ACF) : + (mode_reg & ~MPFS_CANFD_MODE_ACF); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ? + (mode_reg | MPFS_CANFD_MODE_NISOFD) : + (mode_reg & ~MPFS_CANFD_MODE_NISOFD); + + mode_reg &= ~MPFS_CANFD_MODE_RTRTH; + mode_reg = (mode->flags & CAN_CTRLMODE_ONE_SHOT) ? + (mode_reg | MPFS_CANFD_MODE_RTRLE) : + (mode_reg & ~MPFS_CANFD_MODE_RTRLE); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + mode_reg |= MPFS_CANFD_MODE_AFM; +#endif + + /* Disable test mode */ + + mode_reg &= ~MPFS_CANFD_MODE_TSTM; + + putreg32(mode_reg, priv->base + MPFS_CANFD_MODE_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_add_hw_filter + * + * Description: + * Add new hw filter to CAN Controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * filter_type - Filter A, B, C or Range + * can_id_type - std CAN ID / ext CAN ID + * can_type - classical CAN / CANFD + * filter_id1 - filter id 1 (can be filter value for bit filter or range + * low for range filter) + * filter_id2 - filter id 2 (can be filter mask for bit filter or range + * high for range filter) + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, + uint8_t filter_type, + uint8_t can_id_type, + uint8_t can_type, + uint32_t fid1, + uint32_t fid2) +{ + uint32_t fc_reg; + + fc_reg = getreg32(priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Clean up filter control reg */ + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFB; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANB; + + /* Transform fid1, fid2 */ + + uint32_t fid1_trans = (can_id_type == CAN_EXT_ID) ? + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT & + (fid1 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT)) : + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + (fid1 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT)); + + uint32_t fid2_trans = (can_id_type == CAN_EXT_ID) ? + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT & + (fid2 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT)) : + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + (fid2 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT)); + + switch (filter_type) + { + case HW_FILTER_A: + + /* Set filter control reg for filter A */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FANE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FANB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FAFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FAFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_A_MASK_OFFSET); + break; + + case HW_FILTER_B: + + /* Set filter control reg for filter B */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_B_MASK_OFFSET); + break; + + case HW_FILTER_C: + + /* Set filter control reg for filter C */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_C_MASK_OFFSET); + break; + + case HW_FILTER_RANGE: + + /* Set filter control reg for filter range */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set range filter low / high */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); + break; + + default: + + /* Unsupported filter type */ + + break; + } +} +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/**************************************************************************** + * Name: mpfs_can_reset_hw_filter + * + * Description: + * Reset all hw filters (both bit and range filter) to default settings + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_reset_hw_filter(struct mpfs_driver_s *priv) +{ + uint32_t reg; + + /* Reset filter control */ + + reg = 0; + reg |= MPFS_CANFD_FILTER_CONTROL_FANB; + reg |= MPFS_CANFD_FILTER_CONTROL_FANE; + reg |= MPFS_CANFD_FILTER_CONTROL_FAFB; + reg |= MPFS_CANFD_FILTER_CONTROL_FAFE; + putreg32(reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Reset bit filter A */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_A_MASK_OFFSET); + + /* Reset bit filter B */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_B_MASK_OFFSET); + + /* Reset bit filter C */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_C_MASK_OFFSET); + + /* Reset range filter */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); + + priv->used_bit_filter_number = 0; + priv->used_range_filter = false; +} +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/**************************************************************************** + * Name: mpfs_can_controller_start + * + * Description: + * This routine starts the driver. Routine expects that controller is in + * reset state. It setups initial Tx buffers for FIFO priorities, sets + * bittiming, enables interrupts, switches core to operational mode and + * changes controller state to %CAN_STATE_STOPPED. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success and failure value on error + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_controller_start(struct mpfs_driver_s *priv) +{ + uint32_t int_ena; + uint32_t int_msk; + uint32_t mode_reg; + int err; + struct mpfs_can_ctrlmode_s mode; + + /* Initialize TXT buffer sent / processed counter values */ + + priv->txb_sent = 0; + priv->txb_processed = 0; + + /* Configure TXT buffers priority */ + + priv->txb_prio = 0x01234567; + putreg32(priv->base, priv->base + MPFS_CANFD_TX_PRIORITY_OFFSET); + + /* Configure bit-rates and ssp */ + + err = mpfs_can_config_arbi_bit_timing(priv); + if (err < 0) + { + return err; + } + + err = mpfs_can_config_data_bit_timing(priv); + if (err < 0) + { + return err; + } + + err = mpfs_can_config_ssp(priv); + if (err < 0) + { + return err; + } + + /* Configure modes */ + + mode.flags = priv->can.ctrlmode; + mode.mask = 0xffffffff; + mpfs_can_config_controller_mode(priv, &mode); + + /* Configure interrupts */ + + int_ena = MPFS_CANFD_INT_STAT_RBNEI | + MPFS_CANFD_INT_STAT_TXBHCI | + MPFS_CANFD_INT_STAT_EWLI | + MPFS_CANFD_INT_STAT_FCSI | + MPFS_CANFD_INT_STAT_DOI; + + /* Bus error reporting -> Allow Error/Arb.lost interrupts */ + + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + { + int_ena |= MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI; + } + + int_msk = ~int_ena; /* Mask all disabled interrupts */ + + /* It's after reset, so there is no need to clear anything */ + + uint32_t mask = 0xffffffff; + putreg32(mask, priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); + putreg32(int_msk, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + putreg32(int_ena, priv->base + MPFS_CANFD_INT_ENA_SET_OFFSET); + + /* Put CAN driver to STOPPED state first, CAN controller will enters + * ERROR_ACTIVE on initial FCSI + */ + + priv->can.state = CAN_STATE_STOPPED; + + /* Enable the CAN controller */ + + mode_reg = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + mode_reg |= MPFS_CANFD_MODE_ENA; + putreg32(mode_reg, priv->base + MPFS_CANFD_MODE_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_controller_stop + * + * Description: + * This routine stops the driver. This is the drivers stop routine. It will + * disable the interrupts and disable the CAN controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_controller_stop(struct mpfs_driver_s *priv) +{ + uint32_t mask = 0xffffffff; + uint32_t mode; + + /* Disable interrupts */ + + putreg32(mask, priv->base + MPFS_CANFD_INT_ENA_CLR_OFFSET); + putreg32(mask, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + + /* Disable the CAN controller */ + + mode = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + mode &= ~MPFS_CANFD_MODE_ENA; + putreg32(mode, priv->base + MPFS_CANFD_MODE_OFFSET); + + /* Set CAN driver state to STOPPED */ + + priv->can.state = CAN_STATE_STOPPED; +} + +/**************************************************************************** + * Name: mpfs_reset + * + * Description: + * Put the EMAC in the non-operational, reset state + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * OK for success and -ETIMEDOUT for failure + * + * Assumptions: + * + ****************************************************************************/ + +static int mpfs_reset(struct mpfs_driver_s *priv) +{ + uint32_t i = 100; + uint32_t device_id; + + /* Reset FPGA and FIC3, enable clock for FIC3 before RD WR */ + + modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, + SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3, + 0); + modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, SYSREG_SUBBLK_CLOCK_CR_FIC3); + + /* Reset CAN controller */ + + putreg32(MPFS_CANFD_MODE_RST, priv->base + MPFS_CANFD_MODE_OFFSET); + + /* Check if the device is up again */ + + do + { + device_id = (getreg32(priv->base + MPFS_CANFD_DEVICE_ID_OFFSET) & + MPFS_CANFD_DEVICE_ID_DEVICE_ID) >> + MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT; + + if (device_id == MPFS_CANFD_ID) + { + return OK; + } + + if (!i--) + { + canwarn("Device did not leave reset\n"); + return -ETIMEDOUT; + } + + nxsig_usleep(200); + } + while (1); + + priv->can.can_stats.restarts++; +} + +/**************************************************************************** + * Name: mpfs_ifup + * + * Description: + * NuttX Callback: Start the CAN interface + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + * Assumptions: + * + ****************************************************************************/ + +static int mpfs_ifup(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + if (mpfs_can_controller_start(priv) < 0) + { + canerr("CAN controller start failed\n"); + return -1; + } + + priv->bifup = true; + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + /* Set interrupts */ + + up_enable_irq(priv->config->canfd_fpga_irq); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_ifdown + * + * Description: + * NuttX Callback: Stop the CAN interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_ifdown(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + mpfs_can_controller_stop(priv); + + priv->bifup = false; + return OK; +} + +/**************************************************************************** + * Name: mpfs_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) +{ +#if defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) || \ +defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; +#endif + int ret; + + switch (cmd) + { +#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL + case SIOCGCANBITRATE: + + /* Get bitrate from the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->can.bittiming.bitrate / 1000; /* kbit/s */ + req->arbi_samplep = priv->can.bittiming.sample_point / 10; + req->data_bitrate = priv->can.data_bittiming.bitrate / 1000; /* kbit/s */ + req->data_samplep = priv->can.data_bittiming.sample_point / 10; + ret = OK; + } + break; + + case SIOCSCANBITRATE: + + /* Set bitrate of the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + + if (req->arbi_bitrate > 1000) + { + canerr("Arbitration bitrate > 1Mbps is not supported."); + ret = -EINVAL; + break; + } + priv->can.bittiming.bitrate = req->arbi_bitrate * 1000; /* bit/s */ + + if (req->arbi_samplep > 100 || req->arbi_samplep <= 0) + { + canerr("Invalid arbitration sample point. " + "Range should be (0,100]%%."); + ret = -EINVAL; + break; + } + priv->can.bittiming.sample_point = + req->arbi_samplep * 10; /* In one-tenth of a percent */ + + if (req->data_bitrate > 4000 || + req->data_bitrate < req->arbi_bitrate) + { + canerr("Data bitrate higher than 4Mbps is yet to be supported. " + "Data br cannot be smaller than arbitration br."); + ret = -EINVAL; + break; + } + priv->can.data_bittiming.bitrate = req->data_bitrate * 1000; /* bit/s */ + + if (req->data_samplep > 100 || req->data_samplep <= 0) + { + canerr("Invalid data sample point. Range should be (0,100]%%."); + ret = -EINVAL; + break; + } + priv->can.data_bittiming.sample_point = + req->data_samplep * 10; /* In one-tenth of a percent */ + + /* Calculate arbitration and data bit timing */ + + mpfs_can_btr_compute(priv, + &priv->can.bittiming, + priv->can.bittiming_const); + mpfs_can_btr_compute(priv, + &priv->can.data_bittiming, + priv->can.data_bittiming_const); + + /* CAN controller reset to write bit timing register */ + + mpfs_can_controller_stop(priv); + if (mpfs_can_controller_start(priv) < 0) + { + canerr("CAN controller start failed."); + ret = -1; + break; + } + + ret = OK; + } + break; +#endif /* CONFIG_NETDEV_CAN_BITRATE_IOCTL */ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + case SIOCACANSTDFILTER: + + { + uint8_t filter; + struct can_ioctl_filter_s *req = + (struct can_ioctl_filter_s *)((uintptr_t)arg); + + if (req->ftype == CAN_FILTER_MASK) + { + if (priv->used_bit_filter_number == 0) + { + /* Use bit filter A */ + + filter = HW_FILTER_A; + } + else if (priv->used_bit_filter_number == 1) + { + /* Use bit filter B */ + + filter = HW_FILTER_B; + } + else if (priv->used_bit_filter_number == 2) + { + /* Use bit filter C */ + + filter = HW_FILTER_C; + } + else + { + /* All bit filters used. Return with error */ + + canerr("All bit filters used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + priv->used_bit_filter_number++; + } + else if (req->ftype == CAN_FILTER_RANGE) + { + /* Use range filter */ + + filter = HW_FILTER_RANGE; + priv->used_range_filter = true; + } + else + { + /* Dual address and other filter types not yet support */ + + canerr("Dual address and other filter types not yet support"); + ret = -1; + break; + } + + /* Add hw filter */ + + mpfs_can_add_hw_filter(priv, + filter, + CAN_STD_ID, + req->fprio, /* LOW for CAN, HIGH for FDCAN */ + req->fid1, + req->fid2); + + ret = OK; + } + break; + + case SIOCACANEXTFILTER: + + /* Add CAN EXTENDED ID HW FILTER */ + + { + uint8_t filter; + struct can_ioctl_filter_s *req = + (struct can_ioctl_filter_s *)((uintptr_t)arg); + + if (req->ftype == CAN_FILTER_MASK) + { + if (priv->used_bit_filter_number == 0) + { + /* Use bit filter A */ + + filter = HW_FILTER_A; + } + else if (priv->used_bit_filter_number == 1) + { + /* Use bit filter B */ + + filter = HW_FILTER_B; + } + else if (priv->used_bit_filter_number == 2) + { + /* Use bit filter C */ + + filter = HW_FILTER_C; + } + else + { + /* All bit filters used. Return with error */ + + canerr("All bit filters used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + priv->used_bit_filter_number++; + } + else if (req->ftype == CAN_FILTER_RANGE) + { + /* Use range filter */ + + if (priv->used_range_filter) + { + /* The range filter is already used. Return with error */ + + canerr("Range filter used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + filter = HW_FILTER_RANGE; + priv->used_range_filter = true; + } + else + { + /* Dual address and other filter types not yet support */ + + canerr("Dual address and other filter types not yet support"); + ret = -1; + break; + } + + /* Add hw filter */ + + mpfs_can_add_hw_filter(priv, + filter, + CAN_EXT_ID, + req->fprio, /* CAN Type: LOW for CAN, HIGH for FDCAN */ + req->fid1, + req->fid2); + + ret = OK; + } + break; + + case SIOCDCANSTDFILTER: + case SIOCDCANEXTFILTER: + + /* Reset all HW FILTERs */ + + { + mpfs_can_reset_hw_filter(priv); + ret = OK; + } + break; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_fpga_canfd_init + * + * Description: + * Initialize the CAN controller and driver + * + * Returned Value: + * On success, a pointer to the MPFS CANFD driver is + * returned. NULL is returned on any failure. + * + * Assumptions: + * None + * + ****************************************************************************/ + +int mpfs_fpga_canfd_init(void) +{ +#ifdef CONFIG_MPFS_CANFD0 + caninfo("Initialize CANFD0 driver...\n"); + struct mpfs_driver_s *priv0; + priv0 = &g_canfd0; + memset(priv0, 0, sizeof(struct mpfs_driver_s)); + + priv0->base = CONFIG_MPFS_CANFD_BASE0; + priv0->config = &mpfs_fpga_canfd_config0; + + /* Initialize the CAN common private data structure */ + + priv0->can.state = CAN_STATE_ERROR_ACTIVE; + priv0->ntxbufs = 2; + priv0->can.bittiming_const = &mpfs_can_bit_timing_range; + priv0->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + + priv0->can.can_stats.arbitration_lost = 0; + priv0->can.can_stats.bus_error = 0; + priv0->can.can_stats.bus_off = 0; + priv0->can.can_stats.error_warning = 0; + priv0->can.can_stats.error_passive = 0; + priv0->can.can_stats.restarts = 0; + + /* Get the can_clk info */ + + priv0->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; + + /* Needed for timing adjustment to be performed as soon as possible */ + + priv0->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE0; + priv0->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE0; + priv0->can.bittiming.sjw = 5; + priv0->can.data_bittiming.sjw = 5; + + /* Calculate nominal and data bit timing */ + + mpfs_can_btr_compute(priv0, + &priv0->can.bittiming, + priv0->can.bittiming_const); + mpfs_can_btr_compute(priv0, + &priv0->can.data_bittiming, + priv0->can.data_bittiming_const); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* Init hw filter runtime var */ + + priv0->used_bit_filter_number = 0; + priv0->used_range_filter = false; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* Set CAN control modes */ + + priv0->can.ctrlmode = CAN_CTRLMODE_FD + | CAN_CTRLMODE_BERR_REPORTING; + + /* Attach the interrupt handler */ + + if (irq_attach(priv0->config->canfd_fpga_irq, mpfs_interrupt, priv0)) + { + /* We could not attach the ISR to the interrupt */ + + canerr("ERROR: Failed to attach to CAN0 IRQ\n"); + return -EAGAIN; + } + + /* Initialize TX/RX descriptor structure */ + + priv0->txdesc = (struct canfd_frame *)&g_tx_pool0; + priv0->rxdesc = (struct canfd_frame *)&g_rx_pool0; + + /* Initialize the driver network device structure */ + + priv0->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ + priv0->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ + priv0->dev.d_txavail = mpfs_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv0->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ +#endif + priv0->dev.d_private = priv0; /* Used to recover private state from dev */ + + /* Reset controller */ + + if (mpfs_reset(priv0) < 0) + { + return -1; + } + + caninfo("CANFD0 driver init done\n"); + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling mpfs_ifdown(). + */ + + mpfs_ifdown(&priv0->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv0->dev, NET_LL_CAN); +#endif /* CONFIG_MPFS_CANFD0 */ + +#ifdef CONFIG_MPFS_CANFD1 + caninfo("Initialize CANFD1 driver...\n"); + struct mpfs_driver_s *priv1; + priv1 = &g_canfd1; + memset(priv1, 0, sizeof(struct mpfs_driver_s)); + + priv1->base = CONFIG_MPFS_CANFD_BASE1; + priv1->config = &mpfs_fpga_canfd_config1; + + /* Initialize the CAN common private data structure */ + + priv1->can.state = CAN_STATE_ERROR_ACTIVE; + priv1->ntxbufs = 2; + priv1->can.bittiming_const = &mpfs_can_bit_timing_range; + priv1->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + + priv1->can.can_stats.arbitration_lost = 0; + priv1->can.can_stats.bus_error = 0; + priv1->can.can_stats.bus_off = 0; + priv1->can.can_stats.error_warning = 0; + priv1->can.can_stats.error_passive = 0; + priv1->can.can_stats.restarts = 0; + + /* Get the can_clk info */ + + priv1->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; + + /* Needed for timing adjustment to be performed as soon as possible */ + + priv1->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE1; + priv1->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE1; + priv1->can.bittiming.sjw = 5; + priv1->can.data_bittiming.sjw = 5; + + /* Calculate nominal and data bit timing */ + + mpfs_can_btr_compute(priv1, + &priv1->can.bittiming, + priv1->can.bittiming_const); + mpfs_can_btr_compute(priv1, + &priv1->can.data_bittiming, + priv1->can.data_bittiming_const); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* Init hw filter runtime var */ + + priv1->used_bit_filter_number = 0; + priv1->used_range_filter = false; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* Set CAN control modes */ + + priv1->can.ctrlmode = CAN_CTRLMODE_FD + | CAN_CTRLMODE_BERR_REPORTING; + + /* Attach the interrupt handler */ + + if (irq_attach(priv1->config->canfd_fpga_irq, mpfs_interrupt, priv1)) + { + /* We could not attach the ISR to the interrupt */ + + canerr("ERROR: Failed to attach to CAN1 IRQ\n"); + return -EAGAIN; + } + + /* Initialize TX/RX descriptor structure */ + + priv1->txdesc = (struct canfd_frame *)&g_tx_pool1; + priv1->rxdesc = (struct canfd_frame *)&g_rx_pool1; + + /* Initialize the driver network device structure */ + + priv1->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ + priv1->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ + priv1->dev.d_txavail = mpfs_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv1->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ +#endif + priv1->dev.d_private = priv1; /* Used to recover private state from dev */ + + /* Reset controller */ + + if (mpfs_reset(priv1) < 0) + { + return -1; + } + + caninfo("CANFD1 driver init done\n"); + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling mpfs_ifdown(). + */ + + mpfs_ifdown(&priv1->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv1->dev, NET_LL_CAN); +#endif /* CONFIG_MPFS_CANFD1 */ + + return OK; +} diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h new file mode 100644 index 0000000000000..d7dc98098bba0 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_fpga_canfd.h + * + * 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_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Check if CAN-FD support is enabled. */ + +#ifdef CONFIG_MPFS_HAVE_CANFD + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/mpfs_fpga_canfd.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_fpga_canfd_init + * + * Description: + * Initialize a CANFD block. + * + * Returned Value: + * OK on success, Negated errno on failure + * + ****************************************************************************/ + +int mpfs_fpga_canfd_init(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_MPFS_HAVE_CANFD */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_head.S b/arch/risc-v/src/mpfs/mpfs_head.S index af25f49b98ed5..465cf1f0f60a5 100644 --- a/arch/risc-v/src/mpfs/mpfs_head.S +++ b/arch/risc-v/src/mpfs/mpfs_head.S @@ -166,6 +166,16 @@ __start: .continue_boot: + /* L2 needs to be zeroed before ECC (error correction) is enabled later. */ + + la a4, __l2lim_start + la a5, __l2lim_end + +.clear_l2lim: + sd x0, 0(a4) + add a4, a4, 8 + blt a4, a5, .clear_l2lim + /* Clear PMP */ csrw pmpcfg0, zero diff --git a/arch/risc-v/src/mpfs/mpfs_ihc.c b/arch/risc-v/src/mpfs/mpfs_ihc.c index 02bd8a2182692..037cb2de5cc80 100644 --- a/arch/risc-v/src/mpfs/mpfs_ihc.c +++ b/arch/risc-v/src/mpfs/mpfs_ihc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -86,24 +87,24 @@ #define VRINGS 0x02 /* Number of vrings */ #define VRING_ALIGN 0x1000 /* Vring alignment */ #define VRING_NR 256 /* Number of descriptors */ -#define VRING_SIZE 512 /* Size of one descriptor */ +#define VRING_SIZE 612 /* Size of one descriptor */ +#define VDEV_NOTIFYID 4 /* virtio device notify id */ #ifndef CONFIG_MPFS_IHC_RPMSG_CH2 /* This is the RPMSG default channel used with only one RPMSG channel */ -#define VRING_SHMEM 0xa2410000 /* Vring shared memory start */ -#define VRING0_DESCRIPTORS 0xa2400000 /* Vring0 descriptor area */ -#define VRING1_DESCRIPTORS 0xa2408000 /* Vring1 descriptor area */ -#define VRING0_NOTIFYID 0 /* Vring0 id */ -#define VRING1_NOTIFYID 1 /* Vring1 id */ +#define VRING_SHMEM CONFIG_MPFS_CH1_VRING_SHMEM_ADDR /* Vring shared memory start */ +#define VRING0_DESCRIPTORS CONFIG_MPFS_CH1_VRING0_DESC_ADDR /* Vring0 descriptor area */ +#define VRING1_DESCRIPTORS CONFIG_MPFS_CH1_VRING1_DESC_ADDR /* Vring1 descriptor area */ +#define VRING0_NOTIFYID 0 /* Vring0 id */ +#define VRING1_NOTIFYID 1 /* Vring1 id */ #else /* This is the RPMSG channel 2, enabled separately */ - -#define VRING_SHMEM 0xa2460000 /* Vring shared memory start */ -#define VRING0_DESCRIPTORS 0xa2450000 /* Vring0 descriptor area */ -#define VRING1_DESCRIPTORS 0xa2458000 /* Vring1 descriptor area */ -#define VRING0_NOTIFYID 2 /* Vring0 id */ -#define VRING1_NOTIFYID 3 /* Vring1 id */ +#define VRING_SHMEM CONFIG_MPFS_CH2_VRING_SHMEM_ADDR /* Vring shared memory start */ +#define VRING0_DESCRIPTORS CONFIG_MPFS_CH2_VRING0_DESC_ADDR /* Vring0 descriptor area */ +#define VRING1_DESCRIPTORS CONFIG_MPFS_CH2_VRING1_DESC_ADDR /* Vring1 descriptor area */ +#define VRING0_NOTIFYID 2 /* Vring0 id */ +#define VRING1_NOTIFYID 3 /* Vring1 id */ #endif /**************************************************************************** @@ -138,6 +139,12 @@ struct mpfs_queue_table_s void *data; }; +struct mpfs_ihc_work_arg_s +{ + uint32_t mhartid; + uint32_t rhartid; +}; + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -155,6 +162,7 @@ static int mpfs_rptun_notify(struct rptun_dev_s *dev, uint32_t notifyid); static int mpfs_rptun_register_callback(struct rptun_dev_s *dev, rptun_callback_t callback, void *arg); +static void mpfs_rptun_worker(void *arg); /**************************************************************************** * Private Data @@ -169,7 +177,9 @@ static int mpfs_rptun_register_callback(struct rptun_dev_s *dev, * HSS. */ +#ifdef CONFIG_MPFS_IHC_WITH_HSS uint8_t unused_filler[0x80000] __attribute__((section(".filler_area"))); +#endif static struct rpmsg_endpoint g_mpgs_echo_ping_ept; static struct mpfs_queue_table_s g_mpfs_virtqueue_table[VRINGS]; @@ -177,8 +187,11 @@ static struct mpfs_rptun_shmem_s g_shmem; static struct rpmsg_device *g_mpfs_rpmsg_device; static struct rpmsg_virtio_device *g_mpfs_virtio_device; -static sem_t g_mpfs_ack_sig = SEM_INITIALIZER(0); +#ifdef MPFS_RPTUN_USE_THREAD static sem_t g_mpfs_rx_sig = SEM_INITIALIZER(0); +#else +static struct work_s g_rptun_work; +#endif static struct list_node g_dev_list = LIST_INITIAL_VALUE(g_dev_list); static uint32_t g_connected_hart_ints; @@ -187,6 +200,11 @@ static uint16_t g_vq_idx; static int g_plic_irq; static bool g_rptun_initialized; +#ifdef IHC_AVOID_ACK_AND_MP +static struct mpfs_ihc_work_arg_s g_work_arg; +static struct work_s g_ihc_work; +#endif + const uint32_t ihcia_remote_harts[MPFS_NUM_HARTS] = { IHCIA_H0_REMOTE_HARTS, @@ -235,6 +253,7 @@ static const struct rptun_ops_s g_mpfs_rptun_ops = * mhartid base on the context, not necessarily the actual * mhartid. * is_ack - Boolean that is set true if an ack has been found + * is_msg - Boolean that is set true if a message is present * * Returned Value: * Remote hart id @@ -242,7 +261,8 @@ static const struct rptun_ops_s g_mpfs_rptun_ops = ****************************************************************************/ static uint32_t mpfs_ihc_parse_incoming_hartid(uint32_t mhartid, - bool *is_ack) + bool *is_ack, + bool *is_msg) { uint32_t hart_id = 0; uint32_t return_hart_id = UNDEFINED_HART_ID; @@ -260,6 +280,13 @@ static uint32_t mpfs_ihc_parse_incoming_hartid(uint32_t mhartid, { return_hart_id = hart_id; *is_ack = true; + + test_int = (1 << (hart_id * 2)); + + if ((g_connected_hart_ints & test_int) == test_int) + { + *is_msg = true; + } break; } } @@ -271,7 +298,7 @@ static uint32_t mpfs_ihc_parse_incoming_hartid(uint32_t mhartid, if (((g_connected_hart_ints & test_int) == test_int)) { return_hart_id = hart_id; - *is_ack = false; + *is_msg = true; break; } } @@ -413,38 +440,67 @@ static uint32_t mpfs_ihc_context_to_local_hart_id(ihc_channel_t channel) * Name: mpfs_ihc_rx_handler * * Description: - * This handles the received information and either lets the vq to proceed - * via posting g_mpfs_ack_sig, or lets the mpfs_rptun_thread() run as it - * waits for the g_mpfs_rx_sig. virtqueue_notification() cannot be called - * from the interrupt context, thus the thread that will perform it. + * This handles the received information and lets the vq to proceed. + * virtqueue_notification() cannot be called from the interrupt context, + * thus the thread or work queue that will perform it. * * Input Parameters: * message - Pointer to the incoming message - * is_ack - Boolean indicating whether an ack is received * * Returned Value: * None * ****************************************************************************/ -static void mpfs_ihc_rx_handler(uint32_t *message, bool is_ack) +static void mpfs_ihc_rx_handler(uint32_t *message) { - if (is_ack) - { - /* Received the ack */ + g_vq_idx = message[0]; - nxsem_post(&g_mpfs_ack_sig); - } - else - { - g_vq_idx = (message[0] >> 16); + DEBUGASSERT((g_vq_idx == VRING0_NOTIFYID) || + (g_vq_idx == VRING1_NOTIFYID)); + +#ifdef MPFS_RPTUN_USE_THREAD + nxsem_post(&g_mpfs_rx_sig); +#else + work_queue(HPWORK, &g_rptun_work, mpfs_rptun_worker, NULL, 0); +#endif +} + +/**************************************************************************** + * Name: mpfs_ihc_worker + * + * Description: + * This function is used to wait for the remote message present condition, + * after which the ACK is sent. ACK wasn't sent before, as the remote end + * has no way of knowing which one came first: the ACK or RMP. + * + * Input Parameters: + * arg - Pointer to the arguments struct + * + * Returned Value: + * None + * + ****************************************************************************/ - DEBUGASSERT((g_vq_idx == VRING0_NOTIFYID) || - (g_vq_idx == VRING1_NOTIFYID)); +#ifdef IHC_AVOID_ACK_AND_MP +static void mpfs_ihc_worker(void *arg) +{ + uint32_t ctrl_reg; + uint32_t retries = 5000; - nxsem_post(&g_mpfs_rx_sig); + do + { + ctrl_reg = getreg32(MPFS_IHC_CTRL(g_work_arg.mhartid, + g_work_arg.rhartid)); } + while ((ctrl_reg & (RMP_MESSAGE_PRESENT)) && --retries); + + DEBUGASSERT(retries != 0); + + modifyreg32(MPFS_IHC_CTRL(g_work_arg.mhartid, + g_work_arg.rhartid), 0, ACK_INT); } +#endif /**************************************************************************** * Name: mpfs_ihc_rx_message @@ -457,7 +513,6 @@ static void mpfs_ihc_rx_handler(uint32_t *message, bool is_ack) * channel - Enum that describes the channel used. * mhartid - Context hart id, not necessarily the absolute mhartid but * rather, the primary hartid of the set of harts. - * is_ack - Boolean indicating an ack message * msg - For storing data, could be NULL * * Returned Value: @@ -466,58 +521,54 @@ static void mpfs_ihc_rx_handler(uint32_t *message, bool is_ack) ****************************************************************************/ static void mpfs_ihc_rx_message(ihc_channel_t channel, uint32_t mhartid, - bool is_ack, uint32_t *msg) + uint32_t *msg) { uint32_t rhartid = mpfs_ihc_context_to_remote_hart_id(channel); uint32_t ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)); - if (is_ack) - { - if (mhartid == CONTEXTB_HARTID) - { - uintptr_t msg_in = MPFS_IHC_MSG_IN(mhartid, rhartid); - DEBUGASSERT(msg == NULL); - mpfs_ihc_rx_handler((uint32_t *)msg_in, is_ack); - } - else - { - /* This path is meant for the OpenSBI vendor extension only */ + /* Check if we have a message */ - DEBUGPANIC(); - } + if (mhartid == CONTEXTB_HARTID) + { + uintptr_t msg_in = MPFS_IHC_MSG_IN(mhartid, rhartid); + DEBUGASSERT(msg == NULL); + mpfs_ihc_rx_handler((uint32_t *)msg_in); } - else if (MP_MESSAGE_PRESENT == (ctrl_reg & MP_MASK)) + else { - /* Check if we have a message */ + /* This path is meant for the OpenSBI vendor extension only */ - if (mhartid == CONTEXTB_HARTID) - { - uintptr_t msg_in = MPFS_IHC_MSG_IN(mhartid, rhartid); - DEBUGASSERT(msg == NULL); - mpfs_ihc_rx_handler((uint32_t *)msg_in, is_ack); - } - else - { - /* This path is meant for the OpenSBI vendor extension only */ + DEBUGPANIC(); + } - DEBUGPANIC(); - } + /* Set MP to 0. Note this generates an interrupt on the other hart + * if it has RMPIE bit set in the control register + */ - /* Set MP to 0. Note this generates an interrupt on the other hart - * if it has RMPIE bit set in the control register + ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)); + if (ctrl_reg & RMP_MESSAGE_PRESENT) + { + /* If we send the ACK here, Linux will have the ACK and the + * MP flags sets. IHC_AVOID_ACK_AND_MP assures only one + * is present at once. */ - volatile uint32_t temp = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)) & - ~MP_MASK; - - /* Check if ACKIE_EN is set */ - - if (temp & ACKIE_EN) - { - temp |= ACK_INT; - } +#ifdef IHC_AVOID_ACK_AND_MP + g_work_arg.mhartid = mhartid; + g_work_arg.rhartid = rhartid; + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), MP_MASK, 0); + work_queue(HPWORK, &g_ihc_work, mpfs_ihc_worker, NULL, 0); +#else + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), MP_MASK, 0); + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, ACK_INT); +#endif + } + else + { + /* We can send the ACK now and clear the MP */ - putreg32(temp, MPFS_IHC_CTRL(mhartid, rhartid)); + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), MP_MASK, 0); + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, ACK_INT); } } @@ -539,11 +590,13 @@ static void mpfs_ihc_rx_message(ihc_channel_t channel, uint32_t mhartid, static void mpfs_ihc_message_present_isr(void) { uint64_t mhartid = riscv_mhartid(); - bool is_ack; + bool is_ack = false; + bool is_msg = false; /* Check all our channels */ - uint32_t origin_hart = mpfs_ihc_parse_incoming_hartid(mhartid, &is_ack); + uint32_t origin_hart = mpfs_ihc_parse_incoming_hartid(mhartid, &is_ack, + &is_msg); if (origin_hart != UNDEFINED_HART_ID) { @@ -562,7 +615,10 @@ static void mpfs_ihc_message_present_isr(void) /* Process incoming packet */ - mpfs_ihc_rx_message(origin_hart, mhartid, is_ack, NULL); + if (is_msg) + { + mpfs_ihc_rx_message(origin_hart, mhartid, NULL); + } if (is_ack) { @@ -660,6 +716,10 @@ static void mpfs_ihc_local_remote_config(uint32_t hart_to_configure, putreg32(ihcia_remote_hart_ints[hart_to_configure], MPFS_IHC_INT_EN(hart_to_configure)); + /* This register INT_EN(0) is used for flow control only */ + + putreg32(0, MPFS_IHC_INT_EN(0)); + modifyreg32(MPFS_IHC_CTRL(hart_to_configure, rhartid), 0, MPIE_EN | ACKIE_EN); } @@ -696,7 +756,7 @@ static int mpfs_ihc_tx_message(ihc_channel_t channel, uint32_t *message) { ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)); } - while ((ctrl_reg & (RMP_MESSAGE_PRESENT | ACK_INT)) && --retries); + while ((ctrl_reg & (RMP_MESSAGE_PRESENT)) && --retries); /* Return if RMP bit 1 indicating busy */ @@ -704,10 +764,6 @@ static int mpfs_ihc_tx_message(ihc_channel_t channel, uint32_t *message) { return -EBUSY; } - else if (ACK_INT == (ctrl_reg & ACK_INT_MASK)) - { - return -EBUSY; - } else { /* Fill the buffer */ @@ -717,18 +773,18 @@ static int mpfs_ihc_tx_message(ihc_channel_t channel, uint32_t *message) putreg32(message[i], MPFS_IHC_MSG_OUT(mhartid, rhartid) + i * 4); } - /* Set the MP bit. This will notify other of incoming hart message */ - - modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, RMP_MESSAGE_PRESENT); + ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)); - /* Wait for the ACK to arrive to maintain the logic */ + /* If we're unlucky, we cannot send MP yet.. come back later */ - if (mhartid == CONTEXTB_HARTID) + if (ctrl_reg & (MP_MESSAGE_PRESENT)) { - /* Only applicable for the CONTEXTB_HART */ - - nxsem_wait_uninterruptible(&g_mpfs_ack_sig); + return -EBUSY; } + + /* Set the MP bit. This will notify other of incoming hart message */ + + modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, RMP_MESSAGE_PRESENT); } return OK; @@ -842,13 +898,12 @@ mpfs_rptun_get_resource(struct rptun_dev_s *dev) rpmsg_vdev); rsc->rpmsg_vdev.type = RSC_VDEV; rsc->rpmsg_vdev.id = VIRTIO_ID_RPMSG; + rsc->rpmsg_vdev.notifyid = VDEV_NOTIFYID; rsc->rpmsg_vdev.dfeatures = 1 << VIRTIO_RPMSG_F_NS | - 1 << VIRTIO_RPMSG_F_ACK | - VIRTIO_RING_F_EVENT_IDX; + 1 << VIRTIO_RPMSG_F_ACK; rsc->rpmsg_vdev.gfeatures = 1 << VIRTIO_RPMSG_F_NS | - 1 << VIRTIO_RPMSG_F_ACK | - VIRTIO_RING_F_EVENT_IDX; + 1 << VIRTIO_RPMSG_F_ACK; /* Set to VIRTIO_CONFIG_STATUS_DRIVER_OK when master is up */ @@ -977,18 +1032,28 @@ static int mpfs_rptun_stop(struct rptun_dev_s *dev) static int mpfs_rptun_notify(struct rptun_dev_s *dev, uint32_t notifyid) { uint32_t tx_msg[IHC_MAX_MESSAGE_SIZE]; + uint32_t retries = 5; + int ret = OK; /* We only care about the queue with notifyid VRING0 */ if (notifyid == VRING0_NOTIFYID) { - tx_msg[0] = (notifyid << 16); + tx_msg[0] = notifyid; tx_msg[1] = 0; - return mpfs_ihc_tx_message(CONTEXTA_HARTID, tx_msg); + /* This failure should happen very rarely */ + + do + { + ret = mpfs_ihc_tx_message(CONTEXTA_HARTID, tx_msg); + } + while ((ret != OK) && --retries); + + DEBUGASSERT(ret == OK); } - return OK; + return ret; } /**************************************************************************** @@ -1141,7 +1206,6 @@ static void mpfs_rpmsg_device_created(struct rpmsg_device *rdev, void *priv_) struct rpmsg_virtio_device *vdev = container_of(rdev, struct rpmsg_virtio_device, rdev); - g_mpfs_virtio_device = vdev; g_mpfs_rpmsg_device = rdev; @@ -1151,6 +1215,33 @@ static void mpfs_rpmsg_device_created(struct rpmsg_device *rdev, void *priv_) mpfs_echo_ping_init(rdev, &g_mpgs_echo_ping_ept); } +/**************************************************************************** + * Name: mpfs_rptun_worker + * + * Description: + * This is used to notify the associated virtqueue via the scheduled work. + * This doesn't use a separate thread, but a HPWORK instead, which is a + * way to avoid deadlocks with net_lock() that also originate from HPWORK. + * + * Input Parameters: + * arg - Argument + + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef MPFS_RPTUN_USE_THREAD +static void mpfs_rptun_worker(void *arg) +{ + struct mpfs_queue_table_s *info; + + DEBUGASSERT((g_vq_idx - VRING0_NOTIFYID) < VRINGS); + info = &g_mpfs_virtqueue_table[g_vq_idx - VRING0_NOTIFYID]; + virtqueue_notification((struct virtqueue *)info->data); +} +#endif + /**************************************************************************** * Name: mpfs_rptun_thread * @@ -1168,6 +1259,7 @@ static void mpfs_rpmsg_device_created(struct rpmsg_device *rdev, void *priv_) * ****************************************************************************/ +#ifdef MPFS_RPTUN_USE_THREAD static int mpfs_rptun_thread(int argc, char *argv[]) { struct mpfs_queue_table_s *info; @@ -1183,6 +1275,7 @@ static int mpfs_rptun_thread(int argc, char *argv[]) return 0; } +#endif /**************************************************************************** * Public Functions @@ -1208,8 +1301,10 @@ static int mpfs_rptun_thread(int argc, char *argv[]) int mpfs_ihc_init(void) { uint32_t mhartid = (uint32_t)riscv_mhartid(); +#ifdef MPFS_RPTUN_USE_THREAD char *argv[3]; char arg1[19]; +#endif uint32_t rhartid; int ret; @@ -1255,6 +1350,12 @@ int mpfs_ihc_init(void) ihcinfo("Waiting for the master online...\n"); ret = mpfs_rptun_init(MPFS_RPTUN_SHMEM_NAME, MPFS_RPTUN_CPU_NAME); + if (ret < 0) + { + ihcerr("ERROR: Not able to init RPTUN\n"); + goto init_error; + } + ihcinfo("..master is online\n"); /* Register callback to notify when rpmsg device is ready */ @@ -1267,6 +1368,8 @@ int mpfs_ihc_init(void) goto init_error; } +#ifdef MPFS_RPTUN_USE_THREAD + /* Thread initialization */ snprintf(arg1, sizeof(arg1), "%p", @@ -1284,6 +1387,9 @@ int mpfs_ihc_init(void) NULL, NULL, NULL); goto init_error; } +#else + +#endif return OK; diff --git a/arch/risc-v/src/mpfs/mpfs_ihc_sbi.c b/arch/risc-v/src/mpfs/mpfs_ihc_sbi.c index bf90abc20f98a..aa77f022fd2b3 100644 --- a/arch/risc-v/src/mpfs/mpfs_ihc_sbi.c +++ b/arch/risc-v/src/mpfs/mpfs_ihc_sbi.c @@ -67,6 +67,34 @@ static uint32_t g_connected_harts_c; * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: mpfs_modifyreg32 + * + * Description: + * This is a copy of modifyreg32() without spinlock. That function is a + * real danger here as it is likely located in eNVM, thus being a real + * bottleneck. + * + * Input Parameters: + * addr - Address to perform the operation + * clearbits - Bits to clear + * setbits - Bits to set + * + * Returned Value: + * Remote hart id + * + ****************************************************************************/ + +void mpfs_modifyreg32(uintptr_t addr, uint32_t clearbits, uint32_t setbits) +{ + uint32_t regval; + + regval = getreg32(addr); + regval &= ~clearbits; + regval |= setbits; + putreg32(regval, addr); +} + /**************************************************************************** * Name: mpfs_ihc_sbi_parse_incoming_hartid * @@ -79,6 +107,7 @@ static uint32_t g_connected_harts_c; * mhartid base on the context, not necessarily the actual * mhartid. * is_ack - Boolean that is set true if an ack has been found + * is_mp - Boolean that is set true if a msg is present also * * Returned Value: * Remote hart id @@ -86,7 +115,8 @@ static uint32_t g_connected_harts_c; ****************************************************************************/ static uint32_t mpfs_ihc_sbi_parse_incoming_hartid(uint32_t mhartid, - bool *is_ack) + bool *is_ack, + bool *is_mp) { uint32_t hart_id = 0; uint32_t return_hart_id = UNDEFINED_HART_ID; @@ -112,6 +142,16 @@ static uint32_t mpfs_ihc_sbi_parse_incoming_hartid(uint32_t mhartid, { return_hart_id = hart_id; *is_ack = true; + + /* We might also have a msg present */ + + test_int = (1 << (hart_id * 2)); + + if (msg_avail & test_int) + { + *is_mp = true; + } + break; } } @@ -124,6 +164,7 @@ static uint32_t mpfs_ihc_sbi_parse_incoming_hartid(uint32_t mhartid, { return_hart_id = hart_id; *is_ack = false; + *is_mp = true; break; } } @@ -231,7 +272,6 @@ static uint32_t mpfs_ihc_sbi_context_to_local_hart_id(ihc_channel_t channel) } DEBUGASSERT(hart < MPFS_NUM_HARTS); - return hart; } @@ -259,7 +299,8 @@ static uint32_t mpfs_ihc_sbi_context_to_local_hart_id(ihc_channel_t channel) static void mpfs_ihc_sbi_message_present_handler(uint32_t *message, uint32_t mhartid, uint32_t rhartid, - bool is_ack) + bool is_ack, + bool is_mp) { struct ihc_sbi_rx_msg_s *msg; uintptr_t message_ihc = (uintptr_t)MPFS_IHC_MSG_IN(mhartid, rhartid); @@ -267,17 +308,22 @@ static void mpfs_ihc_sbi_message_present_handler(uint32_t *message, msg = (struct ihc_sbi_rx_msg_s *)message; - if (is_ack) + if (is_ack && !is_mp) { msg->irq_type = ACK_IRQ; /* msg->ihc_msg content doesn't matter here */ } - else + else if (is_mp && !is_ack) { msg->irq_type = MP_IRQ; msg->ihc_msg = *(struct mpfs_ihc_msg_s *)message_ihc; } + else + { + msg->irq_type = ACK_IRQ | MP_IRQ; + msg->ihc_msg = *(struct mpfs_ihc_msg_s *)message_ihc; + } DEBUGASSERT(sizeof(msg->ihc_msg) >= message_size_ihc); } @@ -302,11 +348,9 @@ static void mpfs_ihc_sbi_message_present_handler(uint32_t *message, ****************************************************************************/ static void mpfs_ihc_sbi_rx_message(uint32_t rhartid, uint32_t mhartid, - bool is_ack, uint32_t *msg) + bool is_ack, bool is_mp, uint32_t *msg) { - uint32_t ctrl_reg = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)); - - if (is_ack) + if (is_ack && !is_mp) { if (mhartid == CONTEXTB_HARTID) { @@ -318,10 +362,14 @@ static void mpfs_ihc_sbi_rx_message(uint32_t rhartid, uint32_t mhartid, DEBUGASSERT(msg != NULL); mpfs_ihc_sbi_message_present_handler(msg, mhartid, rhartid, - is_ack); + is_ack, is_mp); + + /* Clear the ack */ + + mpfs_modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), ACK_CLR, 0); } } - else if (MP_MESSAGE_PRESENT == (ctrl_reg & MP_MASK)) + else if (is_mp && !is_ack) { /* Check if we have a message */ @@ -335,24 +383,25 @@ static void mpfs_ihc_sbi_rx_message(uint32_t rhartid, uint32_t mhartid, DEBUGASSERT(msg != NULL); mpfs_ihc_sbi_message_present_handler(msg, mhartid, rhartid, - is_ack); + is_ack, is_mp); } /* Set MP to 0. Note this generates an interrupt on the other hart * if it has RMPIE bit set in the control register */ - volatile uint32_t temp = getreg32(MPFS_IHC_CTRL(mhartid, rhartid)) & - ~MP_MASK; - - /* Check if ACKIE_EN is set */ + mpfs_modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), MP_MASK, ACK_INT); + } + else if (is_ack && is_mp) + { + DEBUGASSERT(msg != NULL); + mpfs_ihc_sbi_message_present_handler(msg, mhartid, rhartid, + is_ack, is_mp); - if (temp & ACKIE_EN) - { - temp |= ACK_INT; - } + /* Clear the ack and mp */ - putreg32(temp, MPFS_IHC_CTRL(mhartid, rhartid)); + mpfs_modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), ACK_CLR | MP_MASK, + ACK_INT); } } @@ -377,22 +426,16 @@ void mpfs_ihc_sbi_message_present_indirect_isr(ihc_channel_t channel, uint32_t *msg) { bool is_ack; + bool is_mp = false; uint32_t mhartid = mpfs_ihc_sbi_context_to_local_hart_id(channel); uint32_t origin_hart = mpfs_ihc_sbi_parse_incoming_hartid(mhartid, - &is_ack); - + &is_ack, + &is_mp); if (origin_hart != UNDEFINED_HART_ID) { /* Process incoming packet */ - mpfs_ihc_sbi_rx_message(origin_hart, mhartid, is_ack, msg); - - if (is_ack) - { - /* Clear the ack */ - - modifyreg32(MPFS_IHC_CTRL(mhartid, origin_hart), ACK_CLR, 0); - } + mpfs_ihc_sbi_rx_message(origin_hart, mhartid, is_ack, is_mp, msg); } } @@ -470,16 +513,16 @@ static void mpfs_ihc_sbi_local_remote_config(uint32_t hart_to_configure, } #endif - modifyreg32(MPFS_IHC_CTRL(hart_to_configure, rhartid), 0, MPIE_EN | - ACKIE_EN); + mpfs_modifyreg32(MPFS_IHC_CTRL(hart_to_configure, rhartid), 0, MPIE_EN | + ACKIE_EN); /* OpenSBI extension may configure 2x consecutive harts */ #ifdef CONFIG_MPFS_IHC_TWO_RPMSG_CHANNELS if ((hart_to_configure + 1) < MPFS_NUM_HARTS) { - modifyreg32(MPFS_IHC_CTRL(hart_to_configure + 1, rhartid + 1), 0, - MPIE_EN | ACKIE_EN); + mpfs_modifyreg32(MPFS_IHC_CTRL(hart_to_configure + 1, rhartid + 1), 0, + MPIE_EN | ACKIE_EN); } #endif } @@ -539,7 +582,8 @@ static int mpfs_ihc_sbi_tx_message(ihc_channel_t channel, uint32_t *message) /* Set the MP bit. This will notify other of incoming hart message */ - modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, RMP_MESSAGE_PRESENT); + mpfs_modifyreg32(MPFS_IHC_CTRL(mhartid, rhartid), 0, + RMP_MESSAGE_PRESENT); } return OK; @@ -624,6 +668,10 @@ int mpfs_ihc_sbi_ecall_handler(unsigned long funcid, uint32_t remote_channel, break; case SBI_EXT_IHC_SEND: + /* Send and wait for the ACK: disable all incoming traffic + * meanwhile with the SW flow control. + */ + result = mpfs_ihc_sbi_tx_message(remote_channel, message_ptr); break; diff --git a/arch/risc-v/src/mpfs/mpfs_lowputc.c b/arch/risc-v/src/mpfs/mpfs_lowputc.c index 93dede2fd4ad0..8daa7d6b82f3c 100644 --- a/arch/risc-v/src/mpfs/mpfs_lowputc.c +++ b/arch/risc-v/src/mpfs/mpfs_lowputc.c @@ -40,6 +40,8 @@ ****************************************************************************/ /* Select UART parameters for the selected console */ + +#ifndef CONFIG_MPFS_FPGA_UART #if defined(CONFIG_UART0_SERIAL_CONSOLE) # define MPFS_CONSOLE_BASE MPFS_UART0_BASE # define MPFS_CONSOLE_BAUD CONFIG_UART0_BAUD @@ -89,6 +91,93 @@ # error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" # endif +#else /* CONFIG_MPFS_FPGA_UART */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART0_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART0_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART0_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART0_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART0_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART1_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART1_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART1_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART1_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART1_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART2_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART2_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART2_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART2_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART2_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +# elif defined(CONFIG_UART3_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART3_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART3_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART3_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART3_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART3_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART4_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART4_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART4_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART4_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART4_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART5_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART5_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART5_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART5_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART5_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART6_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART6_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART6_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART6_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART6_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART6_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART7_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART7_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART7_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART7_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART7_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(HAVE_UART) +# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" +#endif +#endif /* CONFIG_MPFS_FPGA_UART */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -111,7 +200,16 @@ static void config_baud_divisors(void) uint32_t fractional_baud_value; uint64_t pclk_freq; - pclk_freq = MPFS_MSS_APB_AHB_CLK; + if (MPFS_CONSOLE_CLOCKBIT == SYSREG_SUBBLK_CLOCK_CR_FIC3) + { + /* This is an FPGA UART */ + + pclk_freq = MPFS_FPGA_PERIPHERAL_CLK; + } + else + { + pclk_freq = MPFS_MSS_APB_AHB_CLK; + } /* Compute baud value based on requested baud rate and PCLK frequency. * The baud value is computed using the following equation: @@ -189,20 +287,23 @@ void mpfs_lowsetup(void) #if defined(HAVE_SERIAL_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) uint32_t lcr = 0; - /* reset on */ + /* reset on - only for non-FPGA uarts */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - 0, MPFS_CONSOLE_RESETBIT); + if (SYSREG_SUBBLK_CLOCK_CR_FIC3 != MPFS_CONSOLE_CLOCKBIT) + { + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, 0, + MPFS_CONSOLE_RESETBIT); + } /* reset off */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - 0, MPFS_CONSOLE_CLOCKBIT); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + MPFS_CONSOLE_RESETBIT, 0); /* clock on */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - MPFS_CONSOLE_RESETBIT, 0); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + 0, MPFS_CONSOLE_CLOCKBIT); switch (MPFS_CONSOLE_BITS) { diff --git a/arch/risc-v/src/mpfs/mpfs_mm_init.c b/arch/risc-v/src/mpfs/mpfs_mm_init.c index 90f69b33fe440..6c5bdd394dacc 100644 --- a/arch/risc-v/src/mpfs/mpfs_mm_init.c +++ b/arch/risc-v/src/mpfs/mpfs_mm_init.c @@ -54,9 +54,9 @@ #define PGT_L2_VBASE PGT_L2_PBASE #define PGT_L3_VBASE PGT_L3_PBASE -#define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ -#define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ -#define PGT_L3_SIZE (1024) /* Enough to map 4 MiB */ +#define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ +#define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ +#define PGT_L3_SIZE (40 * 1024) /* Enough to map 40 MiB */ /* Calculate the minimum size for the L3 table */ @@ -251,4 +251,9 @@ void mpfs_kernel_mappings(void) mmu_ln_map_region(2, PGT_L2_VBASE, PGPOOL_START, PGPOOL_START, PGPOOL_SIZE, MMU_KDATA_FLAGS); + + /* Map the MTIME counter to the start of USR IO region */ + + map_region(MPFS_CLINT_MTIME & (~RV_MMU_PAGE_MASK), USRIO_START, + RV_MMU_PAGE_SIZE, PTE_R | PTE_U | PTE_G); } diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c index 769e9075a0d7b..7544ec493b503 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi.c +++ b/arch/risc-v/src/mpfs/mpfs_opensbi.c @@ -28,8 +28,31 @@ #include #ifdef CONFIG_MPFS_IHC_SBI #include +#include +#endif +#include "mpfs_entrypoints.h" + +/* Make sure that anything that intefraces with the SBI uses the same data + * types as the SBI code (e.g. same "bool") + */ + +#ifdef bool +#undef bool +#endif + +#ifdef true +#undef true +#endif + +#ifdef false +#undef false #endif +#ifdef NULL +#undef NULL +#endif + +#include #include #include #include @@ -41,10 +64,6 @@ #include #include -#ifdef CONFIG_MPFS_IHC_SBI -#include -#endif - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -185,30 +204,7 @@ static struct aclint_mswi_data mpfs_mswi = * Unused hart is marked with -1. Mpfs will always have the hart0 unused. */ -static const u32 mpfs_hart_index2id[MPFS_HART_COUNT] = -{ - [0] = -1, -#ifdef CONFIG_MPFS_HART1_SBI - [1] = 1, -#else - [1] = -1, -#endif -#ifdef CONFIG_MPFS_HART2_SBI - [2] = 2, -#else - [2] = -1, -#endif -#ifdef CONFIG_MPFS_HART3_SBI - [3] = 3, -#else - [3] = -1, -#endif -#ifdef CONFIG_MPFS_HART4_SBI - [4] = 4, -#else - [4] = -1, -#endif -}; +static u32 mpfs_hart_index2id[MPFS_HART_COUNT]; static const struct sbi_platform platform = { @@ -602,6 +598,13 @@ static int mpfs_opensbi_ecall_handler(long extid, long funcid, void __attribute__((noreturn)) mpfs_opensbi_setup(void) { uint32_t hartid = current_hartid(); + size_t i; + + for (i = 0; i < sizeof(mpfs_hart_index2id) / sizeof(mpfs_hart_index2id[0]); + i++) + { + mpfs_hart_index2id[i] = mpfs_get_use_sbi(i) ? i : -1; + } mpfs_opensbi_pmp_setup(); diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S b/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S new file mode 100644 index 0000000000000..87000330c4b9c --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S @@ -0,0 +1,226 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_opensbi_trap.S + * + * mpfs_exception_opensbi function is based on OpenSBI fw_base.S + * + * The 2-Clause BSD License + * SPDX short identifier: BSD-2-Clause + * + * Copyright (c) 2019 Western Digital Corporation or its affiliates and other + * contributors. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .global mpfs_exception_opensbi + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +mpfs_global_pointer: + .dword __global_pointer$ + +/**************************************************************************** + * Name: mpfs_exception_opensbi: + * + * Description: + * This is the trap entry into OpenSBI. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + + .align 3 + mpfs_exception_opensbi: + /* Swap TP and MSCRATCH */ + + csrrw tp, CSR_MSCRATCH, tp + + /* Save T0 in scratch space */ + + REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp) + + /* + * Set T0 to appropriate exception stack + * + * Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1; + * Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP)) + * + * Came_From_M_Mode = 0 ==> Exception_Stack = TP + * Came_From_M_Mode = -1 ==> Exception_Stack = SP + */ + + csrr t0, CSR_MSTATUS + srl t0, t0, MSTATUS_MPP_SHIFT + and t0, t0, PRV_M + slti t0, t0, PRV_M + add t0, t0, -1 + xor sp, sp, tp + and t0, t0, sp + xor sp, sp, tp + xor t0, tp, t0 + + /* Save original SP on exception stack */ + + REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0) + + /* Set SP to exception stack and make room for trap registers */ + + add sp, t0, -(SBI_TRAP_REGS_SIZE) + + /* Restore T0 from scratch space */ + + REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp) + + /* Save T0 on stack */ + + REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp) + + /* Swap TP and MSCRATCH */ + + csrrw tp, CSR_MSCRATCH, tp + + /* Save MEPC and MSTATUS CSRs */ + + csrr t0, CSR_MEPC + REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) + csrr t0, CSR_MSTATUS + REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) + REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp) + + /* Save all general regisers except SP and T0 */ + + REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) + REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp) + REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp) + REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp) + REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp) + REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp) + REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp) + REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp) + REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp) + REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp) + REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp) + REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp) + REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp) + REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp) + REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp) + REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp) + REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp) + REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp) + REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp) + REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp) + REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp) + REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp) + REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp) + REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp) + REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp) + REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp) + REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp) + REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp) + REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp) + REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp) + + /* Restore GP */ + + .option push + .option norelax + la gp, __global_pointer$ + .option pop + + /* Call C routine */ + + add a0, sp, zero + call sbi_trap_handler + + /* Restore all general regisers except A0 and T0 */ + + REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0) + REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0) + REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0) + REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0) + REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0) + REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0) + REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0) + REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0) + REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0) + REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0) + REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0) + REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0) + REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0) + REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0) + REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0) + REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0) + REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0) + REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0) + REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0) + REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0) + REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0) + REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0) + REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0) + REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0) + REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0) + REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0) + REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0) + REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0) + REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0) + + /* Restore MEPC and MSTATUS CSRs */ + + REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0) + csrw CSR_MEPC, t0 + REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0) + csrw CSR_MSTATUS, t0 + + /* Restore T0 */ + + REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0) + + /* Restore A0 */ + + REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0) + + mret diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S index b933bdb5d4495..6f623ed560def 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S +++ b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S @@ -1,34 +1,22 @@ /**************************************************************************** * arch/risc-v/src/mpfs/mpfs_opensbi_utils.S * - * mpfs_exception_opensbi function is based on OpenSBI fw_base.S + * 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 * - * The 2-Clause BSD License - * SPDX short identifier: BSD-2-Clause + * http://www.apache.org/licenses/LICENSE-2.0 * - * Copyright (c) 2019 Western Digital Corporation or its affiliates and other - * contributors. + * 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. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + ****************************************************************************/ /**************************************************************************** * Included Files @@ -51,7 +39,22 @@ ****************************************************************************/ .global mpfs_opensbi_prepare_hart - .global mpfs_exception_opensbi + .global mpfs_opensbi_relocate_from_envm + + /* Add some weak default values to make this compile without */ + + .weak _sbi_zerodev_loadaddr + .weak _ssbi_zerodev + .weak _esbi_zerodev + + /* These are the weak pointless variables, only to get this PR compile */ + +_sbi_zerodev_loadaddr: + .dword 0x0a006000 +_ssbi_zerodev: + .dword _stext +_esbi_zerodev: + .dword _stext /**************************************************************************** * Private Data @@ -81,21 +84,43 @@ mpfs_global_pointer: * ****************************************************************************/ + .align 3 +mpfs_opensbi_relocate_from_envm: + + /* Relocate the code from eNVM into L2 zero device */ + + la a0, _sbi_zerodev_loadaddr + la a1, _ssbi_zerodev + la a2, _esbi_zerodev +.check_if_opensbi_copy_done: + bge a1, a2, .opensbi_copy_done + ld a3, 0(a0) + sd a3, 0(a1) + addi a0, a0, 8 + addi a1, a1, 8 + j .check_if_opensbi_copy_done +.opensbi_copy_done: + + /* To make a store to instruction memory visible to all RISC-V harts, the + * writing hart has to execute a data FENCE before requesting that all + * remote RISC-V harts execute a FENCE.I. This is hart0 only. + */ + + fence + ret + .align 3 mpfs_opensbi_prepare_hart: + /* These are harts other than 0. Thus, fence.i */ + + fence.i + /* Setup OpenSBI exception handler */ la t0, mpfs_exception_opensbi csrw mtvec, t0 - /* la gp, __global_pointer$ will not work. We want to have the gp as seen - * in the .map file exactly. We need to restore gp in the trap handler. - */ - - la t0, mpfs_global_pointer - ld gp, 0(t0) - /* Setup stacks per hart, the stack top is the end of the hart's scratch */ csrr a0, mhartid @@ -103,169 +128,4 @@ mpfs_opensbi_prepare_hart: mul t0, a0, t1 la sp, g_scratches add sp, sp, t0 - jal mpfs_opensbi_setup - -/**************************************************************************** - * Name: mpfs_exception_opensbi: - * - * Description: - * This is the trap entry into OpenSBI. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - - .align 3 -mpfs_exception_opensbi: - - /* Swap TP and MSCRATCH */ - - csrrw tp, CSR_MSCRATCH, tp - - /* Save T0 in scratch space */ - - REG_S t0, SBI_SCRATCH_TMP0_OFFSET(tp) - - /* - * Set T0 to appropriate exception stack - * - * Came_From_M_Mode = ((MSTATUS.MPP < PRV_M) ? 1 : 0) - 1; - * Exception_Stack = TP ^ (Came_From_M_Mode & (SP ^ TP)) - * - * Came_From_M_Mode = 0 ==> Exception_Stack = TP - * Came_From_M_Mode = -1 ==> Exception_Stack = SP - */ - - csrr t0, CSR_MSTATUS - srl t0, t0, MSTATUS_MPP_SHIFT - and t0, t0, PRV_M - slti t0, t0, PRV_M - add t0, t0, -1 - xor sp, sp, tp - and t0, t0, sp - xor sp, sp, tp - xor t0, tp, t0 - - /* Save original SP on exception stack */ - - REG_S sp, (SBI_TRAP_REGS_OFFSET(sp) - SBI_TRAP_REGS_SIZE)(t0) - - /* Set SP to exception stack and make room for trap registers */ - - add sp, t0, -(SBI_TRAP_REGS_SIZE) - - /* Restore T0 from scratch space */ - - REG_L t0, SBI_SCRATCH_TMP0_OFFSET(tp) - - /* Save T0 on stack */ - - REG_S t0, SBI_TRAP_REGS_OFFSET(t0)(sp) - - /* Swap TP and MSCRATCH */ - - csrrw tp, CSR_MSCRATCH, tp - - /* Save MEPC and MSTATUS CSRs */ - - csrr t0, CSR_MEPC - REG_S t0, SBI_TRAP_REGS_OFFSET(mepc)(sp) - csrr t0, CSR_MSTATUS - REG_S t0, SBI_TRAP_REGS_OFFSET(mstatus)(sp) - REG_S zero, SBI_TRAP_REGS_OFFSET(mstatusH)(sp) - - /* Save all general regisers except SP and T0 */ - - REG_S zero, SBI_TRAP_REGS_OFFSET(zero)(sp) - REG_S ra, SBI_TRAP_REGS_OFFSET(ra)(sp) - REG_S gp, SBI_TRAP_REGS_OFFSET(gp)(sp) - REG_S tp, SBI_TRAP_REGS_OFFSET(tp)(sp) - REG_S t1, SBI_TRAP_REGS_OFFSET(t1)(sp) - REG_S t2, SBI_TRAP_REGS_OFFSET(t2)(sp) - REG_S s0, SBI_TRAP_REGS_OFFSET(s0)(sp) - REG_S s1, SBI_TRAP_REGS_OFFSET(s1)(sp) - REG_S a0, SBI_TRAP_REGS_OFFSET(a0)(sp) - REG_S a1, SBI_TRAP_REGS_OFFSET(a1)(sp) - REG_S a2, SBI_TRAP_REGS_OFFSET(a2)(sp) - REG_S a3, SBI_TRAP_REGS_OFFSET(a3)(sp) - REG_S a4, SBI_TRAP_REGS_OFFSET(a4)(sp) - REG_S a5, SBI_TRAP_REGS_OFFSET(a5)(sp) - REG_S a6, SBI_TRAP_REGS_OFFSET(a6)(sp) - REG_S a7, SBI_TRAP_REGS_OFFSET(a7)(sp) - REG_S s2, SBI_TRAP_REGS_OFFSET(s2)(sp) - REG_S s3, SBI_TRAP_REGS_OFFSET(s3)(sp) - REG_S s4, SBI_TRAP_REGS_OFFSET(s4)(sp) - REG_S s5, SBI_TRAP_REGS_OFFSET(s5)(sp) - REG_S s6, SBI_TRAP_REGS_OFFSET(s6)(sp) - REG_S s7, SBI_TRAP_REGS_OFFSET(s7)(sp) - REG_S s8, SBI_TRAP_REGS_OFFSET(s8)(sp) - REG_S s9, SBI_TRAP_REGS_OFFSET(s9)(sp) - REG_S s10, SBI_TRAP_REGS_OFFSET(s10)(sp) - REG_S s11, SBI_TRAP_REGS_OFFSET(s11)(sp) - REG_S t3, SBI_TRAP_REGS_OFFSET(t3)(sp) - REG_S t4, SBI_TRAP_REGS_OFFSET(t4)(sp) - REG_S t5, SBI_TRAP_REGS_OFFSET(t5)(sp) - REG_S t6, SBI_TRAP_REGS_OFFSET(t6)(sp) - - /* Restore GP */ - - la a0, mpfs_global_pointer - ld gp, 0(a0) - - /* Call C routine */ - - add a0, sp, zero - call sbi_trap_handler - - /* Restore all general regisers except A0 and T0 */ - - REG_L ra, SBI_TRAP_REGS_OFFSET(ra)(a0) - REG_L sp, SBI_TRAP_REGS_OFFSET(sp)(a0) - REG_L gp, SBI_TRAP_REGS_OFFSET(gp)(a0) - REG_L tp, SBI_TRAP_REGS_OFFSET(tp)(a0) - REG_L t1, SBI_TRAP_REGS_OFFSET(t1)(a0) - REG_L t2, SBI_TRAP_REGS_OFFSET(t2)(a0) - REG_L s0, SBI_TRAP_REGS_OFFSET(s0)(a0) - REG_L s1, SBI_TRAP_REGS_OFFSET(s1)(a0) - REG_L a1, SBI_TRAP_REGS_OFFSET(a1)(a0) - REG_L a2, SBI_TRAP_REGS_OFFSET(a2)(a0) - REG_L a3, SBI_TRAP_REGS_OFFSET(a3)(a0) - REG_L a4, SBI_TRAP_REGS_OFFSET(a4)(a0) - REG_L a5, SBI_TRAP_REGS_OFFSET(a5)(a0) - REG_L a6, SBI_TRAP_REGS_OFFSET(a6)(a0) - REG_L a7, SBI_TRAP_REGS_OFFSET(a7)(a0) - REG_L s2, SBI_TRAP_REGS_OFFSET(s2)(a0) - REG_L s3, SBI_TRAP_REGS_OFFSET(s3)(a0) - REG_L s4, SBI_TRAP_REGS_OFFSET(s4)(a0) - REG_L s5, SBI_TRAP_REGS_OFFSET(s5)(a0) - REG_L s6, SBI_TRAP_REGS_OFFSET(s6)(a0) - REG_L s7, SBI_TRAP_REGS_OFFSET(s7)(a0) - REG_L s8, SBI_TRAP_REGS_OFFSET(s8)(a0) - REG_L s9, SBI_TRAP_REGS_OFFSET(s9)(a0) - REG_L s10, SBI_TRAP_REGS_OFFSET(s10)(a0) - REG_L s11, SBI_TRAP_REGS_OFFSET(s11)(a0) - REG_L t3, SBI_TRAP_REGS_OFFSET(t3)(a0) - REG_L t4, SBI_TRAP_REGS_OFFSET(t4)(a0) - REG_L t5, SBI_TRAP_REGS_OFFSET(t5)(a0) - REG_L t6, SBI_TRAP_REGS_OFFSET(t6)(a0) - - /* Restore MEPC and MSTATUS CSRs */ - - REG_L t0, SBI_TRAP_REGS_OFFSET(mepc)(a0) - csrw CSR_MEPC, t0 - REG_L t0, SBI_TRAP_REGS_OFFSET(mstatus)(a0) - csrw CSR_MSTATUS, t0 - - /* Restore T0 */ - - REG_L t0, SBI_TRAP_REGS_OFFSET(t0)(a0) - - /* Restore A0 */ - - REG_L a0, SBI_TRAP_REGS_OFFSET(a0)(a0) - - mret + tail mpfs_opensbi_setup diff --git a/arch/risc-v/src/mpfs/mpfs_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c index ec9ab908cf712..8fb857274a557 100644 --- a/arch/risc-v/src/mpfs/mpfs_serial.c +++ b/arch/risc-v/src/mpfs/mpfs_serial.c @@ -80,6 +80,15 @@ # elif defined(CONFIG_UART4_SERIAL_CONSOLE) # define CONSOLE_DEV g_uart4port /* UART4 is console */ # define SERIAL_CONSOLE 5 +# elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart5port /* UART5 is console */ +# define SERIAL_CONSOLE 6 +# elif defined(CONFIG_UART6_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart6port /* UART6 is console */ +# define SERIAL_CONSOLE 7 +# elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart7port /* UART7 is console */ +# define SERIAL_CONSOLE 8 # else # error "I'm confused... Do we have a serial console or not?" # endif @@ -90,6 +99,9 @@ # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # if defined(CONFIG_MPFS_UART0) # define SERIAL_CONSOLE 1 # elif defined(CONFIG_MPFS_UART1) @@ -100,6 +112,12 @@ # define SERIAL_CONSOLE 4 # elif defined(CONFIG_MPFS_UART4) # define SERIAL_CONSOLE 5 +# elif defined(CONFIG_MPFS_UART5) +# define SERIAL_CONSOLE 6 +# elif defined(CONFIG_MPFS_UART6) +# define SERIAL_CONSOLE 7 +# elif defined(CONFIG_MPFS_UART7) +# define SERIAL_CONSOLE 8 # else # undef TTYS0_DEV # undef TTYS1_DEV @@ -127,6 +145,7 @@ struct up_dev_s uint8_t parity; /* 0=none, 1=odd, 2=even */ uint8_t bits; /* Number of bits (7 or 8) */ bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + bool fpga; /* true: this is an FPGA based driver */ }; /**************************************************************************** @@ -197,6 +216,22 @@ static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; #endif +#ifdef CONFIG_MPFS_UART5 +static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; +static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; +#endif + +#ifdef CONFIG_MPFS_UART6 +static char g_uart6rxbuffer[CONFIG_UART6_RXBUFSIZE]; +static char g_uart6txbuffer[CONFIG_UART6_TXBUFSIZE]; +#endif + +#ifdef CONFIG_MPFS_UART7 +static char g_uart7rxbuffer[CONFIG_UART7_RXBUFSIZE]; +static char g_uart7txbuffer[CONFIG_UART7_TXBUFSIZE]; +#endif + +#ifndef CONFIG_MPFS_FPGA_UART #ifdef CONFIG_MPFS_UART0 static struct up_dev_s g_uart0priv = { @@ -206,6 +241,7 @@ static struct up_dev_s g_uart0priv = .parity = CONFIG_UART0_PARITY, .bits = CONFIG_UART0_BITS, .stopbits2 = CONFIG_UART0_2STOP, + .fpga = false, }; static uart_dev_t g_uart0port = @@ -237,6 +273,7 @@ static struct up_dev_s g_uart1priv = .parity = CONFIG_UART1_PARITY, .bits = CONFIG_UART1_BITS, .stopbits2 = CONFIG_UART1_2STOP, + .fpga = false, }; static uart_dev_t g_uart1port = @@ -268,6 +305,7 @@ static struct up_dev_s g_uart2priv = .parity = CONFIG_UART2_PARITY, .bits = CONFIG_UART2_BITS, .stopbits2 = CONFIG_UART2_2STOP, + .fpga = false, }; static uart_dev_t g_uart2port = @@ -299,6 +337,7 @@ static struct up_dev_s g_uart3priv = .parity = CONFIG_UART3_PARITY, .bits = CONFIG_UART3_BITS, .stopbits2 = CONFIG_UART3_2STOP, + .fpga = false, }; static uart_dev_t g_uart3port = @@ -330,6 +369,7 @@ static struct up_dev_s g_uart4priv = .parity = CONFIG_UART4_PARITY, .bits = CONFIG_UART4_BITS, .stopbits2 = CONFIG_UART4_2STOP, + .fpga = false, }; static uart_dev_t g_uart4port = @@ -352,6 +392,266 @@ static uart_dev_t g_uart4port = }; #endif +#else /* CONFIG_MPFS_FPGA_UART */ + +#ifdef CONFIG_MPFS_UART0 +static struct up_dev_s g_uart0priv = +{ + .uartbase = MPFS_FPGA_UART0_BASE, + .baud = CONFIG_UART0_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_12, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart0port = +{ +#if SERIAL_CONSOLE == 1 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART1 +static struct up_dev_s g_uart1priv = +{ + .uartbase = MPFS_FPGA_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_13, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart1port = +{ +#if SERIAL_CONSOLE == 2 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART2 +static struct up_dev_s g_uart2priv = +{ + .uartbase = MPFS_FPGA_UART2_BASE, + .baud = CONFIG_UART2_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_14, + .parity = CONFIG_UART2_PARITY, + .bits = CONFIG_UART2_BITS, + .stopbits2 = CONFIG_UART2_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart2port = +{ +#if SERIAL_CONSOLE == 3 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART3 +static struct up_dev_s g_uart3priv = +{ + .uartbase = MPFS_FPGA_UART3_BASE, + .baud = CONFIG_UART3_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_15, + .parity = CONFIG_UART3_PARITY, + .bits = CONFIG_UART3_BITS, + .stopbits2 = CONFIG_UART3_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart3port = +{ +#if SERIAL_CONSOLE == 4 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART3_RXBUFSIZE, + .buffer = g_uart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART3_TXBUFSIZE, + .buffer = g_uart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart3priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART4 +static struct up_dev_s g_uart4priv = +{ + .uartbase = MPFS_FPGA_UART4_BASE, + .baud = CONFIG_UART4_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_16, + .parity = CONFIG_UART4_PARITY, + .bits = CONFIG_UART4_BITS, + .stopbits2 = CONFIG_UART4_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart4port = +{ +#if SERIAL_CONSOLE == 5 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART4_RXBUFSIZE, + .buffer = g_uart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART4_TXBUFSIZE, + .buffer = g_uart4txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart4priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART5 +static struct up_dev_s g_uart5priv = +{ + .uartbase = MPFS_FPGA_UART5_BASE, + .baud = CONFIG_UART5_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_17, + .parity = CONFIG_UART5_PARITY, + .bits = CONFIG_UART5_BITS, + .stopbits2 = CONFIG_UART5_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart5port = +{ +#if SERIAL_CONSOLE == 6 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART5_RXBUFSIZE, + .buffer = g_uart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART5_TXBUFSIZE, + .buffer = g_uart5txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart5priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART6 +static struct up_dev_s g_uart6priv = +{ + .uartbase = MPFS_FPGA_UART6_BASE, + .baud = CONFIG_UART6_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_18, + .parity = CONFIG_UART6_PARITY, + .bits = CONFIG_UART6_BITS, + .stopbits2 = CONFIG_UART6_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart6port = +{ +#if SERIAL_CONSOLE == 7 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART6_RXBUFSIZE, + .buffer = g_uart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART6_TXBUFSIZE, + .buffer = g_uart6txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart6priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART7 +static struct up_dev_s g_uart7priv = +{ + .uartbase = MPFS_FPGA_UART7_BASE, + .baud = CONFIG_UART7_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_19, + .parity = CONFIG_UART7_PARITY, + .bits = CONFIG_UART7_BITS, + .stopbits2 = CONFIG_UART7_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart7port = +{ +#if SERIAL_CONSOLE == 7 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART7_RXBUFSIZE, + .buffer = g_uart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART7_TXBUFSIZE, + .buffer = g_uart7txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart7priv, +}; +#endif + +#endif /* CONFIG_MPFS_FPGA_UART */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -447,34 +747,55 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable) clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART4; reset_bit = SYSREG_SOFT_RESET_CR_MMUART4; break; + case MPFS_FPGA_UART0_BASE: + case MPFS_FPGA_UART1_BASE: + case MPFS_FPGA_UART2_BASE: + case MPFS_FPGA_UART3_BASE: + case MPFS_FPGA_UART4_BASE: + case MPFS_FPGA_UART5_BASE: + case MPFS_FPGA_UART6_BASE: + case MPFS_FPGA_UART7_BASE: + clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3; + reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA; + break; default: return; } - /* reset on */ + /* reset on for non-fpga */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - 0, reset_bit); + if (!priv->fpga) + { + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + 0, reset_bit); + } if (enable) { /* reset off */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - 0, reset_bit); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + reset_bit, 0); /* clock on */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - clock_bit, 0); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + 0, clock_bit); } else { - /* clock off */ + /* clock off for non-fpga */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - clock_bit, 0); + if (!priv->fpga) + { + /* Turning off FPGA clk would disable it for all other FPGA + * peripherals as well. Don't touch it without refcnt mechanism. + */ + + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + clock_bit, 0); + } } } @@ -494,7 +815,14 @@ static void up_config_baud_divisors(struct up_dev_s *priv, uint32_t baudrate) uint32_t fractional_baud_value; uint64_t pclk_freq; - pclk_freq = MPFS_MSS_APB_AHB_CLK; + if (!priv->fpga) + { + pclk_freq = MPFS_MSS_APB_AHB_CLK; + } + else + { + pclk_freq = MPFS_FPGA_PERIPHERAL_CLK; + } /* Compute baud value based on requested baud rate and PCLK frequency. * The baud value is computed using the following equation: @@ -1140,6 +1468,18 @@ void riscv_earlyserialinit(void) up_disableuartint(g_uart4port.priv, NULL); #endif +#ifdef CONFIG_MPFS_UART5 + up_disableuartint(g_uart5port.priv, NULL); +#endif + +#ifdef CONFIG_MPFS_UART6 + up_disableuartint(g_uart6port.priv, NULL); +#endif + +#ifdef CONFIG_MPFS_UART7 + up_disableuartint(g_uart7port.priv, NULL); +#endif + /* Configuration whichever one is the console */ #ifdef HAVE_SERIAL_CONSOLE @@ -1183,6 +1523,15 @@ void riscv_serialinit(void) #ifdef CONFIG_MPFS_UART4 uart_register("/dev/ttyS4", &g_uart4port); #endif +#ifdef CONFIG_MPFS_UART5 + uart_register("/dev/ttyS5", &g_uart5port); +#endif +#ifdef CONFIG_MPFS_UART6 + uart_register("/dev/ttyS6", &g_uart6port); +#endif +#ifdef CONFIG_MPFS_UART7 + uart_register("/dev/ttyS7", &g_uart7port); +#endif } /**************************************************************************** diff --git a/arch/risc-v/src/mpfs/mpfs_timerisr.c b/arch/risc-v/src/mpfs/mpfs_timerisr.c index 3a43fa278f18e..b8c635811fef9 100644 --- a/arch/risc-v/src/mpfs/mpfs_timerisr.c +++ b/arch/risc-v/src/mpfs/mpfs_timerisr.c @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -32,11 +31,8 @@ #include #include #include -#include -#include "hardware/mpfs_clint.h" #include "riscv_internal.h" -#include "riscv_mtimer.h" #include "mpfs.h" #include "mpfs_clockconfig.h" @@ -45,7 +41,81 @@ * Pre-processor Definitions ****************************************************************************/ -#define MTIMER_FREQ MPFS_MSS_RTC_TOGGLE_CLK +#define TICK_COUNT (MPFS_MSS_RTC_TOGGLE_CLK / TICK_PER_SEC) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifndef CONFIG_BUILD_KERNEL +static bool _b_tick_started; +static uint64_t *_mtime_cmp; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint64_t get_current(void) +{ +#ifndef CONFIG_BUILD_KERNEL + if (!_b_tick_started) + { + _b_tick_started = true; + return getreg64(MPFS_CLINT_MTIME); + } + else + { + return getreg64(_mtime_cmp); + } +#else + return riscv_sbi_get_time(); +#endif +} + +static void set_next(uint64_t next) +{ +#ifndef CONFIG_BUILD_KERNEL + putreg64(next, _mtime_cmp); +#else + riscv_sbi_set_timer(next); +#endif +} + +/**************************************************************************** + * Name: mpfs_reload_mtimecmp + ****************************************************************************/ + +static void mpfs_reload_mtimecmp(void) +{ + irqstate_t flags = spin_lock_irqsave(NULL); + + uint64_t current; + uint64_t next; + + current = get_current(); + uint64_t tick = TICK_COUNT; + next = current + tick; + + set_next(next); + + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: mpfs_timerisr + ****************************************************************************/ + +static int mpfs_timerisr(int irq, void *context, void *arg) +{ + mpfs_reload_mtimecmp(); + + /* Process timer interrupt */ + + nxsched_process_timer(); + + return 0; +} /**************************************************************************** * Public Functions @@ -62,15 +132,22 @@ void up_timer_initialize(void) { +#ifndef CONFIG_BUILD_KERNEL /* what is our timecmp address for this hart */ uintptr_t hart_id = riscv_mhartid(); + _mtime_cmp = (uint64_t *)MPFS_CLINT_MTIMECMP0 + hart_id; +#endif + + /* Attach timer interrupt handler */ + + irq_attach(RISCV_IRQ_TIMER, mpfs_timerisr, NULL); + + /* Reload CLINT mtimecmp */ - struct oneshot_lowerhalf_s *lower = riscv_mtimer_initialize( - MPFS_CLINT_MTIME, MPFS_CLINT_MTIMECMP0 + hart_id * sizeof(uintptr_t), - RISCV_IRQ_TIMER, MTIMER_FREQ); + mpfs_reload_mtimecmp(); - DEBUGASSERT(lower); + /* And enable the timer interrupt */ - up_alarm_set_lowerhalf(lower); + up_enable_irq(RISCV_IRQ_TIMER); } diff --git a/arch/risc-v/src/mpfs/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index 8f0e11bc20e1c..c8983b16c1ab3 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -129,6 +129,10 @@ # define MSB 1 #endif +#ifndef MPFS_USB_DMA_ADDR_UPPER_OFFSET +# define MPFS_USB_DMA_ADDR_UPPER_OFFSET 0x14u +#endif + #define MPFS_NUM_USB_PKT 1 #define MPFS_MIN_EP_FIFO_SIZE 8 #define MPFS_USB_REG_MAX 0x2000 @@ -3685,6 +3689,10 @@ static void mpfs_hw_setup(struct mpfs_usbdev_s *priv) modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, SYSREG_SOFT_RESET_CR_USB | SYSREG_SOFT_RESET_CR_FPGA, 0); + /* Set USB upper address offset to enable USB DMA support for himen */ + + mpfs_putreg32(MPFS_USB_DMA_ADDR_UPPER_OFFSET, MPFS_USB_DMA_ADDR_UPPER_REG); + /* Reset the controller */ mpfs_putreg8(SOFT_RESET_REG_MASK, MPFS_USB_SOFT_RST); diff --git a/arch/risc-v/src/mpfs/mpfs_userspace.c b/arch/risc-v/src/mpfs/mpfs_userspace.c index a4409e2dcb088..7c13fd6a41ac3 100644 --- a/arch/risc-v/src/mpfs/mpfs_userspace.c +++ b/arch/risc-v/src/mpfs/mpfs_userspace.c @@ -31,6 +31,7 @@ #include #include +#include "hardware/mpfs_clint.h" #include "mpfs_userspace.h" #include "riscv_internal.h" @@ -53,7 +54,7 @@ #define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ #define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ -#define PGT_L3_SIZE (1024) /* Enough to map 4 MiB */ +#define PGT_L3_SIZE (2048) /* Enough to map 8 MiB */ #define SLAB_COUNT (sizeof(m_l3_pgtable) / RV_MMU_PAGE_SIZE) @@ -248,6 +249,11 @@ static void configure_mmu(void) map_region(UFLASH_START, UFLASH_START, UFLASH_SIZE, MMU_UTEXT_FLAGS); map_region(USRAM_START, USRAM_START, USRAM_SIZE, MMU_UDATA_FLAGS); + /* Map the MTIME counter to the start of USR IO region */ + + map_region(MPFS_CLINT_MTIME & (~RV_MMU_PAGE_MASK), USRIO_START, + RV_MMU_PAGE_SIZE, PTE_R | PTE_U | PTE_G); + /* Connect the L1 and L2 page tables */ mmu_ln_setentry(1, PGT_L1_VBASE, PGT_L2_PBASE, UFLASH_START, PTE_G); diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index b60878639b8e5..b7d0ca61e232d 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -37,10 +37,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = 4998a712b2ab504eff306110879ee05af6050177 -OPENSBI_URL = https://github.com/riscv-software-src/opensbi/tarball +OPENSBI_COMMIT = a082fb83f218a647d2009b565e573dac8f179cb9 +OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = riscv-software-src-opensbi-4998a71 +OPENSBI_DIR = tiiuae-opensbi-a082fb8 $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) diff --git a/boards/risc-v/litex/arty_a7/Kconfig b/boards/risc-v/litex/arty_a7/Kconfig index 7977b985b27c8..92df0ad54c723 100644 --- a/boards/risc-v/litex/arty_a7/Kconfig +++ b/boards/risc-v/litex/arty_a7/Kconfig @@ -5,44 +5,6 @@ if ARCH_BOARD_ARTY_A7 - -config LITEX_SDIO - bool "SDIO" - default n - select SCHED_HPWORK - select MMCSD - select MMCSD_SDIO - select SDIO_BLOCKSETUP - select ARCH_HAVE_SDIO - select SDIO_DMA - -config LITEX_SDIO1 - bool "Enable SDIO1" - default LITEX_SDIO - select LITEX_SDIO_DMA - depends on LITEX_SDIO - -config LITEX_IDMODE_FREQ - int "ID mode frequency" - default 400000 - depends on LITEX_SDIO - ---help--- - Initial, ID mode SD frequency - -config LITEX_MMCXFR_FREQ - int "MMC transfer frequency" - default 25000000 - depends on LITEX_SDIO - ---help--- - Frequency to use for transferring data to/from an MMC card - -config LITEX_SD4BIT_FREQ - int "SD 4-bit transfer frequency" - default 50000000 - depends on LITEX_SDIO - ---help--- - Frequency to use for transferring data to/from an SD card using all four data lines. - config LITEX_SDIO_MOUNT bool "Mount SDIO at startup" default n diff --git a/boards/risc-v/litex/arty_a7/configs/sdmmc/defconfig b/boards/risc-v/litex/arty_a7/configs/sdmmc/defconfig deleted file mode 100644 index 5ee0e4d97c24e..0000000000000 --- a/boards/risc-v/litex/arty_a7/configs/sdmmc/defconfig +++ /dev/null @@ -1,74 +0,0 @@ -# -# 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_DISABLE_PTHREAD is not set -# CONFIG_FS_PROCFS_EXCLUDE_BLOCKS is not set -# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set -# CONFIG_FS_PROCFS_EXCLUDE_MEMDUMP is not set -# CONFIG_FS_PROCFS_EXCLUDE_MEMINFO is not set -# CONFIG_FS_PROCFS_EXCLUDE_MOUNT is not set -# CONFIG_FS_PROCFS_EXCLUDE_MOUNTS is not set -# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set -# CONFIG_FS_PROCFS_EXCLUDE_UPTIME is not set -# CONFIG_FS_PROCFS_EXCLUDE_USAGE is not set -# CONFIG_FS_PROCFS_EXCLUDE_VERSION is not set -# CONFIG_NSH_DISABLEBG is not set -# CONFIG_NSH_DISABLE_LOSMART is not set -# CONFIG_NSH_DISABLE_UNAME is not set -# CONFIG_STANDARD_SERIAL is not set -CONFIG_ARCH="risc-v" -CONFIG_ARCH_BOARD="arty_a7" -CONFIG_ARCH_BOARD_ARTY_A7=y -CONFIG_ARCH_CHIP="litex" -CONFIG_ARCH_CHIP_LITEX=y -CONFIG_ARCH_INTERRUPTSTACK=8192 -CONFIG_ARCH_RISCV=y -CONFIG_ARCH_STACKDUMP=y -CONFIG_BOARD_LOOPSPERMSEC=10000 -CONFIG_BUILTIN=y -CONFIG_DEBUG_FULLOPT=y -CONFIG_DEBUG_SYMBOLS=y -CONFIG_DEFAULT_SMALL=y -CONFIG_DEV_ZERO=y -CONFIG_EXAMPLES_HELLO=y -CONFIG_EXAMPLES_HELLO_STACKSIZE=8192 -CONFIG_FAT_DMAMEMORY=y -CONFIG_FAT_FORCE_INDIRECT=y -CONFIG_FAT_LFN=y -CONFIG_FS_FAT=y -CONFIG_FS_FATTIME=y -CONFIG_FS_PROCFS=y -CONFIG_GRAN=y -CONFIG_IDLETHREAD_STACKSIZE=8192 -CONFIG_INIT_ENTRYPOINT="nsh_main" -CONFIG_INIT_STACKSIZE=8192 -CONFIG_INTELHEX_BINARY=y -CONFIG_LIBC_PERROR_STDOUT=y -CONFIG_LIBC_STRERROR=y -CONFIG_LITEX_SDIO=y -CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6 -CONFIG_NSH_ARCHINIT=y -CONFIG_NSH_BUILTIN_APPS=y -CONFIG_NSH_FILEIOSIZE=64 -CONFIG_NSH_STRERROR=y -CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=8192 -CONFIG_PTHREAD_STACK_DEFAULT=8192 -CONFIG_RAM_SIZE=268435456 -CONFIG_RAM_START=0x40000000 -CONFIG_RAW_BINARY=y -CONFIG_RR_INTERVAL=200 -CONFIG_SCHED_WAITPID=y -CONFIG_STACK_COLORATION=y -CONFIG_START_DAY=20 -CONFIG_START_MONTH=3 -CONFIG_START_YEAR=2020 -CONFIG_SYSTEM_NSH=y -CONFIG_TASK_NAME_SIZE=12 -CONFIG_TESTING_GETPRIME=y -CONFIG_UART0_RXBUFSIZE=128 -CONFIG_UART0_SERIAL_CONSOLE=y -CONFIG_UART0_TXBUFSIZE=128 diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig new file mode 100644 index 0000000000000..7bcc1380138d6 --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -0,0 +1,86 @@ +# +# 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_DISABLE_OS_API is not set +# CONFIG_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +CONFIG_ALLOW_BSD_COMPONENTS=y +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="icicle" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ICICLE_MPFS=y +CONFIG_ARCH_CHIP="mpfs" +CONFIG_ARCH_CHIP_MPFS250T_FCVG484=y +CONFIG_ARCH_CHIP_MPFS=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=54000 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_NET=y +CONFIG_DEBUG_NET_ERROR=y +CONFIG_DEBUG_NET_INFO=y +CONFIG_DEBUG_NET_WARN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WARN=y +CONFIG_DEV_ZERO=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_HOSTNAME="icicle" +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_CANFD0=y +CONFIG_MPFS_CANFD1=y +CONFIG_MPFS_ENABLE_DPFPU=y +CONFIG_MPFS_HAVE_CANFD=y +CONFIG_MPFS_UART1=y +CONFIG_NET=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_UMOUNT=y +CONFIG_NSH_LINELEN=160 +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=1048576 +CONFIG_RAM_START=0x80200000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SERIAL_NPOLLWAITERS=2 +CONFIG_STACK_COLORATION=y +CONFIG_START_MONTH=4 +CONFIG_START_YEAR=2021 +CONFIG_SYSLOG_COLOR_OUTPUT=y +CONFIG_SYSTEM_CLE_CMD_HISTORY=y +CONFIG_SYSTEM_COLOR_CLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TASK_NAME_SIZE=20 +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART1_SERIAL_CONSOLE=y diff --git a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig index cd526cb972ac6..415a2892d4136 100644 --- a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig @@ -50,7 +50,6 @@ CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y CONFIG_MM_IOB=y CONFIG_MPFS_IHC_CLIENT=y -CONFIG_MPFS_IHC_LINUX_ON_HART4=0 CONFIG_MPFS_IHC_NUTTX_ON_HART1=1 CONFIG_MPFS_IHC_NUTTX_ON_HART2=0 CONFIG_MPFS_UART1=y diff --git a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig index 5dc95abc1fc44..3341c583e9c86 100644 --- a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig @@ -51,6 +51,7 @@ CONFIG_MEMSET_OPTSPEED=y CONFIG_MM_IOB=y CONFIG_MPFS_IHC_CLIENT=y CONFIG_MPFS_IHC_LINUX_ON_HART3=0 +CONFIG_MPFS_IHC_LINUX_ON_HART4=1 CONFIG_MPFS_IHC_RPMSG_CH2=y CONFIG_MPFS_UART2=y CONFIG_NSH_ARCHINIT=y diff --git a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig new file mode 100644 index 0000000000000..78d417dfdee52 --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig @@ -0,0 +1,62 @@ +# +# 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_ARCH="risc-v" +CONFIG_ARCH_BOARD="icicle" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ICICLE_MPFS=y +CONFIG_ARCH_CHIP="mpfs" +CONFIG_ARCH_CHIP_MPFS250T_FCVG484=y +CONFIG_ARCH_CHIP_MPFS=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=54000 +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ERROR=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_HOSTNAME="icicle" +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_BOOTLOADER=y +CONFIG_MPFS_BOOT_HART=1 +CONFIG_MPFS_DDR_INIT=y +CONFIG_MPFS_ENABLE_DPFPU=y +CONFIG_MPFS_UART0=y +CONFIG_MPFS_UART1=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_DISABLE_MKDIR=y +CONFIG_NSH_DISABLE_RM=y +CONFIG_NSH_DISABLE_RMDIR=y +CONFIG_NSH_DISABLE_UMOUNT=y +CONFIG_NSH_LINELEN=160 +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=1048576 +CONFIG_RAM_START=0x08000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_SCHED_HPWORK=y +CONFIG_START_MONTH=4 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TASK_NAME_SIZE=20 +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_UART1_BAUD=2000000 +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/risc-v/mpfs/icicle/include/board.h b/boards/risc-v/mpfs/icicle/include/board.h index ad8da65db8e8f..28adc89988025 100644 --- a/boards/risc-v/mpfs/icicle/include/board.h +++ b/boards/risc-v/mpfs/icicle/include/board.h @@ -45,6 +45,8 @@ # define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_25MHZ #endif +#define MPFS_USB_DMA_ADDR_UPPER_OFFSET 0x14u + /* Clocking TODO: */ #define MPFS_MSS_EXT_SGMII_REF_CLK (125000000UL) diff --git a/boards/risc-v/mpfs/icicle/include/board_memorymap.h b/boards/risc-v/mpfs/icicle/include/board_memorymap.h index 47cac1185796c..353112aa86d6d 100644 --- a/boards/risc-v/mpfs/icicle/include/board_memorymap.h +++ b/boards/risc-v/mpfs/icicle/include/board_memorymap.h @@ -65,6 +65,11 @@ #define USRAM_START (uintptr_t)__usram_start #define USRAM_SIZE (uintptr_t)__usram_size +/* User IO */ + +#define USRIO_START (uintptr_t)__usrio_start +#define USRIO_SIZE (uintptr_t)__usrio_size + /**************************************************************************** * Public Data ****************************************************************************/ @@ -95,4 +100,9 @@ extern uint8_t __uflash_size[]; extern uint8_t __usram_start[]; extern uint8_t __usram_size[]; +/* User IO (R) */ + +extern uint8_t __usrio_start[]; +extern uint8_t __usrio_size[]; + #endif /* __BOARDS_RISC_V_MPFS_ICICLE_INCLUDE_BOARD_MEMORYMAP_H */ diff --git a/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld b/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld index 20ecbffab506b..bd0b3675ce8b5 100644 --- a/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld +++ b/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld @@ -30,6 +30,8 @@ __uflash_start = ORIGIN(uflash); __uflash_size = LENGTH(uflash); __usram_start = ORIGIN(usram); __usram_size = LENGTH(usram); +__usrio_start = ORIGIN(usrio); +__usrio_size = LENGTH(usrio); /* Provide the kernel boundaries as well */ diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script index 7843d3f82af4d..c17cd90439c2e 100644 --- a/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script +++ b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script @@ -32,6 +32,9 @@ ENTRY(_stext) EXTERN(__start) SECTIONS { + PROVIDE(__l2lim_start = ORIGIN(l2lim)); + PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); + .text.sbi : { sbi* riscv_atomic* diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-envm.script b/boards/risc-v/mpfs/icicle/scripts/ld-envm.script index ceaf236ef4655..08072e667e7b4 100644 --- a/boards/risc-v/mpfs/icicle/scripts/ld-envm.script +++ b/boards/risc-v/mpfs/icicle/scripts/ld-envm.script @@ -35,6 +35,9 @@ ENTRY(_stext) EXTERN(__start) SECTIONS { + PROVIDE(__l2lim_start = ORIGIN(lim)); + PROVIDE(__l2lim_end = ORIGIN(lim) + LENGTH(lim)); + .text : { _stext = ABSOLUTE(.); *(.start .start.*) diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script b/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script index cea4ae185760d..0e8a29c657fb5 100644 --- a/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script +++ b/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script @@ -28,6 +28,7 @@ MEMORY kflash (rx) : ORIGIN = 0x80000000, LENGTH = 2048K /* w/ cache */ ksram (rwx) : ORIGIN = 0x80200000, LENGTH = 2048K /* w/ cache */ pgram (rwx) : ORIGIN = 0x80400000, LENGTH = 4096K /* w/ cache */ + usrio (r) : ORIGIN = 0x80800000, LENGTH = 32K /* w/ cache */ } OUTPUT_ARCH("riscv") @@ -45,6 +46,11 @@ __ksram_end = ORIGIN(ksram) + LENGTH(ksram); __pgheap_start = ORIGIN(pgram); __pgheap_size = LENGTH(pgram); +/* User I/O */ + +__usrio_start = ORIGIN(usrio); +__usrio_size = LENGTH(usrio); + ENTRY(_stext) EXTERN(__start) SECTIONS diff --git a/boards/risc-v/mpfs/icicle/scripts/memory.ld b/boards/risc-v/mpfs/icicle/scripts/memory.ld index 890ba735baf8c..f31a88d4eaacc 100644 --- a/boards/risc-v/mpfs/icicle/scripts/memory.ld +++ b/boards/risc-v/mpfs/icicle/scripts/memory.ld @@ -25,4 +25,6 @@ MEMORY ksram (rwx) : ORIGIN = 0x80080000, LENGTH = 256K /* w/ cache */ usram (rwx) : ORIGIN = 0x800C0000, LENGTH = 256K /* w/ cache */ + + usrio (r) : ORIGIN = 0x80100000, LENGTH = 32K } diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 1baee5e782bd0..53c8d97598895 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -149,54 +149,51 @@ static void mmcsd_unlock(FAR struct mmcsd_state_s *priv); /* Command/response helpers *************************************************/ static int mmcsd_sendcmdpoll(FAR struct mmcsd_state_s *priv, - uint32_t cmd, uint32_t arg); + uint32_t cmd, uint32_t arg); static int mmcsd_recv_r1(FAR struct mmcsd_state_s *priv, uint32_t cmd); static int mmcsd_recv_r6(FAR struct mmcsd_state_s *priv, uint32_t cmd); static int mmcsd_get_scr(FAR struct mmcsd_state_s *priv, - uint32_t scr[2]); + uint32_t scr[2]); static void mmcsd_decode_csd(FAR struct mmcsd_state_s *priv, - uint32_t csd[4]); + uint32_t csd[4]); #ifdef CONFIG_DEBUG_FS_INFO static void mmcsd_decode_cid(FAR struct mmcsd_state_s *priv, - uint32_t cid[4]); + uint32_t cid[4]); #else # define mmcsd_decode_cid(priv,cid) #endif static void mmcsd_decode_scr(FAR struct mmcsd_state_s *priv, - uint32_t scr[2]); + uint32_t scr[2]); static int mmcsd_get_r1(FAR struct mmcsd_state_s *priv, - FAR uint32_t *r1); + FAR uint32_t *r1); static int mmcsd_verifystate(FAR struct mmcsd_state_s *priv, - uint32_t status); + uint32_t status); /* Transfer helpers *********************************************************/ static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv); static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv, - sdio_eventset_t failevents); + sdio_eventset_t failevents); static int mmcsd_transferready(FAR struct mmcsd_state_s *priv); #if MMCSD_MULTIBLOCK_LIMIT != 1 static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv); #endif static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, - uint32_t blocklen); + uint32_t blocklen); static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock); + FAR uint8_t *buffer, off_t startblock); #if MMCSD_MULTIBLOCK_LIMIT != 1 static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, - FAR uint8_t *buffer, off_t startblock, - size_t nblocks); + FAR uint8_t *buffer, off_t startblock, size_t nblocks); #endif static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, - off_t startblock); + FAR const uint8_t *buffer, off_t startblock); #if MMCSD_MULTIBLOCK_LIMIT != 1 static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, - FAR const uint8_t *buffer, - off_t startblock, - size_t nblocks); + FAR const uint8_t *buffer, off_t startblock, + size_t nblocks); #endif /* Block driver methods *****************************************************/ @@ -204,15 +201,14 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, static int mmcsd_open(FAR struct inode *inode); static int mmcsd_close(FAR struct inode *inode); static ssize_t mmcsd_read(FAR struct inode *inode, FAR unsigned char *buffer, - blkcnt_t startsector, unsigned int nsectors); + blkcnt_t startsector, unsigned int nsectors); static ssize_t mmcsd_write(FAR struct inode *inode, - FAR const unsigned char *buffer, - blkcnt_t startsector, - unsigned int nsectors); + FAR const unsigned char *buffer, blkcnt_t startsector, + unsigned int nsectors); static int mmcsd_geometry(FAR struct inode *inode, - FAR struct geometry *geometry); + FAR struct geometry *geometry); static int mmcsd_ioctl(FAR struct inode *inode, int cmd, - unsigned long arg); + unsigned long arg); /* Initialization/uninitialization/reset ************************************/ @@ -362,7 +358,6 @@ static inline int mmcsd_sendcmd4(FAR struct mmcsd_state_s *priv) if (priv->dsrimp != false) { - finfo("Card supports DSR - send DSR.\n"); /* CMD4 = SET_DSR will set the cards DSR register. The DSR and CMD4 * support are optional. However, since this is a broadcast command * with no response (like CMD0), we will never know if the DSR was @@ -377,10 +372,6 @@ static inline int mmcsd_sendcmd4(FAR struct mmcsd_state_s *priv) mmcsd_sendcmdpoll(priv, MMCSD_CMD4, CONFIG_MMCSD_DSR << 16); nxsig_usleep(MMCSD_DSR_DELAY); } - else - { - finfo("Card does not support DSR.\n"); - } #endif return ret; @@ -1581,8 +1572,8 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks); SDIO_WAITENABLE(priv->dev, - SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, - nblocks * MMCSD_BLOCK_RDATADELAY); + SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, + nblocks * MMCSD_BLOCK_RDATADELAY); #ifdef CONFIG_SDIO_DMA if ((priv->caps & SDIO_CAPS_DMASUPPORTED) != 0) @@ -2484,14 +2475,9 @@ static int mmcsd_widebus(FAR struct mmcsd_state_s *priv) * SCR or in the SDIO driver capabililities) */ - if (IS_SD(priv->type) && - (priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0 && + if ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0 && (priv->caps & SDIO_CAPS_1BIT_ONLY) == 0) { - /* SD card supports 4-bit BUS and host settings is not 1-bit only. */ - - finfo("Setting SD BUS width to 4-bit. Card type: %d\n", priv->type); - /* Disconnect any CD/DAT3 pull up using ACMD42. ACMD42 is optional and * need not be supported by all SD calls. * @@ -2521,7 +2507,7 @@ static int mmcsd_widebus(FAR struct mmcsd_state_s *priv) return ret; } - /* Now send ACMD6 to select bus width operation, beginning + /* Now send ACMD6 to select wide, 4-bit bus operation, beginning * with CMD55, APP_CMD: */ @@ -2536,80 +2522,27 @@ static int mmcsd_widebus(FAR struct mmcsd_state_s *priv) /* Then send ACMD6 */ mmcsd_sendcmdpoll(priv, SD_ACMD6, MMCSD_ACMD6_BUSWIDTH_4); - ret = mmcsd_recv_r1(priv, SD_ACMD6); if (ret != OK) { return ret; } - } -#ifdef CONFIG_MMCSD_MMCSUPPORT - else if (IS_MMC(priv->type) && - ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0 && - (priv->caps & SDIO_CAPS_1BIT_ONLY) == 0)) - { - /* SD card supports 4-bit BUS and host settings is not 1-bit only. - * Configuring MMC - Use MMC_SWITCH access modes. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD6, - MMCSD_CMD6_MODE_WRITE_BYTE | MMCSD_CMD6_BUSWIDTH_RW | - MMCSD_CMD6_BUS_WIDTH_4); - ret = mmcsd_recv_r1(priv, MMCSD_CMD6); - - if (ret != OK) - { - ferr("ERROR: (MMCSD_CMD6) Setting MMC BUS width: %d\n", ret); - return ret; - } - } -#endif /* #ifdef CONFIG_MMCSD_MMCSUPPORT */ - else - { - fwarn("No card inserted.\n"); - SDIO_WIDEBUS(priv->dev, false); - priv->widebus = false; - SDIO_CLOCK(priv->dev, CLOCK_SDIO_DISABLED); - nxsig_usleep(MMCSD_CLK_DELAY); - - return OK; - } - /* Configure the SDIO peripheral */ + /* Configure the SDIO peripheral */ - if ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0) - { finfo("Wide bus operation selected\n"); SDIO_WIDEBUS(priv->dev, true); priv->widebus = true; - } - else - { - finfo("Narrow bus operation selected\n"); - SDIO_WIDEBUS(priv->dev, false); - priv->widebus = false; - } - if (IS_SD(priv->type)) - { - if ((priv->buswidth & MMCSD_SCR_BUSWIDTH_4BIT) != 0) - { - SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_4BIT); - } - else - { - SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_1BIT); - } - } -#ifdef CONFIG_MMCSD_MMCSUPPORT - else - { - SDIO_CLOCK(priv->dev, CLOCK_MMC_TRANSFER); + SDIO_CLOCK(priv->dev, CLOCK_SD_TRANSFER_4BIT); + nxsig_usleep(MMCSD_CLK_DELAY); + return OK; } -#endif /* #ifdef CONFIG_MMCSD_MMCSUPPORT */ - nxsig_usleep(MMCSD_CLK_DELAY); - return OK; + /* Wide bus operation not supported */ + + fwarn("WARNING: Card does not support wide-bus operation\n"); + return -ENOSYS; } /**************************************************************************** @@ -2641,8 +2574,6 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) * identification state / card-identification mode. */ - finfo("Initialising MMC card.\n"); - mmcsd_sendcmdpoll(priv, MMCSD_CMD2, 0); ret = SDIO_RECVR2(priv->dev, MMCSD_CMD2, cid); if (ret != OK) @@ -2659,7 +2590,7 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) */ priv->rca = 1; /* There is only one card */ - mmcsd_sendcmdpoll(priv, MMC_CMD3, (uint32_t)priv->rca << 16); + mmcsd_sendcmdpoll(priv, MMC_CMD3, priv->rca << 16); ret = mmcsd_recv_r1(priv, MMC_CMD3); if (ret != OK) { @@ -2669,8 +2600,8 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) /* This should have caused a transition to standby state. However, this * will not be reflected in the present R1/6 status. R1/6 contains the - * state of the card when the command was received, not when it - * completed execution. + * state of the card when the command was received, not when it completed + * execution. * * Verify that we are in standby state/data-transfer mode */ @@ -2684,18 +2615,10 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) /* Send CMD9, SEND_CSD in standby state/data-transfer mode to obtain the * Card Specific Data (CSD) register, e.g., block length, card storage - * capacity, etc. (Stays in standby state/data-transfer mode). - * NOTE in v2.0 high capacity cards, the following values are always - * returned: - * - write block length = 9 = 2^9 = 512 - * - read block length = 9 = 512 - * - rw2 factor = 0x2 (010b) - * - size_mult = 0 - * We can't decode the CSD register yet as we also need to read the - * extended CSD register. + * capacity, etc. (Stays in standby state/data-transfer mode) */ - mmcsd_sendcmdpoll(priv, MMCSD_CMD9, (uint32_t)priv->rca << 16); + mmcsd_sendcmdpoll(priv, MMCSD_CMD9, priv->rca << 16); ret = SDIO_RECVR2(priv->dev, MMCSD_CMD9, csd); if (ret != OK) { @@ -2703,13 +2626,6 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) return ret; } - /* Decode the CSD register to obtain version. We will need to - * decode further if card is v4.0 or higher as it supports - * ext_csd commands. - */ - - mmcsd_decode_csd(priv, csd); - /* Set the Driver Stage Register (DSR) if (1) a CONFIG_MMCSD_DSR has been * provided and (2) the card supports a DSR register. If no DSR value * the card default value (0x0404) will be used. @@ -2717,8 +2633,7 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) mmcsd_sendcmd4(priv); - /* Select the card. - * Send CMD7 with the argument == RCA in order to select the card + /* Send CMD7 with the argument == RCA in order to select the card * and send it in data-trasfer mode. Since we are supporting * only a single card, we just leave the card selected all of the time. */ @@ -2731,33 +2646,14 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) return ret; } - /* If the hardware only supports 4-bit transfer mode then we forced to - * attempt to setup the card in this mode before checking the ext CSD - * register. - */ - - if ((priv->caps & SDIO_CAPS_4BIT_ONLY) != 0) - { - /* Select width (4-bit) bus operation */ - - priv->buswidth = MMCSD_SCR_BUSWIDTH_4BIT; - ret = mmcsd_widebus(priv); - - if (ret != OK) - { - ferr("ERROR: Failed to set wide bus operation: %d\n", ret); - } - } - /* CSD Decoding for MMC should be done after entering in data-transfer mode * because if the card has block addressing then extended CSD register * must be read in order to get the right number of blocks and capacity, - * and BUS width but it has to be done in data-transfer mode. + * but it has to be done in data-transfer mode. */ if (IS_BLOCK(priv->type)) { - finfo("Card supports eMMC spec 4.0 (or greater). Reading ext_csd.\n"); ret = mmcsd_read_csd(priv); if (ret != OK) { @@ -2768,17 +2664,10 @@ static int mmcsd_mmcinitialize(FAR struct mmcsd_state_s *priv) mmcsd_decode_csd(priv, csd); - if ((priv->caps & SDIO_CAPS_4BIT_ONLY) != 0) - { - /* Select width (4-bit) bus operation (if the card supports it) */ - - ret = mmcsd_widebus(priv); - if (ret != OK) - { - ferr("ERROR: Failed to set wide bus operation: %d\n", ret); - } - } + /* Select high speed MMC clocking (which may depend on the DSR setting) */ + SDIO_CLOCK(priv->dev, CLOCK_MMC_TRANSFER); + nxsig_usleep(MMCSD_CLK_DELAY); return OK; } @@ -2812,7 +2701,6 @@ static int mmcsd_read_csd(FAR struct mmcsd_state_s *priv) memset(buffer, 0, sizeof(buffer)); #if defined(CONFIG_SDIO_DMA) && defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) - /* If we think we are going to perform a DMA transfer, make sure that we * will be able to before we commit the card to the operation. */ @@ -2841,7 +2729,7 @@ static int mmcsd_read_csd(FAR struct mmcsd_state_s *priv) return ret; } - /* Select the block size for the card (CMD16) */ + /* Select the block size for the card */ ret = mmcsd_setblocklen(priv, 512); if (ret != OK) @@ -2860,7 +2748,6 @@ static int mmcsd_read_csd(FAR struct mmcsd_state_s *priv) #ifdef CONFIG_SDIO_DMA if ((priv->caps & SDIO_CAPS_DMASUPPORTED) != 0) { - finfo("Setting up for DMA transfer.\n"); ret = SDIO_DMARECVSETUP(priv->dev, buffer, 512); if (ret != OK) { @@ -3390,9 +3277,8 @@ static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv) { /* Select width (4-bit) bus operation */ - priv->buswidth = MMCSD_SCR_BUSWIDTH_4BIT; + priv->buswidth = 4; ret = mmcsd_widebus(priv); - if (ret != OK) { ferr("ERROR: Failed to set wide bus operation: %d\n", ret); @@ -3413,7 +3299,7 @@ static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv) mmcsd_decode_scr(priv, scr); - if ((priv->caps & SDIO_CAPS_4BIT_ONLY) != 0) + if ((priv->caps & SDIO_CAPS_4BIT_ONLY) == 0) { /* Select width (4-bit) bus operation (if the card supports it) */ @@ -3452,8 +3338,6 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) clock_t elapsed; int ret; - finfo("Identifying card...\n"); - /* Assume failure to identify the card */ priv->type = MMCSD_CARDTYPE_UNKNOWN; @@ -3468,13 +3352,6 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) return -ENODEV; } - /* For eMMC, Send CMD0 with argument 0xf0f0f0f0 as per JEDEC v4.41 - * for pre-idle. No effect for SD. - */ - - mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0xf0f0f0f0); - nxsig_usleep(MMCSD_IDLE_DELAY); - /* Set ID mode clocking (<400KHz) */ SDIO_CLOCK(priv->dev, CLOCK_IDMODE); @@ -3502,14 +3379,12 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) if (ret != OK) { - fwarn("WARNING: CMD1 RECVR3: %d. " - "NOTE: This is expected for SD cards.\n", ret); + ferr("ERROR: CMD1 RECVR3: %d\n", ret); - /* CMD1 did not succeed, card is not MMC. Return to idle - * to allow the communication to recover before another send. + /* CMD1 did not succeed, card is not MMC. This sleep let + * the communication to recover before another send. */ - mmcsd_sendcmdpoll(priv, MMCSD_CMD0, 0); nxsig_usleep(MMCSD_IDLE_DELAY); } else @@ -3599,7 +3474,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) } } - /* At this point, type is either UNKNOWN, eMMC or SDV2. Try sending + /* At this point, type is either UNKNOWN or SDV2. Try sending * CMD55 and (maybe) ACMD41 for up to 1 second or until the card * exits the IDLE state. CMD55 is supported by SD V1.x and SD V2.x, * but not MMC @@ -3609,7 +3484,7 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) elapsed = 0; do { - /* We may have already determined that this card is an MMC card from + /* We may have already determined that his card is an MMC card from * an earlier pass through this loop. In that case, we should * skip the SD-specific commands. */ @@ -3730,8 +3605,6 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) { /* CMD1 succeeded... this must be an MMC card */ - finfo("Confirmed MMC card present.\n"); - priv->type = MMCSD_CARDTYPE_MMC; /* Now, check if this is a MMC card/chip that supports block @@ -3763,13 +3636,9 @@ static int mmcsd_cardidentify(FAR struct mmcsd_state_s *priv) * Then break out of the look with an MMC card identified */ - finfo("MMC card/chip is ready!\n"); + finfo("MMC card/chip ready!\n"); break; } - else - { - finfo("MMC card/chip is busy. Waiting for reply...\n"); - } } } #endif @@ -3842,8 +3711,6 @@ static int mmcsd_probe(FAR struct mmcsd_state_s *priv) { /* Yes.. probe it. First, what kind of card was inserted? */ - finfo("Card present. Probing....\n"); - ret = mmcsd_cardidentify(priv); if (ret != OK) { @@ -3858,33 +3725,24 @@ static int mmcsd_probe(FAR struct mmcsd_state_s *priv) /* Bit 1: SD version 1.x */ case MMCSD_CARDTYPE_SDV1: - finfo("SD version 1.x .\n"); - ret = mmcsd_sdinitialize(priv); - break; /* SD version 2.x with byte addressing */ case MMCSD_CARDTYPE_SDV2: - finfo("SD version 2.x with byte addressing.\n"); - ret = mmcsd_sdinitialize(priv); - break; /* SD version 2.x with block addressing */ case MMCSD_CARDTYPE_SDV2 | MMCSD_CARDTYPE_BLOCK: - finfo("SD version 2.x with block addressing.\n"); ret = mmcsd_sdinitialize(priv); break; /* MMC card with byte addressing */ case MMCSD_CARDTYPE_MMC: - finfo("MMC card with byte addressing.\n"); /* MMC card with block addressing */ case MMCSD_CARDTYPE_MMC | MMCSD_CARDTYPE_BLOCK: - finfo("MMC card with block addressing.\n"); #ifdef CONFIG_MMCSD_MMCSUPPORT ret = mmcsd_mmcinitialize(priv); break; @@ -3969,10 +3827,8 @@ static int mmcsd_removed(FAR struct mmcsd_state_s *priv) /* Go back to the default 1-bit data bus. */ - priv->buswidth = MMCSD_SCR_BUSWIDTH_1BIT; SDIO_WIDEBUS(priv->dev, false); priv->widebus = false; - mmcsd_widebus(priv); /* Disable clocking to the card */ diff --git a/drivers/mmcsd/mmcsd_sdio.h b/drivers/mmcsd/mmcsd_sdio.h index 031a81a76d1ea..83e1c445c82be 100644 --- a/drivers/mmcsd/mmcsd_sdio.h +++ b/drivers/mmcsd/mmcsd_sdio.h @@ -32,32 +32,6 @@ * Pre-processor Definitions ****************************************************************************/ -/* CMD6 (MMC_SWITCH) argument - * MMC_SWITCH argument format: - * - * [31:26] Always 0 - * [25:24] Access Mode - * [23:16] Location of target Byte in EXT_CSD - * [15:08] Value Byte - * [07:03] Always 0 - * [02:00] Command Set - */ -#define MMCSD_CMD6_BUSWIDTH_RWSHIFT (16) -# define MMCSD_CMD6_BUSWIDTH_RW ((uint32_t)0xb7 << MMCSD_CMD6_BUSWIDTH_RWSHIFT) /* R/W */ - -#define MMCSD_CMD6_WRITE_BYTE_SHIFT (24) -# define MMCSD_CMD6_MODE_CMD_SET ((uint32_t)0x00 << MMCSD_CMD6_WRITE_BYTE_SHIFT) /* Change the command set */ -# define MMCSD_CMD6_MODE_SET_BITS ((uint32_t)0x01 << MMCSD_CMD6_WRITE_BYTE_SHIFT) /* Set bits which are 1 in value */ -# define MMCSD_CMD6_MODE_CLEAR_BITS ((uint32_t)0x02 << MMCSD_CMD6_WRITE_BYTE_SHIFT) /* Clear bits which are 1 in value */ -# define MMCSD_CMD6_MODE_WRITE_BYTE ((uint32_t)0x03 << MMCSD_CMD6_WRITE_BYTE_SHIFT) /* Set target to value */ - -#define MMCSD_CMD6_BUS_WIDTH_SHIFT (8) -# define MMCSD_CMD6_BUS_WIDTH_1 ((uint32_t)0x00 << MMCSD_CMD6_BUS_WIDTH_SHIFT) /* Card is in 1 bit mode */ -# define MMCSD_CMD6_BUS_WIDTH_4 ((uint32_t)0x01 << MMCSD_CMD6_BUS_WIDTH_SHIFT) /* Card is in 4 bit mode */ -# define MMCSD_CMD6_CSD_BUS_WIDTH_8 ((uint32_t)0x02 << MMCSD_CMD6_BUS_WIDTH_SHIFT) /* Card is in 8 bit mode */ -# define MMCSD_CMD6_DDR_BUS_WIDTH_4 ((uint32_t)0x05 << MMCSD_CMD6_BUS_WIDTH_SHIFT) /* Card is in 4 bit DDR mode */ -# define MMCSD_CMD6_DDR_BUS_WIDTH_8 ((uint32_t)0x06 << MMCSD_CMD6_BUS_WIDTH_SHIFT) /* Card is in 8 bit DDR mode */ - /* CMD8 Argument: * [31:12]: Reserved (shall be set to '0') * [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) diff --git a/drivers/net/rpmsgdrv.c b/drivers/net/rpmsgdrv.c index 33309d1c7ba9f..a6ed0719313c8 100644 --- a/drivers/net/rpmsgdrv.c +++ b/drivers/net/rpmsgdrv.c @@ -612,6 +612,13 @@ static int net_rpmsg_drv_send_recv(FAR struct net_driver_s *dev, FAR struct net_rpmsg_drv_cookie_s cookie; int ret; + /* TODO: Only TRANSFER command is implemeted on Linux side */ + + if (command != NET_RPMSG_TRANSFER) + { + return 0; + } + nxsem_init(&cookie.sem, 0, 0); cookie.header = header; @@ -1113,6 +1120,7 @@ int net_rpmsg_drv_init(FAR const char *cpuname, { FAR struct net_rpmsg_drv_s *priv; FAR struct net_driver_s *dev; + int ret; /* Allocate the interface structure */ @@ -1152,6 +1160,6 @@ int net_rpmsg_drv_init(FAR const char *cpuname, /* Register the device with the OS so that socket IOCTLs can be performed */ - netdev_register(dev, lltype); - return OK; + ret = netdev_register(dev, lltype); + return ret; } diff --git a/drivers/timers/pcf85263.c b/drivers/timers/pcf85263.c index e28685669a78d..0c7de5899a4f0 100644 --- a/drivers/timers/pcf85263.c +++ b/drivers/timers/pcf85263.c @@ -309,7 +309,7 @@ int up_rtc_getdatetime(FAR struct tm *tp) ret = I2C_TRANSFER(g_pcf85263.i2c, msg, 4); if (ret < 0) { - rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret) + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); return ret; } } @@ -400,7 +400,7 @@ int up_rtc_settime(FAR const struct timespec *tp) if (localtime_r(&newtime, &newtm) == NULL) { - rtcerr("ERROR: localtime_r failed\n") + rtcerr("ERROR: localtime_r failed\n"); return -EINVAL; } @@ -477,7 +477,7 @@ int up_rtc_settime(FAR const struct timespec *tp) ret = I2C_TRANSFER(g_pcf85263.i2c, msg, 3); if (ret < 0) { - rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret) + rtcerr("ERROR: I2C_TRANSFER failed: %d\n", ret); return ret; } } diff --git a/net/can/can_callback.c b/net/can/can_callback.c index d8ebfc65506ef..ac5de920937f5 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -62,6 +62,9 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, uint16_t flags) { int buflen = dev->d_len; +#ifdef CONFIG_NET_TIMESTAMP + buflen -= sizeof(struct timeval); +#endif uint16_t recvlen; uint16_t ret; @@ -133,6 +136,19 @@ uint16_t can_callback(FAR struct net_driver_s *dev, if ((flags & CAN_NEWDATA) != 0) { + if (dev->d_iob->io_flink != NULL || + dev->d_iob->io_pktlen == 0 || + dev->d_iob->io_offset <= 0) + { + if (dev->d_iob->io_flink == NULL) + { + iob_free(dev->d_iob); + } + + netdev_iob_clear(dev); + return flags; + } + #ifdef CONFIG_NET_TIMESTAMP /* TIMESTAMP sockopt is activated, * create timestamp and copy to iob diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index 66639d42eee22..b03344bdcd10c 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -232,6 +232,19 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) if ((iob = iob_peek_queue(&conn->readahead)) != NULL && pstate->pr_buflen > 0) { + if (iob->io_flink != NULL || + iob->io_pktlen == 0 || + iob->io_offset <= 0) + { + if (iob->io_pktlen == 0 || iob->io_offset <= 0) + { + iob_free(iob); + } + + iob_remove_queue(&conn->readahead); + return 0; + } + DEBUGASSERT(iob->io_pktlen > 0); #ifdef CONFIG_NET_TIMESTAMP @@ -254,31 +267,23 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) * beginning of the I/O buffer chain. */ - if (recvlen >= iob->io_pktlen) - { - FAR struct iob_s *tmp; + /* No trimming needed since one CAN/CANFD frame can perfectly + * fit in one iob + */ - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ + FAR struct iob_s *tmp; - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); + /* Remove the I/O buffer chain from the head of the read-ahead + * buffer queue. + */ - /* And free the I/O buffer chain */ + tmp = iob_remove_queue(&conn->readahead); + DEBUGASSERT(tmp == iob); + UNUSED(tmp); - iob_free_chain(iob); - } - else - { - /* The bytes that we have received from the head of the I/O - * buffer chain (probably changing the head of the I/O - * buffer queue). - */ + /* And free the I/O buffer chain */ - iob_trimhead_queue(&conn->readahead, recvlen); - } + iob_free_chain(iob); /* do not pass frames with DLC > 8 to a legacy socket */ #if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD) diff --git a/net/devif/devif_send.c b/net/devif/devif_send.c index 943b737bbdba4..15ec735f7cfbf 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -102,7 +102,12 @@ int devif_send(FAR struct net_driver_s *dev, FAR const void *buf, /* Prepare device buffer before poll callback */ - iob_update_pktlen(dev->d_iob, offset, false); + /* if pktlen is 0, no need to update */ + + if (offset != 0) + { + iob_update_pktlen(dev->d_iob, offset, false); + } ret = iob_trycopyin(dev->d_iob, buf, len, offset, false); if (ret != len)