diff --git a/scalp_fast_router_firmware_petalinux/.petalinux/metadata b/scalp_fast_router_firmware_petalinux/.petalinux/metadata index 85613960f0227f7de5aaa795241fcb3c2c15d366..c15beda93bb7bda57b7329a244b6736d1d91b168 100644 --- a/scalp_fast_router_firmware_petalinux/.petalinux/metadata +++ b/scalp_fast_router_firmware_petalinux/.petalinux/metadata @@ -2,5 +2,5 @@ PETALINUX_VER=2020.2 VALIDATE_HW_CHKSUM=1 HARDWARE_CHECKSUM=f2c3aa42b9c1cc33b3fae6a00a47c742 YOCTO_SDK=5ff8fc5f85d1566b314bb73eaa378212 -RFSCONFIG_CHKSUM=3f80b80381dcceaf27f1ea1b2d4f4a22 +RFSCONFIG_CHKSUM=875fef99c2cf2a1f1c40d3a7bfaa5b32 HARDWARE_PATH=/home/jo/Documents/Projets/Hepia/scalp_project/scalp_firmware/designs/vivado/scalp_fast_router_firmware/2020.2/lin64/scalp_fast_router_firmware/scalp_fast_router_firmware.xsa diff --git a/scalp_fast_router_firmware_petalinux/project-spec/configs/rootfs_config b/scalp_fast_router_firmware_petalinux/project-spec/configs/rootfs_config index 64de46eb3a138cabd9ec1ec2dd64430a3d228804..5efa805dcbd78a5501e8f3b67d70715569ebeca1 100644 --- a/scalp_fast_router_firmware_petalinux/project-spec/configs/rootfs_config +++ b/scalp_fast_router_firmware_petalinux/project-spec/configs/rootfs_config @@ -4025,6 +4025,7 @@ CONFIG_imagefeature-debug-tweaks=y CONFIG_bitstream-conf=y CONFIG_bitstream-init=y CONFIG_dmatest=y +CONFIG_dmatest-devmem=y # CONFIG_gpio-demo is not set CONFIG_peekpoke=y # CONFIG_sampleapp is not set diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/conf/user-rootfsconfig b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/conf/user-rootfsconfig index e2b7a7204994029926d95997ee62338068794bed..c1ae806a7855a73c5c4589a48ec3073282bf46ff 100644 --- a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/conf/user-rootfsconfig +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/conf/user-rootfsconfig @@ -15,3 +15,4 @@ CONFIG_sampleread CONFIG_scalp-locaddr CONFIG_scalplocaddr CONFIG_dmatest +CONFIG_dmatest-devmem diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/.gdbinit b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/.gdbinit new file mode 100644 index 0000000000000000000000000000000000000000..d59fb8d90efb393c83d35becbecddcfa493a5e67 --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/.gdbinit @@ -0,0 +1,2 @@ +# Load the PetaLinux SDK main gdbinit script +source plnx_gdbinit diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/README b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/README new file mode 100644 index 0000000000000000000000000000000000000000..75747ec34bce94292ef94f880aadcfda9a296200 --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/README @@ -0,0 +1,32 @@ +PetaLinux User Application Template +=================================== + +This directory contains a PetaLinux user application created from a template. + +If you are developing your application from scratch, simply start editing the +file dmatest-devmem.c. + +You can easily import any existing application code by copying it into this +directory, and editing the automatically generated Makefile. + +Before building the application, you will need to enable the application +from PetaLinux menuconfig by running: + "petalinux-config -c rootfs" +You will see your application in the "apps --->" submenu. + +To build your application, simply run "petalinux-build -c dmatest-devmem". +This command will build your application and will install your application +into the target file system host copy. + +You will also need to rebuild PetaLinux bootable images so that the images +is updated with the updated target filesystem copy, run this command: + "petalinux-build -c rootfs" + +You can also run one PetaLinux command to install the application to the +target filesystem host copy and update the bootable images as follows: + "petalinux-build" + +To add extra source code files (for example, to split a large application into +multiple source files), add the relevant .o files to the list in the local +Makefile where indicated. + diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/dmatest-devmem.bb b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/dmatest-devmem.bb new file mode 100644 index 0000000000000000000000000000000000000000..0df8759a05f7ae9764c60fe89acb6a946812d21c --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/dmatest-devmem.bb @@ -0,0 +1,23 @@ +# +# This file is the dmatest-devmem recipe. +# + +SUMMARY = "Simple dmatest-devmem application" +SECTION = "PETALINUX/apps" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +SRC_URI = "file://dmatest-devmem.c \ + file://Makefile \ + " + +S = "${WORKDIR}" + +do_compile() { + oe_runmake +} + +do_install() { + install -d ${D}${bindir} + install -m 0755 dmatest-devmem ${D}${bindir} +} diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/Makefile b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..84d398da8fcb8517f057e375b47053f15897ab1a --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/Makefile @@ -0,0 +1,14 @@ +APP = dmatest-devmem + +# Add any other object files to this list below +APP_OBJS = dmatest-devmem.o + +all: build + +build: $(APP) + +$(APP): $(APP_OBJS) + $(CC) -o $@ $(APP_OBJS) $(LDFLAGS) $(LDLIBS) +clean: + rm -f $(APP) *.o + diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c new file mode 100644 index 0000000000000000000000000000000000000000..e45a8c8007c3ef2e42341973a08714c06315637b --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c @@ -0,0 +1,423 @@ +/* +* Copyright (C) 2013 - 2016 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in this +* Software without prior written authorization from Xilinx. +* +*/ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <termios.h> +#include <sys/mman.h> + +#define MM2S_CONTROL_REGISTER 0x00 +#define MM2S_STATUS_REGISTER 0x04 +#define MM2S_SRC_ADDRESS_REGISTER 0x18 +#define MM2S_TRNSFR_LENGTH_REGISTER 0x28 + +#define S2MM_CONTROL_REGISTER 0x30 +#define S2MM_STATUS_REGISTER 0x34 +#define S2MM_DST_ADDRESS_REGISTER 0x48 +#define S2MM_BUFF_LENGTH_REGISTER 0x58 + +#define IOC_IRQ_FLAG 1<<12 +#define IDLE_FLAG 1<<1 + +#define STATUS_HALTED 0x00000001 +#define STATUS_IDLE 0x00000002 +#define STATUS_SG_INCLDED 0x00000008 +#define STATUS_DMA_INTERNAL_ERR 0x00000010 +#define STATUS_DMA_SLAVE_ERR 0x00000020 +#define STATUS_DMA_DECODE_ERR 0x00000040 +#define STATUS_SG_INTERNAL_ERR 0x00000100 +#define STATUS_SG_SLAVE_ERR 0x00000200 +#define STATUS_SG_DECODE_ERR 0x00000400 +#define STATUS_IOC_IRQ 0x00001000 +#define STATUS_DELAY_IRQ 0x00002000 +#define STATUS_ERR_IRQ 0x00004000 + +#define HALT_DMA 0x00000000 +#define RUN_DMA 0x00000001 +#define RESET_DMA 0x00000004 +#define ENABLE_IOC_IRQ 0x00001000 +#define ENABLE_DELAY_IRQ 0x00002000 +#define ENABLE_ERR_IRQ 0x00004000 +#define ENABLE_ALL_IRQ 0x00007000 + +#define BUFF_SIZE 32 + +#define H0_1 0x01000002 +#define H0_2 0x01000001 +#define H1_1 0x00000001 +#define H1_2 0x00000002 +#define H2 0x00000800 + +unsigned int write_dma(unsigned int *virtual_addr, int offset, unsigned int value) +{ + virtual_addr[offset>>2] = value; + + return 0; +} + +unsigned int read_dma(unsigned int *virtual_addr, int offset) +{ + return virtual_addr[offset>>2]; +} + +void dma_s2mm_status(unsigned int *virtual_addr) +{ + unsigned int status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + + printf("Stream to memory-mapped status (0x%08x@0x%02x):", status, S2MM_STATUS_REGISTER); + + if (status & STATUS_HALTED) { + printf(" Halted.\n"); + } else { + printf(" Running.\n"); + } + + if (status & STATUS_IDLE) { + printf(" Idle.\n"); + } + + if (status & STATUS_SG_INCLDED) { + printf(" SG is included.\n"); + } + + if (status & STATUS_DMA_INTERNAL_ERR) { + printf(" DMA internal error.\n"); + } + + if (status & STATUS_DMA_SLAVE_ERR) { + printf(" DMA slave error.\n"); + } + + if (status & STATUS_DMA_DECODE_ERR) { + printf(" DMA decode error.\n"); + } + + if (status & STATUS_SG_INTERNAL_ERR) { + printf(" SG internal error.\n"); + } + + if (status & STATUS_SG_SLAVE_ERR) { + printf(" SG slave error.\n"); + } + + if (status & STATUS_SG_DECODE_ERR) { + printf(" SG decode error.\n"); + } + + if (status & STATUS_IOC_IRQ) { + printf(" IOC interrupt occurred.\n"); + } + + if (status & STATUS_DELAY_IRQ) { + printf(" Interrupt on delay occurred.\n"); + } + + if (status & STATUS_ERR_IRQ) { + printf(" Error interrupt occurred.\n"); + } +} + +void dma_mm2s_status(unsigned int *virtual_addr) +{ + unsigned int status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + + printf("Memory-mapped to stream status (0x%08x@0x%02x):", status, MM2S_STATUS_REGISTER); + + if (status & STATUS_HALTED) { + printf(" Halted.\n"); + } else { + printf(" Running.\n"); + } + + if (status & STATUS_IDLE) { + printf(" Idle.\n"); + } + + if (status & STATUS_SG_INCLDED) { + printf(" SG is included.\n"); + } + + if (status & STATUS_DMA_INTERNAL_ERR) { + printf(" DMA internal error.\n"); + } + + if (status & STATUS_DMA_SLAVE_ERR) { + printf(" DMA slave error.\n"); + } + + if (status & STATUS_DMA_DECODE_ERR) { + printf(" DMA decode error.\n"); + } + + if (status & STATUS_SG_INTERNAL_ERR) { + printf(" SG internal error.\n"); + } + + if (status & STATUS_SG_SLAVE_ERR) { + printf(" SG slave error.\n"); + } + + if (status & STATUS_SG_DECODE_ERR) { + printf(" SG decode error.\n"); + } + + if (status & STATUS_IOC_IRQ) { + printf(" IOC interrupt occurred.\n"); + } + + if (status & STATUS_DELAY_IRQ) { + printf(" Interrupt on delay occurred.\n"); + } + + if (status & STATUS_ERR_IRQ) { + printf(" Error interrupt occurred.\n"); + } +} + +int dma_mm2s_sync(unsigned int *virtual_addr) +{ + unsigned int mm2s_status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + + // sit in this while loop as long as the status does not read back 0x00001002 (4098) + // 0x00001002 = IOC interrupt has occured and DMA is idle + while(!(mm2s_status & IOC_IRQ_FLAG) || !(mm2s_status & IDLE_FLAG)) + { + dma_s2mm_status(virtual_addr); + dma_mm2s_status(virtual_addr); + + mm2s_status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + } + + return 0; +} + +int dma_s2mm_sync(unsigned int *virtual_addr) +{ + unsigned int s2mm_status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + + // sit in this while loop as long as the status does not read back 0x00001002 (4098) + // 0x00001002 = IOC interrupt has occured and DMA is idle + while(!(s2mm_status & IOC_IRQ_FLAG) || !(s2mm_status & IDLE_FLAG)) + { + dma_s2mm_status(virtual_addr); + dma_mm2s_status(virtual_addr); + + s2mm_status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + } + + return 0; +} + +void print_mem(void *virtual_address, int byte_count) +{ + char *data_ptr = virtual_address; + + for(int i=0;i<byte_count;i++){ + printf("%02X", data_ptr[i]); + + // print a space every 4 bytes (0 indexed) + if(i%4==3){ + printf(" "); + } + } + + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + printf("Hello World! - Running DMA transfer test application.\n"); + + printf("Opening a character device file of the Arty's DDR memeory...\n"); + int ddr_memory = open("/dev/mem", O_RDWR | O_SYNC); + + printf("Memory map the address of the DMA AXI IP via its AXI lite control interface register block.\n"); + unsigned int *dma_virtual_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x40400000); + + printf("Memory map the MM2S source address register block.\n"); + unsigned int *virtual_src_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x0e000000); + + printf("Memory map the S2MM destination address register block.\n"); + unsigned int *virtual_dst_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x0f000000); + + printf("Writing random data to source register block...\n"); + + if(argc == 2) + { + if(strcmp(argv[1], "1") == 0) + { + printf("#> 1\n"); + virtual_src_addr[0]= H0_1; + virtual_src_addr[1]= H1_1; + virtual_src_addr[2]= H2; + } + else if(strcmp(argv[1], "2") == 0) + { + printf("#> 2\n"); + virtual_src_addr[0]= H0_2; + virtual_src_addr[1]= H1_2; + virtual_src_addr[2]= H2; + } + else + { + virtual_src_addr[0]= 0xCDCDCDCD; + virtual_src_addr[1]= 0x00001111; + virtual_src_addr[2]= 0x22223333; + } + } + + virtual_src_addr[3]= 0xCDCDCDCD; + virtual_src_addr[4]= 0x00001111; + virtual_src_addr[5]= 0x22223333; + virtual_src_addr[6]= 0x44445555; + virtual_src_addr[7]= 0x66667777; + + printf("Clearing the destination register block...\n"); + memset(virtual_dst_addr, 0, BUFF_SIZE); + + printf("Source memory block data: "); + print_mem(virtual_src_addr, BUFF_SIZE); + + printf("Destination memory block data: "); + print_mem(virtual_dst_addr, BUFF_SIZE); + + printf("Reset the DMA.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, RESET_DMA); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, RESET_DMA); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Halt the DMA.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, HALT_DMA); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, HALT_DMA); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Enable all interrupts.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, ENABLE_ALL_IRQ); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, ENABLE_ALL_IRQ); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing source address of the data from MM2S in DDR...\n"); + write_dma(dma_virtual_addr, MM2S_SRC_ADDRESS_REGISTER, 0x0e000000); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing the destination address for the data from S2MM in DDR...\n"); + write_dma(dma_virtual_addr, S2MM_DST_ADDRESS_REGISTER, 0x0f000000); + dma_s2mm_status(dma_virtual_addr); + + printf("Run the MM2S channel.\n"); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, RUN_DMA); + dma_mm2s_status(dma_virtual_addr); + + printf("Run the S2MM channel.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, RUN_DMA); + dma_s2mm_status(dma_virtual_addr); + + printf("#> Press any key...\n"); + getchar(); + + if(argc == 2) + { + if(strcmp(argv[1], "1") == 0) + { + printf("Writing MM2S transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, MM2S_TRNSFR_LENGTH_REGISTER, BUFF_SIZE); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing S2MM transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, S2MM_BUFF_LENGTH_REGISTER, 0); + dma_s2mm_status(dma_virtual_addr); + + printf("Waiting for MM2S synchronization...\n"); + dma_mm2s_sync(dma_virtual_addr); + + //printf("Waiting for S2MM sychronization...\n"); + //dma_s2mm_sync(dma_virtual_addr); + } + else if(strcmp(argv[1], "2") == 0) + { + printf("Writing MM2S transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, MM2S_TRNSFR_LENGTH_REGISTER, 0); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing S2MM transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, S2MM_BUFF_LENGTH_REGISTER, BUFF_SIZE); + dma_s2mm_status(dma_virtual_addr); + + //printf("Waiting for MM2S synchronization...\n"); + //dma_mm2s_sync(dma_virtual_addr); + + printf("Waiting for S2MM sychronization...\n"); + dma_s2mm_sync(dma_virtual_addr); + } + else + { + printf("Writing MM2S transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, MM2S_TRNSFR_LENGTH_REGISTER, BUFF_SIZE); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing S2MM transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, S2MM_BUFF_LENGTH_REGISTER, BUFF_SIZE); + dma_s2mm_status(dma_virtual_addr); + + printf("Waiting for MM2S synchronization...\n"); + dma_mm2s_sync(dma_virtual_addr); + + printf("Waiting for S2MM sychronization...\n"); + dma_s2mm_sync(dma_virtual_addr); + } + } + + + /* printf("Writing MM2S transfer length of 32 bytes...\n"); */ + /* write_dma(dma_virtual_addr, MM2S_TRNSFR_LENGTH_REGISTER, BUFF_SIZE); */ + /* dma_mm2s_status(dma_virtual_addr); */ + + /* printf("Writing S2MM transfer length of 32 bytes...\n"); */ + /* write_dma(dma_virtual_addr, S2MM_BUFF_LENGTH_REGISTER, BUFF_SIZE); */ + /* dma_s2mm_status(dma_virtual_addr); */ + + /* printf("Waiting for MM2S synchronization...\n"); */ + /* dma_mm2s_sync(dma_virtual_addr); */ + + /* printf("Waiting for S2MM sychronization...\n"); */ + /* dma_s2mm_sync(dma_virtual_addr); */ + + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Destination memory block: "); + print_mem(virtual_dst_addr, BUFF_SIZE); + + printf("\n"); + + return 0; +} diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c~ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c~ new file mode 100644 index 0000000000000000000000000000000000000000..f76dae1d432c64ed54c8ae72a2ff09a2f0de0557 --- /dev/null +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/dmatest-devmem/files/dmatest-devmem.c~ @@ -0,0 +1,343 @@ +/* +* Copyright (C) 2013 - 2016 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in this +* Software without prior written authorization from Xilinx. +* +*/ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <termios.h> +#include <sys/mman.h> + +#define MM2S_CONTROL_REGISTER 0x00 +#define MM2S_STATUS_REGISTER 0x04 +#define MM2S_SRC_ADDRESS_REGISTER 0x18 +#define MM2S_TRNSFR_LENGTH_REGISTER 0x28 + +#define S2MM_CONTROL_REGISTER 0x30 +#define S2MM_STATUS_REGISTER 0x34 +#define S2MM_DST_ADDRESS_REGISTER 0x48 +#define S2MM_BUFF_LENGTH_REGISTER 0x58 + +#define IOC_IRQ_FLAG 1<<12 +#define IDLE_FLAG 1<<1 + +#define STATUS_HALTED 0x00000001 +#define STATUS_IDLE 0x00000002 +#define STATUS_SG_INCLDED 0x00000008 +#define STATUS_DMA_INTERNAL_ERR 0x00000010 +#define STATUS_DMA_SLAVE_ERR 0x00000020 +#define STATUS_DMA_DECODE_ERR 0x00000040 +#define STATUS_SG_INTERNAL_ERR 0x00000100 +#define STATUS_SG_SLAVE_ERR 0x00000200 +#define STATUS_SG_DECODE_ERR 0x00000400 +#define STATUS_IOC_IRQ 0x00001000 +#define STATUS_DELAY_IRQ 0x00002000 +#define STATUS_ERR_IRQ 0x00004000 + +#define HALT_DMA 0x00000000 +#define RUN_DMA 0x00000001 +#define RESET_DMA 0x00000004 +#define ENABLE_IOC_IRQ 0x00001000 +#define ENABLE_DELAY_IRQ 0x00002000 +#define ENABLE_ERR_IRQ 0x00004000 +#define ENABLE_ALL_IRQ 0x00007000 + +#define BUFF_SIZE 32 + +#define H0 0x01000002 +#define H1 0x00000001 +#define H1 0x00000800 + +unsigned int write_dma(unsigned int *virtual_addr, int offset, unsigned int value) +{ + virtual_addr[offset>>2] = value; + + return 0; +} + +unsigned int read_dma(unsigned int *virtual_addr, int offset) +{ + return virtual_addr[offset>>2]; +} + +void dma_s2mm_status(unsigned int *virtual_addr) +{ + unsigned int status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + + printf("Stream to memory-mapped status (0x%08x@0x%02x):", status, S2MM_STATUS_REGISTER); + + if (status & STATUS_HALTED) { + printf(" Halted.\n"); + } else { + printf(" Running.\n"); + } + + if (status & STATUS_IDLE) { + printf(" Idle.\n"); + } + + if (status & STATUS_SG_INCLDED) { + printf(" SG is included.\n"); + } + + if (status & STATUS_DMA_INTERNAL_ERR) { + printf(" DMA internal error.\n"); + } + + if (status & STATUS_DMA_SLAVE_ERR) { + printf(" DMA slave error.\n"); + } + + if (status & STATUS_DMA_DECODE_ERR) { + printf(" DMA decode error.\n"); + } + + if (status & STATUS_SG_INTERNAL_ERR) { + printf(" SG internal error.\n"); + } + + if (status & STATUS_SG_SLAVE_ERR) { + printf(" SG slave error.\n"); + } + + if (status & STATUS_SG_DECODE_ERR) { + printf(" SG decode error.\n"); + } + + if (status & STATUS_IOC_IRQ) { + printf(" IOC interrupt occurred.\n"); + } + + if (status & STATUS_DELAY_IRQ) { + printf(" Interrupt on delay occurred.\n"); + } + + if (status & STATUS_ERR_IRQ) { + printf(" Error interrupt occurred.\n"); + } +} + +void dma_mm2s_status(unsigned int *virtual_addr) +{ + unsigned int status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + + printf("Memory-mapped to stream status (0x%08x@0x%02x):", status, MM2S_STATUS_REGISTER); + + if (status & STATUS_HALTED) { + printf(" Halted.\n"); + } else { + printf(" Running.\n"); + } + + if (status & STATUS_IDLE) { + printf(" Idle.\n"); + } + + if (status & STATUS_SG_INCLDED) { + printf(" SG is included.\n"); + } + + if (status & STATUS_DMA_INTERNAL_ERR) { + printf(" DMA internal error.\n"); + } + + if (status & STATUS_DMA_SLAVE_ERR) { + printf(" DMA slave error.\n"); + } + + if (status & STATUS_DMA_DECODE_ERR) { + printf(" DMA decode error.\n"); + } + + if (status & STATUS_SG_INTERNAL_ERR) { + printf(" SG internal error.\n"); + } + + if (status & STATUS_SG_SLAVE_ERR) { + printf(" SG slave error.\n"); + } + + if (status & STATUS_SG_DECODE_ERR) { + printf(" SG decode error.\n"); + } + + if (status & STATUS_IOC_IRQ) { + printf(" IOC interrupt occurred.\n"); + } + + if (status & STATUS_DELAY_IRQ) { + printf(" Interrupt on delay occurred.\n"); + } + + if (status & STATUS_ERR_IRQ) { + printf(" Error interrupt occurred.\n"); + } +} + +int dma_mm2s_sync(unsigned int *virtual_addr) +{ + unsigned int mm2s_status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + + // sit in this while loop as long as the status does not read back 0x00001002 (4098) + // 0x00001002 = IOC interrupt has occured and DMA is idle + while(!(mm2s_status & IOC_IRQ_FLAG) || !(mm2s_status & IDLE_FLAG)) + { + dma_s2mm_status(virtual_addr); + dma_mm2s_status(virtual_addr); + + mm2s_status = read_dma(virtual_addr, MM2S_STATUS_REGISTER); + } + + return 0; +} + +int dma_s2mm_sync(unsigned int *virtual_addr) +{ + unsigned int s2mm_status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + + // sit in this while loop as long as the status does not read back 0x00001002 (4098) + // 0x00001002 = IOC interrupt has occured and DMA is idle + while(!(s2mm_status & IOC_IRQ_FLAG) || !(s2mm_status & IDLE_FLAG)) + { + dma_s2mm_status(virtual_addr); + dma_mm2s_status(virtual_addr); + + s2mm_status = read_dma(virtual_addr, S2MM_STATUS_REGISTER); + } + + return 0; +} + +void print_mem(void *virtual_address, int byte_count) +{ + char *data_ptr = virtual_address; + + for(int i=0;i<byte_count;i++){ + printf("%02X", data_ptr[i]); + + // print a space every 4 bytes (0 indexed) + if(i%4==3){ + printf(" "); + } + } + + printf("\n"); +} + +int main() +{ + printf("Hello World! - Running DMA transfer test application.\n"); + + printf("Opening a character device file of the Arty's DDR memeory...\n"); + int ddr_memory = open("/dev/mem", O_RDWR | O_SYNC); + + printf("Memory map the address of the DMA AXI IP via its AXI lite control interface register block.\n"); + unsigned int *dma_virtual_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x40400000); + + printf("Memory map the MM2S source address register block.\n"); + unsigned int *virtual_src_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x0e000000); + + printf("Memory map the S2MM destination address register block.\n"); + unsigned int *virtual_dst_addr = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, ddr_memory, 0x0f000000); + + printf("Writing random data to source register block...\n"); + virtual_src_addr[0]= H1; + virtual_src_addr[1]= H2; + virtual_src_addr[2]= H3; + virtual_src_addr[3]= 0xCDCDCDCD; + virtual_src_addr[4]= 0x00001111; + virtual_src_addr[5]= 0x22223333; + virtual_src_addr[6]= 0x44445555; + virtual_src_addr[7]= 0x66667777; + + printf("Clearing the destination register block...\n"); + memset(virtual_dst_addr, 0, BUFF_SIZE); + + printf("Source memory block data: "); + print_mem(virtual_src_addr, BUFF_SIZE); + + printf("Destination memory block data: "); + print_mem(virtual_dst_addr, BUFF_SIZE); + + printf("Reset the DMA.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, RESET_DMA); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, RESET_DMA); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Halt the DMA.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, HALT_DMA); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, HALT_DMA); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Enable all interrupts.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, ENABLE_ALL_IRQ); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, ENABLE_ALL_IRQ); + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing source address of the data from MM2S in DDR...\n"); + write_dma(dma_virtual_addr, MM2S_SRC_ADDRESS_REGISTER, 0x0e000000); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing the destination address for the data from S2MM in DDR...\n"); + write_dma(dma_virtual_addr, S2MM_DST_ADDRESS_REGISTER, 0x0f000000); + dma_s2mm_status(dma_virtual_addr); + + printf("Run the MM2S channel.\n"); + write_dma(dma_virtual_addr, MM2S_CONTROL_REGISTER, RUN_DMA); + dma_mm2s_status(dma_virtual_addr); + + printf("Run the S2MM channel.\n"); + write_dma(dma_virtual_addr, S2MM_CONTROL_REGISTER, RUN_DMA); + dma_s2mm_status(dma_virtual_addr); + + printf("Writing MM2S transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, MM2S_TRNSFR_LENGTH_REGISTER, BUFF_SIZE); + dma_mm2s_status(dma_virtual_addr); + + printf("Writing S2MM transfer length of 32 bytes...\n"); + write_dma(dma_virtual_addr, S2MM_BUFF_LENGTH_REGISTER, BUFF_SIZE); + dma_s2mm_status(dma_virtual_addr); + + printf("Waiting for MM2S synchronization...\n"); + dma_mm2s_sync(dma_virtual_addr); + + printf("Waiting for S2MM sychronization...\n"); + dma_s2mm_sync(dma_virtual_addr); + + dma_s2mm_status(dma_virtual_addr); + dma_mm2s_status(dma_virtual_addr); + + printf("Destination memory block: "); + print_mem(virtual_dst_addr, BUFF_SIZE); + + printf("\n"); + + return 0; +} diff --git a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/libscalp/files/scalp.cc b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/libscalp/files/scalp.cc index 296123f84992d1a76d6b513eeefdc51a1055e6e8..321a0967b7ef22c840886cb2dcdfbc3f37da0f66 100644 --- a/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/libscalp/files/scalp.cc +++ b/scalp_fast_router_firmware_petalinux/project-spec/meta-user/recipes-apps/libscalp/files/scalp.cc @@ -21,7 +21,7 @@ using namespace std; libscalp::uio::uio(const char *dev) { - if((_uiofd = open(dev, O_RDWR)) < 0) + if((_uiofd = open(dev, O_RDWR | O_SYNC)) < 0) { throw std::runtime_error("failed to open UIO device"); }