diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 698aa21607252..79d9afc3f1bf7 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" @@ -91,7 +91,7 @@ jobs: - name: Checkout nuttx repo uses: actions/checkout@v3 with: - repository: apache/nuttx + repository: tiiuae/nuttx ref: ${{ steps.gittargets.outputs.os_ref }} path: sources/nuttx fetch-depth: 1 @@ -101,7 +101,7 @@ jobs: - name: Checkout apps repo uses: actions/checkout@v3 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..28adffb82a5e3 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -32,7 +32,7 @@ jobs: - name: Checkout nuttx repo uses: actions/checkout@v3 with: - repository: apache/nuttx + repository: tiiuae/nuttx path: nuttx fetch-depth: 0 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/Kconfig b/arch/risc-v/Kconfig index a0ded26b0bda8..8467895753889 100644 --- a/arch/risc-v/Kconfig +++ b/arch/risc-v/Kconfig @@ -149,7 +149,6 @@ config ARCH_CHIP_MPFS select ARCH_HAVE_SPI_CS_CONTROL select ARCH_HAVE_PWM_MULTICHAN select ARCH_HAVE_S_MODE - select PMP_HAS_LIMITED_FEATURES select ONESHOT select ALARM_ARCH ---help--- @@ -321,29 +320,6 @@ config ARCH_USE_S_MODE and/or U-mode (in case of separate kernel-/userspaces). This provides an option to run the kernel in S-mode, if the target supports it. -# MPU has certain architecture dependent configurations, which are presented -# here. Default is that the full RISC-V PMP specification is supported. - -config PMP_HAS_LIMITED_FEATURES - bool - default n - -config ARCH_MPU_MIN_BLOCK_SIZE - int "Minimum MPU (PMP) block size" - default 4 if !PMP_HAS_LIMITED_FEATURES - -config ARCH_MPU_HAS_TOR - bool "PMP supports TOR" - default y if !PMP_HAS_LIMITED_FEATURES - -config ARCH_MPU_HAS_NO4 - bool "PMP supports NO4" - default y if !PMP_HAS_LIMITED_FEATURES - -config ARCH_MPU_HAS_NAPOT - bool "PMP supports NAPOT" - default y if !PMP_HAS_LIMITED_FEATURES - choice prompt "Toolchain Selection" default RISCV_TOOLCHAIN_GNU_RV64 diff --git a/arch/risc-v/src/common/Toolchain.defs b/arch/risc-v/src/common/Toolchain.defs index 9032d5a89d1c5..47fd54fca979e 100644 --- a/arch/risc-v/src/common/Toolchain.defs +++ b/arch/risc-v/src/common/Toolchain.defs @@ -133,12 +133,17 @@ endif ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG) - # Generic GNU RVG toolchain + # Generic GNU RVG toolchain, prefer to use riscv-none-elf-gcc from xPack + # if CROSSDEV is not defined. - ifeq ($(CONFIG_RISCV_TOOLCHAIN_GNU_RV32),y) - CROSSDEV ?= riscv32-unknown-elf- + ifeq ($(shell riscv-none-elf-gcc --version > /dev/null 2>&1; echo $$?), 0) + CROSSDEV ?= riscv-none-elf- else - CROSSDEV ?= riscv64-unknown-elf- + ifeq ($(CONFIG_RISCV_TOOLCHAIN_GNU_RV32),y) + CROSSDEV ?= riscv32-unknown-elf- + else + CROSSDEV ?= riscv64-unknown-elf- + endif endif # Detect cpu ISA support flags @@ -178,12 +183,14 @@ ifeq ($(CONFIG_RISCV_TOOLCHAIN),GNU_RVG) ARCHTYPE = rv64 ARCHABITYPE = lp64 LLVM_ARCHTYPE := riscv64 + # https://www.sifive.com/blog/all-aboard-part-4-risc-v-code-models + ARCHCPUFLAGS = -mcmodel=medany endif # Construct arch flags ARCHCPUEXTFLAGS = i$(ARCHRVISAM)$(ARCHRVISAA)$(ARCHRVISAF)$(ARCHRVISAD)$(ARCHRVISAC)$(ARCHRVISAZ) - ARCHCPUFLAGS = -march=$(ARCHTYPE)$(ARCHCPUEXTFLAGS) + ARCHCPUFLAGS += -march=$(ARCHTYPE)$(ARCHCPUEXTFLAGS) # Construct arch abi flags diff --git a/arch/risc-v/src/common/addrenv.h b/arch/risc-v/src/common/addrenv.h index 8cb949af314e1..7be666e84ebf0 100644 --- a/arch/risc-v/src/common/addrenv.h +++ b/arch/risc-v/src/common/addrenv.h @@ -58,7 +58,7 @@ /* User address environment end */ -#define ARCH_ADDRENV_VEND (ARCH_ADDRENV_VBASE + ARCH_ADDRENV_MAX_SIZE) +#define ARCH_ADDRENV_VEND (ARCH_ADDRENV_VBASE + ARCH_ADDRENV_MAX_SIZE - 1) /**************************************************************************** * Public Function Prototypes diff --git a/arch/risc-v/src/common/pgalloc.h b/arch/risc-v/src/common/pgalloc.h index 8619038ac7eb7..be39da0d3a0d5 100644 --- a/arch/risc-v/src/common/pgalloc.h +++ b/arch/risc-v/src/common/pgalloc.h @@ -75,6 +75,10 @@ static inline uintptr_t riscv_pgvaddr(uintptr_t paddr) { return paddr - CONFIG_ARCH_PGPOOL_PBASE + CONFIG_ARCH_PGPOOL_VBASE; } + else if (paddr >= CONFIG_RAM_START && paddr < CONFIG_RAM_END) + { + return paddr - CONFIG_RAM_START + CONFIG_RAM_VSTART; + } return 0; } @@ -95,7 +99,11 @@ static inline bool riscv_uservaddr(uintptr_t vaddr) * heap, or stack regions. */ - return vaddr >= ARCH_ADDRENV_VBASE && vaddr < ARCH_ADDRENV_VEND; + return ((vaddr >= ARCH_ADDRENV_VBASE && vaddr < ARCH_ADDRENV_VEND) +#ifdef CONFIG_ARCH_VMA_MAPPING + || (vaddr >= CONFIG_ARCH_SHM_VBASE && vaddr < ARCH_SHM_VEND) +#endif + ); } /**************************************************************************** diff --git a/arch/risc-v/src/common/riscv_addrenv.c b/arch/risc-v/src/common/riscv_addrenv.c index 685dea744e6d0..dfdcfb6aea2fb 100644 --- a/arch/risc-v/src/common/riscv_addrenv.c +++ b/arch/risc-v/src/common/riscv_addrenv.c @@ -65,6 +65,7 @@ #include #include #include +#include #include @@ -421,6 +422,12 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, heapsize = heapsize + MM_PGALIGNUP(CONFIG_DEFAULT_TASK_STACKSIZE); +#ifdef CONFIG_TLS_ALIGNED + /* Need more stack for TLS alignment */ + + heapsize += MM_PGALIGNUP(2 * TLS_MAXSTACK); +#endif + /* Map the reserved area */ ret = create_region(addrenv, resvbase, resvsize, MMU_UDATA_FLAGS); @@ -535,28 +542,24 @@ int up_addrenv_destroy(arch_addrenv_t *addrenv) { for (i = 0; i < ENTRIES_PER_PGT; i++, vaddr += pgsize) { - if (vaddr_is_shm(vaddr)) - { - /* Do not free memory from SHM area */ - - continue; - } - ptlast = (uintptr_t *)riscv_pgvaddr(mmu_pte_to_paddr(ptprev[i])); if (ptlast) { - /* Page table allocated, free any allocated memory */ - - for (j = 0; j < ENTRIES_PER_PGT; j++) + if (!vaddr_is_shm(vaddr)) { - paddr = mmu_pte_to_paddr(ptlast[j]); - if (paddr) + /* Free the allocated pages, but not from SHM area */ + + for (j = 0; j < ENTRIES_PER_PGT; j++) { - mm_pgfree(paddr, 1); + paddr = mmu_pte_to_paddr(ptlast[j]); + if (paddr) + { + mm_pgfree(paddr, 1); + } } } - /* Then free the page table itself */ + /* Regardless, free the page table itself */ mm_pgfree((uintptr_t)ptlast, 1); } diff --git a/arch/risc-v/src/common/riscv_addrenv_pgmap.c b/arch/risc-v/src/common/riscv_addrenv_pgmap.c index 9dbac8592fecc..edf9687649105 100644 --- a/arch/risc-v/src/common/riscv_addrenv_pgmap.c +++ b/arch/risc-v/src/common/riscv_addrenv_pgmap.c @@ -202,7 +202,7 @@ int up_addrenv_kmap_pages(void **pages, unsigned int npages, uintptr_t vaddr, } /**************************************************************************** - * Name: riscv_unmap_pages + * Name: up_addrenv_kunmap_pages * * Description: * Unmap a previously mapped virtual memory region. diff --git a/arch/risc-v/src/common/riscv_addrenv_utils.c b/arch/risc-v/src/common/riscv_addrenv_utils.c index 810563aedd47a..e13fb89ff9e64 100644 --- a/arch/risc-v/src/common/riscv_addrenv_utils.c +++ b/arch/risc-v/src/common/riscv_addrenv_utils.c @@ -63,13 +63,22 @@ uintptr_t riscv_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr) uintptr_t paddr; uintptr_t ptprev; uint32_t ptlevel; + uint32_t flags; /* Get the current level MAX_LEVELS-1 entry corresponding to this vaddr */ ptlevel = ARCH_SPGTS; ptprev = riscv_pgvaddr(addrenv->spgtables[ARCH_SPGTS - 1]); - paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr)); + if (!ptprev) + { + /* Something is very wrong */ + + return 0; + } + + /* Find the physical address of the final level page table */ + paddr = mmu_pte_to_paddr(mmu_ln_getentry(ptlevel, ptprev, vaddr)); if (!paddr) { /* No page table has been allocated... allocate one now */ @@ -77,10 +86,21 @@ uintptr_t riscv_get_pgtable(arch_addrenv_t *addrenv, uintptr_t vaddr) paddr = mm_pgalloc(1); if (paddr) { + /* Determine page table flags */ + + if (riscv_uservaddr(vaddr)) + { + flags = MMU_UPGT_FLAGS; + } + else + { + flags = MMU_KPGT_FLAGS; + } + /* Wipe the page and assign it */ riscv_pgwipe(paddr); - mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, MMU_UPGT_FLAGS); + mmu_ln_setentry(ptlevel, ptprev, paddr, vaddr, flags); } } diff --git a/arch/risc-v/src/common/riscv_mmu.h b/arch/risc-v/src/common/riscv_mmu.h index 0c0c6b5373749..6c9d1baebb997 100644 --- a/arch/risc-v/src/common/riscv_mmu.h +++ b/arch/risc-v/src/common/riscv_mmu.h @@ -59,6 +59,10 @@ #define MMU_IO_FLAGS (PTE_R | PTE_W | PTE_G) +/* Flags for kernel page tables */ + +#define MMU_KPGT_FLAGS (PTE_G) + /* Kernel FLASH and RAM are mapped globally */ #define MMU_KTEXT_FLAGS (PTE_R | PTE_X | PTE_G) diff --git a/arch/risc-v/src/common/riscv_pmp.c b/arch/risc-v/src/common/riscv_pmp.c index 9a19c94a39550..2f63c2596db6d 100644 --- a/arch/risc-v/src/common/riscv_pmp.c +++ b/arch/risc-v/src/common/riscv_pmp.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "riscv_internal.h" @@ -47,18 +48,6 @@ #define PMP_XLEN (64) #endif -/* Minimum supported block size */ - -#if !defined CONFIG_ARCH_MPU_MIN_BLOCK_SIZE -#define MIN_BLOCK_SIZE (PMP_XLEN / 8) -#else -#define MIN_BLOCK_SIZE CONFIG_ARCH_MPU_MIN_BLOCK_SIZE -#endif - -/* Address and block size alignment mask */ - -#define BLOCK_ALIGN_MASK (MIN_BLOCK_SIZE - 1) - #define PMP_CFG_BITS_CNT (8) #define PMP_CFG_FLAG_MASK ((uintptr_t)0xFF) @@ -101,89 +90,74 @@ typedef struct pmp_entry_s pmp_entry_t; ****************************************************************************/ /**************************************************************************** - * Name: pmp_check_addrmatch_type + * Name: pmp_check_region_attrs * * Description: - * Test if an address matching type is supported by the architecture. + * Test if the base address and size of region meet alignment requirements. * * Input Parameters: - * type - The type to test. + * base - The base address of the region. + * size - The memory length of the region. + * type - Address matching type. * * Returned Value: * true if it is, false otherwise. * ****************************************************************************/ -static bool pmp_check_addrmatch_type(uintptr_t type) +static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size, + uintptr_t type) { - /* Parameter is potentially unused */ + switch (type) + { + case PMPCFG_A_TOR: - UNUSED(type); -#ifdef CONFIG_ARCH_MPU_HAS_TOR - if (type == PMPCFG_A_TOR) - { - return true; - } + /* For TOR any size is good, but alignment requirement stands */ -#endif -#ifdef CONFIG_ARCH_MPU_HAS_NO4 - if (type == PMPCFG_A_NA4) - { - return true; - } + if ((base & 0x03) != 0) + { + return false; + } -#endif -#ifdef CONFIG_ARCH_MPU_HAS_NAPOT - if (type == PMPCFG_A_NAPOT) - { - return true; - } -#endif + break; - /* None of the supported types match */ + case PMPCFG_A_NA4: - return false; -} + /* For NA4 only size 4 is good, and base must be aligned */ -/**************************************************************************** - * Name: pmp_check_region_attrs - * - * Description: - * Test if the base address and size of region meet alignment requirements. - * - * Input Parameters: - * base - The base address of the region. - * size - The memory length of the region. - * - * Returned Value: - * true if it is, false otherwise. - * - ****************************************************************************/ + if ((base & 0x03) != 0 || size != 4) + { + return false; + } -static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size) -{ - /* Check that the size is not too small */ + break; - if (size < MIN_BLOCK_SIZE) - { - return false; - } + case PMPCFG_A_NAPOT: + { + /* For NAPOT, both base and size must be properly aligned */ - /* Check that the base address is aligned properly */ + if ((base & 0x07) != 0 || size < 8) + { + return false; + } - if ((base & BLOCK_ALIGN_MASK) != 0) - { - return false; - } + /* Get the power-of-two for size, rounded up */ - /* Check that the size is aligned properly */ + if ((base & ((UINT64_C(1) << LOG2_CEIL(size)) - 1)) != 0) + { + /* The start address is not properly aligned with size */ - if ((size & BLOCK_ALIGN_MASK) != 0) - { - return false; - } + return false; + } + } - return OK; + break; + + default: + break; + } + + return true; } /**************************************************************************** @@ -446,16 +420,9 @@ int riscv_config_pmp_region(uintptr_t region, uintptr_t attr, uintptr_t cfg = 0; uintptr_t type = (attr & PMPCFG_A_MASK); - /* Check that the architecture supports address matching type */ - - if (pmp_check_addrmatch_type(type) == false) - { - return -EINVAL; - } - /* Check the region attributes */ - if (pmp_check_region_attrs(base, size)) + if (pmp_check_region_attrs(base, size, type) == false) { return -EINVAL; } @@ -463,7 +430,7 @@ int riscv_config_pmp_region(uintptr_t region, uintptr_t attr, /* Calculate new base address from type */ addr = base >> 2; - if (PMPCFG_A_NAPOT == (attr & PMPCFG_A_MASK)) + if (type == PMPCFG_A_NAPOT) { addr |= (size - 1) >> 3; } diff --git a/arch/risc-v/src/espressif/esp_libc_stubs.c b/arch/risc-v/src/espressif/esp_libc_stubs.c index f9b6c2897d960..da6eddf4c76c0 100644 --- a/arch/risc-v/src/espressif/esp_libc_stubs.c +++ b/arch/risc-v/src/espressif/esp_libc_stubs.c @@ -243,52 +243,52 @@ void _lock_release_recursive(_lock_t *lock) #if ESP_ROM_HAS_RETARGETABLE_LOCKING void __retarget_lock_init(_LOCK_T *lock) { - _lock_init(lock); + _lock_init((_lock_t *)lock); } void __retarget_lock_init_recursive(_LOCK_T *lock) { - _lock_init_recursive(lock); + _lock_init_recursive((_lock_t *)lock); } void __retarget_lock_close(_LOCK_T lock) { - _lock_close(&lock); + _lock_close((_lock_t *)&lock); } void __retarget_lock_close_recursive(_LOCK_T lock) { - _lock_close_recursive(&lock); + _lock_close_recursive((_lock_t *)&lock); } void __retarget_lock_acquire(_LOCK_T lock) { - _lock_acquire(&lock); + _lock_acquire((_lock_t *)&lock); } void __retarget_lock_acquire_recursive(_LOCK_T lock) { - _lock_acquire_recursive(&lock); + _lock_acquire_recursive((_lock_t *)&lock); } int __retarget_lock_try_acquire(_LOCK_T lock) { - return _lock_try_acquire(&lock); + return _lock_try_acquire((_lock_t *)&lock); } int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { - return _lock_try_acquire_recursive(&lock); + return _lock_try_acquire_recursive((_lock_t *)&lock); } void __retarget_lock_release(_LOCK_T lock) { - _lock_release(&lock); + _lock_release((_lock_t *)&lock); } void __retarget_lock_release_recursive(_LOCK_T lock) { - _lock_release_recursive(&lock); + _lock_release_recursive((_lock_t *)&lock); } #endif 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..156309df1f219 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -46,6 +46,15 @@ config MPFS_BOOTLOADER ---help--- This NuttX image is used as a bootloader, which will boot only on one hart, putting the others in WFI +config MPFS_BOARD_PMP + bool "Enable board specific PMP configuration" + depends on ARCH_USE_MPU && MPFS_BOOTLOADER + default n + ---help--- + If true, the board must provide "mpfs_board_pmp_setup" for PMP + configuration. If false, set ALL memory accessible for every + configured HART. Only the bootloader should do this. + config MPFS_OPENSBI bool "Use OpenSBI" depends on MPFS_BOOTLOADER && OPENSBI @@ -243,15 +252,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 +330,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 @@ -334,6 +400,9 @@ config MPFS_EMMCSD select ARCH_HAVE_SDIO select SDIO_BLOCKSETUP select SDIO_DMA + select FAT_DMAMEMORY + select FAT_FORCE_INDIRECT + select GRAN default n ---help--- Selects the MPFS eMMCSD driver. @@ -357,6 +426,12 @@ config MPFS_COREMMC_IRQNUM range 0 63 depends on MPFS_COREMMC +config MPFS_TAMPER + bool "Tamper detection" + default n + ---help--- + Enable tamper detection mechanisms. + config MPFS_IHC_CLIENT bool "IHC slave" depends on RPTUN && !MPFS_BOOTLOADER @@ -398,7 +473,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 +526,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 +640,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 +663,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 +675,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 @@ -615,6 +765,8 @@ config MPFS_MAC_NO_BROADCAST config MPFS_MAC_AUTONEG bool "Use autonegotiation" + depends on !MPFS_ETH0_PHY_KSZ9477 + depends on !MPFS_ETH1_PHY_KSZ9477 default y ---help--- Use PHY autonegotiation to determine speed and mode @@ -633,6 +785,34 @@ config MPFS_PHYINIT ---help--- call mpfs_phy_boardinitialize() on init +config MPFS_ETH0_PHY_KSZ9477 + bool "Use ksz9477 switch as an SGMII PHY for ETH0" + default n + select NET_KSZ9477 + ---help--- + Select to use ksz9477 connected to SGMII + +config MPFS_ETH1_PHY_KSZ9477 + bool "Use ksz9477 switch as an SGMII PHY for ETH1" + default n + select NET_KSZ9477 + ---help--- + Select to use ksz9477 connected to SGMII + +config MPFS_ETH0_PHY_KSZ9477_I2C_BUS + int "Management I2C bus number for ksz9477 switch" + depends on MPFS_ETH0_PHY_KSZ9477 + default 5 + ---help--- + The i2c port number for switch management + +config MPFS_ETH1_PHY_KSZ9477_I2C_BUS + int "Management I2C bus number for ksz9477 switch" + depends on MPFS_ETH1_PHY_KSZ9477 + default 5 + ---help--- + The i2c port number for switch management + if !MPFS_MAC_AUTONEG config MPFS_MAC_ETHFD @@ -644,6 +824,7 @@ config MPFS_MAC_ETHFD choice prompt "MAC Speed" + default MPFS_MAC_ETH1000MBPS if MPFS_ETH0_PHY_KSZ9477 || MPFS_ETH1_PHY_KSZ9477 default MPFS_MAC_ETH100MBPS ---help--- If autonegotiation is not used, then you must select the fixed speed @@ -727,16 +908,12 @@ config MPFS_CORERMII_ADDRESS default 1 depends on MPFS_HAVE_CORERMII -# Override the default values for MPU / PMP parameters here - -config ARCH_MPU_MIN_BLOCK_SIZE - default 4096 - -config ARCH_MPU_HAS_TOR - default n - -config ARCH_MPU_HAS_NO4 +config MPFS_CRYPTO + bool "Enable MPFS HW crypto" default n -config ARCH_MPU_HAS_NAPOT +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..e168aa6586171 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 @@ -62,6 +62,10 @@ ifeq ($(CONFIG_MPFS_EMMCSD),y) CHIP_CSRCS += mpfs_emmcsd.c endif +ifeq ($(CONFIG_FAT_DMAMEMORY),y) +CHIP_CSRCS += mpfs_dma_alloc.c +endif + ifeq ($(CONFIG_MPFS_COREMMC),y) CHIP_CSRCS += mpfs_coremmc.c endif @@ -74,6 +78,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 +92,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 +112,10 @@ ifeq ($(CONFIG_MPFS_CORESPI),y) CHIP_CSRCS += mpfs_corespi.c endif +ifeq ($(CONFIG_MPFS_TAMPER),y) +CHIP_CSRCS += mpfs_tamper.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/hardware/mpfs_wdog.h b/arch/risc-v/src/mpfs/hardware/mpfs_wdog.h new file mode 100644 index 0000000000000..a2059e1f41958 --- /dev/null +++ b/arch/risc-v/src/mpfs/hardware/mpfs_wdog.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/hardware/mpfs_wdog.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_WDOG_H +#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_WDOG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Magic value for REFRESH register to reload watchdog countdown counter */ + +#define WDOG_REFRESH_RELOAD (0xdeadc0de) + +/* Magic value for FORCE register to perform immediate system reset */ + +#define WDOG_FORCE_IMMEDIATE_RESET (0x0c) + +/**************************************************************************** + * Register Offsets + ****************************************************************************/ + +#define MPFS_WDOG_REFRESH_OFFSET 0x000 /* Write value 0xdeadc0de to reset wdog. Read to get current count value */ +#define MPFS_WDOG_CONTROL_OFFSET 0x004 /* WDOG counter register */ +#define MPFS_WDOG_STATUS_OFFSET 0x008 /* WDOG status register */ +#define MPFS_WDOG_TIME_OFFSET 0x00C /* Set WDOG time value */ +#define MPFS_WDOG_MSVP_OFFSET 0x010 /* Set MSVP int level */ +#define MPFS_WDOG_TRIGGER_OFFSET 0x014 /* Set NMI int level */ +#define MPFS_WDOG_FORCE_OFFSET 0x018 /* Force trigger WDOG NMI seq. Writing 0xc triggers immediate reset */ + +/**************************************************************************** + * Control register masks + ****************************************************************************/ + +#define WDOG_CONTROL_INTEN_MSVP_MASK (1 << 0) /* Bit 0: Enable MVRP interrupt when MVRP level is passed */ +#define WDOG_CONTROL_INTEN_TRIG_MASK (1 << 1) /* Bit 1: Enable NMI interrupt. This bit is permanenty set */ +#define WDOG_CONTROL_INTEN_SLEEP_MASK (1 << 2) /* Bit 2: Enable MVRP interrupt when MVRP level is passed and M3 is sleeping */ +#define WDOG_CONTROL_ACTIVE_SLEEP_MASK (1 << 3) /* Bit 3: Set WDOG operational during CPU sleep */ +#define WDOG_CONTROL_ENABLE_FORBITTEN_MASK (1 << 4) /* Bit 4: Enable trigger wdog from write during forbitten window */ + +/**************************************************************************** + * Status register masks + ****************************************************************************/ + +#define WDOG_STATUS_MVRP_TRIPPED_MASK (1 << 0) /* Bit 0: MVRP level has passed. Write to clear interrupt */ +#define WDOG_STATUS_WDOG_TRIPPED_MASK (1 << 1) /* Bit 1: TRIGGER level has passed and NMI is asserted. Write to clear interrupt */ +#define WDOG_STATUS_FORBITTEN_MASK (1 << 2) /* Bit 2: Watchdog in forbitten window */ +#define WDOG_STATUS_TRIGGERED_MASK (1 << 3) /* Bit 3: Watchdog has triggered */ +#define WDOG_STATUS_LOCKED_MASK (1 << 4) /* Bit 4: Following registers are locked and cannot be changed */ +#define WDOG_STATUS_DEVRST_MASK (1 << 5) /* Bit 5: DEVRST caused NMI */ + +#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_WDOG_H */ 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_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index 43b1cacf3abe5..3e23479a5dc64 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -528,6 +528,13 @@ static uint32_t mpfs_spi_setfrequency(struct spi_dev_s *dev, DEBUGASSERT(frequency > 0); + if (priv->frequency == frequency) + { + /* Nothing changes */ + + return priv->actual; + } + if (priv->enabled) { modifyreg32(MPFS_SPI_CONTROL, MPFS_SPI_ENABLE, 0); @@ -738,54 +745,38 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s *priv, { uint16_t *data16; uint8_t *data8; - int last; int i; DEBUGASSERT(nwords > 0); data16 = (uint16_t *)txbuffer; data8 = (uint8_t *)txbuffer; - last = nwords - 1; - for (i = 0; i < nwords; i++) + if (!txbuffer) { - if (txbuffer) + for (i = 0; i < nwords - 1; i++) { - if (priv->nbits == 8) - { - if (i == last) - { - putreg32((uint32_t)data8[priv->tx_pos], MPFS_SPI_TX_LAST); - } - else - { - putreg32((uint32_t)data8[priv->tx_pos], MPFS_SPI_TX_DATA); - } - } - else - { - if (i == last) - { - putreg32((uint32_t)data16[priv->tx_pos], MPFS_SPI_TX_LAST); - } - else - { - putreg32((uint32_t)data16[priv->tx_pos], MPFS_SPI_TX_DATA); - } - } + putreg32(0, MPFS_SPI_TX_DATA); } - else + + putreg32(0, MPFS_SPI_TX_LAST); + } + else if (priv->nbits == 8) + { + for (i = 0; i < nwords - 1; i++) { - if (i == last) - { - putreg32(0, MPFS_SPI_TX_LAST); - } - else - { - putreg32(0, MPFS_SPI_TX_DATA); - } + putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_DATA); + } + + putreg32((uint32_t)data8[priv->tx_pos++], MPFS_SPI_TX_LAST); + } + else + { + for (i = 0; i < nwords - 1; i++) + { + putreg32((uint32_t)data16[priv->tx_pos++], MPFS_SPI_TX_DATA); } - priv->tx_pos++; + putreg32((uint32_t)data16[priv->tx_pos++], MPFS_SPI_TX_LAST); } } @@ -812,48 +803,40 @@ static void mpfs_spi_unload_rx_fifo(struct mpfs_spi_priv_s *priv, { uint16_t *data16; uint8_t *data8; - int last; int i; DEBUGASSERT(nwords > 0); data16 = (uint16_t *)rxbuffer; data8 = (uint8_t *)rxbuffer; - last = nwords - 1; - for (i = 0; i < nwords; i++) + if (!rxbuffer) { - /* The last character might not be available yet due to bus delays */ - - if (i == last) + modifyreg32(MPFS_SPI_COMMAND, 0, MPFS_SPI_RXFIFORST); + } + else if (priv->nbits == 8) + { + for (i = 0; i < nwords - 1; i++) { - if (mpfs_rx_wait_last_frame(priv) < 0) - { - /* Nothing came, get out */ - - return; - } + data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - if (rxbuffer) + if (mpfs_rx_wait_last_frame(priv) == 0) { - if (priv->nbits == 8) - { - data8[priv->rx_pos] = getreg32(MPFS_SPI_RX_DATA); - } - else - { - data16[priv->rx_pos] = getreg32(MPFS_SPI_RX_DATA); - } + data8[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - else + } + else if (priv->nbits == 16) + { + for (i = 0; i < nwords - 1; i++) { - getreg32(MPFS_SPI_RX_DATA); + data16[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); } - priv->rx_pos++; - - DEBUGASSERT(priv->rx_pos <= priv->rxwords); + if (mpfs_rx_wait_last_frame(priv) == 0) + { + data16[priv->rx_pos++] = getreg32(MPFS_SPI_RX_DATA); + } } } @@ -934,10 +917,6 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s *priv, MPFS_SPI_INTRXOVRFLOW | MPFS_SPI_INTTXDONE); - /* Make sure the RX interrupt is disabled */ - - modifyreg32(MPFS_SPI_CONTROL2, MPFS_SPI_INTEN_DATA_RX, 0); - if (mpfs_spi_sem_waitdone(priv) < 0) { spiinfo("Message timed out\n"); @@ -1303,22 +1282,6 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) spiinfo("irq status=%x\n", status); - if (status & MPFS_SPI_DATA_RX) - { - remaining = priv->rxwords - priv->rx_pos; - - if (remaining <= priv->fifosize) - { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, remaining); - } - else - { - mpfs_spi_unload_rx_fifo(priv, priv->rxbuf, priv->fifolevel); - } - - putreg32(MPFS_SPI_DATA_RX, MPFS_SPI_INT_CLEAR); - } - if (status & MPFS_SPI_TXDONE) { /* TX is done, we know RX is done too -> offload the RX FIFO */ @@ -1356,6 +1319,14 @@ static int mpfs_spi_irq(int cpuint, void *context, void *arg) } } + if (status & MPFS_SPI_DATA_RX) + { + /* We don't expect data RX interrupts, just reset RX FIFO */ + + modifyreg32(MPFS_SPI_COMMAND, 0, MPFS_SPI_RXFIFORST); + putreg32(MPFS_SPI_DATA_RX, MPFS_SPI_INT_CLEAR); + } + if (status & MPFS_SPI_RXCHOVRFLW) { /* Handle receive overflow */ @@ -1448,6 +1419,10 @@ static void mpfs_spi_init(struct spi_dev_s *dev) 0); modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, MPFS_SYSREG_SUBBLK_CORESPI); + /* Make sure the RX interrupt is disabled (we don't use it) */ + + modifyreg32(MPFS_SPI_CONTROL2, MPFS_SPI_INTEN_DATA_RX, 0); + /* Install some default values, mode and nbits for read back */ mpfs_spi_setfrequency(dev, config->clk_freq); diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index b2f8b368ec1d4..6f211e47cacf3 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -99,8 +99,6 @@ /* Retraining limits */ -#define ABNORMAL_RETRAIN_CA_DECREASE_COUNT 2 -#define ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT 2 #define DQ_DQS_NUM_TAPS 5 /* PLL convenience bits */ @@ -192,37 +190,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 +205,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 +271,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 +338,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 +495,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 +543,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 +795,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 +1696,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 +1716,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 +1863,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 +1887,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 +1966,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 +1994,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 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); - } + uint8_t cal_value = cal_data & 0xf; + uint8_t mask = (uint8_t)(0x1 << lane); - /* Check the result */ + /* Check if this lane is not yet done and the test passes */ - 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 +2059,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 +2986,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 +3002,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 +3077,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(); @@ -3434,15 +3404,15 @@ static int mpfs_training_addcmd(void) static int mpfs_training_verify(void) { - uint32_t low_ca_dly_count; - uint32_t decrease_count; uint32_t addcmd_status0; uint32_t addcmd_status1; uint32_t retries = MPFS_DEFAULT_RETRIES; uint32_t t_status = 0; uint32_t lane_sel; - uint32_t last; uint32_t i; + uint32_t off_taps; + uint32_t width_taps; + uint32_t gt_clk_sel; while (!(getreg32(MPFS_DDR_CSR_APB_STAT_DFI_TRAINING_COMPLETE) & 0x01) && --retries); @@ -3453,19 +3423,15 @@ static int mpfs_training_verify(void) return -ETIMEDOUT; } - for (lane_sel = 0; lane_sel < LIBERO_SETTING_DATA_LANES_USED; lane_sel++) - { - mpfs_wait_cycles(10); - - putreg32(lane_sel, MPFS_CFG_DDR_SGMII_PHY_LANE_SELECT); - mpfs_wait_cycles(10); - - /* Verify cmd address results, rejects if not acceptable */ + /* Verify cmd address results, rejects if not acceptable */ - addcmd_status0 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS0); - addcmd_status1 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS1); + addcmd_status0 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS0); + addcmd_status1 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS1); - uint32_t ca_status[8] = + if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) + { + unsigned low_ca_dly_count = 0; + uint8_t ca_status[8] = { ((addcmd_status0) & 0xff), ((addcmd_status0 >> 8) & 0xff), @@ -3477,46 +3443,40 @@ static int mpfs_training_verify(void) ((addcmd_status1 >> 24) & 0xff) }; - low_ca_dly_count = 0; - last = 0; - decrease_count = 0; + uint8_t last = ca_status[7]; + + /* Retrain if abnormal CA training result detected + * Expected result is increasing numbers, starting at index n and + * wrapping around. For example: + * [0x35, 0x3b, 0x4, 0x14, 0x1b, 0x21, 0x28, 0x2f]. + * + * Also they need to be separated by at least 5 + */ for (i = 0; i < 8; i++) { - if (ca_status[i] < 5) + if (ca_status[i] < last + 5) { low_ca_dly_count++; } - if (ca_status[i] <= last) - { - decrease_count++; - } - last = ca_status[i]; } - if (ca_status[0] <= ca_status[7]) - { - decrease_count++; - } - - if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) + if (low_ca_dly_count > 1) { - /* Retrain if abnormal CA training result detected */ + /* Retrain via reset */ - if (low_ca_dly_count > ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT) - { - t_status |= 0x01; - } + return -EIO; + } + } - /* Retrain if abnormal CA training result detected */ + for (lane_sel = 0; lane_sel < LIBERO_SETTING_DATA_LANES_USED; lane_sel++) + { + mpfs_wait_cycles(10); - if (decrease_count > ABNORMAL_RETRAIN_CA_DECREASE_COUNT) - { - t_status |= 0x01; - } - } + putreg32(lane_sel, MPFS_CFG_DDR_SGMII_PHY_LANE_SELECT); + mpfs_wait_cycles(10); /* Check that gate training passed without error */ @@ -3530,56 +3490,27 @@ static int mpfs_training_verify(void) t_status |= 0x01; } - /* Check that DQ/DQS calculated window is above 5 taps. */ + /* Check that DQ/DQS calculated window is above 5 taps + * and centered with margin + */ + + off_taps = getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1); + width_taps = getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2); - if (getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1) < DQ_DQS_NUM_TAPS) + if (width_taps < DQ_DQS_NUM_TAPS || + width_taps + off_taps <= 16 + DQ_DQS_NUM_TAPS / 2) { t_status |= 0x01; } /* Extra checks */ - uint32_t temp = 0; - uint32_t gt_clk_sel = getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL) & - 0x03; + /* Check the GT_TXDLY result for the selected clock */ - if ((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 0) - { - t_status |= 0x01; - } - } - - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 8) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 1) - { - t_status |= 0x01; - } - } + gt_clk_sel = getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL) & 0x03; - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 16) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 2) - { - t_status |= 0x01; - } - } - - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 24) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 3) - { - t_status |= 0x01; - } - } - - if (temp > 1) + if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> (gt_clk_sel * 8)) & + 0xff) == 0) { t_status |= 0x01; } @@ -3710,29 +3641,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 +3695,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 +3707,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_dma_alloc.c b/arch/risc-v/src/mpfs/mpfs_dma_alloc.c new file mode 100644 index 0000000000000..3dbfcd9863a36 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_dma_alloc.c @@ -0,0 +1,94 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_dma_alloc.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 + +#if defined(CONFIG_FAT_DMAMEMORY) && defined(CONFIG_GRAN) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define MPFS_DMA_ALLOC_POOL_SIZE (8*512) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static GRAN_HANDLE dma_allocator; + +/* The DMA heap size constrains the total number of things that can be + * ready to do DMA at a time. + * + * For example, FAT DMA depends on one sector-sized buffer per filesystem + * plus one sector-sized buffer per file. + * + * We use a fundamental alignment / granule size of 64B; it fulfills the + * requirement for any DMA engine. + */ + +static uint8_t g_dma_heap[MPFS_DMA_ALLOC_POOL_SIZE] aligned_data(64); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_dma_alloc + * + * Description: + * All boards may optionally provide this API to instantiate a pool of + * memory for uses with FAST FS DMA operations. + * + ****************************************************************************/ + +int mpfs_dma_alloc_init(void) +{ + /* Allocate 128B granules with 64B alignment */ + + dma_allocator = gran_initialize(g_dma_heap, sizeof(g_dma_heap), 7, 6); + + if (dma_allocator == NULL) + { + return -ENOMEM; + } + + return OK; +} + +void *fat_dma_alloc(size_t size) +{ + return gran_alloc(dma_allocator, size); +} + +void fat_dma_free(void *memory, size_t size) +{ + gran_free(dma_allocator, memory, size); +} + +#endif /* CONFIG_FAT_DMAMEMORY && CONFIG_GRAN */ diff --git a/arch/risc-v/src/mpfs/mpfs_dma_alloc.h b/arch/risc-v/src/mpfs/mpfs_dma_alloc.h new file mode 100644 index 0000000000000..2ed3198b6459c --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_dma_alloc.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_dma_alloc.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_RISC_V_SRC_MPFS_MPFS_DMA_ALLOC_H +#define __ARCH_RISC_V_SRC_MPFS_MPFS_DMA_ALLOC_H + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_dma_alloc + * + * Description: + * All boards may optionally provide this API to instantiate a pool of + * memory for uses with FAST FS DMA operations. + * + ****************************************************************************/ + +int mpfs_dma_alloc_init(void); + +#endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_DMA_ALLOC_H */ 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..ef6cbbd337dbf 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); + } } /**************************************************************************** @@ -2208,7 +2280,11 @@ static int mpfs_dmarecvsetup(struct sdio_dev_s *dev, mcinfo("Receive: %zu bytes\n", buflen); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uintptr_t)buffer & 3) == 0); + if (((uintptr_t)buffer & 3) != 0) + { + mcerr("Unaligned buffer: %p\n", buffer); + return -EFAULT; + } priv->buffer = (uint32_t *)buffer; priv->remaining = buflen; @@ -2268,7 +2344,11 @@ static int mpfs_dmasendsetup(struct sdio_dev_s *dev, mcinfo("Send: %zu bytes\n", buflen); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uintptr_t)buffer & 3) == 0); + if (((uintptr_t)buffer & 3) != 0) + { + mcerr("Unaligned buffer: %p\n", buffer); + return -EFAULT; + } /* DMA send doesn't work in 0x08xxxxxxx address range. Default to IRQ mode * in this special case. diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.c b/arch/risc-v/src/mpfs/mpfs_entrypoints.c index 44fe89f7117f0..fdcbc1a3b4d56 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.c +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.c @@ -33,6 +33,8 @@ #include +#include "riscv_internal.h" + /**************************************************************************** * Extern Function Declarations ****************************************************************************/ @@ -43,8 +45,13 @@ extern void mpfs_opensbi_prepare_hart(void); * Pre-processor Definitions ****************************************************************************/ +#define ENTRY_STACK 512 #define ENTRYPT_CNT sizeof(g_app_entrypoints) / sizeof(g_app_entrypoints[0]) +/* Default PMP permissions */ + +#define PMP_DEFAULT_PERM (PMPCFG_A_NAPOT | PMPCFG_R | PMPCFG_W | PMPCFG_X) + /**************************************************************************** * Private Data ****************************************************************************/ @@ -78,6 +85,11 @@ static uint64_t g_hart_use_sbi = #endif 0; +#ifdef CONFIG_MPFS_BOARD_PMP +uint8_t g_mpfs_boot_stacks[ENTRY_STACK * ENTRYPT_CNT] + aligned_data(STACK_ALIGNMENT); +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -88,17 +100,41 @@ void mpfs_jump_to_app(void) __asm__ __volatile__ ( "csrr a0, mhartid\n" /* Hart ID */ +#ifdef CONFIG_MPFS_BOARD_PMP + "li t1, %0\n" /* Size of hart's stack */ + "mul t0, a0, t1\n" /* Hart stack base */ + "add t0, t0, t1\n" /* Hart stack top */ + "la sp, g_mpfs_boot_stacks\n" /* Stack area base */ + "add sp, sp, t0\n" /* Set stack pointer */ + "call mpfs_board_pmp_setup\n" /* Run PMP configuration */ + "csrr a0, mhartid\n" /* Restore hartid */ +#else + "li t0, -1\n" /* Open the whole SoC */ + "csrw pmpaddr0, t0\n" + "li t0, %0\n" /* Grant RWX permissions */ + "csrw pmpcfg0, t0\n" + "csrw pmpcfg2, zero\n" +#endif #ifdef CONFIG_MPFS_OPENSBI "ld t0, g_hart_use_sbi\n" /* Load sbi usage bitmask */ "srl t0, t0, a0\n" /* Shift right by this hart */ "andi t0, t0, 1\n" /* Check the 0 bit */ - "bgtz t0, mpfs_opensbi_prepare_hart\n" /* If bit was 1, jump to sbi */ + "beqz t0, 1f\n" /* If bit was 1, jump to sbi */ + "tail mpfs_opensbi_prepare_hart\n" + "1:\n" #endif "slli t1, a0, 3\n" /* To entrypoint offset */ "la t0, g_app_entrypoints\n" /* Entrypoint table base */ "add t0, t0, t1\n" /* Index in table */ "ld t0, 0(t0)\n" /* Load the address from table */ "jr t0\n" /* Jump to entrypoint */ + : +#ifdef CONFIG_MPFS_BOARD_PMP + : "i" (ENTRY_STACK) +#else + : "i" (PMP_DEFAULT_PERM) +#endif + : ); } @@ -185,4 +221,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..c15d83c4cec87 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -50,9 +50,31 @@ # include #endif +#include + #include "riscv_internal.h" #include "mpfs_memorymap.h" #include "mpfs_ethernet.h" +#include "mpfs_dsn.h" +#include "mpfs_i2c.h" + +#if defined(CONFIG_MPFS_ETH0_PHY_KSZ9477) ||\ + defined(CONFIG_MPFS_ETH1_PHY_KSZ9477) +# if !defined(CONFIG_MPFS_MAC_SGMII) +# error Using KSZ9477 as a PHY requires CONFIG_MPFS_MAC_SGMII to be set +# endif + +# define ETH_HAS_KSZ_SWITCH + +# ifdef CONFIG_MPFS_ETH0_PHY_KSZ9477 +# define ETH_PHY_KSZ9477_I2C_BUS CONFIG_MPFS_ETH0_PHY_KSZ9477_I2C_BUS +# else +# define ETH_PHY_KSZ9477_I2C_BUS CONFIG_MPFS_ETH1_PHY_KSZ9477_I2C_BUS +# endif + +#else +# define ETH_HAS_MDIO_PHY +#endif #if defined(CONFIG_NET) && defined(CONFIG_MPFS_ETHMAC) @@ -89,7 +111,7 @@ # endif #endif -#ifndef CONFIG_MPFS_PHYADDR +#if defined(ETH_HAS_MDIO_PHY) && !defined(CONFIG_MPFS_PHYADDR) # error "CONFIG_MPFS_PHYADDR must be defined in the NuttX configuration" #endif @@ -155,6 +177,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) @@ -248,8 +274,11 @@ struct mpfs_ethmac_s irq_t mac_q_int[MPFS_MAC_QUEUE_COUNT]; /* irq numbers */ uint8_t ifup : 1; /* true:ifup false:ifdown */ uint8_t intf; /* Ethernet interface number */ +#ifdef ETH_HAS_MDIO_PHY uint8_t phyaddr; /* PHY address */ +#endif 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 */ @@ -332,10 +361,13 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); /* PHY Initialization */ +static int mpfs_phyinit(struct mpfs_ethmac_s *priv); + +#ifdef ETH_HAS_MDIO_PHY + static void mpfs_enablemdio(struct mpfs_ethmac_s *priv); static void mpfs_disablemdio(struct mpfs_ethmac_s *priv); static int mpfs_phyreset(struct mpfs_ethmac_s *priv); -static int mpfs_phyinit(struct mpfs_ethmac_s *priv); static int mpfs_phyread(struct mpfs_ethmac_s *priv, uint8_t phyaddr, uint8_t regaddr, uint16_t *phyval); static int mpfs_phywrite(struct mpfs_ethmac_s *priv, uint8_t phyaddr, @@ -344,16 +376,21 @@ static int mpfs_phywait(struct mpfs_ethmac_s *priv); static int mpfs_phyfind(struct mpfs_ethmac_s *priv, uint8_t *phyaddr); #ifdef CONFIG_MPFS_MAC_AUTONEG static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv); -#else -static void mpfs_linkspeed(struct mpfs_ethmac_s *priv); #endif -#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_INFO) +#endif /* ETH_HAS_MDIO_PHY */ + +#if defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_INFO) && \ + defined(ETH_HAS_MDIO_PHY) static void mpfs_phydump(struct mpfs_ethmac_s *priv); #else # define mpfs_phydump(priv) #endif +#ifndef CONFIG_MPFS_MAC_AUTONEG +static void mpfs_linkspeed(struct mpfs_ethmac_s *priv); +#endif + /* MAC/DMA Initialization */ static void mpfs_txreset(struct mpfs_ethmac_s *priv); @@ -366,6 +403,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 +485,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 +1092,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 +1133,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(); @@ -1149,6 +1194,13 @@ static void mpfs_txreset(struct mpfs_ethmac_s *priv) priv->queue[qi].txhead = 0; priv->queue[qi].txtail = 0; + if (!txdesc || !txbuffer) + { + /* The queue index is not set up */ + + continue; + } + for (ndx = 0; ndx < CONFIG_MPFS_ETHMAC_NTXBUFFERS; ndx++) { bufaddr = (uintptr_t)&txbuffer[ndx * GMAC_TX_UNITSIZE]; @@ -1224,6 +1276,13 @@ static void mpfs_rxreset(struct mpfs_ethmac_s *priv) rxdesc = priv->queue[qi].rx_desc_tab; priv->queue[qi].rxndx = 0; + if (!rxdesc || !rxbuffer) + { + /* The queue index is not set up */ + + continue; + } + for (ndx = 0; ndx < CONFIG_MPFS_ETHMAC_NRXBUFFERS; ndx++) { bufaddr = (uintptr_t)&rxbuffer[ndx * GMAC_RX_UNITSIZE]; @@ -1483,7 +1542,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 +1587,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 +1637,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. @@ -1848,6 +1918,8 @@ static int mpfs_rmmac(struct net_driver_s *dev, const uint8_t *mac) } #endif +#ifdef ETH_HAS_MDIO_PHY + /**************************************************************************** * Function: mpfs_enablemdio * @@ -2478,6 +2550,8 @@ static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv) } #endif +#endif /* ETH_HAS_MDIO_PHY */ + /**************************************************************************** * Function: mpfs_linkspeed * @@ -2493,7 +2567,7 @@ static int mpfs_autonegotiate(struct mpfs_ethmac_s *priv) * ****************************************************************************/ -#ifndef CONFIG_MPFS_MAC_AUTONEG +#if !defined(CONFIG_MPFS_MAC_AUTONEG) || !defined(ETH_HAS_MDIO_PHY) static void mpfs_linkspeed(struct mpfs_ethmac_s *priv) { uint32_t regval; @@ -2569,7 +2643,7 @@ static void mpfs_linkspeed(struct mpfs_ethmac_s *priv) #ifdef CONFIG_NETDEV_IOCTL static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) { -#ifdef CONFIG_NETDEV_PHY_IOCTL +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(ETH_HAS_MDIO_PHY) struct mpfs_ethmac_s *priv = (struct mpfs_ethmac_s *)dev->d_private; #endif int ret; @@ -2577,6 +2651,7 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) switch (cmd) { #ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef ETH_HAS_MDIO_PHY #ifdef CONFIG_ARCH_PHY_INTERRUPT case SIOCMIINOTIFY: /* Set up for PHY event notifications */ { @@ -2640,6 +2715,7 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) mpfs_disablemdio(priv); } break; +#endif /* ETH_HAS_MDIO_PHY */ #endif /* CONFIG_NETDEV_PHY_IOCTL */ default: @@ -2754,10 +2830,10 @@ static void mpfs_buffer_free(struct mpfs_ethmac_s *priv, unsigned int queue) #ifndef CONFIG_MPFS_GMAC_PREALLOCATE /* Free allocated buffers */ - if (priv->queue[queue].rx_desc_tab != NULL) + if (priv->queue[queue].tx_desc_tab != NULL) { - kmm_free(priv->queue[queue].rx_desc_tab); - priv->queue[queue].rx_desc_tab = NULL; + kmm_free(priv->queue[queue].tx_desc_tab); + priv->queue[queue].tx_desc_tab = NULL; } if (priv->queue[queue].rx_desc_tab != NULL) @@ -2772,10 +2848,10 @@ static void mpfs_buffer_free(struct mpfs_ethmac_s *priv, unsigned int queue) priv->queue[queue].txbuffer = NULL; } - if (priv->queue[queue].txbuffer != NULL) + if (priv->queue[queue].rxbuffer != NULL) { - kmm_free(priv->queue[queue].txbuffer); - priv->queue[queue].txbuffer = NULL; + kmm_free(priv->queue[queue].rxbuffer); + priv->queue[queue].rxbuffer = NULL; } #endif } @@ -3214,6 +3290,8 @@ static int mpfs_macenable(struct mpfs_ethmac_s *priv) * ****************************************************************************/ +#ifdef ETH_HAS_MDIO_PHY + static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) { uint32_t ncfgr; @@ -3268,6 +3346,8 @@ static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) mac_putreg(priv, NETWORK_CONTROL, ncr); } +#endif + /**************************************************************************** * Function: mpfs_phyinit * @@ -3284,7 +3364,9 @@ static void mpfs_mdcclock(struct mpfs_ethmac_s *priv) static int mpfs_phyinit(struct mpfs_ethmac_s *priv) { - int ret; + int ret = -EINVAL; + +#ifdef ETH_HAS_MDIO_PHY /* Configure PHY clocking */ @@ -3303,7 +3385,20 @@ static int mpfs_phyinit(struct mpfs_ethmac_s *priv) /* We have a PHY address. Reset the PHY */ mpfs_phyreset(priv); - return OK; + +#elif defined(ETH_HAS_KSZ_SWITCH) + struct i2c_master_s *bus; + + bus = mpfs_i2cbus_initialize(ETH_PHY_KSZ9477_I2C_BUS); + + if (bus) + { + ret = ksz9477_i2c_init(bus, KSZ9477_PORT_SGMII); + } + +#endif + + return ret; } /**************************************************************************** @@ -3322,6 +3417,8 @@ static int mpfs_phyinit(struct mpfs_ethmac_s *priv) * ****************************************************************************/ +#ifdef ETH_HAS_MDIO_PHY + static int mpfs_phyreset(struct mpfs_ethmac_s *priv) { uint16_t mcr; @@ -3391,6 +3488,8 @@ static int mpfs_phyreset(struct mpfs_ethmac_s *priv) return ret; } +#endif + /**************************************************************************** * Function: mpfs_ethconfig * @@ -3543,6 +3642,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..50dd2709226d4 100644 --- a/arch/risc-v/src/mpfs/mpfs_head.S +++ b/arch/risc-v/src/mpfs/mpfs_head.S @@ -129,6 +129,10 @@ __start: .option pop #ifdef CONFIG_MPFS_BOOTLOADER + /* Clear PMP */ + + csrw pmpcfg0, zero + csrw pmpcfg2, zero /* Set all but the boot hart into wfi */ @@ -166,10 +170,15 @@ __start: .continue_boot: - /* Clear PMP */ + /* L2 needs to be zeroed before ECC (error correction) is enabled later. */ - csrw pmpcfg0, zero - csrw pmpcfg2, zero + la a4, __l2lim_start + la a5, __l2lim_end + +.clear_l2lim: + sd x0, 0(a4) + add a4, a4, 8 + blt a4, a5, .clear_l2lim #endif /* Set stack pointer to the idle thread stack */ diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 0f760820c0a3e..35701ae5d491b 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -68,6 +68,11 @@ #define MPFS_I2C_DATA (priv->hw_base + MPFS_I2C_DATA_OFFSET) #define MPFS_I2C_ADDR (priv->hw_base + MPFS_I2C_SLAVE0ADR_OFFSET) +/* Gives TTOA in microseconds, ~4.8% bias, +1 rounds up */ + +#define I2C_TTOA_US(n, f) ((((n) << 20) / (f)) + 1) +#define I2C_TTOA_MARGIN 20 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -143,6 +148,7 @@ struct mpfs_i2c_priv_s uint32_t frequency; /* Current I2C frequency */ uint8_t msgid; /* Current message ID */ + uint8_t msgc; /* Message count */ ssize_t bytes; /* Processed data bytes */ uint8_t ser_address; /* Own i2c address */ @@ -163,6 +169,7 @@ struct mpfs_i2c_priv_s bool initialized; /* Bus initialization status */ bool fpga; /* FPGA i2c */ + bool inflight; /* Transfer ongoing */ }; #ifndef CONFIG_MPFS_COREI2C @@ -267,6 +274,7 @@ static struct mpfs_i2c_priv_s static int mpfs_i2c_setfrequency(struct mpfs_i2c_priv_s *priv, uint32_t frequency); +static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv); /**************************************************************************** * Private Functions @@ -399,7 +407,8 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv) static int mpfs_i2c_sem_waitdone(struct mpfs_i2c_priv_s *priv) { - return nxsem_tickwait_uninterruptible(&priv->sem_isr, SEC2TICK(1)); + uint32_t timeout = mpfs_i2c_timeout(priv->msgc, priv->msgv); + return nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout)); } /**************************************************************************** @@ -447,6 +456,8 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) { priv->tx_idx = 0u; } + + priv->inflight = true; break; case MPFS_I2C_ST_LOST_ARB: @@ -479,9 +490,12 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) clear_irq = 0u; modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STA_MASK); - /* Jump to the next message */ + /* Jump to the next message */ - priv->msgid++; + if (priv->msgid < (priv->msgc - 1)) + { + priv->msgid++; + } } else { @@ -498,9 +512,12 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) clear_irq = 0u; modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STA_MASK); - /* Jump to the next message */ + /* Jump to the next message */ - priv->msgid++; + if (priv->msgid < (priv->msgc - 1)) + { + priv->msgid++; + } } else { @@ -566,12 +583,33 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) break; case MPFS_I2C_ST_IDLE: - case MPFS_I2C_ST_STOP_SENT: /* No activity, bus idle */ break; + case MPFS_I2C_ST_STOP_SENT: + + /* FPGA driver terminates all transactions with STOP sent irq + * if there has been no errors, the transfer succeeded. + * Due to the IP bug that extra data & STOPs can be sent after + * the actual transaction, filter out any extra stops with + * priv->inflight flag + */ + + if (priv->inflight) + { + if (priv->status == MPFS_I2C_IN_PROGRESS) + { + priv->status = MPFS_I2C_SUCCESS; + } + + nxsem_post(&priv->sem_isr); + } + + priv->inflight = false; + break; + case MPFS_I2C_ST_RESET_ACTIVATED: case MPFS_I2C_ST_BUS_ERROR: /* Bus errors */ default: @@ -586,31 +624,12 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) break; } - if (priv->fpga) - { - /* FPGA driver terminates all transactions with STOP sent irq */ + if (!priv->fpga && priv->status != MPFS_I2C_IN_PROGRESS) + { + /* MSS I2C has no STOP sent irq */ - if (status == MPFS_I2C_ST_STOP_SENT) - { - /* Don't post on a new request, STOPs possible initially */ - - if (!((priv->rx_idx == 0 && priv->rx_size > 0) || - (priv->tx_idx == 0 && priv->tx_size > 0))) - { - nxsem_post(&priv->sem_isr); - } - else if (priv->status == MPFS_I2C_FAILED) - { - nxsem_post(&priv->sem_isr); - } - } - } - else if (priv->status != MPFS_I2C_IN_PROGRESS) - { - /* MSS I2C has no STOP SENT irq */ - - nxsem_post(&priv->sem_isr); - } + nxsem_post(&priv->sem_isr); + } if (clear_irq) { @@ -642,7 +661,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) static void mpfs_i2c_sendstart(struct mpfs_i2c_priv_s *priv) { up_enable_irq(priv->plic_irq); - modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_STA_MASK, MPFS_I2C_CTRL_STA_MASK); + modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STA_MASK); } static int mpfs_i2c_transfer(struct i2c_master_s *dev, @@ -661,12 +680,8 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, return ret; } - if (priv->status != MPFS_I2C_SUCCESS) - { - priv->status = MPFS_I2C_SUCCESS; - } - priv->msgv = msgs; + priv->msgc = count; for (int i = 0; i < count; i++) { @@ -728,6 +743,7 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, if (mpfs_i2c_sem_waitdone(priv) < 0) { i2cinfo("Message %" PRIu8 " timed out.\n", priv->msgid); + priv->inflight = false; ret = -ETIMEDOUT; break; } @@ -741,7 +757,6 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, } else { - priv->status = MPFS_I2C_SUCCESS; ret = OK; } } @@ -784,6 +799,8 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev) up_disable_irq(priv->plic_irq); + priv->inflight = false; + priv->status = MPFS_I2C_SUCCESS; priv->initialized = false; ret = mpfs_i2c_init(priv); @@ -884,6 +901,37 @@ static int mpfs_i2c_setfrequency(struct mpfs_i2c_priv_s *priv, return OK; } +/**************************************************************************** + * Name: mpfs_i2c_timeout + * + * Description: + * Calculate the time a full I2C transaction (message vector) will take + * to transmit, used for bus timeout. + * + * Input Parameters: + * msgc - Message count in message vector + * msgv - Message vector containing the messages to send + * + * Returned Value: + * I2C transaction timeout in microseconds (with some margin) + * + ****************************************************************************/ + +static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv) +{ + uint32_t usec = 0; + int i; + + for (i = 0; i < msgc; i++) + { + /* start + stop + address is 12 bits, each byte is 9 bits */ + + usec += I2C_TTOA_US(12 + msgv[i].length * 9, msgv[i].frequency); + } + + return usec + I2C_TTOA_MARGIN; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/arch/risc-v/src/mpfs/mpfs_ihc.c b/arch/risc-v/src/mpfs/mpfs_ihc.c index 02bd8a2182692..3310f6070153e 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,77 @@ 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 */ + uint32_t msg = message[0]; + + /* After a warm reboot, the message may be initially corrupt as the renote + * doesn't know we restarted and reinitialized the registers. + */ - nxsem_post(&g_mpfs_ack_sig); + if ((msg == VRING0_NOTIFYID) || (msg == VRING1_NOTIFYID)) + { + g_vq_idx = msg; } else { - g_vq_idx = (message[0] >> 16); + return; + } + +#ifdef MPFS_RPTUN_USE_THREAD + nxsem_post(&g_mpfs_rx_sig); +#else + work_queue(HPWORK, &g_rptun_work, mpfs_rptun_worker, NULL, 0); +#endif +} - DEBUGASSERT((g_vq_idx == VRING0_NOTIFYID) || - (g_vq_idx == VRING1_NOTIFYID)); +/**************************************************************************** + * 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 + * + ****************************************************************************/ - nxsem_post(&g_mpfs_rx_sig); +#ifdef IHC_AVOID_ACK_AND_MP +static void mpfs_ihc_worker(void *arg) +{ + uint32_t ctrl_reg; + uint32_t retries = 5000; + + 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 +523,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 +531,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 +600,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 +625,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 +726,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 +766,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 +774,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 +783,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,17 +908,19 @@ 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 */ + /* If the master is up already, don't clear the status here */ - rsc->rpmsg_vdev.status = 0; + if (!g_shmem.master_up) + { + rsc->rpmsg_vdev.status = 0; + } rsc->rpmsg_vdev.config_len = sizeof(struct fw_rsc_config); rsc->rpmsg_vdev.num_of_vrings = VRINGS; @@ -977,18 +1045,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 +1219,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 +1228,40 @@ 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; + + /* Check whether the struct is initialized yet */ + + if (*(uintptr_t *)&g_mpfs_virtqueue_table[0] == 0) + { + return; + } + + 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,12 +1279,20 @@ 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; while (1) { + /* Check whether the struct is initialized yet */ + + if (*(uintptr_t *)&g_mpfs_virtqueue_table[0] == 0) + { + return 0; + } + DEBUGASSERT((g_vq_idx - VRING0_NOTIFYID) < VRINGS); info = &g_mpfs_virtqueue_table[g_vq_idx - VRING0_NOTIFYID]; virtqueue_notification((struct virtqueue *)info->data); @@ -1183,6 +1302,7 @@ static int mpfs_rptun_thread(int argc, char *argv[]) return 0; } +#endif /**************************************************************************** * Public Functions @@ -1208,8 +1328,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; @@ -1254,7 +1376,25 @@ int mpfs_ihc_init(void) /* Initialize and wait for the master. This will block until. */ ihcinfo("Waiting for the master online...\n"); + + /* Check if the remote is already up. This is the case after reboot of + * this particular hart only. + */ + + if ((getreg32(MPFS_IHC_CTRL(CONTEXTA_HARTID, CONTEXTB_HARTID)) & (MPIE_EN + | ACKIE_EN)) != 0) + { + g_shmem.master_up = true; + g_shmem.rsc.rpmsg_vdev.status |= VIRTIO_CONFIG_STATUS_DRIVER_OK; + } + 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 +1407,8 @@ int mpfs_ihc_init(void) goto init_error; } +#ifdef MPFS_RPTUN_USE_THREAD + /* Thread initialization */ snprintf(arg1, sizeof(arg1), "%p", @@ -1284,6 +1426,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..90f6995e85520 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 ****************************************************************************/ @@ -56,9 +75,6 @@ #define MPFS_ACLINT_MSWI_ADDR MPFS_CLINT_MSIP0 #define MPFS_ACLINT_MTIMER_ADDR MPFS_CLINT_MTIMECMP0 -#define MPFS_PMP_DEFAULT_ADDR 0xfffffffff -#define MPFS_PMP_DEFAULT_PERM 0x000000009f - #define MPFS_SYSREG_SOFT_RESET_CR (MPFS_SYSREG_BASE + \ MPFS_SYSREG_SOFT_RESET_CR_OFFSET) #define MPFS_SYSREG_SUBBLK_CLOCK_CR (MPFS_SYSREG_BASE + \ @@ -87,6 +103,10 @@ typedef struct sbi_scratch_holder_s sbi_scratch_holder_t; extern const uint8_t __mpfs_nuttx_start[]; extern const uint8_t __mpfs_nuttx_end[]; +extern const uint8_t _ssbi_zerodev[]; +extern const uint8_t _esbi_zerodev[]; +extern const uint8_t _sbi_heap_start[]; +extern const uint8_t _sbi_heap_size[]; /**************************************************************************** * Private Function Prototypes @@ -99,8 +119,8 @@ static int mpfs_irqchip_init(bool cold_boot); static int mpfs_ipi_init(bool cold_boot); static int mpfs_timer_init(bool cold_boot); #ifdef CONFIG_MPFS_IHC_SBI -static int mpfs_opensbi_vendor_ext_check(long extid); -static int mpfs_opensbi_ecall_handler(long extid, long funcid, +static bool mpfs_opensbi_vendor_ext_check(void); +static int mpfs_opensbi_ecall_handler(long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap); @@ -151,7 +171,7 @@ static struct aclint_mtimer_data mpfs_mtimer = .mtimecmp_size = ACLINT_DEFAULT_MTIMECMP_SIZE, .first_hartid = 0, .hart_count = MPFS_HART_COUNT, - .has_64bit_mmio = TRUE, + .has_64bit_mmio = true, }; static const struct sbi_platform_operations platform_ops = @@ -185,30 +205,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 = { @@ -475,48 +472,71 @@ static void mpfs_opensbi_scratch_setup(uint32_t hartid) (unsigned long)mpfs_hart_to_scratch; g_scratches[hartid].scratch.platform_addr = (unsigned long)&platform; - /* Our FW area in l2lim section. OpenSBI needs to be aware of it in order - * to protect the area. However, we set the PMP values already and lock - * them so that OpenSBI has no chance override then. + /* Our FW area, heap and the scratch area are in l2lim. + * + * The memory is organized as follows: + * + * ---------------------------------------------------------------------- + * | | | | + * | SBI .text (0000h) | SBI heap (8000h) | SBI scratch (8000h + 4000h) | + * | | | | + * ---------------------------------------------------------------------- + * + * The reason for this organization is that the RX and RW areas can be set + * to the physical memory protection unit (PMP) as two contiguous areas. */ - g_scratches[hartid].scratch.fw_start = (unsigned long)__mpfs_nuttx_start; - g_scratches[hartid].scratch.fw_size = (unsigned long)__mpfs_nuttx_end - - (unsigned long)__mpfs_nuttx_start; -} + g_scratches[hartid].scratch.fw_start = (unsigned long)_ssbi_zerodev; + g_scratches[hartid].scratch.fw_size = (unsigned long)_esbi_zerodev - + (unsigned long)_ssbi_zerodev; -/**************************************************************************** - * Name: mpfs_opensbi_pmp_setup - * - * Description: - * Initializes the PMP registers in a known default state. All harts need - * to set these registers. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ + /* RW area starts from the heap */ -static void mpfs_opensbi_pmp_setup(void) -{ - /* All access granted */ + g_scratches[hartid].scratch.fw_heap_offset = + (unsigned long)_sbi_heap_start - + (unsigned long)g_scratches[hartid].scratch.fw_start; + + g_scratches[hartid].scratch.fw_heap_size = + (unsigned long)_sbi_heap_size; + + g_scratches[hartid].scratch.fw_rw_offset = + g_scratches[hartid].scratch.fw_heap_offset; - csr_write(pmpaddr0, MPFS_PMP_DEFAULT_ADDR); - csr_write(pmpcfg0, MPFS_PMP_DEFAULT_PERM); - csr_write(pmpcfg2, 0); + /* Because sbi_heap_init does not work otherwise */ + + g_scratches[hartid].scratch.fw_size = + g_scratches[hartid].scratch.fw_heap_offset + + g_scratches[hartid].scratch.fw_heap_size; + + /* Heap minimum is 16k. Otherwise sbi_heap.c fails: + * hpctrl.hksize = hpctrl.size / HEAP_HOUSEKEEPING_FACTOR; + * hpctrl.hksize &= ~((unsigned long)HEAP_BASE_ALIGN - 1); + * eg. 8k: (0x2000 / 16) & ~(1024 - 1) = 0 (Fail!) + * 16k: (0x4000 / 16) & ~(1024 - 1) = 0x400 (Ok) + * hpctrl.hksize gets to be zero making the OpenSBI crash. + */ + + if (g_scratches[hartid].scratch.fw_heap_size < 0x4000) + { + sbi_panic(__func__); + } + + /* fw_rw_offset needs to be an aligned address */ + + if (g_scratches[hartid].scratch.fw_rw_offset & 0x7ff) + { + sbi_panic(__func__); + } } /**************************************************************************** * Name: mpfs_opensbi_vendor_ext_check * * Description: - * Used by the OpenSBI in vendor probe to check the vendor ID. + * Used by the OpenSBI to check if vendor extension is enabled. * * Input Parameters: - * extid - Vendor ID to be checked + * None * * Returned Value: * 1 on match, zero in case of no match @@ -524,9 +544,9 @@ static void mpfs_opensbi_pmp_setup(void) ****************************************************************************/ #ifdef CONFIG_MPFS_IHC_SBI -static int mpfs_opensbi_vendor_ext_check(long extid) +static bool mpfs_opensbi_vendor_ext_check(void) { - return (SBI_EXT_MICROCHIP_TECHNOLOGY == extid); + return true; } /**************************************************************************** @@ -537,7 +557,6 @@ static int mpfs_opensbi_vendor_ext_check(long extid) * related to Inter-Hart Communication (IHC). * * Input Parameters: - * extid - Vendor ID * funcid - One of the valid functions * sbi_trap_regs - SBI trap registers * out_val - Error code location @@ -548,7 +567,7 @@ static int mpfs_opensbi_vendor_ext_check(long extid) * ****************************************************************************/ -static int mpfs_opensbi_ecall_handler(long extid, long funcid, +static int mpfs_opensbi_ecall_handler(long funcid, const struct sbi_trap_regs *regs, unsigned long *out_val, struct sbi_trap_info *out_trap) @@ -602,8 +621,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; - mpfs_opensbi_pmp_setup(); + 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; + } sbi_console_set_device(&mpfs_console); mpfs_opensbi_scratch_setup(hartid); 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..9064a1f060c4d 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: @@ -1027,6 +1355,13 @@ static void up_send(struct uart_dev_s *dev, int ch) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; +#ifdef HAVE_SERIAL_CONSOLE + if (dev == &CONSOLE_DEV && !dev->isconsole) + { + return; + } +#endif + while ((up_serialin(priv, MPFS_UART_LSR_OFFSET) & UART_LSR_THRE) == 0); @@ -1140,6 +1475,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 +1530,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 } /**************************************************************************** @@ -1198,6 +1554,12 @@ int up_putc(int ch) #ifdef HAVE_SERIAL_CONSOLE struct up_dev_s *priv = (struct up_dev_s *)CONSOLE_DEV.priv; uint32_t ier; + + if (!CONSOLE_DEV.isconsole) + { + return ch; + } + up_disableuartint(priv, &ier); #endif diff --git a/arch/risc-v/src/mpfs/mpfs_tamper.c b/arch/risc-v/src/mpfs/mpfs_tamper.c new file mode 100644 index 0000000000000..0a268a722f2f5 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_tamper.c @@ -0,0 +1,390 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_tamper.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 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register base-addresses */ + +#define MPFS_TAMPER_CTRL_BASE 0x4b00c000 +#define MPFS_TAMPER_TVS_BASE 0x4b00d000 + +/* CTRL Register offsets */ + +#define MPFS_SELECTED_EVENTS_OFFSET 0x00 +#define MPFS_STATUS_EVENTS_OFFSET 0x04 +#define MPFS_CLEAR_EVENTS_OFFSET 0x08 +#define MPFS_ENABLE_EVENTS_OFFSET 0x0c +#define MPFS_ENABLE_TVS_OFFSET 0x10 +#define MPFS_RESET_REASON_OFFSET 0x14 +#define MPFS_TAMPER_RESPONSE_OFFSET 0x18 + +/* Selected eventlist */ + +#define MPFS_SELECTED_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_SELECTED_EVENTS_OFFSET) + +#define FLAG_JTAG_ACTIVE (1 << 0) +#define FLAG_MESH_ERROR (1 << 1) +#define FLAG_CLOCK_MONITOR_GLITCH (1 << 2) +#define FLAG_CLOCK_MONITOR_FREQ (1 << 3) +#define FLAG_SECDED (1 << 4) +#define FLAG_SCB_BUS_ERROR (1 << 5) +#define FLAG_SC_WATCHDOG (1 << 6) +#define FLAG_LOCK_ERROR (1 << 7) +#define FLAG_DIGEST (1 << 8) +#define FLAG_INST_PASSCODE_FAIL (1 << 9) +#define FLAG_INST_KEY_VALIDATION_FAIL (1 << 10) +#define FLAG_INST_UNUSED (1 << 11) +#define FLAG_BITSTREAM_AUTHENTICATION_FAIL (1 << 12) +#define FLAG_DETECT_LOW_1P0 (1 << 13) +#define FLAG_DETECT_LOW_1P8 (1 << 14) +#define FLAG_DETECT_LOW_2P5 (1 << 15) +#define FLAG_DETECT_HIGH_1P0 (1 << 16) +#define FLAG_DETECT_HIGH_1P8 (1 << 17) +#define FLAG_DETECT_HIGH_2P5 (1 << 18) +#define FLAG_DETECT_TEMPERATURE_LOW (1 << 19) +#define FLAG_DETECT_TEMPERATURE_HIGH (1 << 20) + +#define FLAGS_ALL 0x1fffff +#define FLAG_BITS 21 + +/* Status eventlist */ + +#define MPFS_STATUS_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_STATUS_EVENTS_OFFSET) + +/* Clear eventlist */ + +#define MPFS_CLEAR_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_CLEAR_EVENTS_OFFSET) + +/* Enable eventlist */ + +#define MPFS_ENABLE_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_ENABLE_EVENTS_OFFSET) + +/* Enable TVS */ + +#define MPFS_ENABLE_TVS (MPFS_TAMPER_CTRL_BASE +\ + MPFS_ENABLE_TVS_OFFSET) + +#define MPFS_ENABLE_TVS_MONITORING (1 << 0) +#define MPFS_ENABLE_VOLTAGE_MONITORING (1 << 1) + +/* Reset reason */ + +#define MPFS_RESET_REASON (MPFS_TAMPER_CTRL_BASE + \ + MPFS_RESET_REASON_OFFSET) + +/* Clock and reset */ + +#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) + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* Mesh system defines */ + +#define MPFS_MESH_CR 0x200020b0 +#define MPFS_MESH_START (1 << 0) + +/* Debug output defines, info promoted to _err for visibility */ + +#ifdef CONFIG_DEBUG_ERROR +# define tinfo _err +#else +# define tinfo _none +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_tamper_event_string + * + * Description: + * Tamper event to string function + * + * Input Parameters: + * List of events + * + * Returned Value: + * Readable string + * + ****************************************************************************/ + +static const char *mpfs_tamper_event_string(uint32_t eventlist) +{ + int i; + + static const char *const names[] = + { + "JTAG ACTIVE", + "MESH ERROR", + "CLOCK MONITOR GLITCH", + "CLOCK MONITOR FREQ", + "SECDED", + "SCB BUS ERROR", + "SC WATCHDOG", + "LOCK ERROR", + "DIGEST", + "PASSCODE FAIL", + "KEY VALIDATION FAIL", + "INST UNUSED", + "BITSTREAM AUTH FAIL", + "LOW 1P0", + "LOW 1P8", + "LOW 2P5", + "HIGH 1P0", + "HIGH 1P8", + "HIGH 2P5", + "TEMPERATURE LOW", + "TEMPERATURE HIGH", + }; + + for (i = 0; i < ARRAY_SIZE(names); i++) + { + if ((1 << i) & eventlist) + { + break; + } + } + + if (i >= ARRAY_SIZE(names)) + { + return "UNDEFINED"; + } + + return names[i]; +} + +/**************************************************************************** + * Name: mpfs_tamper_interrupt + * + * Description: + * Tamper intinfoupt handler + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int mpfs_tamper_interrupt(int irq, void *context, void *arg) +{ + uint32_t eventlist; + uint32_t sel; + uint32_t status; + uint32_t clr; + uint32_t enabled; + uint32_t entvs; + int i; + + sel = getreg32(MPFS_SELECTED_EVENTS); + status = getreg32(MPFS_STATUS_EVENTS); + clr = getreg32(MPFS_CLEAR_EVENTS); + enabled = getreg32(MPFS_ENABLE_EVENTS); + entvs = getreg32(MPFS_ENABLE_TVS); + + eventlist = sel; + + if (eventlist) + { + tinfo("**********************************************************\n"); + tinfo("Tamper detection has caught out the following event(s):\n"); + for (i = 0; i < FLAG_BITS; i++) + { + if ((1 << i) & eventlist) + { + tinfo(" <%s>\n", mpfs_tamper_event_string(eventlist)); + eventlist &= ~(1 << i); + } + } + + tinfo("Regs: 0x00: 0x%x, 0x04: 0x%x, 0x08: 0x%x, 0x0c: 0x%x," + " 0x10: 0x%x\n", + sel, status, clr, enabled, entvs); + tinfo("**********************************************************\n"); + } + + putreg32(sel, MPFS_CLEAR_EVENTS); + + return 0; +} + +/**************************************************************************** + * Name: mpfs_tamper_tests + * + * Description: + * Various tamper tests for testing + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef TAMPER_TESTS +extern uint16_t mpfs_sys_unlock_debug_passcode(uint8_t *cmd_data, + uint16_t mb_offset, + uint16_t resp_offset); +extern uint16_t mpfs_sys_authenticate_iap_image(uint32_t spi_idx); + +static void mpfs_tamper_tests(void) +{ + /* MPFS_SYS_UNLOCK_DEBUG_PASSCODE_DATA_LEN = 32 */ + + uint8_t buf[32]; + + /* Looks like the buf needs to be gargabed first */ + + memset(buf, 0xaa, sizeof(buf)); + + /* Issue: */ + + mpfs_sys_unlock_debug_passcode(buf, 0, 0); + + /* Issue: */ + + mpfs_sys_authenticate_iap_image(0); +} +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_tamper_enable + * + * Description: + * Enables the tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_enable(void) +{ + int ret; + + 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); + + tinfo("Enabling Tamper detection - if no FPGA support, will hang here\n"); + tinfo("Tamper reset reason 0x%x\n", getreg32(MPFS_RESET_REASON)); + + /* Enable events */ + + putreg32(FLAGS_ALL, MPFS_ENABLE_EVENTS); + putreg32(MPFS_ENABLE_TVS_MONITORING | MPFS_ENABLE_VOLTAGE_MONITORING, + MPFS_ENABLE_TVS); + + /* Start the mesh system */ + + modifyreg32(MPFS_MESH_CR, 0, MPFS_MESH_START); + + ret = irq_attach(MPFS_IRQ_FABRIC_F2H_10, mpfs_tamper_interrupt, NULL); + + if (ret == 0) + { + up_enable_irq(MPFS_IRQ_FABRIC_F2H_10); + } + else + { + tinfo("Tamper IRQ attach failed"); + } + +#ifdef TAMPER_TESTS + mpfs_tamper_tests(); +#endif +} + +/**************************************************************************** + * Name: mpfs_tamper_disable + * + * Description: + * Disables tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_disable(void) +{ + modifyreg32(MPFS_MESH_CR, MPFS_MESH_START, 0); + + up_disable_irq(MPFS_IRQ_FABRIC_F2H_10); + irq_detach(MPFS_IRQ_FABRIC_F2H_10); + + putreg32(0x00, MPFS_ENABLE_EVENTS); + putreg32(0, MPFS_ENABLE_TVS); +} diff --git a/arch/risc-v/src/mpfs/mpfs_tamper.h b/arch/risc-v/src/mpfs/mpfs_tamper.h new file mode 100644 index 0000000000000..800c4471d956a --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_tamper.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_tamper.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_TAMPER_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_TAMPER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mpfs_tamper_enable + * + * Description: + * Enables the tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_enable(void); + +/**************************************************************************** + * Name: mpfs_tamper_disable + * + * Description: + * Disables tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_disable(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_TAMPER_H */ 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..c893e17a0a28f 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -28,6 +28,12 @@ SBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/ipi/aclint_mswi.c SBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/irqchip/plic.c SBI_CSRCS += opensbi/opensbi-3rdparty/lib/utils/timer/aclint_mtimer.c +EXCLUDED_FILES = opensbi/opensbi-3rdparty/lib/sbi/sbi_pmu.c +EXCLUDED_FILES += opensbi/opensbi-3rdparty/lib/sbi/sbi_ecall_dbcn.c + +TMPVAR := $(SBI_CSRCS) +SBI_CSRCS = $(filter-out $(EXCLUDED_FILES), $(TMPVAR)) + SBI_ASRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_expected_trap.S SBI_ASRCS += opensbi/opensbi-3rdparty/lib/sbi/sbi_hfence.S SBI_ASRCS += opensbi/opensbi-3rdparty/lib/sbi/riscv_hardfp.S @@ -37,10 +43,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 = fbaaafe808f3da7745760d757c436ef1b293d3ed +OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = riscv-software-src-opensbi-4998a71 +OPENSBI_DIR = tiiuae-opensbi-fbaaafe $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) @@ -50,6 +56,7 @@ $(OPENSBI_TARBALL): $(Q) tar xzf opensbi/$(OPENSBI_TARBALL) -C opensbi $(Q) mv opensbi/$(OPENSBI_DIR) opensbi/$(OPENSBI_UNPACK) $(Q) touch opensbi/.opensbi_unpack + $(Q) opensbi/$(OPENSBI_UNPACK)/scripts/carray.sh -i opensbi/$(OPENSBI_UNPACK)/lib/sbi/sbi_ecall_exts.carray -l "ecall_base ecall_hsm ecall_ipi ecall_rfence ecall_time ecall_vendor" > opensbi/$(OPENSBI_UNPACK)/lib/sbi/sbi_ecall_exts.c ifeq ($(wildcard opensbi/$(OPENSBI_UNPACK)/.git),) context:: .opensbi_unpack diff --git a/arch/risc-v/src/rv32m1/rv32m1_irq.c b/arch/risc-v/src/rv32m1/rv32m1_irq.c index 9de192d2f879d..3f21f49721237 100644 --- a/arch/risc-v/src/rv32m1/rv32m1_irq.c +++ b/arch/risc-v/src/rv32m1/rv32m1_irq.c @@ -95,7 +95,7 @@ void up_irqinitialize(void) #if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 15 size_t intstack_size = (CONFIG_ARCH_INTERRUPTSTACK & ~15); - riscv_stack_color(g_intstacktop - intstack_size, intstack_size); + riscv_stack_color(g_intstackalloc, intstack_size); #endif /* Clear all pending flags */ diff --git a/binfmt/CMakeLists.txt b/binfmt/CMakeLists.txt index f0e0abe3713ec..9af12e1a3bc86 100644 --- a/binfmt/CMakeLists.txt +++ b/binfmt/CMakeLists.txt @@ -63,3 +63,4 @@ endif() target_sources(binfmt PRIVATE ${SRCS}) target_include_directories(binfmt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(binfmt PRIVATE ${CMAKE_SOURCE_DIR}/sched) diff --git a/binfmt/Makefile b/binfmt/Makefile index 9f8dbf8f058f0..004ef03a8a2a3 100644 --- a/binfmt/Makefile +++ b/binfmt/Makefile @@ -58,6 +58,8 @@ endif include libnxflat/Make.defs include libelf/Make.defs +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)sched + AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) diff --git a/binfmt/binfmt_exec.c b/binfmt/binfmt_exec.c index ba1d2f3cb7b8f..9c9396636bbf0 100644 --- a/binfmt/binfmt_exec.c +++ b/binfmt/binfmt_exec.c @@ -37,11 +37,11 @@ #ifndef CONFIG_BINFMT_DISABLE /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: exec_spawn + * Name: exec_internal * * Description: * exec() configurable version, delivery the spawn attribute if this @@ -64,6 +64,7 @@ * nexports - The number of symbols in the exports table. * actions - The spawn file actions * attr - The spawn attributes. + * spawn - Is spawn in new task. * * Returned Value: * It returns the PID of the exec'ed module. On failure, it returns @@ -71,10 +72,11 @@ * ****************************************************************************/ -int exec_spawn(FAR const char *filename, FAR char * const *argv, - FAR char * const *envp, FAR const struct symtab_s *exports, - int nexports, FAR const posix_spawn_file_actions_t *actions, - FAR const posix_spawnattr_t *attr) +static int exec_internal(FAR const char *filename, + FAR char * const *argv, FAR char * const *envp, + FAR const struct symtab_s *exports, int nexports, + FAR const posix_spawn_file_actions_t *actions, + FAR const posix_spawnattr_t *attr, bool spawn) { FAR struct binary_s *bin; irqstate_t flags; @@ -132,7 +134,7 @@ int exec_spawn(FAR const char *filename, FAR char * const *argv, /* Then start the module */ - pid = exec_module(bin, filename, argv, envp, actions); + pid = exec_module(bin, filename, argv, envp, actions, attr, spawn); if (pid < 0) { ret = pid; @@ -175,6 +177,50 @@ int exec_spawn(FAR const char *filename, FAR char * const *argv, return ret; } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: exec_spawn + * + * Description: + * exec() configurable version, delivery the spawn attribute if this + * process has special customization. + * + * Input Parameters: + * filename - The path to the program to be executed. If + * CONFIG_LIBC_ENVPATH is defined in the configuration, then + * this may be a relative path from the current working + * directory. Otherwise, path must be the absolute path to the + * program. + * argv - A pointer to an array of string arguments. The end of the + * array is indicated with a NULL entry. + * envp - A pointer to an array of environment strings. Terminated with + * a NULL entry. + * exports - The address of the start of the caller-provided symbol + * table. This symbol table contains the addresses of symbols + * exported by the caller and made available for linking the + * module into the system. + * nexports - The number of symbols in the exports table. + * actions - The spawn file actions + * attr - The spawn attributes. + * + * Returned Value: + * It returns the PID of the exec'ed module. On failure, it returns + * the negative errno value appropriately. + * + ****************************************************************************/ + +int exec_spawn(FAR const char *filename, FAR char * const *argv, + FAR char * const *envp, FAR const struct symtab_s *exports, + int nexports, FAR const posix_spawn_file_actions_t *actions, + FAR const posix_spawnattr_t *attr) +{ + return exec_internal(filename, argv, envp, + exports, nexports, actions, attr, true); +} + /**************************************************************************** * Name: exec * @@ -245,7 +291,8 @@ int exec(FAR const char *filename, FAR char * const *argv, { int ret; - ret = exec_spawn(filename, argv, envp, exports, nexports, NULL, NULL); + ret = exec_internal(filename, argv, envp, + exports, nexports, NULL, NULL, false); if (ret < 0) { set_errno(-ret); diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c index b660e3eef26bc..ccfe5a81a21c4 100644 --- a/binfmt/binfmt_execmodule.c +++ b/binfmt/binfmt_execmodule.c @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -96,6 +98,91 @@ static void exec_ctors(FAR void *arg) } #endif +/**************************************************************************** + * Name: exec_swap + * + * Description: + * swap the pid of tasks, and reverse parent-child relationship. + * + * Input Parameters: + * ptcb - parent task tcb. + * chtcb - child task tcb. + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void exec_swap(FAR struct tcb_s *ptcb, FAR struct tcb_s *chtcb) +{ + int pndx; + int chndx; + pid_t pid; + irqstate_t flags; +#ifdef HAVE_GROUP_MEMBERS + FAR pid_t *tg_members; +#endif +#ifdef CONFIG_SCHED_HAVE_PARENT +# ifdef CONFIG_SCHED_CHILD_STATUS + FAR struct child_status_s *tg_children; +# else + uint16_t tg_nchildren; +# endif +#endif + + DEBUGASSERT(ptcb); + DEBUGASSERT(chtcb); + + flags = enter_critical_section(); + + pndx = PIDHASH(ptcb->pid); + chndx = PIDHASH(chtcb->pid); + + DEBUGASSERT(g_pidhash[pndx]); + DEBUGASSERT(g_pidhash[chndx]); + + /* Exchange g_pidhash index */ + + g_pidhash[pndx] = chtcb; + g_pidhash[chndx] = ptcb; + + /* Exchange pid */ + + pid = chtcb->pid; + chtcb->pid = ptcb->pid; + ptcb->pid = pid; + + /* Exchange group info. This will reverse parent-child relationship */ + + pid = chtcb->group->tg_pid; + chtcb->group->tg_pid = ptcb->group->tg_pid; + ptcb->group->tg_pid = pid; + + pid = chtcb->group->tg_ppid; + chtcb->group->tg_ppid = ptcb->group->tg_ppid; + ptcb->group->tg_ppid = pid; + +#ifdef HAVE_GROUP_MEMBERS + tg_members = chtcb->group->tg_members; + chtcb->group->tg_members = ptcb->group->tg_members; + ptcb->group->tg_members = tg_members; +#endif + +#ifdef CONFIG_SCHED_HAVE_PARENT +# ifdef CONFIG_SCHED_CHILD_STATUS + tg_children = chtcb->group->tg_children; + chtcb->group->tg_children = ptcb->group->tg_children; + ptcb->group->tg_children = tg_children; +# else + tg_nchildren = chtcb->group->tg_nchildren; + chtcb->group->tg_nchildren = ptcb->group->tg_nchildren; + ptcb->group->tg_nchildren = tg_nchildren; +# endif +#endif + + leave_critical_section(flags); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -116,12 +203,15 @@ static void exec_ctors(FAR void *arg) int exec_module(FAR struct binary_s *binp, FAR const char *filename, FAR char * const *argv, FAR char * const *envp, - FAR const posix_spawn_file_actions_t *actions) + FAR const posix_spawn_file_actions_t *actions, + FAR const posix_spawnattr_t *attr, + bool spawn) { FAR struct task_tcb_s *tcb; #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) FAR struct arch_addrenv_s *addrenv = &binp->addrenv->addrenv; FAR void *vheap; + char name[CONFIG_PATH_MAX]; #endif FAR void *stackaddr = NULL; pid_t pid; @@ -166,6 +256,14 @@ int exec_module(FAR struct binary_s *binp, } #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) + /* If there is no argument vector, the process name must be copied here */ + + if (argv == NULL) + { + strlcpy(name, filename, CONFIG_PATH_MAX); + filename = name; + } + /* Instantiate the address environment containing the user heap */ ret = addrenv_select(binp->addrenv, &binp->oldenv); @@ -230,17 +328,6 @@ int exec_module(FAR struct binary_s *binp, binfmt_freeargv(argv); binfmt_freeenv(envp); - /* Perform file actions */ - - if (actions != NULL) - { - ret = spawn_file_actions(&tcb->cmn, actions); - if (ret < 0) - { - goto errout_with_tcbinit; - } - } - #ifdef CONFIG_PIC /* Add the D-Space address as the PIC base address. By convention, this * must be the first allocated address space. @@ -276,10 +363,6 @@ int exec_module(FAR struct binary_s *binp, } #endif - /* Get the assigned pid before we start the task */ - - pid = tcb->cmn.pid; - #ifdef CONFIG_SCHED_USER_IDENTITY if (binp->mode & S_ISUID) { @@ -292,9 +375,14 @@ int exec_module(FAR struct binary_s *binp, } #endif - /* Then activate the task at the provided priority */ + if (!spawn) + { + exec_swap(this_task(), (FAR struct tcb_s *)tcb); + } - nxtask_activate((FAR struct tcb_s *)tcb); + /* Get the assigned pid before we start the task */ + + pid = tcb->cmn.pid; #if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL) /* Restore the address environment of the caller */ @@ -307,6 +395,32 @@ int exec_module(FAR struct binary_s *binp, } #endif + /* Perform file actions */ + + if (actions != NULL) + { + ret = spawn_file_actions(&tcb->cmn, actions); + if (ret < 0) + { + goto errout_with_tcbinit; + } + } + + /* Set the attributes */ + + if (attr) + { + ret = spawn_execattrs(pid, attr); + if (ret < 0) + { + goto errout_with_tcbinit; + } + } + + /* Then activate the task at the provided priority */ + + nxtask_activate((FAR struct tcb_s *)tcb); + return pid; errout_with_tcbinit: diff --git a/boards/risc-v/c906/smartl-c906/kernel/Makefile b/boards/risc-v/c906/smartl-c906/kernel/Makefile index 6b4cb180ba601..9da36f4eee988 100644 --- a/boards/risc-v/c906/smartl-c906/kernel/Makefile +++ b/boards/risc-v/c906/smartl-c906/kernel/Makefile @@ -43,7 +43,7 @@ USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex) USER_SRECFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.srec) USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin) -USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) +USER_LDFLAGS = -melf64lriscv --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS)))) USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}" diff --git a/boards/risc-v/c906/smartl-c906/scripts/Make.defs b/boards/risc-v/c906/smartl-c906/scripts/Make.defs index 13aa6816c17d4..ee56bdbdb0cea 100644 --- a/boards/risc-v/c906/smartl-c906/scripts/Make.defs +++ b/boards/risc-v/c906/smartl-c906/scripts/Make.defs @@ -27,17 +27,8 @@ ifeq ($(CONFIG_C906_WITH_QEMU),y) else LDSCRIPT = ld.script endif - ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) -# The following options are for the toolchain from T-HEAD. -# For more info ahout the T-HEAD ISA extensions, please refer to the C906 user guide. -# ARCHCPUFLAGS = -march=rv64gcxthead -mabi=lp64d -mtune=c906 -mcmodel=medany -# TODO: We are not going to enable this at this time for the CI compatibility. - -ARCHCPUFLAGS += -mcmodel=medany - - CFLAGS = $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe @@ -49,7 +40,7 @@ AFLAGS += $(CFLAGS) -D__ASSEMBLY__ CMODULEFLAGS = $(CFLAGS) -LDMODULEFLAGS = -r -e module_initialize +LDMODULEFLAGS = -melf64lriscv -r -e module_initialize LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) # ELF module definitions @@ -57,5 +48,5 @@ LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) CELFFLAGS = $(CFLAGS) CXXELFFLAGS = $(CXXFLAGS) -LDELFFLAGS = -r -e main +LDELFFLAGS = -melf64lriscv -r -e main LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) diff --git a/boards/risc-v/jh7110/star64/scripts/Make.defs b/boards/risc-v/jh7110/star64/scripts/Make.defs index 0048a3c6e0b70..4cdac79de7e8f 100644 --- a/boards/risc-v/jh7110/star64/scripts/Make.defs +++ b/boards/risc-v/jh7110/star64/scripts/Make.defs @@ -24,8 +24,6 @@ include $(TOPDIR)/arch/risc-v/src/common/Toolchain.defs LDSCRIPT = ld.script ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) - -ARCHCPUFLAGS += -mcmodel=medany ARCHPICFLAGS = -fpic -msingle-pic-base CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe diff --git a/boards/risc-v/k210/maix-bit/kernel/Makefile b/boards/risc-v/k210/maix-bit/kernel/Makefile index a78a4a69ecc7c..7df8fc03d6c3f 100644 --- a/boards/risc-v/k210/maix-bit/kernel/Makefile +++ b/boards/risc-v/k210/maix-bit/kernel/Makefile @@ -35,7 +35,7 @@ USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex) USER_SRECFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.srec) USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin) -USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) +USER_LDFLAGS = -melf64lriscv --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS)))) USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}" diff --git a/boards/risc-v/k210/maix-bit/scripts/Make.defs b/boards/risc-v/k210/maix-bit/scripts/Make.defs index 10c24c8273208..f40ceb860b7fe 100644 --- a/boards/risc-v/k210/maix-bit/scripts/Make.defs +++ b/boards/risc-v/k210/maix-bit/scripts/Make.defs @@ -25,8 +25,6 @@ include $(TOPDIR)/arch/risc-v/src/common/Toolchain.defs LDSCRIPT = ld.script ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) -ARCHCPUFLAGS += -mcmodel=medany -mstrict-align - CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe @@ -38,7 +36,7 @@ AFLAGS += $(CFLAGS) -D__ASSEMBLY__ CMODULEFLAGS = $(CFLAGS) -LDMODULEFLAGS = -r -e module_initialize +LDMODULEFLAGS = -melf64lriscv -r -e module_initialize LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) # ELF module definitions @@ -46,5 +44,5 @@ LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) CELFFLAGS = $(CFLAGS) CXXELFFLAGS = $(CXXFLAGS) -LDELFFLAGS = -r -e main +LDELFFLAGS = -melf64lriscv -r -e main LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) 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/common/kernel/Makefile b/boards/risc-v/mpfs/common/kernel/Makefile index 3447d2f7d18c2..0566d6873f90c 100644 --- a/boards/risc-v/mpfs/common/kernel/Makefile +++ b/boards/risc-v/mpfs/common/kernel/Makefile @@ -39,7 +39,7 @@ USER_HEXFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.hex) USER_SRECFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.srec) USER_BINFILE += $(call CONVERT_PATH,$(TOPDIR)$(DELIM)nuttx_user.bin) -USER_LDFLAGS = --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) +USER_LDFLAGS = -melf64lriscv --undefined=$(ENTRYPT) --entry=$(ENTRYPT) $(USER_LDSCRIPT) USER_LDLIBS = $(patsubst lib%,-l%,$(basename $(notdir $(USERLIBS)))) USER_LIBGCC = "${shell "$(CC)" $(ARCHCPUFLAGS) -print-libgcc-file-name}" 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/Make.defs b/boards/risc-v/mpfs/icicle/scripts/Make.defs index c81ebf1a96b80..f5a36739866af 100644 --- a/boards/risc-v/mpfs/icicle/scripts/Make.defs +++ b/boards/risc-v/mpfs/icicle/scripts/Make.defs @@ -53,14 +53,6 @@ ifneq ($(LDMEMORY),) endif ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) -# The following options are for the toolchain from T-HEAD. -# For more info ahout the T-HEAD ISA extensions, please refer to the MPFS user guide. -# ARCHCPUFLAGS = -march=rv64gcxthead -mabi=lp64d -mcmodel=medany -# TODO: We are not going to enable this at this time for the CI compatibility. - -ARCHCPUFLAGS += -mcmodel=medany - - CFLAGS = $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe @@ -72,7 +64,7 @@ AFLAGS += $(CFLAGS) -D__ASSEMBLY__ CMODULEFLAGS = $(CFLAGS) -LDMODULEFLAGS = -r -e module_initialize +LDMODULEFLAGS = -melf64lriscv -r -e module_initialize LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) # ELF module definitions @@ -80,5 +72,5 @@ LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) CELFFLAGS = $(CFLAGS) CXXELFFLAGS = $(CXXFLAGS) -LDELFFLAGS = -r -e main +LDELFFLAGS = -melf64lriscv -r -e main LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) 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/boards/risc-v/mpfs/m100pfsevp/scripts/Make.defs b/boards/risc-v/mpfs/m100pfsevp/scripts/Make.defs index b74eb4721a581..e39fda5107ce6 100644 --- a/boards/risc-v/mpfs/m100pfsevp/scripts/Make.defs +++ b/boards/risc-v/mpfs/m100pfsevp/scripts/Make.defs @@ -27,17 +27,8 @@ ifeq ($(CONFIG_MPFS_BOOTLOADER),y) else LDSCRIPT = ld.script endif - ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) -# The following options are for the toolchain from T-HEAD. -# For more info ahout the T-HEAD ISA extensions, please refer to the MPFS user guide. -# ARCHCPUFLAGS = -march=rv64gcxthead -mabi=lp64d -mcmodel=medany -# TODO: We are not going to enable this at this time for the CI compatibility. - -ARCHCPUFLAGS += -mcmodel=medany - - CFLAGS = $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) CXXFLAGS = $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe @@ -57,5 +48,5 @@ LDMODULEFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld) CELFFLAGS = $(CFLAGS) CXXELFFLAGS = $(CXXFLAGS) -LDELFFLAGS = -r -e main +LDELFFLAGS = -melf64lriscv -r -e main LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) diff --git a/boards/risc-v/qemu-rv/rv-virt/scripts/Make.defs b/boards/risc-v/qemu-rv/rv-virt/scripts/Make.defs index ab13f19b9c6b9..453bad37bc62c 100644 --- a/boards/risc-v/qemu-rv/rv-virt/scripts/Make.defs +++ b/boards/risc-v/qemu-rv/rv-virt/scripts/Make.defs @@ -35,8 +35,6 @@ endif endif ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) - -ARCHCPUFLAGS += -mcmodel=medany ARCHPICFLAGS = -fpic -msingle-pic-base CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe 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/Kconfig b/drivers/net/Kconfig index ff289b2fb021c..5028e0db17521 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -392,6 +392,30 @@ menuconfig NET_W5500 References: W5500 Datasheet, Version 1.0.9, 2013 WIZnet Co., Ltd. +config NET_KSZ9477 + bool "Management interface for ksz9477 ethernet switch" + default n + ---help--- + Support for Microchip/Micrel KSZ9477 managed switch. To use this, + one must also select the management interface (I2C / SPI) and + call the driver's init from board initialization code or from the + ethernet driver. + +choice + prompt "Management bus for the kzs9477 switch" + default NET_KSZ9477_I2C + depends on NET_KSZ9477 + ---help--- + Select the used management interface + +config NET_KSZ9477_I2C + bool "Use I2C management interface" + +config NET_KSZ9477_SPI + bool "Use SPI management interface" + +endchoice + if NET_W5500 config NET_W5500_NINTERFACES diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs index 76aa70e6b73d4..070df18e55e66 100644 --- a/drivers/net/Make.defs +++ b/drivers/net/Make.defs @@ -80,6 +80,15 @@ ifeq ($(CONFIG_ARCH_PHY_INTERRUPT),y) CSRCS += phy_notify.c endif +ifeq ($(CONFIG_NET_KSZ9477),y) + CSRCS += ksz9477.c + +ifeq ($(CONFIG_NET_KSZ9477_I2C),y) + CSRCS += ksz9477_i2c.c +endif + +endif + # Include network build support DEPPATH += --dep-path net diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c new file mode 100644 index 0000000000000..4cb5cb5d2ef3c --- /dev/null +++ b/drivers/net/ksz9477.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * drivers/net/ksz9477.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 "ksz9477_reg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint16_t bswap16(uint16_t data) +{ + return (data << 8) | (data >> 8); +} + +static uint32_t bswap32(uint32_t data) +{ + return (data << 24) | (data >> 24) | ((data << 8) & 0xff0000) | + ((data >> 8) & 0xff00); +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_read8(uint16_t reg, uint8_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 3; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = read_msg.data; + return ret; +} +#endif + +static int ksz9477_reg_read16(uint16_t reg, uint16_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 4; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = bswap16(read_msg.data); + return ret; +} + +static int ksz9477_reg_read32(uint16_t reg, uint32_t *data) +{ + int ret; + struct ksz9477_transfer_s read_msg; + read_msg.len = 6; + read_msg.reg = bswap16(reg); + ret = ksz9477_read(&read_msg); + *data = bswap32(read_msg.data); + return ret; +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_write8(uint16_t reg, uint8_t data) +{ + struct ksz9477_transfer_s write_msg; + write_msg.len = 3; + write_msg.reg = bswap16(reg); + write_msg.data = data; + return ksz9477_write(&write_msg); +} +#endif + +static int ksz9477_reg_write32(uint16_t reg, uint32_t data) +{ + struct ksz9477_transfer_s write_msg; + write_msg.len = 6; + write_msg.reg = bswap16(reg); + write_msg.data = bswap32(data); + return ksz9477_write(&write_msg); +} + +#if 0 /* Enable when needed */ +static int ksz9477_reg_write16(uint16_t reg, uint16_t data) +{ + int ret; + struct ksz9477_transfer_s write_msg; + uint16_t addr = reg; + uint32_t data32; + + /* Errata: 16-bit writes to registers 0xN120-0xN13f will corrupt the + * adjacent regsters. Workaround: perform only 32-bit writes to this + * area + */ + + if ((reg & 0xfff) >= 0x120 && (reg & 0xfff) <= 0x13f) + { + /* Align write on lower 16-byte boundary */ + + addr = reg & (~1); + + /* Read the full 32-bit register */ + + ret = ksz9477_reg_read32(addr, &data32); + if (ret != OK) + { + return ret; + } + + /* Inject the data to the 32-bit write data */ + + if (reg & 1) + { + data32 = (data32 & 0xff0000ff) | ((uint32_t)data << 8); + } + else + { + data32 = (data32 & 0xffff0000) | data; + } + + write_msg.len = 6; + write_msg.data = bswap32(data32); + } + else + { + write_msg.len = 4; + write_msg.data = bswap16(data); + } + + write_msg.reg = bswap16(reg); + + return ksz9477_write(&write_msg); +} +#endif + +static int ksz9477_sgmii_read_indirect(uint32_t address, uint16_t *value, + unsigned len) +{ + int ret; + uint32_t data; + + address |= SGMII_PORT_ADDRESS_AUTO_INC_ENB; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_ADDRESS, address); + while (len-- && ret == OK) + { + ret = ksz9477_reg_read32(KSZ9477_SGMII_PORT_DATA, &data); + *value++ = (uint16_t)data; + } + + return ret; +} + +static int ksz9477_sgmii_write_indirect(uint32_t address, uint16_t *value, + unsigned len) +{ + int ret; + uint32_t data; + + address |= SGMII_PORT_ADDRESS_AUTO_INC_ENB; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_ADDRESS, address); + while (len-- && ret == OK) + { + data = *value++; + ret = ksz9477_reg_write32(KSZ9477_SGMII_PORT_DATA, data); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ksz9477_init + * + * Description: + * Switches the ksz9477's SGMII port into PHY mode and sets the + * default settings to work directly with an external MAC + * + * Input Parameters: + * master_port: Port connected to the host MAC + * + * Returned Value: + * OK or negative error number + * + ****************************************************************************/ + +int ksz9477_init(ksz9477_port_t master_port) +{ + int ret; + uint16_t regval16; + uint32_t regval32; + + /* Read the ID registers */ + + ret = ksz9477_reg_read16(KSZ9477_ID1, ®val16); + if (ret != OK || regval16 != KSZ9477_ID) + { + nerr("Device not found, id %x, ret %d\n", regval16, ret); + return ret ? ret : -EINVAL; + } + + /* Check that the SGMII block is alive and indirect accesses work */ + + ret = ksz9477_sgmii_read_indirect(KSZ9477_SGMII_ID1, + (uint16_t *)®val32, 2); + if (ret != OK || regval32 != SGMII_PHY_ID) + { + nerr("SGMII port access failure, id %x, ret %d\n", regval32, ret); + return ret ? ret : -EINVAL; + } + + if (master_port == KSZ9477_PORT_SGMII) + { + /* Set the switch's SGMII port into "PHY" mode and enable link */ + + regval16 = (SGMII_AUTONEG_CONTROL_PCS_SGMII | + SGMII_AUTONEG_CONTROL_TC_MASTER | + SGMII_AUTONEG_CONTROL_LINK_STATUS); + ret = ksz9477_sgmii_write_indirect(KSZ9477_SGMII_AUTONEG_CONTROL, + ®val16, 1); + + /* Write to autonegotiation advertisement register activates the new + * setting. Advertise only full duplex. + */ + + regval16 = SGMII_AUTONEG_ADVERTISE_FD; + ret = ksz9477_sgmii_write_indirect(KSZ9477_SGMII_AUTONEG_ADVERTISE, + ®val16, 1); + } + + return ret; +} diff --git a/drivers/net/ksz9477_i2c.c b/drivers/net/ksz9477_i2c.c new file mode 100644 index 0000000000000..35618d826cfbc --- /dev/null +++ b/drivers/net/ksz9477_i2c.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * drivers/net/ksz9477_i2c.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 "ksz9477_reg.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct i2c_master_s *g_ksz9477_i2c_bus; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void setup_i2c_transfer(struct i2c_msg_s *msg, uint8_t *data, + size_t len, bool read) +{ + msg[0].frequency = KSZ9477_I2C_SPEED; + msg[0].addr = KSZ9477_I2C_ADDRESS; + msg[0].flags = read ? I2C_M_READ : 0; + msg[0].buffer = data; + msg[0].length = len; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int ksz9477_read(struct ksz9477_transfer_s *read_msg) +{ + struct i2c_msg_s msg[2]; + + /* Set up to write the address */ + + setup_i2c_transfer(&msg[0], (uint8_t *)&read_msg->reg, + sizeof(read_msg->reg), false); + + /* Followed by the read data */ + + setup_i2c_transfer(&msg[1], (uint8_t *)&read_msg->data, + read_msg->len - sizeof(read_msg->reg), true); + + return I2C_TRANSFER(g_ksz9477_i2c_bus, msg, 2); +} + +int ksz9477_write(struct ksz9477_transfer_s *write_msg) +{ + struct i2c_msg_s msg; + + /* Set up to write the address and data */ + + setup_i2c_transfer(&msg, (uint8_t *)&write_msg->reg, + write_msg->len, false); + + return I2C_TRANSFER(g_ksz9477_i2c_bus, &msg, 1); +} + +/**************************************************************************** + * Name: ksz9477_i2c_init + * + * Description: + * Stores the configured i2c_master and calls the main init function + * + * Input Parameters: + * i2c_bus: The i2c master used as a control interface + * master_port: The switch port connected to the host MAC + * Returned Value: + * OK or negative error number + * + ****************************************************************************/ + +int ksz9477_i2c_init(struct i2c_master_s *i2c_bus, + ksz9477_port_t master_port) +{ + if (!i2c_bus) + { + return -EINVAL; + } + + g_ksz9477_i2c_bus = i2c_bus; + + /* Call the main init function */ + + return ksz9477_init(master_port); +} diff --git a/drivers/net/ksz9477_reg.h b/drivers/net/ksz9477_reg.h new file mode 100644 index 0000000000000..3423edb8ef603 --- /dev/null +++ b/drivers/net/ksz9477_reg.h @@ -0,0 +1,155 @@ +/**************************************************************************** + * drivers/net/ksz9477_reg.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 __DRIVERS_NET_KSZ9477_REG_H +#define __DRIVERS_NET_KSZ9477_REG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* These define only a subset of full register map. New registers can added + * as needed + */ + +#define KSZ9477_I2C_ADDRESS 0x5f +#define KSZ9477_I2C_SPEED I2C_SPEED_FAST + +/* Global registers */ + +#define KSZ9477_ID0 0x0 +#define KSZ9477_ID1 0x1 +#define KSZ9477_ID2 0x2 +#define KSZ9477_ID3 0x3 + +/* Port registers */ + +#define KSZ9477_PORT_REG(p,r) ((((uint16_t)(p)) << 12) | (r)) + +#define KSZ9477_PORT_DEFAULT_TAG0(p) KSZ9477_PORT_REG(p, 0x0) +#define KSZ9477_PORT_DEFAULT_TAG1(p) KSZ9477_PORT_REG(p, 0x1) + +#define KSZ9477_PHY_CONTROL(p) KSZ9477_PORT_REG(p, 0x100) +#define KSZ9477_PHY_STATUS(p) KSZ9477_PORT_REG(p, 0x102) + +/* Note! Unlike in data sheet, the indirect data register reads and + * writes must be done with 32-bit accesses and the address is + * 0x204 + */ + +#define KSZ9477_PORT_ADDRESS(p) KSZ9477_PORT_REG(p, 0x200) +#define KSZ9477_PORT_DATA(p) KSZ9477_PORT_REG(p, 0x204) + +#define KSZ9477_SGMII_PORT_ADDRESS KSZ9477_PORT_ADDRESS(7) +#define KSZ9477_SGMII_PORT_DATA KSZ9477_PORT_DATA(7) + +/* SGMII indirect registers */ + +#define KSZ9477_SGMII_CONTROL 0x1F0000 +#define KSZ9477_SGMII_STATUS 0x1F0001 +#define KSZ9477_SGMII_ID1 0x1F0002 +#define KSZ9477_SGMII_ID2 0x1F0003 +#define KSZ9477_SGMII_AUTONEG_ADVERTISE 0x1F0004 +#define KSZ9477_SGMII_LINK_PARTNER_ABILITY 0x1F0005 +#define KSZ9477_SGMII_AUTONEG_EXPANSION 0x1F0006 +#define KSZ9477_SGMII_DIGITAL_CONTROL 0x1F8000 +#define KSZ9477_SGMII_AUTONEG_CONTROL 0x1F8001 +#define KSZ9477_SGMII_AUTONEG_STATUS 0x1F8002 + +/* Register bit definitions */ + +/* KSZ9477_ID2, KSZ9477_ID1 */ + +#define KSZ9477_ID 0x9477 + +/* KSZ9477_SGMII_ID2, KSZ9477_SGMII_ID1 */ + +#define SGMII_PHY_ID 0xced07996 + +/* KSZ9477_SGMII_PORT_ADDRESS */ + +#define SGMII_PORT_ADDRESS_AUTO_INC_ENB (1 << 23) + +/* KSZ9477_SGMII_AUTONEG_ADVERTISE */ + +#define SGMII_AUTONEG_ADVERTISE_FD (1 << 5) +#define SGMII_AUTONEG_ADVERTISE_HD (1 << 5) + +/* KSZ9477_SGMII_AUTONEG_CONTROL */ + +#define SGMII_AUTONEG_CONTROL_IE (1 << 0) +#define SGMII_AUTONEG_CONTROL_PCS_SERDES (0 << 1) +#define SGMII_AUTONEG_CONTROL_PCS_SGMII (2 << 1) +#define SGMII_AUTONEG_CONTROL_TC_MASTER (1 << 3) +#define SGMII_AUTONEG_CONTROL_LINK_STATUS (1 << 4) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct ksz9477_transfer_s +{ + uint16_t len; + uint16_t reg; + uint32_t data; +} +__attribute__((packed)); + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +int ksz9477_init(ksz9477_port_t master_port); + +int ksz9477_read(struct ksz9477_transfer_s *read_msg); + +int ksz9477_write(struct ksz9477_transfer_s *write_msg); + +#if defined(__cplusplus) +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* __DRIVERS_NET_KSZ9477_REG_H */ 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/include/nuttx/arch.h b/include/nuttx/arch.h index 4a647afedb2af..9f4bdf78221ad 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1352,7 +1352,7 @@ int up_addrenv_kmap_pages(FAR void **pages, unsigned int npages, #endif /**************************************************************************** - * Name: riscv_unmap_pages + * Name: up_addrenv_kunmap_pages * * Description: * Unmap a previously mapped virtual memory region. diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h index 1c90c60fe15d5..3037dfb2f9a6d 100644 --- a/include/nuttx/binfmt/binfmt.h +++ b/include/nuttx/binfmt/binfmt.h @@ -272,7 +272,9 @@ int unload_module(FAR struct binary_s *bin); int exec_module(FAR struct binary_s *binp, FAR const char *filename, FAR char * const *argv, FAR char * const *envp, - FAR const posix_spawn_file_actions_t *actions); + FAR const posix_spawn_file_actions_t *actions, + FAR const posix_spawnattr_t *attr, + bool spawn); /**************************************************************************** * Name: exec diff --git a/include/nuttx/mm/kmap.h b/include/nuttx/mm/kmap.h index f81536352a9fb..baa5630dca1e4 100644 --- a/include/nuttx/mm/kmap.h +++ b/include/nuttx/mm/kmap.h @@ -72,7 +72,7 @@ FAR void *kmm_map(FAR void **pages, size_t npages, int prot); void kmm_unmap(FAR void *kaddr); /**************************************************************************** - * Name: kmm_user_map + * Name: kmm_map_user * * Description: * Map a region of user memory (physical pages) for kernel use through @@ -87,7 +87,7 @@ void kmm_unmap(FAR void *kaddr); * ****************************************************************************/ -FAR void *kmm_user_map(FAR void *uaddr, size_t size); +FAR void *kmm_map_user(FAR void *uaddr, size_t size); /**************************************************************************** * Name: kmm_map_user_page diff --git a/include/nuttx/net/ksz9477.h b/include/nuttx/net/ksz9477.h new file mode 100644 index 0000000000000..cc37adb48a40a --- /dev/null +++ b/include/nuttx/net/ksz9477.h @@ -0,0 +1,101 @@ +/**************************************************************************** + * include/nuttx/net/ksz9477.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 __INCLUDE_NUTTX_NET_KSZ9477_H +#define __INCLUDE_NUTTX_NET_KSZ9477_H + +#ifdef CONFIG_NET_KSZ9477 + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + KSZ9477_PORT_NONE = -1, + KSZ9477_PORT_GLOBAL = 0, + KSZ9477_PORT_PHY1 = 1, + KSZ9477_PORT_PHY2 = 2, + KSZ9477_PORT_PHY3 = 3, + KSZ9477_PORT_PHY4 = 4, + KSZ9477_PORT_PHY5 = 5, + KSZ9477_PORT_RMII = 6, + KSZ9477_PORT_SGMII = 7, +} ksz9477_port_t; + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ksz9477_i2c_init + * + * Description: + * Switches the ksz9477's SGMII port into PHY mode and sets the + * default settings to work directly with an external MAC + * + * Input Parameters: + * i2c_bus: Management i2c bus + * master_port: The port of the switch connected to host MAC + * + * Returned Value: + * OK or ERROR + * + ****************************************************************************/ + +#ifdef CONFIG_NET_KSZ9477_I2C +int ksz9477_i2c_init(struct i2c_master_s *i2c_bus, + ksz9477_port_t master_port); +#else +# error Only I2c interface currently supported +#endif + +#if defined(__cplusplus) +} +#endif +#undef EXTERN + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_NET_KSZ9477 */ +#endif /* __INCLUDE_NUTTX_NET_KSZ9477_H */ diff --git a/libs/libc/stdio/lib_libfread.c b/libs/libc/stdio/lib_libfread.c index 1633b3ad9c42f..a6aa85fc92c48 100644 --- a/libs/libc/stdio/lib_libfread.c +++ b/libs/libc/stdio/lib_libfread.c @@ -130,17 +130,18 @@ ssize_t lib_fread(FAR void *ptr, size_t count, FAR FILE *stream) if (gulp_size > 0) { - if (gulp_size > count) + if (gulp_size > remaining) { /* Clip the gulp size to the requested byte count */ - gulp_size = count; + gulp_size = remaining; } memcpy(dest, stream->fs_bufpos, gulp_size); remaining -= gulp_size; stream->fs_bufpos += gulp_size; + dest += gulp_size; } /* The buffer is empty OR we have already supplied the number diff --git a/mm/kmap/kmm_map.c b/mm/kmap/kmm_map.c index 883b019c44a78..cb270706f137b 100644 --- a/mm/kmap/kmm_map.c +++ b/mm/kmap/kmm_map.c @@ -82,7 +82,7 @@ static int get_user_pages(FAR void **pages, size_t npages, uintptr_t vaddr) for (i = 0; i < npages; i++, vaddr += MM_PGSIZE) { - page = up_addrenv_find_page(&tcb->addrenv_own->addrenv, vaddr); + page = up_addrenv_find_page(&tcb->addrenv_curr->addrenv, vaddr); if (!page) { /* Something went wrong, get out */ @@ -125,7 +125,7 @@ static FAR void *map_pages(FAR void **pages, size_t npages, int prot) /* Find a virtual memory area that fits */ - vaddr = gran_alloc(&g_kmm_map_vpages, size); + vaddr = gran_alloc(g_kmm_map_vpages, size); if (!vaddr) { return NULL; @@ -182,7 +182,7 @@ static FAR void *map_single_user_page(uintptr_t vaddr) /* Find the page associated with this virtual address */ - page = up_addrenv_find_page(&tcb->addrenv_own->addrenv, vaddr); + page = up_addrenv_find_page(&tcb->addrenv_curr->addrenv, vaddr); if (!page) { return NULL; @@ -192,6 +192,47 @@ static FAR void *map_single_user_page(uintptr_t vaddr) return (FAR void *)vaddr; } +/**************************************************************************** + * Name: map_single_page + * + * Description: + * Map (find) a single page from the kernel addressable virtual memory + * pool. + * + * Input Parameters: + * page - The physical page. + * + * Returned Value: + * The kernel virtual address for the page, or NULL if page is not kernel + * addressable. + * + ****************************************************************************/ + +static FAR void *map_single_page(uintptr_t page) +{ + return (FAR void *)up_addrenv_page_vaddr(page); +} + +/**************************************************************************** + * Name: is_kmap_vaddr + * + * Description: + * Return true if the virtual address, vaddr, lies in the kmap address + * space. + * + * Input Parameters: + * vaddr - The kernel virtual address where the mapping begins. + * + * Returned Value: + * True if vaddr is in the kmap address space; false otherwise. + * + ****************************************************************************/ + +static bool is_kmap_vaddr(uintptr_t vaddr) +{ + return (vaddr >= CONFIG_ARCH_KMAP_VBASE && vaddr < ARCH_KMAP_VEND); +} + /**************************************************************************** * Name: kmm_map_lock * @@ -270,6 +311,13 @@ FAR void *kmm_map(FAR void **pages, size_t npages, int prot) return NULL; } + /* A single page can be addressed directly, if it is a kernel page */ + + if (npages == 1) + { + return map_single_page((uintptr_t)pages[0]); + } + /* Attempt to map the pages */ vaddr = (uintptr_t)map_pages(pages, npages, prot); @@ -301,6 +349,15 @@ void kmm_unmap(FAR void *kaddr) unsigned int npages; int ret; + /* Speed optimization: check that addr is within kmap area */ + + if (!is_kmap_vaddr((uintptr_t)kaddr)) + { + /* Nope: get out */ + + return; + } + /* Lock the mapping list when we fiddle around with it */ ret = kmm_map_lock(); @@ -308,7 +365,7 @@ void kmm_unmap(FAR void *kaddr) { /* Find the entry, it is OK if none found */ - entry = mm_map_find(get_current_mm(), kaddr, 1); + entry = mm_map_find(&g_kmm_map, kaddr, 1); if (entry) { npages = MM_NPAGES(entry->length); @@ -331,7 +388,7 @@ void kmm_unmap(FAR void *kaddr) } /**************************************************************************** - * Name: kmm_user_map + * Name: kmm_map_user * * Description: * Map a region of user memory (physical pages) for kernel use through @@ -346,9 +403,9 @@ void kmm_unmap(FAR void *kaddr) * ****************************************************************************/ -FAR void *kmm_user_map(FAR void *uaddr, size_t size) +FAR void *kmm_map_user(FAR void *uaddr, size_t size) { - FAR void *pages; + FAR void **pages; uintptr_t vaddr; uintptr_t offset; size_t npages; @@ -385,7 +442,7 @@ FAR void *kmm_user_map(FAR void *uaddr, size_t size) /* No, the area must be mapped into kernel virtual address space */ - pages = kmm_zalloc(npages * sizeof(FAR void *)); + pages = (FAR void **)kmm_zalloc(npages * sizeof(FAR void *)); if (!pages) { return NULL; @@ -393,7 +450,7 @@ FAR void *kmm_user_map(FAR void *uaddr, size_t size) /* Fetch the physical pages for the user virtual address range */ - ret = get_user_pages(&pages, npages, vaddr); + ret = get_user_pages(pages, npages, vaddr); if (ret < 0) { goto errout_with_pages; @@ -401,7 +458,7 @@ FAR void *kmm_user_map(FAR void *uaddr, size_t size) /* Map the physical pages to kernel memory */ - vaddr = (uintptr_t)map_pages(&pages, npages, PROT_READ | PROT_WRITE); + vaddr = (uintptr_t)map_pages(pages, npages, PROT_READ | PROT_WRITE); if (!vaddr) { goto errout_with_pages; @@ -409,6 +466,7 @@ FAR void *kmm_user_map(FAR void *uaddr, size_t size) /* Ok, we have a virtual memory area, add the offset back */ + kmm_free(pages); return (FAR void *)(vaddr + offset); errout_with_pages: 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) diff --git a/sched/misc/assert.c b/sched/misc/assert.c index 1cbe45aef76b5..95ec7ce5a428a 100644 --- a/sched/misc/assert.c +++ b/sched/misc/assert.c @@ -553,11 +553,21 @@ void _assert(FAR const char *filename, int linenum, FAR const char *msg, FAR void *regs) { FAR struct tcb_s *rtcb = running_task(); +#if CONFIG_TASK_NAME_SIZE > 0 + FAR struct tcb_s *ptcb = NULL; +#endif struct panic_notifier_s notifier_data; struct utsname name; bool fatal = true; int flags; +#if CONFIG_TASK_NAME_SIZE > 0 + if (rtcb->group && !(rtcb->flags & TCB_FLAG_TTYPE_KERNEL)) + { + ptcb = nxsched_get_tcb(rtcb->group->tg_pid); + } +#endif + flags = enter_critical_section(); sched_lock(); @@ -602,6 +612,7 @@ void _assert(FAR const char *filename, int linenum, ": " #if CONFIG_TASK_NAME_SIZE > 0 "%s " + "process: %s " #endif "%p\n", msg ? msg : "", @@ -611,6 +622,7 @@ void _assert(FAR const char *filename, int linenum, #endif #if CONFIG_TASK_NAME_SIZE > 0 rtcb->name, + ptcb ? ptcb->name : "Kernel", #endif rtcb->entry.main); diff --git a/sched/task/task_posixspawn.c b/sched/task/task_posixspawn.c index 0fb56c97b9549..a0ff0c0d5d365 100644 --- a/sched/task/task_posixspawn.c +++ b/sched/task/task_posixspawn.c @@ -102,13 +102,6 @@ static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path, exec_getsymtab(&symtab, &nsymbols); - /* Disable pre-emption so that we can modify the task parameters after - * we start the new task; the new task will not actually begin execution - * until we re-enable pre-emption. - */ - - sched_lock(); - /* Start the task */ pid = exec_spawn(path, argv, envp, symtab, nsymbols, actions, attr); @@ -116,7 +109,7 @@ static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path, { ret = -pid; serr("ERROR: exec failed: %d\n", ret); - goto errout; + return ret; } /* Return the task ID to the caller */ @@ -126,20 +119,6 @@ static int nxposix_spawn_exec(FAR pid_t *pidp, FAR const char *path, *pidp = pid; } - /* Now set the attributes. Note that we ignore all of the return values - * here because we have already successfully started the task. If we - * return an error value, then we would also have to stop the task. - */ - - if (attr) - { - spawn_execattrs(pid, attr); - } - - /* Re-enable pre-emption and return */ - -errout: - sched_unlock(); return ret; } diff --git a/sched/task/task_spawn.c b/sched/task/task_spawn.c index 7c261286a0059..aa753abd93830 100644 --- a/sched/task/task_spawn.c +++ b/sched/task/task_spawn.c @@ -80,7 +80,8 @@ static int nxtask_spawn_create(FAR const char *name, int priority, FAR void *stack_addr, int stack_size, main_t entry, FAR char * const argv[], FAR char * const envp[], - FAR const posix_spawn_file_actions_t *actions) + FAR const posix_spawn_file_actions_t *actions, + FAR const posix_spawnattr_t *attr) { FAR struct task_tcb_s *tcb; pid_t pid; @@ -109,6 +110,10 @@ static int nxtask_spawn_create(FAR const char *name, int priority, return ret; } + /* Get the assigned pid before we start the task */ + + pid = tcb->cmn.pid; + /* Perform file actions */ if (actions != NULL) @@ -116,20 +121,30 @@ static int nxtask_spawn_create(FAR const char *name, int priority, ret = spawn_file_actions(&tcb->cmn, actions); if (ret < 0) { - nxtask_uninit(tcb); - return ret; + goto errout_with_taskinit; } } - /* Get the assigned pid before we start the task */ + /* Set the attributes */ - pid = tcb->cmn.pid; + if (attr) + { + ret = spawn_execattrs(pid, attr); + if (ret < 0) + { + goto errout_with_taskinit; + } + } /* Activate the task */ nxtask_activate(&tcb->cmn); return pid; + +errout_with_taskinit: + nxtask_uninit(tcb); + return ret; } /**************************************************************************** @@ -188,13 +203,6 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name, int pid; int ret = OK; - /* Disable pre-emption so that we can modify the task parameters after - * we start the new task; the new task will not actually begin execution - * until we re-enable pre-emption. - */ - - sched_lock(); - /* Use the default priority and stack size if no attributes are provided */ if (attr) @@ -212,7 +220,7 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name, ret = nxsched_get_param(0, ¶m); if (ret < 0) { - goto errout; + return ret; } priority = param.sched_priority; @@ -223,12 +231,12 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name, pid = nxtask_spawn_create(name, priority, stackaddr, stacksize, entry, argv, - envp ? envp : environ, actions); + envp ? envp : environ, actions, attr); if (pid < 0) { ret = pid; serr("ERROR: nxtask_spawn_create failed: %d\n", ret); - goto errout; + return ret; } /* Return the task ID to the caller */ @@ -238,20 +246,6 @@ static int nxtask_spawn_exec(FAR pid_t *pidp, FAR const char *name, *pidp = pid; } - /* Now set the attributes. Note that we ignore all of the return values - * here because we have already successfully started the task. If we - * return an error value, then we would also have to stop the task. - */ - - if (attr) - { - spawn_execattrs(pid, attr); - } - - /* Re-enable pre-emption and return */ - -errout: - sched_unlock(); return ret; } diff --git a/tools/ci/cibuild.sh b/tools/ci/cibuild.sh index e96b9f45b39c0..a53b45cafa287 100755 --- a/tools/ci/cibuild.sh +++ b/tools/ci/cibuild.sh @@ -57,7 +57,7 @@ function arm-clang-toolchain { rm LLVMEmbeddedToolchainForArm-14.0.0-${flavor}.tar.gz fi - clang --version + command clang --version } function arm-gcc-toolchain { @@ -81,7 +81,7 @@ function arm-gcc-toolchain { rm arm-gnu-toolchain-12.3.rel1${flavor}-x86_64-arm-none-eabi.tar fi - arm-none-eabi-gcc --version + command arm-none-eabi-gcc --version } function arm64-gcc-toolchain { @@ -105,7 +105,7 @@ function arm64-gcc-toolchain { rm gcc-arm-11.2-2022.02-${flavor}-aarch64-none-elf.tar fi - aarch64-none-elf-gcc --version + command aarch64-none-elf-gcc --version } function avr-gcc-toolchain { @@ -121,7 +121,7 @@ function avr-gcc-toolchain { esac fi - avr-gcc --version + command avr-gcc --version } function binutils { @@ -140,7 +140,7 @@ function binutils { esac fi - objcopy --version + command objcopy --version } function bloaty { @@ -180,7 +180,7 @@ function c-cache { esac fi - ccache --version + command ccache --version } function clang-tidy { @@ -204,7 +204,23 @@ function elf-toolchain { esac fi - x86_64-elf-gcc --version + command x86_64-elf-gcc --version +} + +function util-linux { + if ! type flock &> /dev/null; then + case ${os} in + Darwin) + brew tap discoteq/discoteq + brew install flock + ;; + Linux) + apt-get install -y util-linux + ;; + esac + fi + + command flock --version } function gen-romfs { @@ -264,11 +280,11 @@ function mips-gcc-toolchain { case ${os} in Darwin) add_path "${tools}"/pinguino-compilers/macosx/p32/bin - mips-elf-gcc --version + command mips-elf-gcc --version ;; Linux) add_path "${tools}"/pinguino-compilers/linux64/p32/bin - p32-gcc --version + command p32-gcc --version ;; esac } @@ -308,26 +324,26 @@ function python-tools { } function riscv-gcc-toolchain { - add_path "${tools}"/riscv64-unknown-elf-gcc/bin + add_path "${tools}"/riscv-none-elf-gcc/bin - if [ ! -f "${tools}/riscv64-unknown-elf-gcc/bin/riscv64-unknown-elf-gcc" ]; then + if [ ! -f "${tools}/riscv-none-elf-gcc/bin/riscv-none-elf-gcc" ]; then local flavor case ${os} in Darwin) - flavor=x86_64-apple-darwin + flavor=darwin-x64 ;; Linux) - flavor=x86_64-linux-ubuntu14 + flavor=linux-x64 ;; esac cd "${tools}" - wget --quiet https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-${flavor}.tar.gz - tar zxf riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-${flavor}.tar.gz - mv riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-${flavor} riscv64-unknown-elf-gcc - rm riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-${flavor}.tar.gz + wget --quiet https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-${flavor}.tar.gz + tar zxf xpack-riscv-none-elf-gcc-12.3.0-1-${flavor}.tar.gz + mv xpack-riscv-none-elf-gcc-12.3.0-1 riscv-none-elf-gcc + rm xpack-riscv-none-elf-gcc-12.3.0-1-${flavor}.tar.gz fi - riscv64-unknown-elf-gcc --version + command riscv-none-elf-gcc --version } function rust { @@ -347,7 +363,7 @@ function rust { esac fi - rustc --version + command rustc --version } function rx-gcc-toolchain { @@ -398,7 +414,7 @@ function rx-gcc-toolchain { esac fi - rx-elf-gcc --version + command rx-elf-gcc --version } function sparc-gcc-toolchain { @@ -417,7 +433,7 @@ function sparc-gcc-toolchain { esac fi - sparc-gaisler-elf-gcc --version + command sparc-gaisler-elf-gcc --version } function xtensa-esp32-gcc-toolchain { @@ -441,14 +457,13 @@ function xtensa-esp32-gcc-toolchain { esac fi - xtensa-esp32-elf-gcc --version + command xtensa-esp32-elf-gcc --version } function u-boot-tools { if ! type mkimage &> /dev/null; then case ${os} in Darwin) - rm -f /usr/local/bin/openssl brew install u-boot-tools ;; Linux) @@ -487,8 +502,8 @@ function wasi-sdk { export WASI_SDK_PATH="${tools}/wasi-sdk" - ${WASI_SDK_PATH}/bin/clang --version - wamrc --version + command ${WASI_SDK_PATH}/bin/clang --version + command wamrc --version } function usage { @@ -560,12 +575,20 @@ function install_tools { case ${os} in Darwin) - install="arm-gcc-toolchain arm64-gcc-toolchain avr-gcc-toolchain binutils bloaty elf-toolchain gen-romfs gperf kconfig-frontends mips-gcc-toolchain python-tools riscv-gcc-toolchain rust xtensa-esp32-gcc-toolchain u-boot-tools wasi-sdk c-cache" + install="arm-gcc-toolchain arm64-gcc-toolchain avr-gcc-toolchain binutils bloaty elf-toolchain gen-romfs gperf kconfig-frontends mips-gcc-toolchain python-tools riscv-gcc-toolchain rust xtensa-esp32-gcc-toolchain u-boot-tools util-linux wasi-sdk c-cache" mkdir -p "${tools}"/homebrew export HOMEBREW_CACHE=${tools}/homebrew + # https://github.com/apache/arrow/issues/15025 + rm -f /usr/local/bin/2to3* || : + rm -f /usr/local/bin/idle3* || : + rm -f /usr/local/bin/pydoc3* || : + rm -f /usr/local/bin/python3* || : + rm -f /usr/local/bin/python3-config || : + # same for openssl + rm -f /usr/local/bin/openssl || : ;; Linux) - install="arm-clang-toolchain arm-gcc-toolchain arm64-gcc-toolchain avr-gcc-toolchain binutils bloaty clang-tidy gen-romfs gperf kconfig-frontends mips-gcc-toolchain python-tools riscv-gcc-toolchain rust rx-gcc-toolchain sparc-gcc-toolchain xtensa-esp32-gcc-toolchain u-boot-tools wasi-sdk c-cache" + install="arm-clang-toolchain arm-gcc-toolchain arm64-gcc-toolchain avr-gcc-toolchain binutils bloaty clang-tidy gen-romfs gperf kconfig-frontends mips-gcc-toolchain python-tools riscv-gcc-toolchain rust rx-gcc-toolchain sparc-gcc-toolchain xtensa-esp32-gcc-toolchain u-boot-tools util-linux wasi-sdk c-cache" ;; esac diff --git a/tools/ci/docker/linux/Dockerfile b/tools/ci/docker/linux/Dockerfile index e1e0467d18c5b..272d82ad97ee5 100644 --- a/tools/ci/docker/linux/Dockerfile +++ b/tools/ci/docker/linux/Dockerfile @@ -168,10 +168,10 @@ RUN cd /tools/renesas-tools/build/gcc && \ # Build image for tool required by RISCV builds ############################################################################### FROM nuttx-toolchain-base AS nuttx-toolchain-riscv -# Download the latest RISCV GCC toolchain prebuilt by SiFive -RUN mkdir riscv64-unknown-elf-gcc && \ - curl -s -L "https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz" \ - | tar -C riscv64-unknown-elf-gcc --strip-components 1 -xz +# Download the latest RISCV GCC toolchain prebuilt by xPack +RUN mkdir riscv-none-elf-gcc && \ + curl -s -L "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v12.3.0-1/xpack-riscv-none-elf-gcc-12.3.0-1-linux-x64.tar.gz" \ + | tar -C riscv-none-elf-gcc --strip-components 1 -xz ############################################################################### # Build image for tool required by SPARC builds @@ -350,8 +350,8 @@ COPY --from=nuttx-toolchain-renesas /tools/renesas-toolchain/rx-elf-gcc/ renesas ENV PATH="/tools/renesas-toolchain/rx-elf-gcc/bin:$PATH" # RISCV toolchain -COPY --from=nuttx-toolchain-riscv /tools/riscv64-unknown-elf-gcc/ riscv64-unknown-elf-gcc/ -ENV PATH="/tools/riscv64-unknown-elf-gcc/bin:$PATH" +COPY --from=nuttx-toolchain-riscv /tools/riscv-none-elf-gcc/ riscv-none-elf-gcc/ +ENV PATH="/tools/riscv-none-elf-gcc/bin:$PATH" # SPARC toolchain COPY --from=nuttx-toolchain-sparc /tools/sparc-gaisler-elf-gcc/ sparc-gaisler-elf-gcc/ @@ -393,8 +393,8 @@ RUN mkdir -p /tools/ccache/bin && \ ln -sf `which ccache` /tools/ccache/bin/g++ && \ ln -sf `which ccache` /tools/ccache/bin/p32-gcc && \ ln -sf `which ccache` /tools/ccache/bin/rx-elf-gcc && \ - ln -sf `which ccache` /tools/ccache/bin/riscv64-unknown-elf-gcc && \ - ln -sf `which ccache` /tools/ccache/bin/riscv64-unknown-elf-g++ && \ + ln -sf `which ccache` /tools/ccache/bin/riscv-none-elf-gcc && \ + ln -sf `which ccache` /tools/ccache/bin/riscv-none-elf-g++ && \ ln -sf `which ccache` /tools/ccache/bin/sparc-gaisler-elf-gcc && \ ln -sf `which ccache` /tools/ccache/bin/sparc-gaisler-elf-g++ && \ ln -sf `which ccache` /tools/ccache/bin/xtensa-esp32-elf-gcc && \