arm/rp2040: Add RP2040 DMAC functions
This commit is contained in:
parent
9428ba9186
commit
b69df289bd
@ -73,6 +73,11 @@ config RP2040_UART1_2STOP
|
||||
|
||||
endif
|
||||
|
||||
config RP2040_DMAC
|
||||
bool "DMAC support"
|
||||
default y
|
||||
select ARCH_DMA
|
||||
|
||||
config RP2040_SPI
|
||||
bool "SPI"
|
||||
select SPI
|
||||
|
@ -67,6 +67,10 @@ CHIP_CSRCS += rp2040_cpuidlestack.c
|
||||
CHIP_CSRCS += rp2040_testset.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP2040_DMAC),y)
|
||||
CHIP_CSRCS += rp2040_dmac.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RP2040_SPI),y)
|
||||
CHIP_CSRCS += rp2040_spi.c
|
||||
endif
|
||||
|
222
arch/arm/src/rp2040/hardware/rp2040_dma.h
Normal file
222
arch/arm/src/rp2040/hardware/rp2040_dma.h
Normal file
@ -0,0 +1,222 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/hardware/rp2040_dma.h
|
||||
*
|
||||
* Generated from rp2040.svd originally provided by
|
||||
* Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
*
|
||||
* 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.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_DMA_H
|
||||
#define __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_DMA_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include "hardware/rp2040_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define RP2040_DMA_READ_ADDR_OFFSET 0x000000 /* DMA Read Address pointer */
|
||||
#define RP2040_DMA_WRITE_ADDR_OFFSET 0x000004 /* DMA Write Address pointer */
|
||||
#define RP2040_DMA_TRANS_COUNT_OFFSET 0x000008 /* DMA Transfer Count */
|
||||
#define RP2040_DMA_CTRL_TRIG_OFFSET 0x00000c /* DMA Control and Status */
|
||||
#define RP2040_DMA_AL1_CTRL_OFFSET 0x000010 /* Alias for CTRL register */
|
||||
#define RP2040_DMA_AL1_READ_ADDR_OFFSET 0x000014 /* Alias for READ_ADDR register */
|
||||
#define RP2040_DMA_AL1_WRITE_ADDR_OFFSET 0x000018 /* Alias for WRITE_ADDR register */
|
||||
#define RP2040_DMA_AL1_TRANS_COUNT_TRIG_OFFSET 0x00001c /* Alias for TRANS_COUNT register */
|
||||
#define RP2040_DMA_AL2_CTRL_OFFSET 0x000020 /* Alias for CTRL register */
|
||||
#define RP2040_DMA_AL2_TRANS_COUNT_OFFSET 0x000024 /* Alias for TRANS_COUNT register */
|
||||
#define RP2040_DMA_AL2_READ_ADDR_OFFSET 0x000028 /* Alias for READ_ADDR register */
|
||||
#define RP2040_DMA_AL2_WRITE_ADDR_TRIG_OFFSET 0x00002c /* Alias for WRITE_ADDR register */
|
||||
#define RP2040_DMA_AL3_CTRL_OFFSET 0x000030 /* Alias for CTRL register */
|
||||
#define RP2040_DMA_AL3_WRITE_ADDR_OFFSET 0x000034 /* Alias for WRITE_ADDR register */
|
||||
#define RP2040_DMA_AL3_TRANS_COUNT_OFFSET 0x000038 /* Alias for TRANS_COUNT register */
|
||||
#define RP2040_DMA_AL3_READ_ADDR_TRIG_OFFSET 0x00003c /* Alias for READ_ADDR register */
|
||||
|
||||
#define RP2040_DMA_INTR_OFFSET 0x000400 /* Interrupt Status (raw) */
|
||||
#define RP2040_DMA_INTE0_OFFSET 0x000404 /* Interrupt Enables for IRQ 0 */
|
||||
#define RP2040_DMA_INTF0_OFFSET 0x000408 /* Force Interrupts */
|
||||
#define RP2040_DMA_INTS0_OFFSET 0x00040c /* Interrupt Status for IRQ 0 */
|
||||
#define RP2040_DMA_INTE1_OFFSET 0x000414 /* Interrupt Enables for IRQ 1 */
|
||||
#define RP2040_DMA_INTF1_OFFSET 0x000418 /* Force Interrupts for IRQ 1 */
|
||||
#define RP2040_DMA_INTS1_OFFSET 0x00041c /* Interrupt Status (masked) for IRQ 1 */
|
||||
#define RP2040_DMA_TIMER0_OFFSET 0x000420 /* Pacing (X/Y) Fractional Timer The pacing timer produces TREQ assertions at a rate set by ((X/Y) * sys_clk). This equation is evaluated every sys_clk cycles and therefore can only generate TREQs at a rate of 1 per sys_clk (i.e. permanent TREQ) or less. */
|
||||
#define RP2040_DMA_TIMER1_OFFSET 0x000424 /* Pacing (X/Y) Fractional Timer The pacing timer produces TREQ assertions at a rate set by ((X/Y) * sys_clk). This equation is evaluated every sys_clk cycles and therefore can only generate TREQs at a rate of 1 per sys_clk (i.e. permanent TREQ) or less. */
|
||||
#define RP2040_DMA_TIMER2_OFFSET 0x000428 /* Pacing (X/Y) Fractional Timer The pacing timer produces TREQ assertions at a rate set by ((X/Y) * sys_clk). This equation is evaluated every sys_clk cycles and therefore can only generate TREQs at a rate of 1 per sys_clk (i.e. permanent TREQ) or less. */
|
||||
#define RP2040_DMA_TIMER3_OFFSET 0x00042c /* Pacing (X/Y) Fractional Timer The pacing timer produces TREQ assertions at a rate set by ((X/Y) * sys_clk). This equation is evaluated every sys_clk cycles and therefore can only generate TREQs at a rate of 1 per sys_clk (i.e. permanent TREQ) or less. */
|
||||
#define RP2040_DMA_MULTI_CHAN_TRIGGER_OFFSET 0x000430 /* Trigger one or more channels simultaneously */
|
||||
#define RP2040_DMA_SNIFF_CTRL_OFFSET 0x000434 /* Sniffer Control */
|
||||
#define RP2040_DMA_SNIFF_DATA_OFFSET 0x000438 /* Data accumulator for sniff hardware Write an initial seed value here before starting a DMA transfer on the channel indicated by SNIFF_CTRL_DMACH. The hardware will update this register each time it observes a read from the indicated channel. Once the channel completes, the final result can be read from this register. */
|
||||
#define RP2040_DMA_FIFO_LEVELS_OFFSET 0x000440 /* Debug RAF, WAF, TDF levels */
|
||||
#define RP2040_DMA_CHAN_ABORT_OFFSET 0x000444 /* Abort an in-progress transfer sequence on one or more channels */
|
||||
#define RP2040_DMA_N_CHANNELS_OFFSET 0x000448 /* The number of channels this DMA instance is equipped with. This DMA supports up to 16 hardware channels, but can be configured with as few as one, to minimise silicon area. */
|
||||
#define RP2040_DMA_DBG_CTDREQ_OFFSET(n) (0x000800 + (n) * 0x0040)
|
||||
#define RP2040_DMA_DBG_TCR_OFFSET (0x000804 + (n) * 0x0040)
|
||||
|
||||
/* Register definitions *****************************************************/
|
||||
|
||||
#define RP2040_DMA_CH(n) (RP2040_DMA_BASE + (0x0040 * (n)))
|
||||
#define RP2040_DMA_READ_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_READ_ADDR_OFFSET)
|
||||
#define RP2040_DMA_WRITE_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_WRITE_ADDR_OFFSET)
|
||||
#define RP2040_DMA_TRANS_COUNT(n) (RP2040_DMA_CH(n) + RP2040_DMA_TRANS_COUNT_OFFSET)
|
||||
#define RP2040_DMA_CTRL_TRIG(n) (RP2040_DMA_CH(n) + RP2040_DMA_CTRL_TRIG_OFFSET)
|
||||
#define RP2040_DMA_AL1_CTRL(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL1_CTRL_OFFSET)
|
||||
#define RP2040_DMA_AL1_READ_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL1_READ_ADDR_OFFSET)
|
||||
#define RP2040_DMA_AL1_WRITE_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL1_WRITE_ADDR_OFFSET)
|
||||
#define RP2040_DMA_AL1_TRANS_COUNT_TRIG(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL1_TRANS_COUNT_TRIG_OFFSET)
|
||||
#define RP2040_DMA_AL2_CTRL(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL2_CTRL_OFFSET)
|
||||
#define RP2040_DMA_AL2_TRANS_COUNT(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL2_TRANS_COUNT_OFFSET)
|
||||
#define RP2040_DMA_AL2_READ_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL2_READ_ADDR_OFFSET)
|
||||
#define RP2040_DMA_AL2_WRITE_ADDR_TRIG(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL2_WRITE_ADDR_TRIG_OFFSET)
|
||||
#define RP2040_DMA_AL3_CTRL(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL3_CTRL_OFFSET)
|
||||
#define RP2040_DMA_AL3_WRITE_ADDR(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL3_WRITE_ADDR_OFFSET)
|
||||
#define RP2040_DMA_AL3_TRANS_COUNT(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL3_TRANS_COUNT_OFFSET)
|
||||
#define RP2040_DMA_AL3_READ_ADDR_TRIG(n) (RP2040_DMA_CH(n) + RP2040_DMA_AL3_READ_ADDR_TRIG_OFFSET)
|
||||
|
||||
#define RP2040_DMA_INTR (RP2040_DMA_BASE + RP2040_DMA_INTR_OFFSET)
|
||||
#define RP2040_DMA_INTE0 (RP2040_DMA_BASE + RP2040_DMA_INTE0_OFFSET)
|
||||
#define RP2040_DMA_INTF0 (RP2040_DMA_BASE + RP2040_DMA_INTF0_OFFSET)
|
||||
#define RP2040_DMA_INTS0 (RP2040_DMA_BASE + RP2040_DMA_INTS0_OFFSET)
|
||||
#define RP2040_DMA_INTE1 (RP2040_DMA_BASE + RP2040_DMA_INTE1_OFFSET)
|
||||
#define RP2040_DMA_INTF1 (RP2040_DMA_BASE + RP2040_DMA_INTF1_OFFSET)
|
||||
#define RP2040_DMA_INTS1 (RP2040_DMA_BASE + RP2040_DMA_INTS1_OFFSET)
|
||||
#define RP2040_DMA_TIMER0 (RP2040_DMA_BASE + RP2040_DMA_TIMER0_OFFSET)
|
||||
#define RP2040_DMA_TIMER1 (RP2040_DMA_BASE + RP2040_DMA_TIMER1_OFFSET)
|
||||
#define RP2040_DMA_TIMER2 (RP2040_DMA_BASE + RP2040_DMA_TIMER2_OFFSET)
|
||||
#define RP2040_DMA_TIMER3 (RP2040_DMA_BASE + RP2040_DMA_TIMER3_OFFSET)
|
||||
#define RP2040_DMA_MULTI_CHAN_TRIGGER (RP2040_DMA_BASE + RP2040_DMA_MULTI_CHAN_TRIGGER_OFFSET)
|
||||
#define RP2040_DMA_SNIFF_CTRL (RP2040_DMA_BASE + RP2040_DMA_SNIFF_CTRL_OFFSET)
|
||||
#define RP2040_DMA_SNIFF_DATA (RP2040_DMA_BASE + RP2040_DMA_SNIFF_DATA_OFFSET)
|
||||
#define RP2040_DMA_FIFO_LEVELS (RP2040_DMA_BASE + RP2040_DMA_FIFO_LEVELS_OFFSET)
|
||||
#define RP2040_DMA_CHAN_ABORT (RP2040_DMA_BASE + RP2040_DMA_CHAN_ABORT_OFFSET)
|
||||
#define RP2040_DMA_N_CHANNELS (RP2040_DMA_BASE + RP2040_DMA_N_CHANNELS_OFFSET)
|
||||
|
||||
#define RP2040_DMA_DBG_CTDREQ(n) (RP2040_DMA_BASE + RP2040_DMA_DBG_CTDREQ_OFFSET(n))
|
||||
#define RP2040_DMA_DBG_TCR(n) (RP2040_DMA_BASE + RP2040_DMA_DBG_TCR_OFFSET(n))
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
#define RP2040_DMA_CTRL_TRIG_AHB_ERROR (1 << 31) /* Logical OR of the READ_ERROR and WRITE_ERROR flags. The channel halts when it encounters any bus error, and always raises its channel IRQ flag. */
|
||||
#define RP2040_DMA_CTRL_TRIG_READ_ERROR (1 << 30) /* If 1, the channel received a read bus error. Write one to clear. READ_ADDR shows the approximate address where the bus error was encountered (will not to be earlier, or more than 3 transfers later) */
|
||||
#define RP2040_DMA_CTRL_TRIG_WRITE_ERROR (1 << 29) /* If 1, the channel received a write bus error. Write one to clear. WRITE_ADDR shows the approximate address where the bus error was encountered (will not to be earlier, or more than 5 transfers later) */
|
||||
#define RP2040_DMA_CTRL_TRIG_BUSY (1 << 24) /* This flag goes high when the channel starts a new transfer sequence, and low when the last transfer of that sequence completes. Clearing EN while BUSY is high pauses the channel, and BUSY will stay high while paused. To terminate a sequence early (and clear the BUSY flag), see CHAN_ABORT. */
|
||||
#define RP2040_DMA_CTRL_TRIG_SNIFF_EN (1 << 23) /* If 1, this channel's data transfers are visible to the sniff hardware, and each transfer will advance the state of the checksum. This only applies if the sniff hardware is enabled, and has this channel selected. This allows checksum to be enabled or disabled on a per-control- block basis. */
|
||||
#define RP2040_DMA_CTRL_TRIG_BSWAP (1 << 22) /* Apply byte-swap transformation to DMA data. For byte data, this has no effect. For halfword data, the two bytes of each halfword are swapped. For word data, the four bytes of each word are swapped to reverse order. */
|
||||
#define RP2040_DMA_CTRL_TRIG_IRQ_QUIET (1 << 21) /* In QUIET mode, the channel does not generate IRQs at the end of every transfer block. Instead, an IRQ is raised when NULL is written to a trigger register, indicating the end of a control block chain. This reduces the number of interrupts to be serviced by the CPU when transferring a DMA chain of many small control blocks. */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT (15) /* Select a Transfer Request signal. The channel uses the transfer request signal to pace its data transfer rate. Sources for TREQ signals are internal (TIMERS) or external (DREQ, a Data Request from the system). 0x0 to 0x3a -> select DREQ n as TREQ */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_MASK (0x3f << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_TIMER0 (0x3b << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) /* Select Timer 0 as TREQ */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_TIMER1 (0x3c << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) /* Select Timer 1 as TREQ */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_TIMER2 (0x3d << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) /* Select Timer 2 as TREQ (Optional) */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_TIMER3 (0x3e << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) /* Select Timer 3 as TREQ (Optional) */
|
||||
#define RP2040_DMA_CTRL_TRIG_TREQ_SEL_PERMANENT (0x3f << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) /* Permanent request, for unpaced transfers. */
|
||||
#define RP2040_DMA_CTRL_TRIG_CHAIN_TO_SHIFT (11) /* When this channel completes, it will trigger the channel indicated by CHAIN_TO. Disable by setting CHAIN_TO = _(this channel)_. Reset value is equal to channel number (0). */
|
||||
#define RP2040_DMA_CTRL_TRIG_CHAIN_TO_MASK (0x0f << RP2040_DMA_CTRL_TRIG_CHAIN_TO_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_RING_SEL (1 << 10) /* Select whether RING_SIZE applies to read or write addresses. If 0, read addresses are wrapped on a (1 << RING_SIZE) boundary. If 1, write addresses are wrapped. */
|
||||
#define RP2040_DMA_CTRL_TRIG_RING_SIZE_SHIFT (6) /* Size of address wrap region. If 0, don't wrap. For values n > 0, only the lower n bits of the address will change. This wraps the address on a (1 << n) byte boundary, facilitating access to naturally-aligned ring buffers. Ring sizes between 2 and 32768 bytes are possible. This can apply to either read or write addresses, based on value of RING_SEL. */
|
||||
#define RP2040_DMA_CTRL_TRIG_RING_SIZE_MASK (0x0f << RP2040_DMA_CTRL_TRIG_RING_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_RING_SIZE_RING_NONE (0x0 << RP2040_DMA_CTRL_TRIG_RING_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_INCR_WRITE (1 << 5) /* If 1, the write address increments with each transfer. If 0, each write is directed to the same, initial address. Generally this should be disabled for memory-to-peripheral transfers. */
|
||||
#define RP2040_DMA_CTRL_TRIG_INCR_READ (1 << 4) /* If 1, the read address increments with each transfer. If 0, each read is directed to the same, initial address. Generally this should be disabled for peripheral-to-memory transfers. */
|
||||
#define RP2040_DMA_CTRL_TRIG_DATA_SIZE_SHIFT (2) /* Set the size of each bus transfer (byte/halfword/word). READ_ADDR and WRITE_ADDR advance by this amount (1/2/4 bytes) with each transfer. */
|
||||
#define RP2040_DMA_CTRL_TRIG_DATA_SIZE_MASK (0x03 << RP2040_DMA_CTRL_TRIG_DATA_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_DATA_SIZE_SIZE_BYTE (0x0 << RP2040_DMA_CTRL_TRIG_DATA_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_DATA_SIZE_SIZE_HALFWORD (0x1 << RP2040_DMA_CTRL_TRIG_DATA_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_DATA_SIZE_SIZE_WORD (0x2 << RP2040_DMA_CTRL_TRIG_DATA_SIZE_SHIFT)
|
||||
#define RP2040_DMA_CTRL_TRIG_HIGH_PRIORITY (1 << 1) /* HIGH_PRIORITY gives a channel preferential treatment in issue scheduling: in each scheduling round, all high priority channels are considered first, and then only a single low priority channel, before returning to the high priority channels. This only affects the order in which the DMA schedules channels. The DMA's bus priority is not changed. If the DMA is not saturated then a low priority channel will see no loss of throughput. */
|
||||
#define RP2040_DMA_CTRL_TRIG_EN (1 << 0) /* DMA Channel Enable. When 1, the channel will respond to triggering events, which will cause it to become BUSY and start transferring data. When 0, the channel will ignore triggers, stop issuing transfers, and pause the current transfer sequence (i.e. BUSY will remain high if already high) */
|
||||
|
||||
#define RP2040_DMA_INTR_MASK (0xffff) /* Raw interrupt status for DMA Channels 0..15. Bit n corresponds to channel n. Ignores any masking or forcing. Channel interrupts can be cleared by writing a bit mask to INTR, INTS0 or INTS1. Channel interrupts can be routed to either of two system-level IRQs based on INTE0 and INTE1. This can be used vector different channel interrupts to different ISRs: this might be done to allow NVIC IRQ preemption for more time-critical channels, or to spread IRQ load across different cores. It is also valid to ignore this behaviour and just use INTE0/INTS0/IRQ 0. */
|
||||
|
||||
#define RP2040_DMA_INTE0_MASK (0xffff) /* Set bit n to pass interrupts from channel n to DMA IRQ 0. */
|
||||
|
||||
#define RP2040_DMA_INTF0_MASK (0xffff) /* Write 1s to force the corresponding bits in INTE0. The interrupt remains asserted until INTF0 is cleared. */
|
||||
|
||||
#define RP2040_DMA_INTS0_MASK (0xffff) /* Indicates active channel interrupt requests which are currently causing IRQ 0 to be asserted. Channel interrupts can be cleared by writing a bit mask here. */
|
||||
|
||||
#define RP2040_DMA_INTE1_MASK (0xffff) /* Set bit n to pass interrupts from channel n to DMA IRQ 1. */
|
||||
|
||||
#define RP2040_DMA_INTF1_MASK (0xffff) /* Write 1s to force the corresponding bits in INTE0. The interrupt remains asserted until INTF0 is cleared. */
|
||||
|
||||
#define RP2040_DMA_INTS1_MASK (0xffff) /* Indicates active channel interrupt requests which are currently causing IRQ 1 to be asserted. Channel interrupts can be cleared by writing a bit mask here. */
|
||||
|
||||
#define RP2040_DMA_TIMER0_X_SHIFT (16) /* Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer. */
|
||||
#define RP2040_DMA_TIMER0_X_MASK (0xffff << RP2040_DMA_TIMER0_X_SHIFT)
|
||||
#define RP2040_DMA_TIMER0_Y_MASK (0xffff) /* Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer. */
|
||||
|
||||
#define RP2040_DMA_TIMER1_X_SHIFT (16) /* Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer. */
|
||||
#define RP2040_DMA_TIMER1_X_MASK (0xffff << RP2040_DMA_TIMER1_X_SHIFT)
|
||||
#define RP2040_DMA_TIMER1_Y_MASK (0xffff) /* Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer. */
|
||||
|
||||
#define RP2040_DMA_TIMER2_X_SHIFT (16) /* Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer. */
|
||||
#define RP2040_DMA_TIMER2_X_MASK (0xffff << RP2040_DMA_TIMER2_X_SHIFT)
|
||||
#define RP2040_DMA_TIMER2_Y_MASK (0xffff) /* Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer. */
|
||||
|
||||
#define RP2040_DMA_TIMER3_X_SHIFT (16) /* Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer. */
|
||||
#define RP2040_DMA_TIMER3_X_MASK (0xffff << RP2040_DMA_TIMER3_X_SHIFT)
|
||||
#define RP2040_DMA_TIMER3_Y_MASK (0xffff) /* Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer. */
|
||||
|
||||
#define RP2040_DMA_MULTI_CHAN_TRIGGER_MASK (0xffff) /* Each bit in this register corresponds to a DMA channel. Writing a 1 to the relevant bit is the same as writing to that channel's trigger register; the channel will start if it is currently enabled and not already busy. */
|
||||
|
||||
#define RP2040_DMA_SNIFF_CTRL_OUT_INV (1 << 11) /* If set, the result appears inverted (bitwise complement) when read. This does not affect the way the checksum is calculated; the result is transformed on-the-fly between the result register and the bus. */
|
||||
#define RP2040_DMA_SNIFF_CTRL_OUT_REV (1 << 10) /* If set, the result appears bit-reversed when read. This does not affect the way the checksum is calculated; the result is transformed on-the-fly between the result register and the bus. */
|
||||
#define RP2040_DMA_SNIFF_CTRL_BSWAP (1 << 9) /* Locally perform a byte reverse on the sniffed data, before feeding into checksum. Note that the sniff hardware is downstream of the DMA channel byteswap performed in the read master: if channel CTRL_BSWAP and SNIFF_CTRL_BSWAP are both enabled, their effects cancel from the sniffer's point of view. */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_SHIFT (5)
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_MASK (0x0f << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT)
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_CRC32 (0x0 << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* Calculate a CRC-32 (IEEE802.3 polynomial) */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_CRC32R (0x1 << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* Calculate a CRC-32 (IEEE802.3 polynomial) with bit reversed data */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_CRC16 (0x2 << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* Calculate a CRC-16-CCITT */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_CRC16R (0x3 << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* Calculate a CRC-16-CCITT with bit reversed data */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_EVEN (0xe << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* XOR reduction over all data. == 1 if the total 1 population count is odd. */
|
||||
#define RP2040_DMA_SNIFF_CTRL_CALC_SUM (0xf << RP2040_DMA_SNIFF_CTRL_CALC_SHIFT) /* Calculate a simple 32-bit checksum (addition with a 32 bit accumulator) */
|
||||
#define RP2040_DMA_SNIFF_CTRL_DMACH_SHIFT (1) /* DMA channel for Sniffer to observe */
|
||||
#define RP2040_DMA_SNIFF_CTRL_DMACH_MASK (0x0f << RP2040_DMA_SNIFF_CTRL_DMACH_SHIFT)
|
||||
#define RP2040_DMA_SNIFF_CTRL_EN (1 << 0) /* Enable sniffer */
|
||||
|
||||
#define RP2040_DMA_FIFO_LEVELS_RAF_LVL_SHIFT (16) /* Current Read-Address-FIFO fill level */
|
||||
#define RP2040_DMA_FIFO_LEVELS_RAF_LVL_MASK (0xff << RP2040_DMA_FIFO_LEVELS_RAF_LVL_SHIFT)
|
||||
#define RP2040_DMA_FIFO_LEVELS_WAF_LVL_SHIFT (8) /* Current Write-Address-FIFO fill level */
|
||||
#define RP2040_DMA_FIFO_LEVELS_WAF_LVL_MASK (0xff << RP2040_DMA_FIFO_LEVELS_WAF_LVL_SHIFT)
|
||||
#define RP2040_DMA_FIFO_LEVELS_TDF_LVL_MASK (0xff) /* Current Transfer-Data-FIFO fill level */
|
||||
|
||||
#define RP2040_DMA_CHAN_ABORT_MASK (0xffff) /* Each bit corresponds to a channel. Writing a 1 aborts whatever transfer sequence is in progress on that channel. The bit will remain high until any in-flight transfers have been flushed through the address and data FIFOs. After writing, this register must be polled until it returns all-zero. Until this point, it is unsafe to restart the channel. */
|
||||
|
||||
#define RP2040_DMA_N_CHANNELS_MASK (0x1f)
|
||||
|
||||
#define RP2040_DMA_DBG_CTDREQ_MASK (0x3f)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_HARDWARE_RP2040_DMA_H */
|
492
arch/arm/src/rp2040/rp2040_dmac.c
Normal file
492
arch/arm/src/rp2040/rp2040_dmac.c
Normal file
@ -0,0 +1,492 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_dmac.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 <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
|
||||
#include "arm_arch.h"
|
||||
#include "hardware/rp2040_dma.h"
|
||||
#include "rp2040_dmac.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure describes one DMA channel */
|
||||
|
||||
struct dma_channel_s
|
||||
{
|
||||
uint8_t chan; /* DMA channel number (0-RP2040_DMA_NCHANNELS) */
|
||||
bool inuse; /* TRUE: The DMA channel is in use */
|
||||
dma_config_t config; /* Current configuration */
|
||||
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[RP2040_DMA_NCHANNELS];
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmac_interrupt
|
||||
*
|
||||
* Description:
|
||||
* DMA interrupt handler
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int rp2040_dmac_interrupt(int irq, void *context, FAR void *arg)
|
||||
{
|
||||
struct dma_channel_s *dmach;
|
||||
int result = OK;
|
||||
unsigned int ch;
|
||||
uint32_t stat;
|
||||
uint32_t ctrl;
|
||||
|
||||
/* Get and clear pending DMA interrupt status */
|
||||
|
||||
stat = getreg32(RP2040_DMA_INTS0) & RP2040_DMA_INTS0_MASK;
|
||||
putreg32(stat, RP2040_DMA_INTS0);
|
||||
|
||||
while (stat != 0)
|
||||
{
|
||||
ch = ffs(stat) - 1;
|
||||
stat &= ~(1 << ch);
|
||||
|
||||
ctrl = getreg32(RP2040_DMA_CTRL_TRIG(ch));
|
||||
|
||||
if (ctrl & RP2040_DMA_CTRL_TRIG_AHB_ERROR)
|
||||
{
|
||||
setbits_reg32(RP2040_DMA_CTRL_TRIG_READ_ERROR |
|
||||
RP2040_DMA_CTRL_TRIG_WRITE_ERROR,
|
||||
RP2040_DMA_CTRL_TRIG(ch));
|
||||
result = EIO;
|
||||
}
|
||||
|
||||
dmach = &g_dmach[ch];
|
||||
|
||||
/* Call the DMA completion callback */
|
||||
|
||||
if (dmach->callback)
|
||||
{
|
||||
dmach->callback((DMA_HANDLE)dmach, result, dmach->arg);
|
||||
dmach->callback = NULL;
|
||||
}
|
||||
|
||||
dmach->arg = NULL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: arm_dma_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the DMA subsystem
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void weak_function arm_dma_initialize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
dmainfo("Initialize DMAC\n");
|
||||
|
||||
/* Initialize the channel list */
|
||||
|
||||
nxsem_init(&g_dmac.exclsem, 0, 1);
|
||||
nxsem_init(&g_dmac.chansem, 0, RP2040_DMA_NCHANNELS);
|
||||
|
||||
for (i = 0; i < RP2040_DMA_NCHANNELS; i++)
|
||||
{
|
||||
g_dmach[i].chan = i;
|
||||
putreg32(0, RP2040_DMA_CTRL_TRIG(i));
|
||||
}
|
||||
|
||||
putreg32(0, RP2040_DMA_INTE0);
|
||||
putreg32(RP2040_DMA_INTS0_MASK, RP2040_DMA_INTS0);
|
||||
|
||||
/* Attach DMA completion interrupt handler */
|
||||
|
||||
irq_attach(RP2040_DMA_IRQ_0, rp2040_dmac_interrupt, NULL);
|
||||
up_enable_irq(RP2040_DMA_IRQ_0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmachannel
|
||||
*
|
||||
* Description:
|
||||
* Allocate a DMA channel. This function gives the caller mutually
|
||||
* exclusive access to a DMA channel.
|
||||
*
|
||||
* If no DMA channel is available, then rp2040_dmachannel() will wait
|
||||
* until the holder of a channel relinquishes the channel by calling
|
||||
* rp2040_dmafree().
|
||||
*
|
||||
* Input parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* This function ALWAYS returns a non-NULL, void* DMA channel handle.
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller can wait for a DMA channel to be freed if it is not
|
||||
* available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DMA_HANDLE rp2040_dmachannel(void)
|
||||
{
|
||||
struct dma_channel_s *dmach;
|
||||
unsigned int ch;
|
||||
uint32_t bit = 0;
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
/* Get exclusive access to the DMA channel list */
|
||||
|
||||
ret = nxsem_wait_uninterruptible(&g_dmac.exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxsem_post(&g_dmac.chansem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Search for an available DMA channel */
|
||||
|
||||
for (ch = 0, dmach = NULL; ch < RP2040_DMA_NCHANNELS; ch++)
|
||||
{
|
||||
struct dma_channel_s *candidate = &g_dmach[ch];
|
||||
if (!candidate->inuse)
|
||||
{
|
||||
dmach = candidate;
|
||||
dmach->inuse = true;
|
||||
|
||||
bit = 1 << ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nxsem_post(&g_dmac.exclsem);
|
||||
|
||||
setbits_reg32(bit, RP2040_DMA_INTS0);
|
||||
setbits_reg32(bit, RP2040_DMA_INTE0);
|
||||
|
||||
/* 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);
|
||||
return (DMA_HANDLE)dmach;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel. If another thread is waiting for this DMA
|
||||
* channel in a call to rp2040_dmachannel, then this function will
|
||||
* re-assign the DMA channel to that thread and wake it up. NOTE: The
|
||||
* 'handle' used in this argument must NEVER be used again until
|
||||
* rp2040_dmachannel() is called again to re-gain access to the channel.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller holds the DMA channel.
|
||||
* - There is no DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmafree(DMA_HANDLE handle)
|
||||
{
|
||||
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
|
||||
unsigned int ch;
|
||||
|
||||
DEBUGASSERT(dmach != NULL && dmach->inuse);
|
||||
ch = dmach->chan;
|
||||
dmainfo("DMA channel %d\n", ch);
|
||||
|
||||
/* Disable the channel */
|
||||
|
||||
setbits_reg32(1 << dmach->chan, RP2040_DMA_CHAN_ABORT);
|
||||
putreg32(0, RP2040_DMA_CTRL_TRIG(ch));
|
||||
clrbits_reg32(1 << dmach->chan, RP2040_DMA_INTE0);
|
||||
clrbits_reg32(1 << dmach->chan, RP2040_DMA_INTS0);
|
||||
|
||||
/* Mark the channel no longer in use. Clearing the in-use flag is an
|
||||
* atomic operation and so should be safe.
|
||||
*/
|
||||
|
||||
dmach->inuse = false;
|
||||
|
||||
/* And increment the count of free channels... possibly waking up a
|
||||
* thread that may be waiting for a channel.
|
||||
*/
|
||||
|
||||
nxsem_post(&g_dmac.chansem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_rxdmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure an RX (peripheral-to-memory) DMA before starting the transfer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* paddr - Peripheral address (source)
|
||||
* maddr - Memory address (destination)
|
||||
* nbytes - Number of bytes to transfer. Must be an even multiple of the
|
||||
* configured transfer size.
|
||||
* config - Channel configuration selections
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_rxdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
size_t nbytes, dma_config_t config)
|
||||
{
|
||||
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
|
||||
unsigned int ch;
|
||||
uint32_t count;
|
||||
uint32_t mask;
|
||||
uint32_t ctrl;
|
||||
|
||||
DEBUGASSERT(dmach != NULL && dmach->inuse);
|
||||
ch = dmach->chan;
|
||||
|
||||
/* Save the configuration (for rp2040_dmastart()). */
|
||||
|
||||
dmach->config = config;
|
||||
|
||||
DEBUGASSERT(config.size >= RP2040_DMA_SIZE_BYTE &&
|
||||
config.size <= RP2040_DMA_SIZE_WORD);
|
||||
|
||||
mask = (1 << config.size) - 1;
|
||||
count = nbytes >> config.size;
|
||||
|
||||
DEBUGASSERT(count > 0);
|
||||
|
||||
/* Set DMA registers */
|
||||
|
||||
putreg32(paddr & ~mask, RP2040_DMA_READ_ADDR(ch));
|
||||
putreg32(maddr & ~mask, RP2040_DMA_WRITE_ADDR(ch));
|
||||
putreg32(count, RP2040_DMA_TRANS_COUNT(ch));
|
||||
|
||||
ctrl = RP2040_DMA_CTRL_TRIG_READ_ERROR |
|
||||
RP2040_DMA_CTRL_TRIG_WRITE_ERROR |
|
||||
((config.dreq << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) &
|
||||
RP2040_DMA_CTRL_TRIG_TREQ_SEL_MASK) |
|
||||
((ch << RP2040_DMA_CTRL_TRIG_CHAIN_TO_SHIFT) &
|
||||
RP2040_DMA_CTRL_TRIG_CHAIN_TO_MASK) |
|
||||
config.size;
|
||||
|
||||
if (!config.noincr)
|
||||
{
|
||||
ctrl |= RP2040_DMA_CTRL_TRIG_INCR_WRITE;
|
||||
}
|
||||
|
||||
putreg32(ctrl, RP2040_DMA_CTRL_TRIG(ch));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_txdmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure an TX (memory-to-memory) DMA before starting the transfer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* paddr - Peripheral address (destination)
|
||||
* maddr - Memory address (source)
|
||||
* nbytes - Number of bytes to transfer. Must be an even multiple of the
|
||||
* configured transfer size.
|
||||
* config - Channel configuration selections
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_txdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
size_t nbytes, dma_config_t config)
|
||||
{
|
||||
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
|
||||
unsigned int ch;
|
||||
uint32_t count;
|
||||
uint32_t mask;
|
||||
uint32_t ctrl;
|
||||
|
||||
DEBUGASSERT(dmach != NULL && dmach->inuse);
|
||||
ch = dmach->chan;
|
||||
|
||||
/* Save the configuration (for rp2040_dmastart()). */
|
||||
|
||||
dmach->config = config;
|
||||
|
||||
DEBUGASSERT(config.size >= RP2040_DMA_SIZE_BYTE &&
|
||||
config.size <= RP2040_DMA_SIZE_WORD);
|
||||
|
||||
mask = (1 << config.size) - 1;
|
||||
count = nbytes >> config.size;
|
||||
|
||||
DEBUGASSERT(count > 0);
|
||||
|
||||
/* Set DMA registers */
|
||||
|
||||
putreg32(maddr & ~mask, RP2040_DMA_READ_ADDR(ch));
|
||||
putreg32(paddr & ~mask, RP2040_DMA_WRITE_ADDR(ch));
|
||||
putreg32(count, RP2040_DMA_TRANS_COUNT(ch));
|
||||
|
||||
ctrl = RP2040_DMA_CTRL_TRIG_READ_ERROR |
|
||||
RP2040_DMA_CTRL_TRIG_WRITE_ERROR |
|
||||
((config.dreq << RP2040_DMA_CTRL_TRIG_TREQ_SEL_SHIFT) &
|
||||
RP2040_DMA_CTRL_TRIG_TREQ_SEL_MASK) |
|
||||
((ch << RP2040_DMA_CTRL_TRIG_CHAIN_TO_SHIFT) &
|
||||
RP2040_DMA_CTRL_TRIG_CHAIN_TO_MASK) |
|
||||
config.size;
|
||||
|
||||
if (!config.noincr)
|
||||
{
|
||||
ctrl |= RP2040_DMA_CTRL_TRIG_INCR_READ;
|
||||
}
|
||||
|
||||
putreg32(ctrl, RP2040_DMA_CTRL_TRIG(ch));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmastart
|
||||
*
|
||||
* Description:
|
||||
* Start the DMA transfer
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by rp2040_dmachannel()
|
||||
* - No DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
|
||||
{
|
||||
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
|
||||
uint32_t ch;
|
||||
|
||||
DEBUGASSERT(dmach && dmach->inuse);
|
||||
ch = dmach->chan;
|
||||
|
||||
/* Save the DMA complete callback info */
|
||||
|
||||
dmach->callback = callback;
|
||||
dmach->arg = arg;
|
||||
|
||||
/* Enable the channel */
|
||||
|
||||
setbits_reg32(RP2040_DMA_CTRL_TRIG_EN, RP2040_DMA_CTRL_TRIG(ch));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmastop
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After rp2040_dmastop() is called, the DMA channel is
|
||||
* reset and rp2040_dmasetup() must be called before rp2040_dmastart()
|
||||
* can be called again
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by rp2040_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmastop(DMA_HANDLE handle)
|
||||
{
|
||||
struct dma_channel_s *dmach = (struct dma_channel_s *)handle;
|
||||
uint32_t bit;
|
||||
uint32_t stat;
|
||||
|
||||
DEBUGASSERT(dmach);
|
||||
bit = 1 << dmach->chan;
|
||||
|
||||
/* Disable the channel */
|
||||
|
||||
setbits_reg32(bit, RP2040_DMA_CHAN_ABORT);
|
||||
|
||||
do
|
||||
{
|
||||
stat = getreg32(RP2040_DMA_CHAN_ABORT);
|
||||
}
|
||||
while (stat & bit);
|
||||
}
|
259
arch/arm/src/rp2040/rp2040_dmac.h
Normal file
259
arch/arm/src/rp2040/rp2040_dmac.h
Normal file
@ -0,0 +1,259 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/rp2040/rp2040_dmac.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_ARM_SRC_RP2040_RP2040_DMAC_H
|
||||
#define __ARCH_ARM_SRC_RP2040_RP2040_DMAC_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hardware/rp2040_dma.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define RP2040_DMA_NCHANNELS 12
|
||||
|
||||
/* DREQ channels ************************************************************/
|
||||
|
||||
#define RP2040_DMA_DREQ_PIO0_TX0 0
|
||||
#define RP2040_DMA_DREQ_PIO0_TX1 1
|
||||
#define RP2040_DMA_DREQ_PIO0_TX2 2
|
||||
#define RP2040_DMA_DREQ_PIO0_TX3 3
|
||||
#define RP2040_DMA_DREQ_PIO0_RX0 4
|
||||
#define RP2040_DMA_DREQ_PIO0_RX1 5
|
||||
#define RP2040_DMA_DREQ_PIO0_RX2 6
|
||||
#define RP2040_DMA_DREQ_PIO0_RX3 7
|
||||
#define RP2040_DMA_DREQ_PIO1_TX0 8
|
||||
#define RP2040_DMA_DREQ_PIO1_TX1 9
|
||||
#define RP2040_DMA_DREQ_PIO1_TX2 10
|
||||
#define RP2040_DMA_DREQ_PIO1_TX3 11
|
||||
#define RP2040_DMA_DREQ_PIO1_RX0 12
|
||||
#define RP2040_DMA_DREQ_PIO1_RX1 13
|
||||
#define RP2040_DMA_DREQ_PIO1_RX2 14
|
||||
#define RP2040_DMA_DREQ_PIO1_RX3 15
|
||||
#define RP2040_DMA_DREQ_SPI0_TX 16
|
||||
#define RP2040_DMA_DREQ_SPI0_RX 17
|
||||
#define RP2040_DMA_DREQ_SPI1_TX 18
|
||||
#define RP2040_DMA_DREQ_SPI1_RX 19
|
||||
#define RP2040_DMA_DREQ_UART0_TX 20
|
||||
#define RP2040_DMA_DREQ_UART0_RX 21
|
||||
#define RP2040_DMA_DREQ_UART1_TX 22
|
||||
#define RP2040_DMA_DREQ_UART1_RX 23
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP0 24
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP1 25
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP2 26
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP3 27
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP4 28
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP5 29
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP6 30
|
||||
#define RP2040_DMA_DREQ_PWM_WRAP7 31
|
||||
#define RP2040_DMA_DREQ_I2C0_TX 32
|
||||
#define RP2040_DMA_DREQ_I2C0_RX 33
|
||||
#define RP2040_DMA_DREQ_I2C1_TX 34
|
||||
#define RP2040_DMA_DREQ_I2C1_RX 35
|
||||
#define RP2040_DMA_DREQ_ADC 36
|
||||
#define RP2040_DMA_DREQ_XIP_STREAM 37
|
||||
#define RP2040_DMA_DREQ_XIP_SSITX 38
|
||||
#define RP2040_DMA_DREQ_XIP_SSIRX 39
|
||||
|
||||
/* DMA data size ************************************************************/
|
||||
|
||||
#define RP2040_DMA_SIZE_BYTE 0
|
||||
#define RP2040_DMA_SIZE_HALFWORD 1
|
||||
#define RP2040_DMA_SIZE_WORD 2
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* DMA_HANDLE provides an opaque are reference that can be used to represent
|
||||
* a DMA channel.
|
||||
*/
|
||||
|
||||
typedef FAR void *DMA_HANDLE;
|
||||
|
||||
/* Description:
|
||||
* This is the type of the callback that is used to inform the user of the
|
||||
* completion of the DMA.
|
||||
*
|
||||
* Input Parameters:
|
||||
* handle - Refers to the DMA channel or stream
|
||||
* status - The completion status (0:no error)
|
||||
* arg - A user-provided value that was provided when rp2040_dmastart()
|
||||
* was called.
|
||||
*/
|
||||
|
||||
typedef void (*dma_callback_t)(DMA_HANDLE handle, uint8_t status, void *arg);
|
||||
|
||||
/* Type of 'config' argument passed to rp2040_rxdmasetup() and
|
||||
* rp2040_txdmasetup().
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dreq;
|
||||
uint8_t size;
|
||||
uint8_t noincr;
|
||||
} dma_config_t;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmachannel
|
||||
*
|
||||
* Description:
|
||||
* Allocate a DMA channel. This function gives the caller mutually
|
||||
* exclusive access to a DMA channel.
|
||||
*
|
||||
* If no DMA channel is available, then rp2040_dmachannel() will wait until
|
||||
* the holder of a channel relinquishes the channel by calling
|
||||
* rp2040_dmafree().
|
||||
*
|
||||
* Input parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* This function ALWAYS returns a non-NULL, void* DMA channel handle.
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller can wait for a DMA channel to be freed if it is
|
||||
* not available.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
DMA_HANDLE rp2040_dmachannel(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmafree
|
||||
*
|
||||
* Description:
|
||||
* Release a DMA channel.
|
||||
* If another thread is waiting for this DMA channel in a call to
|
||||
* rp2040_dmachannel, then this function will re-assign the DMA channel to
|
||||
* that thread and wake it up.
|
||||
* NOTE:
|
||||
* The 'handle' used in this argument must NEVER be used again until
|
||||
* rp2040_dmachannel() is called again to re-gain access to the channel.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* - The caller holds the DMA channel.
|
||||
* - There is no DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmafree(DMA_HANDLE handle);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_rxdmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure an RX (peripheral-to-memory) DMA before starting the transfer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* paddr - Peripheral address (source)
|
||||
* maddr - Memory address (destination)
|
||||
* nbytes - Number of bytes to transfer. Must be an even multiple of the
|
||||
* configured transfer size.
|
||||
* config - Channel configuration selections
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_rxdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
size_t nbytes, dma_config_t config);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_txdmasetup
|
||||
*
|
||||
* Description:
|
||||
* Configure an TX (memory-to-memory) DMA before starting the transfer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* paddr - Peripheral address (destination)
|
||||
* maddr - Memory address (source)
|
||||
* nbytes - Number of bytes to transfer. Must be an even multiple of the
|
||||
* configured transfer size.
|
||||
* config - Channel configuration selections
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_txdmasetup(DMA_HANDLE handle, uintptr_t paddr, uintptr_t maddr,
|
||||
size_t nbytes, dma_config_t config);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmastart
|
||||
*
|
||||
* Description:
|
||||
* Start the DMA transfer
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by rp2040_dmachannel()
|
||||
* - No DMA in progress
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_dmastop
|
||||
*
|
||||
* Description:
|
||||
* Cancel the DMA. After rp2040_dmastop() is called, the DMA channel is
|
||||
* reset and rp2040_dmasetup() must be called before rp2040_dmastart() can
|
||||
* be called again.
|
||||
*
|
||||
* Assumptions:
|
||||
* - DMA handle allocated by rp2040_dmachannel()
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_dmastop(DMA_HANDLE handle);
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_ARM_SRC_RP2040_RP2040_DMAC_H */
|
Loading…
Reference in New Issue
Block a user