diff --git a/bsps/aarch64/raspberrypi/dma/raspberrypi-dma.c b/bsps/aarch64/raspberrypi/dma/raspberrypi-dma.c new file mode 100644 index 0000000000..214207afa9 --- /dev/null +++ b/bsps/aarch64/raspberrypi/dma/raspberrypi-dma.c @@ -0,0 +1,300 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsAArch64Raspberrypi4 + * + * @brief Raspberry Pi specific DMA definitions. + */ + +/* + * Copyright (C) 2025 Shaunak Datar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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. + */ + +#include +#define DMA4_AD_SHIFT( addr ) ( addr >> 5 ) +#define DMA4_AD_UNSHIFT( addr ) ( addr << 5 ) +#define ADDRESS_LOW( addr ) ( (uintptr_t) ( addr ) & 0xFFFFFFFF ) +#define ADDRESS_HIGH( addr ) ( ( (uintptr_t) ( addr ) >> 32 ) & 0xFF ) +#define BUS_ADDR( addr ) ( ( ( addr ) & ~0xC0000000 ) | 0xC0000000 ) + +typedef struct { + uint32_t transfer_info; /**< Control register */ + uint32_t source_addr; /**< Source address register */ + uint32_t destination_addr; /**< Destination address register */ + uint32_t transfer_length; /**< Transfer length register */ + uint32_t mode_2d_stride; /**< Stride register */ + uint32_t next_cb; /**< Next control block address register */ + uint32_t reserved[ 2 ]; /**< Reserved */ +} rpi_dma_control_block; + +typedef struct { + uint32_t transfer_info; /**< Control register */ + uint32_t source_addr; /**< Source address register */ + uint32_t destination_addr; /**< Destination address register */ + uint32_t transfer_length; /**< Transfer length register */ + uint32_t reserved_bit; /**< Reserved */ + uint32_t next_cb; /**< Next control block address register */ + uint32_t reserved[ 2 ]; /**< Reserved */ +} rpi_dma_lite_control_block; + +typedef struct { + uint32_t transfer_info; /**< Control register */ + uint32_t source_addr; /**< Source address register */ + uint32_t source_info; /**< Source information */ + uint32_t destination_addr; /**< Destination address register */ + uint32_t destination_info; /**< Destination information */ + uint32_t transfer_length; /**< Transfer length register */ + uint32_t next_cb; /**< Next control block address register */ + uint32_t reserved; /**< Reserved */ +} rpi_dma4_control_block; + +static const uint32_t dma_base_addresses[] = { + BCM2711_DMA0_BASE, + BCM2711_DMA1_BASE, + BCM2711_DMA2_BASE, + BCM2711_DMA3_BASE, + BCM2711_DMA4_BASE, + BCM2711_DMA5_BASE, + BCM2711_DMA6_BASE, + BCM2711_DMA7_BASE, + BCM2711_DMA8_BASE, + BCM2711_DMA9_BASE, + BCM2711_DMA10_BASE, + BCM2711_DMA11_BASE, + BCM2711_DMA12_BASE, + BCM2711_DMA13_BASE, + BCM2711_DMA14_BASE +}; + +static inline uint32_t get_base_address( rpi_dma_channel channel ) +{ + if ( channel >= 0 && channel <= DMA4_CHANNEL_14 ) { + return dma_base_addresses[ channel ]; + } + return 0; +} + +static rpi_dma_control_block *rpi_dma_init_cb( + void *source_address, + void *destination_address, + uint32_t transfer_length +) +{ + rpi_dma_control_block *cb = (rpi_dma_control_block *) + rtems_heap_allocate_aligned_with_boundary( + sizeof( rpi_dma_control_block ), + CPU_CACHE_LINE_BYTES, + 0 + ); + if ( cb == NULL ) { + return NULL; + } + + cb->source_addr = BUS_ADDR( (uint32_t) (uintptr_t) source_address ); + cb->destination_addr = BUS_ADDR( (uint32_t) (uintptr_t) destination_address ); + cb->transfer_length = transfer_length; + cb->transfer_info = ( TI_DEST_INC | TI_SRC_INC ); + cb->mode_2d_stride = 0; + cb->next_cb = 0; + cb->reserved[ 0 ] = 0; + cb->reserved[ 1 ] = 0; + + return cb; +} + +static rpi_dma_lite_control_block *rpi_dma_lite_init_cb( + void *source_address, + void *destination_address, + uint32_t transfer_length +) +{ + rpi_dma_lite_control_block *cb = (rpi_dma_lite_control_block *) + rtems_heap_allocate_aligned_with_boundary( + sizeof( rpi_dma_control_block ), + CPU_CACHE_LINE_BYTES, + 0 + ); + if ( cb == NULL ) { + return NULL; + } + + cb->source_addr = BUS_ADDR( (uint32_t) (uintptr_t) source_address ); + cb->destination_addr = BUS_ADDR( (uint32_t) (uintptr_t) destination_address ); + cb->transfer_length = transfer_length; + cb->transfer_info = ( TI_DEST_INC | TI_SRC_INC ); + cb->next_cb = 0; + cb->reserved_bit = 0; + cb->reserved[ 0 ] = 0; + cb->reserved[ 1 ] = 0; + + return cb; +} + +static rpi_dma4_control_block *rpi_dma4_init_cb( + void *source_address, + void *destination_address, + uint32_t transfer_length +) +{ + rpi_dma4_control_block *cb = (rpi_dma4_control_block *) + rtems_heap_allocate_aligned_with_boundary( + sizeof( rpi_dma4_control_block ), + CPU_CACHE_LINE_BYTES, + 0 + ); + if ( cb == NULL ) { + return NULL; + } + + cb->source_addr = (uint32_t) ADDRESS_LOW( source_address ); + cb->source_info = SI_SRC_INC | ADDRESS_HIGH( source_address ); + cb->destination_addr = (uint32_t) ADDRESS_LOW( destination_address ); + cb->destination_info = DI_DEST_INC | ADDRESS_HIGH( destination_address ); + cb->transfer_length = transfer_length; + cb->transfer_info = 0; + cb->next_cb = 0; + cb->reserved = 0; + + return cb; +} + +static inline void rpi_dma_free_control_block( + rpi_dma_channel channel, + uint32_t base_address +) +{ + uint32_t cb_ad_reg = BCM2835_REG( base_address + CONBLK_AD_OFFSET ); + if ( cb_ad_reg == 0 ) { + return; + } + + uintptr_t cb_addr; + if ( channel >= DMA4_CHANNEL_11 && channel <= DMA4_CHANNEL_14 ) { + cb_addr = DMA4_AD_UNSHIFT( cb_ad_reg ); + } else { + cb_addr = (uintptr_t) cb_ad_reg; + } + + if ( cb_addr != 0 ) { + void *cb = (void *) cb_addr; + free( cb ); + BCM2835_REG( base_address + CONBLK_AD_OFFSET ) = 0; + } +} + +rtems_status_code rpi_dma_start_transfer( rpi_dma_channel channel ) +{ + uint32_t base_address = get_base_address( channel ); + if ( !base_address ) { + return RTEMS_INVALID_NUMBER; + } + BCM2835_REG( base_address + CS_OFFSET ) = CS_WAIT_FOR_OUTSTANDING_WRITES | + CS_PANIC_PRIORITY_SHIFT | + CS_PRIORITY_SHIFT; + BCM2835_REG( base_address + CS_OFFSET ) |= CS_ACTIVE; + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rpi_dma_wait( rpi_dma_channel channel ) +{ + uint32_t base_address = get_base_address( channel ); + if ( !base_address ) { + return RTEMS_INVALID_NUMBER; + } + while (( BCM2835_REG( base_address + CS_OFFSET ) & CS_ACTIVE )); + + rpi_dma_free_control_block( channel, base_address ); + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rpi_dma_mem_to_mem_init( + rpi_dma_channel channel, + void *source_address, + void *destination_address, + uint32_t transfer_length +) +{ + uint32_t base_address = get_base_address( channel ); + if ( !base_address ) { + return RTEMS_INVALID_NUMBER; + } + + if ( ( (uintptr_t) source_address % CPU_CACHE_LINE_BYTES ) != 0 || + ( (uintptr_t) destination_address % CPU_CACHE_LINE_BYTES ) != 0 ) { + return RTEMS_INVALID_ADDRESS; + } + + void *control_block = NULL; + size_t cb_size = 0; + + if ( channel < DMA_LITE_CHANNEL_7 ) { + control_block = rpi_dma_init_cb( + source_address, + destination_address, + transfer_length + ); + cb_size = sizeof( rpi_dma_control_block ); + } else if ( channel > DMA_CHANNEL_6 && channel < DMA4_CHANNEL_11 ) { + control_block = rpi_dma_lite_init_cb( + source_address, + destination_address, + transfer_length + ); + cb_size = sizeof( rpi_dma_lite_control_block ); + } else if ( channel > DMA_LITE_CHANNEL_10 && channel <= DMA4_CHANNEL_14 ) { + control_block = rpi_dma4_init_cb( + source_address, + destination_address, + transfer_length + ); + cb_size = sizeof( rpi_dma4_control_block ); + } else { + return RTEMS_INVALID_NUMBER; + } + + if ( control_block == NULL ) { + return RTEMS_NO_MEMORY; + } + + BCM2835_REG( base_address + CS_OFFSET ) = CS_RESET | CS_ABORT; + rtems_cache_flush_multiple_data_lines( control_block, cb_size ); + rtems_cache_flush_multiple_data_lines( source_address, transfer_length ); + rtems_cache_invalidate_multiple_data_lines( + destination_address, + transfer_length + ); + + if ( ( channel >= DMA4_CHANNEL_11 ) && ( channel <= DMA4_CHANNEL_14 ) ) { + uint32_t cb_addr = (uint32_t) (uintptr_t) control_block; + uint32_t dma4_cb_addr = DMA4_AD_SHIFT( cb_addr ); + BCM2835_REG( base_address + CONBLK_AD_OFFSET ) = dma4_cb_addr; + } else { + BCM2835_REG( base_address + CONBLK_AD_OFFSET ) = (uint32_t) (uintptr_t + ) control_block; + } + + return RTEMS_SUCCESSFUL; +} \ No newline at end of file diff --git a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-dma.h b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-dma.h new file mode 100644 index 0000000000..1aff3502b2 --- /dev/null +++ b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi-dma.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsAArch64Raspberrypi4 + * + * @brief Raspberry Pi specific DMA definitions. + */ + +/* + * Copyright (C) 2025 Shaunak Datar + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 LIBBSP_AARCH64_RASPBERRYPI_DMA_H +#define LIBBSP_AARCH64_RASPBERRYPI_DMA_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief DMA channel identifiers for BCM2711 (0–6 full, 7–10 lite, 11–14 DMA4). + */ +typedef enum { + DMA_CHANNEL_0, + DMA_CHANNEL_1, + DMA_CHANNEL_2, + DMA_CHANNEL_3, + DMA_CHANNEL_4, + DMA_CHANNEL_5, + DMA_CHANNEL_6, + DMA_LITE_CHANNEL_7, + DMA_LITE_CHANNEL_8, + DMA_LITE_CHANNEL_9, + DMA_LITE_CHANNEL_10, + DMA4_CHANNEL_11, + DMA4_CHANNEL_12, + DMA4_CHANNEL_13, + DMA4_CHANNEL_14, +} rpi_dma_channel; +/** + * @brief Start a previously initialized DMA transfer on @a channel. + * + * Expects the channel's CONBLK_AD to point to a valid + * control block. Sets ACTIVE and required priorities. + * + * @param channel DMA channel to start. + * @retval RTEMS_SUCCESSFUL on success. + * @retval RTEMS_INVALID_NUMBER if @a channel is invalid. + */ +rtems_status_code rpi_dma_start_transfer( rpi_dma_channel channel ); + +/** + * @brief Block until the current DMA transfer on @a channel completes. + * + * Busy-waits for ACTIVE to clear and frees the control block previously + * programmed into CONBLK_AD (including DMA4 address unshifting). Does **not** + * invalidate/flush user buffers beyond setup done by the init helpers. + * + * @param channel DMA channel to wait on. + * @retval RTEMS_SUCCESSFUL on success. + * @retval RTEMS_INVALID_NUMBER if @a channel is invalid. + * @retval RTEMS_UNSATISFIED if the channel reports an error. + */ + +rtems_status_code rpi_dma_wait( rpi_dma_channel channel ); + +/** + * @brief Initialize a memcpy-style DMA transfer from @a source_address to + * @a destination_address of @a transfer_length bytes on @a channel. + * + * Allocates and prepares the channel-specific control block, performs required + * cache maintenance (flush control block and source; invalidate destination), + * issues CS reset/abort, and writes CONBLK_AD (with DMA4 address packing via + * DMA4_AD_SHIFT). This function does **not** start the transfer; call + * ::rpi_dma_start_transfer() and then ::rpi_dma_wait(). + * + * @param channel DMA channel to use (0–6 noarmal DMA, 7–10 lite, + * 11–14 DMA4). + * @param source_address Source buffer (must be CPU_CACHE_LINE_BYTES + * aligned). + * @param destination_address Destination buffer (must be CPU_CACHE_LINE_BYTES + * aligned). + * @param transfer_length Number of bytes to copy. + * @retval RTEMS_SUCCESSFUL on success. + * @retval RTEMS_INVALID_NUMBER if @a channel is invalid/unsupported or has + * no base address. + * @retval RTEMS_INVALID_ADDRESS if @a source_address or @a + * destination_address are misaligned. + * @retval RTEMS_NO_MEMORY if control block allocation failed. + */ +rtems_status_code rpi_dma_mem_to_mem_init( + rpi_dma_channel channel, + void *source_address, + void *destination_address, + uint32_t transfer_length +); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBBSP_AARCH64_RASPBERRYPI_DMA_H */ \ No newline at end of file diff --git a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h index ee30a3cf6c..307700dac7 100644 --- a/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h +++ b/bsps/aarch64/raspberrypi/include/bsp/raspberrypi.h @@ -344,6 +344,53 @@ extern "C" { #define BCM2711_10_BIT_ADDR_MASK 0x78 /** @} */ +/** + * @name DMA Registers + * + * @{ + */ + +#define BCM2711_DMA0_BASE ( RPI_PERIPHERAL_BASE + 0x00007000 ) +#define BCM2711_DMA1_BASE ( BCM2711_DMA0_BASE + 0x100 ) +#define BCM2711_DMA2_BASE ( BCM2711_DMA0_BASE + 0x200 ) +#define BCM2711_DMA3_BASE ( BCM2711_DMA0_BASE + 0x300 ) +#define BCM2711_DMA4_BASE ( BCM2711_DMA0_BASE + 0x400 ) +#define BCM2711_DMA5_BASE ( BCM2711_DMA0_BASE + 0x500 ) +#define BCM2711_DMA6_BASE ( BCM2711_DMA0_BASE + 0x600 ) +#define BCM2711_DMA7_BASE ( BCM2711_DMA0_BASE + 0x700 ) +#define BCM2711_DMA8_BASE ( BCM2711_DMA0_BASE + 0x800 ) +#define BCM2711_DMA9_BASE ( BCM2711_DMA0_BASE + 0x900 ) +#define BCM2711_DMA10_BASE ( BCM2711_DMA0_BASE + 0xa00 ) +#define BCM2711_DMA11_BASE ( BCM2711_DMA0_BASE + 0xb00 ) +#define BCM2711_DMA12_BASE ( BCM2711_DMA0_BASE + 0xc00 ) +#define BCM2711_DMA13_BASE ( BCM2711_DMA0_BASE + 0xd00 ) +#define BCM2711_DMA14_BASE ( BCM2711_DMA0_BASE + 0xe00 ) +#define ENABLE ( RPI_PERIPHERAL_BASE + 0x00007FF0 ) +#define CS_OFFSET 0x00 +#define CONBLK_AD_OFFSET 0x04 +#define DEBUG_OFFSET 0x020 +#define INT_STATUS_OFFSET 0xfe0 +#define CS_RESET ( 1 << 31 ) +#define CS_ABORT ( 1 << 30 ) +#define CS_END ( 1 << 1 ) +#define CS_WAIT_FOR_OUTSTANDING_WRITES ( 1 << 28 ) +#define CS_PRIORITY_SHIFT ( 1 << 16 ) +#define CS_PANIC_PRIORITY_SHIFT ( 15 << 20 ) +#define CS_ACTIVE ( 1 << 0 ) +#define CS_ERROR ( 1 << 8 ) +#define TI_DEST_INC ( 1 << 4 ) +#define TI_SRC_INC ( 1 << 8 ) +#define TI_SRC_WIDTH ( 1 << 9 ) +#define TI_DEST_WIDTH ( 1 << 5 ) +#define TI_PERMAP( x ) ( ( x ) << 16 ) +#define TI_SRC_DREQ ( 1 << 10 ) +#define TI_DEST_DREQ ( 1 << 6 ) +#define TI_WAIT_RESP ( 1 << 3 ) +#define TI_NO_WIDE_BURSTS ( 1 << 26 ) +#define SI_SRC_INC ( 1 << 12 ) +#define DI_DEST_INC ( 1 << 12 ) +/** @} */ + /** * @name Mailbox Registers * diff --git a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml index 6a6e47a17e..d73cec5075 100644 --- a/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml +++ b/spec/build/bsps/aarch64/raspberrypi/bspraspberrypi4.yml @@ -69,6 +69,8 @@ links: uid: objpwm - role: build-dependency uid: obji2c +- role: build-dependency + uid: objdma source: - bsps/aarch64/raspberrypi/fdt/bsp_fdt.c - bsps/aarch64/raspberrypi/fdt/rpi4b_dtb.c diff --git a/spec/build/bsps/aarch64/raspberrypi/objdma.yml b/spec/build/bsps/aarch64/raspberrypi/objdma.yml new file mode 100644 index 0000000000..6e93657691 --- /dev/null +++ b/spec/build/bsps/aarch64/raspberrypi/objdma.yml @@ -0,0 +1,17 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +build-type: objects +cflags: [] +copyrights: +- Copyright (C) 2025 Shaunak Datar +cppflags: [] +cxxflags: [] +enabled-by: true +includes: [] +install: +- destination: ${BSP_INCLUDEDIR}/bsp + source: + - bsps/aarch64/raspberrypi/include/bsp/raspberrypi-dma.h +links: [] +source: +- bsps/aarch64/raspberrypi/dma/raspberrypi-dma.c +type: build