This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push: new 102c63be9e bl602: Add initial DMA support, including SPI over DMA. 102c63be9e is described below commit 102c63be9ea325a0f4be2288b0aef77eaeace862 Author: Brennan Ashton <bash...@brennanashton.com> AuthorDate: Sun Aug 14 16:29:30 2022 -0700 bl602: Add initial DMA support, including SPI over DMA. --- arch/risc-v/src/bl602/Kconfig | 19 + arch/risc-v/src/bl602/Make.defs | 4 + arch/risc-v/src/bl602/bl602_dma.c | 491 +++++++++++++++++++++ arch/risc-v/src/bl602/bl602_dma.h | 262 +++++++++++ arch/risc-v/src/bl602/bl602_romapi.h | 3 + arch/risc-v/src/bl602/bl602_spi.c | 426 +++++++++++++++++- arch/risc-v/src/bl602/bl602_spi.h | 4 - arch/risc-v/src/bl602/hardware/bl602_dma.h | 31 ++ arch/risc-v/src/common/riscv_initialize.c | 13 + arch/risc-v/src/common/riscv_internal.h | 6 + boards/risc-v/bl602/bl602evb/configs/dma/defconfig | 82 ++++ 11 files changed, 1327 insertions(+), 14 deletions(-) diff --git a/arch/risc-v/src/bl602/Kconfig b/arch/risc-v/src/bl602/Kconfig index 03de245b00..728fe9e1c3 100644 --- a/arch/risc-v/src/bl602/Kconfig +++ b/arch/risc-v/src/bl602/Kconfig @@ -7,6 +7,11 @@ comment "BL602 Configuration Options" menu "BL602 Peripheral Support" +config BL602_DMA + bool "DMA" + default n + select ARCH_DMA + config BL602_HAVE_UART0 bool "UART0" select BL602_UART0 @@ -42,9 +47,23 @@ config BL602_PWM0 config BL602_I2C0 bool "I2C0" +config BL602_I2C_DMA + bool "I2C DMA support" + default n + depends on BL602_DMA + ---help--- + Select to enable DMA SPI transfers + config BL602_SPI0 bool "SPI0" +config BL602_SPI_DMA + bool "SPI DMA support" + default n + depends on BL602_DMA + ---help--- + Select to enable DMA SPI transfers + config BL602_RTC bool "RTC" diff --git a/arch/risc-v/src/bl602/Make.defs b/arch/risc-v/src/bl602/Make.defs index 6aebdda9e3..4f0c44b944 100644 --- a/arch/risc-v/src/bl602/Make.defs +++ b/arch/risc-v/src/bl602/Make.defs @@ -58,6 +58,10 @@ ifeq ($(CONFIG_RTC_DRIVER),y) CHIP_CSRCS += bl602_rtc.c bl602_rtc_lowerhalf.c endif +ifeq ($(CONFIG_BL602_DMA),y) +CHIP_CSRCS += bl602_dma.c +endif + CHIP_CSRCS += bl602_glb.c bl602_gpio.c bl602_hbn.c bl602_systemreset.c ifeq ($(CONFIG_BL602_WIRELESS),y) diff --git a/arch/risc-v/src/bl602/bl602_dma.c b/arch/risc-v/src/bl602/bl602_dma.c new file mode 100644 index 0000000000..b51bed091f --- /dev/null +++ b/arch/risc-v/src/bl602/bl602_dma.c @@ -0,0 +1,491 @@ +/**************************************************************************** + * arch/risc-v/src/bl602/bl602_dma.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 <nuttx/config.h> +#include <nuttx/arch.h> + +#include <stdint.h> +#include <errno.h> +#include <assert.h> +#include <debug.h> + +#include "chip.h" +#include "riscv_internal.h" +#include "hardware/bl602_dma.h" +#include "bl602_dma.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes one DMA channel */ + +struct dma_channel_s +{ + uint8_t chan; /* DMA channel number (0-BL602_DMA_NCHANNELS) */ + bool inuse; /* TRUE: The DMA channel is in use */ + bl602_dma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ +}; + +/* This structure describes the state of the DMA controller */ + +struct dma_controller_s +{ + sem_t exclsem; /* Protects channel table */ + sem_t chansem; /* Count of free channels */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the overall state of the DMA controller */ + +static struct dma_controller_s g_dmac; + +/* This is the array of all DMA channels */ + +static struct dma_channel_s g_dmach[BL602_DMA_NCHANNELS]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bl602_dma_int_handler + * + * Description: + * DMA interrupt handler. + * + ****************************************************************************/ + +static int bl602_dma_int_handler(int irq, void *context, void *arg) +{ + /* We need to ack the IRQ or a mess is made */ + + /* Itterate over each of the channels checking for and clearing: + * DMA_INTTCSTATUS + * DMA_INTERRORSTATUS + */ + + uint8_t ch; + uint32_t tc_status; + uint32_t err_status; + + tc_status = getreg32(BL602_DMA_INTTCSTATUS) & DMA_INTTCSTATUS_MASK; + err_status = getreg32(BL602_DMA_INTERRORSTATUS) & DMA_INTERRORSTATUS_MASK; + + for (ch = 0; ch < BL602_DMA_NCHANNELS; ch++) + { + if (tc_status & (1 << ch)) + { + dmainfo("CH %d TC Int fired\n", ch); + putreg32((1 << ch), BL602_DMA_INTTCCLEAR); + if (g_dmach[ch].callback != NULL) + { + g_dmach[ch].callback( + ch, + BL602_DMA_INT_EVT_TC, + g_dmach[ch].arg); + } + } + + if (err_status & (1 << ch)) + { + dmainfo("CH %d Error Int fired\n", ch); + putreg32((1 << ch), BL602_DMA_INTERRCLR); + g_dmach[ch].callback(ch, BL602_DMA_INT_EVT_ERR, g_dmach[ch].arg); + } + } + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bl602_dma_channel_request + * + * Description: + * Allocate a new DMA channel. + * + * Input Parameters: + * None + * + * Returned Value: + * 0-3: DMA channel + * -1: Failed + * + ****************************************************************************/ + +int8_t bl602_dma_channel_request(bl602_dma_callback_t callback, void *arg) +{ + struct dma_channel_s *dmach; + unsigned int ch; + int ret; + + /* Take a count from the channel counting semaphore. We may block + * if there are no free channels. When we get the count, then we can + * be assured that a channel is available in the channel list and is + * reserved for us. + */ + + ret = nxsem_wait_uninterruptible(&g_dmac.chansem); + if (ret < 0) + { + return -1; + } + + /* Get exclusive access to the DMA channel list */ + + ret = nxsem_wait_uninterruptible(&g_dmac.exclsem); + if (ret < 0) + { + nxsem_post(&g_dmac.chansem); + return -1; + } + + /* Search for an available DMA channel */ + + for (ch = 0, dmach = NULL; ch < BL602_DMA_NCHANNELS; ch++) + { + struct dma_channel_s *candidate = &g_dmach[ch]; + if (!candidate->inuse) + { + dmainfo("DMA Channel %u assigned.\n", ch); + dmach = candidate; + dmach->inuse = true; + + break; + } + } + + nxsem_post(&g_dmac.exclsem); + + /* Since we have reserved a DMA descriptor by taking a count from chansem, + * it would be a serious logic failure if we could not find a free channel + * for our use. + */ + + DEBUGASSERT(dmach); + dmach->callback = callback; + dmach->arg = arg; + return dmach->chan; +} + +/**************************************************************************** + * Name: bl602_dma_channel_release + * + * Description: + * Release a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_release(uint8_t channel_id) +{ + /* Get exclusive access to the DMA channel list */ + + if (nxsem_wait_uninterruptible(&g_dmac.exclsem) < 0) + { + return -1; + } + + /* Verify if the channel is actually in use */ + + if (g_dmach[channel_id].inuse) + { + /* This channel was infact in use, release it and increment the + * count of free channels for use. + */ + + g_dmach[channel_id].inuse = false; + nxsem_post(&g_dmac.chansem); + } + + nxsem_post(&g_dmac.exclsem); + return 0; +} + +/**************************************************************************** + * Name: bl602_dma_channel_start + * + * Description: + * Start a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_start(uint8_t channel_id) +{ + /* Unmask interrupts for: + * - DMA_INT_TCOMPLETED + * - DMA_INT_ERR + * Enable Terminal Count interrupt. + */ + + modifyreg32(BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, channel_id), + DMA_C0CONFIG_ITC | DMA_C0CONFIG_IE, + 0); + modifyreg32(BL602_DMA_CH_N_REG(BL602_DMA_CONTROL_OFFSET, channel_id), + 0, + DMA_C0CONTROL_I); + + /* Enable channel */ + + modifyreg32(BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, channel_id), + 0, + DMA_C0CONFIG_E); + + return 0; +} + +/**************************************************************************** + * Name: bl602_dma_channel_stop + * + * Description: + * Stop a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_stop(uint8_t channel_id) +{ + /* Disable channel */ + + modifyreg32(BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, channel_id), + DMA_C0CONFIG_E, + 0); + + /* Mask interrupts for: + * - DMA_INT_TCOMPLETED + * - DMA_INT_ERR + */ + + modifyreg32(BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, channel_id), + 0, + DMA_C0CONFIG_ITC | DMA_C0CONFIG_IE); + + /* Clear interrupts for channel in: + * - DMA_INTTCCLEAR + * - DMA_INTERRORSTATUS + */ + + putreg32((1 << channel_id), BL602_DMA_INTTCCLEAR); + putreg32((1 << channel_id), BL602_DMA_INTERRCLR); + + return 0; +} + +/**************************************************************************** + * Name: riscv_dma_initialize + * + * Description: + * Intialize DMA controller. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function riscv_dma_initialize(void) +{ + uint8_t ch; + + #ifdef CONFIG_DEBUG_DMA_INFO + struct bl602_dmaregs_s regs; + #endif + + dmainfo("Initialize DMA\n"); + + /* Note we may want to set EN bits in DMAEN as part of clk_cfg2. + * At reset these bits are already set to enabled, and the documentation + * is a little thin around this. If we implement more low power + * configuration we will want to be more clear about these bits. + */ + + /* Initialize the channel list */ + + nxsem_init(&g_dmac.exclsem, 0, 1); + nxsem_init(&g_dmac.chansem, 0, BL602_DMA_NCHANNELS); + + for (ch = 0; ch < BL602_DMA_NCHANNELS; ch++) + { + g_dmach[ch].chan = ch; + + /* Disable the DMA channel */ + + putreg32(0, BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, ch)); + } + + /* Attach DMA tranfer complete interrupt handler */ + + irq_attach(BL602_IRQ_DMA_ALL, bl602_dma_int_handler, NULL); + up_enable_irq(BL602_IRQ_DMA_ALL); + + /* Enable SMDMA controller */ + + modifyreg32(BL602_DMA_TOP_CONFIG, 0, DMA_TOP_CONFIG_E); + + /* Dump DMA register state */ + + bl602_dmasample(®s); + bl602_dmadump(®s, "Initialized DMA"); +} + +/**************************************************************************** + * Name: bl602_dmasample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void bl602_dmasample(struct bl602_dmaregs_s *regs) +{ + irqstate_t flags; + + /* Sample DMA registers. */ + + flags = enter_critical_section(); + + regs->intstatus = getreg32(BL602_DMA_INTSTATUS); + regs->inttcstatus = getreg32(BL602_DMA_INTTCSTATUS); + regs->inttcclear = getreg32(BL602_DMA_INTTCCLEAR); + regs->interrorstatus = getreg32(BL602_DMA_INTERRORSTATUS); + regs->interrclr = getreg32(BL602_DMA_INTERRCLR); + regs->rawinttcstatus = getreg32(BL602_DMA_RAWINTTCSTATUS); + regs->rawinterrorstatus = getreg32(BL602_DMA_RAWINTERRORSTATUS); + regs->enbldchns = getreg32(BL602_DMA_ENBLDCHNS); + regs->softbreq = getreg32(BL602_DMA_SOFTBREQ); + regs->softsreq = getreg32(BL602_DMA_SOFTSREQ); + regs->softlbreq = getreg32(BL602_DMA_SOFTLBREQ); + regs->softlsreq = getreg32(BL602_DMA_SOFTLSREQ); + regs->top_config = getreg32(BL602_DMA_TOP_CONFIG); + regs->sync = getreg32(BL602_DMA_SYNC); + regs->c0srcaddr = getreg32(BL602_DMA_C0SRCADDR); + regs->c0dstaddr = getreg32(BL602_DMA_C0DSTADDR); + regs->c0lli = getreg32(BL602_DMA_C0LLI); + regs->c0control = getreg32(BL602_DMA_C0CONTROL); + regs->c0config = getreg32(BL602_DMA_C0CONFIG); + regs->c1srcaddr = getreg32(BL602_DMA_C1SRCADDR); + regs->c1dstaddr = getreg32(BL602_DMA_C1DSTADDR); + regs->c1lli = getreg32(BL602_DMA_C1LLI); + regs->c1control = getreg32(BL602_DMA_C1CONTROL); + regs->c1config = getreg32(BL602_DMA_C1CONFIG); + regs->c2srcaddr = getreg32(BL602_DMA_C2SRCADDR); + regs->c2dstaddr = getreg32(BL602_DMA_C2DSTADDR); + regs->c2lli = getreg32(BL602_DMA_C2LLI); + regs->c2control = getreg32(BL602_DMA_C2CONTROL); + regs->c2config = getreg32(BL602_DMA_C2CONFIG); + regs->c3srcaddr = getreg32(BL602_DMA_C3SRCADDR); + regs->c3dstaddr = getreg32(BL602_DMA_C3DSTADDR); + regs->c3lli = getreg32(BL602_DMA_C3LLI); + regs->c3control = getreg32(BL602_DMA_C3CONTROL); + regs->c3config = getreg32(BL602_DMA_C3CONFIG); + + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: bl602_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void bl602_dmadump(const struct bl602_dmaregs_s *regs, + const char *msg) +{ + dmainfo("%s\n", msg); + dmainfo(" DMA Registers:\n"); + dmainfo(" INTSTATUS: %08x\n", regs->intstatus); + dmainfo(" INTTCSTATU: %08x\n", regs->inttcstatus); + dmainfo(" INTTCCLEAR: %08x\n", regs->inttcclear); + dmainfo(" INTERRORST: %08x\n", regs->interrorstatus); + dmainfo(" INTERRCLR: %08x\n", regs->interrclr); + dmainfo(" RAWINTTCST: %08x\n", regs->rawinttcstatus); + dmainfo(" RAWINTERRO: %08x\n", regs->rawinterrorstatus); + dmainfo(" ENBLDCHNS: %08x\n", regs->enbldchns); + dmainfo(" SOFTBREQ: %08x\n", regs->softbreq); + dmainfo(" SOFTSREQ: %08x\n", regs->softsreq); + dmainfo(" SOFTLBREQ: %08x\n", regs->softlbreq); + dmainfo(" SOFTLSREQ: %08x\n", regs->softlsreq); + dmainfo(" TOP_CONFIG: %08x\n", regs->top_config); + dmainfo(" SYNC: %08x\n", regs->sync); + dmainfo(" === Channel 0 ===\n"); + dmainfo(" C0SRCADDR: %08x\n", regs->c0srcaddr); + dmainfo(" C0DSTADDR: %08x\n", regs->c0dstaddr); + dmainfo(" C0LLI: %08x\n", regs->c0lli); + dmainfo(" C0CONTROL: %08x\n", regs->c0control); + dmainfo(" C0CONFIG: %08x\n", regs->c0config); + dmainfo(" === Channel 1 ===\n"); + dmainfo(" C1SRCADDR: %08x\n", regs->c1srcaddr); + dmainfo(" C1DSTADDR: %08x\n", regs->c1dstaddr); + dmainfo(" C1LLI: %08x\n", regs->c1lli); + dmainfo(" C1CONTROL: %08x\n", regs->c1control); + dmainfo(" C1CONFIG: %08x\n", regs->c1config); + dmainfo(" === Channel 2 ===\n"); + dmainfo(" C2SRCADDR: %08x\n", regs->c2srcaddr); + dmainfo(" C2DSTADDR: %08x\n", regs->c2dstaddr); + dmainfo(" C2LLI: %08x\n", regs->c2lli); + dmainfo(" C2CONTROL: %08x\n", regs->c2control); + dmainfo(" C2CONFIG: %08x\n", regs->c2config); + dmainfo(" === Channel 3 ===\n"); + dmainfo(" C3SRCADDR: %08x\n", regs->c3srcaddr); + dmainfo(" C3DSTADDR: %08x\n", regs->c3dstaddr); + dmainfo(" C3LLI: %08x\n", regs->c3lli); + dmainfo(" C3CONTROL: %08x\n", regs->c3control); + dmainfo(" C3CONFIG: %08x\n", regs->c3config); +} +#endif diff --git a/arch/risc-v/src/bl602/bl602_dma.h b/arch/risc-v/src/bl602/bl602_dma.h new file mode 100644 index 0000000000..d9e535c238 --- /dev/null +++ b/arch/risc-v/src/bl602/bl602_dma.h @@ -0,0 +1,262 @@ +/**************************************************************************** + * arch/risc-v/src/bl602/bl602_dma.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_BL602_BL602_DMA_H +#define __ARCH_RISCV_SRC_BL602_BL602_DMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <stdint.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BL602_DMA_NCHANNELS 4 +#define BL602_DMA_INT_EVT_TC 0 /* Interrupt callback status Transfer Complete */ +#define BL602_DMA_INT_EVT_ERR 1 /* Interrupt callback status Error */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +struct bl602_dmaregs_s +{ + uint32_t intstatus; /* Interrupt status. */ + uint32_t inttcstatus; /* Interrupt terminal count request status. */ + uint32_t inttcclear; /* Terminal count request clear. */ + uint32_t interrorstatus; /* Interrupt error status. */ + uint32_t interrclr; /* Interrupt error clear. */ + uint32_t rawinttcstatus; /* Status of the terminal count interrupt prior to masking. */ + uint32_t rawinterrorstatus; /* Status of the error interrupt prior to masking. */ + uint32_t enbldchns; /* Channel enable status. */ + uint32_t softbreq; /* Software burst request. */ + uint32_t softsreq; /* Software single request. */ + uint32_t softlbreq; /* Software last burst request. */ + uint32_t softlsreq; /* Software last single request. */ + uint32_t top_config; /* DMA general configuration. */ + uint32_t sync; /* DMA request asynchronous setting. */ + uint32_t c0srcaddr; /* Channel DMA source address. */ + uint32_t c0dstaddr; /* Channel DMA Destination address. */ + uint32_t c0lli; /* Channel DMA link list. */ + uint32_t c0control; /* Channel DMA bus control. */ + uint32_t c0config; /* Channel DMA configuration. */ + uint32_t c1srcaddr; /* Channel DMA source address. */ + uint32_t c1dstaddr; /* Channel DMA Destination address. */ + uint32_t c1lli; /* Channel DMA link list. */ + uint32_t c1control; /* Channel DMA bus control. */ + uint32_t c1config; /* Channel DMA configuration. */ + uint32_t c2srcaddr; /* Channel DMA source address. */ + uint32_t c2dstaddr; /* Channel DMA Destination address. */ + uint32_t c2lli; /* Channel DMA link list. */ + uint32_t c2control; /* Channel DMA bus control. */ + uint32_t c2config; /* Channel DMA configuration. */ + uint32_t c3srcaddr; /* Channel DMA source address. */ + uint32_t c3dstaddr; /* Channel DMA Destination address. */ + uint32_t c3lli; /* Channel DMA link list. */ + uint32_t c3control; /* Channel DMA bus control. */ + uint32_t c3config; /* Channel DMA configuration. */ +}; +#endif + +/* Configuration for the LLI Control entry, defined as matching + * the DMA channel control register. + */ + +begin_packed_struct struct bl602_dma_ctrl_s +{ + uint32_t transfer_size : 12; + uint32_t src_burst_size : 3; + uint32_t dst_burst_size : 3; + uint32_t src_width : 3; + uint32_t dst_width : 3; + uint32_t sld : 1; + uint32_t rsvd : 1; + uint32_t src_increment : 1; + uint32_t dst_increment : 1; + uint32_t protect : 3; + uint32_t tc_int_en : 1; +} end_packed_struct; + +/* Configuration for the LLI packed data. + * This must be aligned to uint32 pointer. + */ + +begin_packed_struct struct aligned_data(4) bl602_lli_ctrl_s +{ + uint32_t src_addr; + uint32_t dst_addr; + uint32_t next_lli; /* Address for next LLI entry */ + struct bl602_dma_ctrl_s dma_ctrl; /* Control register config for entry */ +} end_packed_struct; + +/* Description: + * This is the type of the callback that is used to inform the user of the + * completion of the DMA. + * + * Input Parameters: + * channel - Refers to the DMA channel + * status - A bit encoded value that provides the completion status. + * See the BL602_DMA_INT_EVT_* definitions above. + * arg - A user-provided value. + */ + +typedef void (*bl602_dma_callback_t) \ + (uint8_t channel, uint8_t status, void *arg); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: bl602_dma_channel_request + * + * Description: + * Allocate a new DMA channel. + * + * Input Parameters: + * None + * + * Returned Value: + * 0-3: DMA channel + * -1: Failed + * + ****************************************************************************/ + +int8_t bl602_dma_channel_request(bl602_dma_callback_t callback, void *arg); + +/**************************************************************************** + * Name: bl602_dma_channel_release + * + * Description: + * Release a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_release(uint8_t channel); + +/**************************************************************************** + * Name: bl602_dma_channel_start + * + * Description: + * Start a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_start(uint8_t channel_id); + +/**************************************************************************** + * Name: bl602_dma_channel_stop + * + * Description: + * Stop a DMA channel. + * + * Input Parameters: + * channel: DMA channel. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_channel_stop(uint8_t channel_id); + +/**************************************************************************** + * Name: bl602_dma_init + * + * Description: + * Intialize DMA controller. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise -1 (ERROR). + * + ****************************************************************************/ + +int bl602_dma_init(void); + +/**************************************************************************** + * Name: bl602_dmasample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void bl602_dmasample(struct bl602_dmaregs_s *regs); +#else +# define bl602_dmasample(regs) +#endif + +/**************************************************************************** + * Name: bl602_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA_INFO +void bl602_dmadump(const struct bl602_dmaregs_s *regs, const char *msg); +#else +# define bl602_dmadump(regs,msg) +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_BL602_BL602_DMA_H */ diff --git a/arch/risc-v/src/bl602/bl602_romapi.h b/arch/risc-v/src/bl602/bl602_romapi.h index f9c17011d8..7f45c66adc 100644 --- a/arch/risc-v/src/bl602/bl602_romapi.h +++ b/arch/risc-v/src/bl602/bl602_romapi.h @@ -31,6 +31,7 @@ #define BL602_ROMAPI_FUNC(idx) (*(uintptr_t *)(BL602_ROMAPI_BASE + (idx)*4)) #define BL602_ROMAPI_ASM_DELAY_US BL602_ROMAPI_FUNC(20) +#define BL602_ROMAPI_MEMCPY4 BL602_ROMAPI_FUNC(24) #define BL602_ROMAPI_EFUSE_CTRL_LOAD_R0 BL602_ROMAPI_FUNC(31) #define BL602_ROMAPI_RST_SYSTEM BL602_ROMAPI_FUNC(47) #define BL602_ROMAPI_RST_CPU_SW BL602_ROMAPI_FUNC(48) @@ -43,4 +44,6 @@ #define BL602_ROMAPI_SFLASH_WRITE_WITHLOCK BL602_ROMAPI_FUNC(171) #define BL602_ROMAPI_SFLASH_EREASE_WITHLOCK BL602_ROMAPI_FUNC(172) +#define bl602_romapi_memcpy_4 ((uint32_t* (*) (uint32_t*, const uint32_t*, uint32_t))BL602_ROMAPI_MEMCPY4) + #endif /* __ARCH_RISCV_SRC_BL602_BL602_ROMAPI_H */ diff --git a/arch/risc-v/src/bl602/bl602_spi.c b/arch/risc-v/src/bl602/bl602_spi.c index c2d9faa3b3..45740432cc 100644 --- a/arch/risc-v/src/bl602/bl602_spi.c +++ b/arch/risc-v/src/bl602/bl602_spi.c @@ -33,15 +33,22 @@ #include <sys/types.h> #include <nuttx/arch.h> +#include <nuttx/compiler.h> + #include <nuttx/irq.h> +#include <nuttx/kmalloc.h> #include <nuttx/semaphore.h> +#include <nuttx/signal.h> #include <nuttx/spi/spi.h> #include <arch/board/board.h> #include "bl602_glb.h" #include "bl602_gpio.h" +#include "bl602_romapi.h" #include "bl602_spi.h" +#include "bl602_dma.h" +#include "hardware/bl602_dma.h" #include "hardware/bl602_glb.h" #include "hardware/bl602_spi.h" #include "hardware/bl602_hbn.h" @@ -52,6 +59,7 @@ ****************************************************************************/ #define SPI_FREQ_DEFAULT 400000 +#define LLI_BUFF_SIZE 2048 /* Maximum transaction count per LLI entry. */ /**************************************************************************** * Private Types @@ -126,7 +134,8 @@ struct bl602_spi_priv_s /* Interrupt wait semaphore */ - sem_t sem_isr; + sem_t sem_isr_tx; + sem_t sem_isr_rx; uint32_t frequency; /* Requested clock frequency */ uint32_t actual; /* Actual clock frequency */ @@ -136,7 +145,8 @@ struct bl602_spi_priv_s /* Actual SPI send/receive bits once transmission */ uint8_t nbits; - uint8_t dma_chan; + int8_t dma_txchan; + int8_t dma_rxchan; }; /**************************************************************************** @@ -227,7 +237,9 @@ static struct bl602_spi_priv_s bl602_spi_priv = { .ops = &bl602_spi_ops }, - .config = &bl602_spi_config + .config = &bl602_spi_config, + .dma_rxchan = -1, + .dma_txchan = -1, }; #endif /* CONFIG_BL602_SPI0 */ @@ -236,6 +248,38 @@ static struct bl602_spi_priv_s bl602_spi_priv = * Private Functions ****************************************************************************/ +#ifdef CONFIG_BL602_SPI_DMA +static void bl602_dma_rx_callback(uint8_t channel, uint8_t status, void *arg) +{ + struct bl602_spi_priv_s *priv = (struct bl602_spi_priv_s *)arg; + UNUSED(channel); + spiinfo("RX interrupt fired with status %u\n", status); + if (status == BL602_DMA_INT_EVT_TC) + { + nxsem_post(&priv->sem_isr_rx); + } + else + { + spierr("DMA transfer failed for RX.\n"); + } +} + +static void bl602_dma_tx_callback(uint8_t channel, uint8_t status, void *arg) +{ + struct bl602_spi_priv_s *priv = (struct bl602_spi_priv_s *)arg; + UNUSED(channel); + spiinfo("TX interrupt fired with status %u\n", status); + if (status == BL602_DMA_INT_EVT_TC) + { + nxsem_post(&priv->sem_isr_tx); + } + else + { + spierr("DMA transfer failed for TX.\n"); + } +} +#endif + /**************************************************************************** * Name: bl602_check_with_new_prescale * @@ -773,6 +817,168 @@ static int bl602_spi_hwfeatures(struct spi_dev_s *dev, } #endif +/**************************************************************************** + * Name: lli_list_init + * + * Description: + * Configure the LLI structure for DMA transactions with SPI + * + * Input Parameters: + * priv - Device-specific state data + * tx_lli - A pointer to the LLI structures for TX. + * rx_lli - A pointer to the LLI structures for RX. + * tx_buffer - A pointer to the transaction buffer for TX. + * rx_buffer - A pointer to the transaction buffer for RX. + * Buffer is null if TX only. + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into + * uint16_t's + * + * Returned Value: + * Error state - 0 on success. + * + ****************************************************************************/ + +#ifdef CONFIG_BL602_SPI_DMA +static int lli_list_init(struct bl602_spi_priv_s *priv, + struct bl602_lli_ctrl_s **tx_lli, + struct bl602_lli_ctrl_s **rx_lli, + const void *txbuffer, + void *rxbuffer, size_t nwords) +{ + uint8_t i; + uint32_t count; + uint32_t remainder; + struct bl602_dma_ctrl_s dma_ctrl; + + /* Determine the how many LLI entries will be required */ + + count = (nwords * priv->nbits / 8) / LLI_BUFF_SIZE; + remainder = (nwords * priv->nbits / 8) % LLI_BUFF_SIZE; + + /* If LLI entry cannot be fully packed with data, add an additional entry + * for the remainder entry. + */ + + if (remainder != 0) + { + count = count + 1; + } + + /* Set the base config that will be used for each entry */ + + dma_ctrl.src_width = (priv->nbits / 8) - 1; /* 8/16/32 bits */ + dma_ctrl.dst_width = dma_ctrl.src_width; + dma_ctrl.src_burst_size = 0; /* 1 item per transaction */ + dma_ctrl.dst_burst_size = 0; /* 1 item per transaction */ + dma_ctrl.protect = 0; + dma_ctrl.tc_int_en = 0; /* We will overwrite this in the last entry */ + dma_ctrl.rsvd = 0; + dma_ctrl.sld = 0; /* Not used for non mem-to-mem transfers. */ + + /* We will set these per entry: + * - transfer_size + * - src_increment + * - dst_increment + */ + + /* Allocate the transfer block. + * TODO consider supporting pre-allocation of these structures. + * most transaction will only use a single LLI, so we could + * actually place the single LLI structure on the stack (4*4 bytes) + */ + + *tx_lli = kmm_malloc(sizeof(struct bl602_lli_ctrl_s) * count); + if (*tx_lli == NULL) + { + spierr("Failed to allocate lli for tx.\n"); + return -1; + } + + if (rxbuffer != NULL) + { + *rx_lli = kmm_malloc(sizeof(struct bl602_lli_ctrl_s) * count); + if (*rx_lli == NULL) + { + spierr("Failed to allocate lli for rx.\n"); + kmm_free(*tx_lli); + return -1; + } + } + else + { + *rx_lli = NULL; + } + + for (i = 0; i < count; i++) + { + /* Check if this is the final entry and there is remainder set */ + + if ((i == (count - 1)) && (remainder != 0)) + { + dma_ctrl.transfer_size = remainder; + } + else + { + dma_ctrl.transfer_size = LLI_BUFF_SIZE; + } + + /* Configure tx side */ + + { + dma_ctrl.dst_increment = 0; + dma_ctrl.src_increment = 1; + (*tx_lli)[i].dma_ctrl = dma_ctrl; + (*tx_lli)[i].dst_addr = BL602_SPI_FIFO_WDATA; + (*tx_lli)[i].src_addr = \ + (uint32_t)txbuffer + (dma_ctrl.src_width * i * LLI_BUFF_SIZE); + + /* Assume last entry, we will overwrite as needed. */ + + (*tx_lli)[i].next_lli = 0; + + /* Link entry */ + + if (i != 0) + { + (*tx_lli)[i - 1].next_lli = (uint32_t)&(*tx_lli)[i]; + } + } + + /* Configure rx side */ + + if (rxbuffer != NULL) + { + dma_ctrl.dst_increment = 1; + dma_ctrl.src_increment = 0; + (*rx_lli)[i].dma_ctrl = dma_ctrl; + (*rx_lli)[i].dst_addr = \ + (uint32_t)rxbuffer + (dma_ctrl.dst_width * i * LLI_BUFF_SIZE); + (*rx_lli)[i].src_addr = BL602_SPI_FIFO_RDATA; + (*rx_lli)[i].next_lli = 0; /* Assume last entry, we will overwrite as needed. */ + + /* Link entry */ + + if (i != 0) + { + (*rx_lli)[i - 1].next_lli = (uint32_t)&(*rx_lli)[i]; + } + } + } + + (*tx_lli)[count - 1].dma_ctrl.tc_int_en = 1; + + if (rxbuffer != NULL) + { + (*rx_lli)[count - 1].dma_ctrl.tc_int_en = 1; + } + + return 0; +} +#endif + /**************************************************************************** * Name: bl602_spi_dma_exchange * @@ -794,13 +1000,97 @@ static int bl602_spi_hwfeatures(struct spi_dev_s *dev, * ****************************************************************************/ +#ifdef CONFIG_BL602_SPI_DMA static void bl602_spi_dma_exchange(struct bl602_spi_priv_s *priv, const void *txbuffer, void *rxbuffer, uint32_t nwords) { - spierr("SPI dma not supported\n"); - DEBUGPANIC(); + int err; + + #ifdef CONFIG_DEBUG_DMA_INFO + struct bl602_dmaregs_s regs; + #endif + + struct bl602_lli_ctrl_s *tx_lli; + struct bl602_lli_ctrl_s *rx_lli; + + /* Enable master */ + + modifyreg32(BL602_SPI_CFG, SPI_CFG_CR_S_EN, SPI_CFG_CR_M_EN); + + err = lli_list_init(priv, &tx_lli, &rx_lli, txbuffer, rxbuffer, nwords); + + if (err < 0) + { + spierr("Failed to initalize DMA LLI\n"); + return; + } + + /* Configure DMA controller with LLI. + * This needs to be set using the ROM API from TCM to initialize all 4 + * registers from the LLI structure. + */ + + bl602_romapi_memcpy_4( + (uint32_t *)BL602_DMA_CH_N_REG(BL602_DMA_SRCADDR_OFFSET, + priv->dma_txchan), + (uint32_t *)tx_lli, 4); + + if (rxbuffer != NULL) + { + bl602_romapi_memcpy_4( + (uint32_t *)BL602_DMA_CH_N_REG(BL602_DMA_SRCADDR_OFFSET, + priv->dma_rxchan), + (uint32_t *)rx_lli, 4); + } + + /* Dump DMA register state */ + + bl602_dmasample(®s); + bl602_dmadump(®s, "Initialized DMA"); + + /* Start channel */ + + if (rxbuffer != NULL) + { + bl602_dma_channel_start(priv->dma_rxchan); + } + + bl602_dma_channel_start(priv->dma_txchan); + + /* Dump DMA register state */ + + bl602_dmasample(®s); + bl602_dmadump(®s, "Post Start DMA"); + + /* Wait for RX and TX to complete. */ + + nxsem_wait_uninterruptible(&priv->sem_isr_tx); + + if (rxbuffer != NULL) + { + nxsem_wait_uninterruptible(&priv->sem_isr_rx); + } + + /* Stop channels */ + + bl602_dma_channel_stop(priv->dma_txchan); + + if (rxbuffer != NULL) + { + bl602_dma_channel_stop(priv->dma_rxchan); + } + + kmm_free(tx_lli); + + if (rx_lli != NULL) + { + kmm_free(rx_lli); + } + + return; } +#endif /**************************************************************************** * Name: bl602_spi_poll_send @@ -869,6 +1159,7 @@ static uint32_t bl602_spi_poll_send(struct bl602_spi_priv_s *priv, * ****************************************************************************/ +#ifdef CONFIG_BL602_SPI_DMA static uint32_t bl602_spi_dma_send(struct bl602_spi_priv_s *priv, uint32_t wd) { @@ -878,6 +1169,7 @@ static uint32_t bl602_spi_dma_send(struct bl602_spi_priv_s *priv, return rd; } +#endif /**************************************************************************** * Name: bl602_spi_send @@ -898,9 +1190,11 @@ static uint32_t bl602_spi_dma_send(struct bl602_spi_priv_s *priv, static uint32_t bl602_spi_send(struct spi_dev_s *dev, uint32_t wd) { struct bl602_spi_priv_s *priv = (struct bl602_spi_priv_s *)dev; + +#ifdef CONFIG_BL602_SPI_DMA uint32_t rd; - if (priv->dma_chan) + if (priv->dma_txchan >= 0 && priv->dma_rxchan >= 0) { rd = bl602_spi_dma_send(priv, wd); } @@ -910,6 +1204,9 @@ static uint32_t bl602_spi_send(struct spi_dev_s *dev, uint32_t wd) } return rd; +#else + return bl602_spi_poll_send(priv, wd); +#endif } /**************************************************************************** @@ -998,7 +1295,8 @@ static void bl602_spi_exchange(struct spi_dev_s *dev, { struct bl602_spi_priv_s *priv = (struct bl602_spi_priv_s *)dev; - if (priv->dma_chan) +#ifdef CONFIG_BL602_SPI_DMA + if (priv->dma_txchan >= 0 && priv->dma_rxchan >= 0) { bl602_spi_dma_exchange(priv, txbuffer, rxbuffer, nwords); } @@ -1006,6 +1304,9 @@ static void bl602_spi_exchange(struct spi_dev_s *dev, { bl602_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords); } +#else + bl602_spi_poll_exchange(priv, txbuffer, rxbuffer, nwords); +#endif } #ifndef CONFIG_SPI_EXCHANGE @@ -1145,6 +1446,100 @@ static void bl602_swap_spi_0_mosi_with_miso(uint8_t swap) } } +#ifdef CONFIG_BL602_SPI_DMA +/**************************************************************************** + * Name: bl602_spi_dma_init + * + * Description: + * Initialize BL SPI connection to DMA engine. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void bl602_spi_dma_init(struct spi_dev_s *dev) +{ + struct bl602_spi_priv_s *priv = (struct bl602_spi_priv_s *)dev; + + #ifdef CONFIG_DEBUG_DMA_INFO + struct bl602_dmaregs_s regs; + #endif + + /* NOTE DMA channels are limited on this device and not all SPI devices + * care about the RX side. Consider making the RX channel optional. + */ + + /* Request a DMA channel for SPI peripheral */ + + priv->dma_rxchan = bl602_dma_channel_request(bl602_dma_rx_callback, + (void *)priv); + if (priv->dma_rxchan < 0) + { + spierr("Failed to allocate GDMA channel\n"); + + DEBUGASSERT(false); + return; + } + + priv->dma_txchan = bl602_dma_channel_request(bl602_dma_tx_callback, + (void *)priv); + if (priv->dma_txchan < 0) + { + spierr("Failed to allocate GDMA channel\n"); + + /* Release the RX channel since we won't be using it. */ + + bl602_dma_channel_release(priv->dma_rxchan); + priv->dma_rxchan = -1; + + DEBUGASSERT(false); + return; + } + + /* Configure channels for SPI DMA */ + + /* Configure channel from SPI to Mem */ + + modifyreg32( + BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, priv->dma_rxchan), + DMA_C0CONFIG_FLOWCNTRL_MASK | \ + DMA_C0CONFIG_DSTPERIPHERAL_MASK | \ + DMA_C0CONFIG_SRCPERIPHERAL_MASK, + (BL602_DMA_TRNS_P2M << DMA_C0CONFIG_FLOWCNTRL_SHIFT) | \ + (BL602_DMA_REQ_SPI_RX << DMA_C0CONFIG_SRCPERIPHERAL_SHIFT)); + + /* Configure channel from Mem to SPI */ + + modifyreg32( + BL602_DMA_CH_N_REG(BL602_DMA_CONFIG_OFFSET, priv->dma_txchan), + DMA_C0CONFIG_FLOWCNTRL_MASK | DMA_C0CONFIG_DSTPERIPHERAL_MASK | \ + DMA_C0CONFIG_SRCPERIPHERAL_MASK, + (BL602_DMA_TRNS_M2P << DMA_C0CONFIG_FLOWCNTRL_SHIFT) | \ + (BL602_DMA_REQ_SPI_TX << DMA_C0CONFIG_DSTPERIPHERAL_SHIFT)); + + /* Set FIFO threshold to trigger DMA */ + + modifyreg32( + BL602_SPI_FIFO_CFG_1, + SPI_FIFO_CFG_1_RX_TH_MASK | SPI_FIFO_CFG_1_TX_TH_MASK, + (0 << SPI_FIFO_CFG_1_RX_TH_SHIFT) | (0 << SPI_FIFO_CFG_1_TX_TH_SHIFT)); + + /* Enable DMA support */ + + modifyreg32(BL602_SPI_FIFO_CFG_0, 0, + SPI_FIFO_CFG_0_DMA_RX_EN | SPI_FIFO_CFG_0_DMA_TX_EN); + + /* Dump DMA register state */ + + bl602_dmasample(®s); + bl602_dmadump(®s, "Initialized DMA"); +} +#endif + /**************************************************************************** * Name: bl602_spi_init * @@ -1167,6 +1562,8 @@ static void bl602_spi_init(struct spi_dev_s *dev) /* Initialize the SPI semaphore that enforces mutually exclusive access */ nxsem_init(&priv->exclsem, 0, 1); + nxsem_init(&priv->sem_isr_rx, 0, 0); + nxsem_init(&priv->sem_isr_tx, 0, 0); bl602_configgpio(BOARD_SPI_CS); bl602_configgpio(BOARD_SPI_MOSI); @@ -1192,9 +1589,11 @@ static void bl602_spi_init(struct spi_dev_s *dev) | SPI_CFG_CR_BYTE_INV | SPI_CFG_CR_BIT_INV, SPI_CFG_CR_DEG_EN); - /* disable rx ignore */ + /* Disable rx ignore. + * Enable continuous mode. + */ - modifyreg32(BL602_SPI_CFG, SPI_CFG_CR_RXD_IGNR_EN, 0); + modifyreg32(BL602_SPI_CFG, SPI_CFG_CR_RXD_IGNR_EN, SPI_CFG_CR_M_CONT_EN); bl602_spi_setfrequency(dev, config->clk_freq); bl602_spi_setbits(dev, 8); @@ -1204,6 +1603,10 @@ static void bl602_spi_init(struct spi_dev_s *dev) modifyreg32(BL602_SPI_FIFO_CFG_0, SPI_FIFO_CFG_0_RX_CLR | SPI_FIFO_CFG_0_TX_CLR, 0); + +#ifdef CONFIG_BL602_SPI_DMA + bl602_spi_dma_init(dev); +#endif } /**************************************************************************** @@ -1230,7 +1633,8 @@ static void bl602_spi_deinit(struct spi_dev_s *dev) priv->actual = 0; priv->mode = SPIDEV_MODE0; priv->nbits = 0; - priv->dma_chan = 0; + priv->dma_txchan = -1; + priv->dma_rxchan = -1; } /**************************************************************************** @@ -1317,6 +1721,8 @@ int bl602_spibus_uninitialize(struct spi_dev_s *dev) bl602_spi_deinit(dev); nxsem_destroy(&priv->exclsem); + nxsem_destroy(&priv->sem_isr_rx); + nxsem_destroy(&priv->sem_isr_tx); return OK; } diff --git a/arch/risc-v/src/bl602/bl602_spi.h b/arch/risc-v/src/bl602/bl602_spi.h index b2ddb0c226..ddf13f97f2 100644 --- a/arch/risc-v/src/bl602/bl602_spi.h +++ b/arch/risc-v/src/bl602/bl602_spi.h @@ -42,8 +42,6 @@ extern "C" #define EXTERN extern #endif -#ifdef CONFIG_BL602_SPI0 - #include <nuttx/spi/spi.h> #include <nuttx/spi/spi_transfer.h> @@ -77,8 +75,6 @@ struct spi_dev_s *bl602_spibus_initialize(int port); int bl602_spibus_uninitialize(struct spi_dev_s *dev); -#endif /* CONFIG_BL602_SPI0 */ - #ifdef __cplusplus } #endif diff --git a/arch/risc-v/src/bl602/hardware/bl602_dma.h b/arch/risc-v/src/bl602/hardware/bl602_dma.h index 6d8a89b8f9..67e4a965a4 100644 --- a/arch/risc-v/src/bl602/hardware/bl602_dma.h +++ b/arch/risc-v/src/bl602/hardware/bl602_dma.h @@ -106,6 +106,18 @@ #define BL602_DMA_C3CONTROL (BL602_DMA_BASE + BL602_DMA_C3CONTROL_OFFSET) #define BL602_DMA_C3CONFIG (BL602_DMA_BASE + BL602_DMA_C3CONFIG_OFFSET) +/* Channel register helpers *************************************************/ + +#define BL602_DMA_CH_REG_OFFSET 0x000100 /* Offset between channels */ +#define BL602_DMA_CH_REG_BASE BL602_DMA_C0SRCADDR +#define BL602_DMA_SRCADDR_OFFSET 0x000000 /* CnSrcAddr */ +#define BL602_DMA_DSTADDR_OFFSET 0x000004 /* CnDstAddr */ +#define BL602_DMA_LLI_OFFSET 0x000008 /* CnLLI */ +#define BL602_DMA_CONTROL_OFFSET 0x00000c /* CnControl */ +#define BL602_DMA_CONFIG_OFFSET 0x000010 /* CnConfig */ + +#define BL602_DMA_CH_N_REG(reg, ch) ((BL602_DMA_CH_REG_BASE + (BL602_DMA_CH_REG_OFFSET * ch)) + reg) + /* Register bit definitions *************************************************/ #define DMA_INTSTATUS_MASK (0xff) @@ -251,4 +263,23 @@ #define DMA_C3CONFIG_SRCPERIPHERAL_MASK (0x1f << DMA_C3CONFIG_SRCPERIPHERAL_SHIFT) #define DMA_C3CONFIG_E (1 << 0) +#define BL602_DMA_TRNS_M2M (0) /* DMA memory to memory */ +#define BL602_DMA_TRNS_M2P (1) /* DMA memory to peripheral */ +#define BL602_DMA_TRNS_P2M (2) /* DMA peripheral to memory */ +#define BL602_DMA_TRNS_P2P (3) /* DMA peripheral to peripheral */ + +#define BL602_DMA_REQ_UART0_RX (0) /* DMA request peripheral UART0 RX */ +#define BL602_DMA_REQ_UART0_TX (1) /* DMA request peripheral UART0 TX */ +#define BL602_DMA_REQ_UART1_RX (2) /* DMA request peripheral UART1 RX */ +#define BL602_DMA_REQ_UART1_TX (3) /* DMA request peripheral UART1 TX */ +#define BL602_DMA_REQ_I2C_RX (6) /* DMA request peripheral I2C RX */ +#define BL602_DMA_REQ_I2C_TX (7) /* DMA request peripheral I2C TX */ +#define BL602_DMA_REQ_SPI_RX (10) /* DMA request peripheral SPI RX */ +#define BL602_DMA_REQ_SPI_TX (11) /* DMA request peripheral SPI TX */ +#define BL602_DMA_REQ_I2S_RX (20) /* DMA request peripheral SPI RX */ +#define BL602_DMA_REQ_I2S_TX (21) /* DMA request peripheral SPI TX */ +#define BL602_DMA_REQ_GPADC0 (22) /* DMA request peripheral GPADC0 */ +#define BL602_DMA_REQ_GPADC1 (23) /* DMA request peripheral GPADC1 */ +#define BL602_DMA_REQ_NONE (0 ) /* DMA request peripheral None */ + #endif /* __ARCH_RISCV_SRC_BL602_HARDWARE_BL602_DMA_H */ diff --git a/arch/risc-v/src/common/riscv_initialize.c b/arch/risc-v/src/common/riscv_initialize.c index d39198b542..0540b16c1e 100644 --- a/arch/risc-v/src/common/riscv_initialize.c +++ b/arch/risc-v/src/common/riscv_initialize.c @@ -105,6 +105,19 @@ void up_initialize(void) riscv_pminitialize(); #endif +#ifdef CONFIG_ARCH_DMA + /* Initialize the DMA subsystem if the weak function arm_dma_initialize has + * been brought into the build + */ + +#ifdef CONFIG_HAVE_WEAKFUNCTIONS + if (riscv_dma_initialize) +#endif + { + riscv_dma_initialize(); + } +#endif + /* Initialize the serial device driver */ #ifdef USE_SERIALDRIVER diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index 861c412cd2..fbfa3f12fa 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -232,6 +232,12 @@ void riscv_pminitialize(void); # define riscv_pminitialize() #endif +/* DMA **********************************************************************/ + +#ifdef CONFIG_ARCH_DMA +void weak_function riscv_dma_initialize(void); +#endif + /* Low level serial output **************************************************/ void riscv_lowputc(char ch); diff --git a/boards/risc-v/bl602/bl602evb/configs/dma/defconfig b/boards/risc-v/bl602/bl602evb/configs/dma/defconfig new file mode 100644 index 0000000000..467b7d51f3 --- /dev/null +++ b/boards/risc-v/bl602/bl602evb/configs/dma/defconfig @@ -0,0 +1,82 @@ +# +# 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_LIBC_FLOATINGPOINT is not set +# CONFIG_LIBC_LONG_LONG is not set +# CONFIG_NDEBUG is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NSH_CMDPARMS is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="bl602evb" +CONFIG_ARCH_BOARD_BL602EVB=y +CONFIG_ARCH_CHIP="bl602" +CONFIG_ARCH_CHIP_BL602=y +CONFIG_ARCH_INTERRUPTSTACK=8192 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BINFMT_DISABLE=y +CONFIG_BL602_DMA=y +CONFIG_BL602_HAVE_UART0=y +CONFIG_BL602_I2C0=y +CONFIG_BL602_I2C_DMA=y +CONFIG_BL602_SPI0=y +CONFIG_BL602_SPI_DMA=y +CONFIG_BL602_TIMER0=y +CONFIG_BOARD_LOOPSPERMSEC=10000 +CONFIG_BUILTIN=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEV_ZERO=y +CONFIG_DISABLE_ENVIRON=y +CONFIG_DISABLE_MQUEUE=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_DISABLE_PSEUDOFS_OPERATIONS=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_HELLO_STACKSIZE=8192 +CONFIG_EXAMPLES_TIMER=y +CONFIG_FS_PROCFS=y +CONFIG_I2C=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_NFILE_DESCRIPTORS_PER_BLOCK=6 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=64 +CONFIG_NSH_LINELEN=64 +CONFIG_NSH_READLINE=y +CONFIG_NSH_STRERROR=y +CONFIG_PTHREAD_MUTEX_UNSAFE=y +CONFIG_PTHREAD_STACK_DEFAULT=8192 +CONFIG_RAM_SIZE=134217728 +CONFIG_RAM_START=0xc0800000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SIG_PREALLOC_IRQ_ACTIONS=4 +CONFIG_SPI=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=20 +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2020 +CONFIG_STDIO_DISABLE_BUFFERING=y +CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SPITOOL=y +CONFIG_TASK_NAME_SIZE=12 +CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=8192 +CONFIG_TESTING_GETPRIME=y +CONFIG_TIMER=y +CONFIG_TIMER_ARCH=y +CONFIG_UART0_BAUD=2000000 +CONFIG_UART0_RXBUFSIZE=128 +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_UART0_TXBUFSIZE=128