--- c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am | 5 + .../libbsp/arm/xilinx-zynq/devcfg/zynq-devcfg.c | 770 +++++++++++++++++++++ .../arm/xilinx-zynq/include/zynq-devcfg-regs.h | 194 ++++++ .../libbsp/arm/xilinx-zynq/include/zynq-devcfg.h | 160 +++++ c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am | 8 + 5 files changed, 1137 insertions(+) create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/devcfg/zynq-devcfg.c create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg-regs.h create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg.h
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am index 08024b9..439399b 100644 --- a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am +++ b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am @@ -49,6 +49,8 @@ include_bsp_HEADERS += include/i2c.h include_bsp_HEADERS += include/irq.h include_bsp_HEADERS += include/zynq-uart.h include_bsp_HEADERS += include/zynq-uart-regs.h +include_bsp_HEADERS += include/zynq-devcfg.h +include_bsp_HEADERS += include/zynq-devcfg-regs.h include_bsp_HEADERS += include/zynq-slcr.h include_bsp_HEADERS += include/zynq-slcr-regs.h @@ -120,6 +122,9 @@ libbsp_a_SOURCES += ../shared/arm-a9mpcore-clock-config.c # I2C libbsp_a_SOURCES += i2c/cadence-i2c.c +# Device Config +libbsp_a_SOURCES += devcfg/zynq-devcfg.c + # System Level Control Registers libbsp_a_SOURCES += slcr/zynq-slcr.c diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/devcfg/zynq-devcfg.c b/c/src/lib/libbsp/arm/xilinx-zynq/devcfg/zynq-devcfg.c new file mode 100644 index 0000000..5610545 --- /dev/null +++ b/c/src/lib/libbsp/arm/xilinx-zynq/devcfg/zynq-devcfg.c @@ -0,0 +1,770 @@ +/* + * Xilinx Zynq7000 Device Configuration Driver Implementation + * + * Notes: + * - There will only ever be 1 of these controllers in the Zynq, so this driver + * is designed to be run as a single instance. + * - Even if an interrupt bit is already asserted, unmasking it will lead to + * triggering the interrupt. In several areas operations are started before + * unmasking an interrupt which could be triggered by those operations; this + * interrupt behavior allows for such code to not be racy. + * + * Copyright (c) 2016 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Florida. All rights reserved. + * Copyright (c) 2017 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Pittsburgh. All rights reserved. + * + * 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of CHREC. + * + * Author: Patrick Gauvin <gau...@hcs.ufl.edu> + */ +#include <stdio.h> +#include <stdlib.h> +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/rtems/sem.h> +#include <rtems/irq-extension.h> +#include <bsp/zynq-slcr.h> +#include <bsp/zynq-slcr-regs.h> +#include <bsp/zynq-devcfg.h> +#include <bsp/zynq-devcfg-regs.h> + +#define WARN( msg ) printf( "%s:%s: %s", __FILE__, __func__, msg ) +/* Timeout for interrupt waits, 2 seconds should be enough for any operation. + */ +#define INT_TIMEOUT ( 2 * rtems_clock_get_ticks_per_second() ) + +typedef struct { + volatile zynq_devcfg_regs *regs; + rtems_id sem_id_open; + rtems_id sem_id_internal; + rtems_id sem_id_int_wait; + /* Indicates if the PCAP will be used for a secure bitstream. Secure + * bitstreams are untested with this driver. Defaults to false. + */ + bool secure; +} drvdata; + +static drvdata data; +/* TODO: Abstract DMA buffer retrieval better */ +static uint8_t *dma_buf = NULL; + +/* Check if bit is set in reg (and not masked by mask), and if it is, write + * that bit to reg, returning true. Otherwise return false. + */ +static inline bool check_and_set( + volatile uint32_t *reg, + uint32_t mask, + uint32_t bit +) +{ + if ( *reg & bit & ~mask ) + { + *reg = bit; + return true; + } + return false; +} + +/* Only one semaphore is used since only one interrupt is unmasked at a time. + * The interrupt is cleared and masked after it is caught here. + */ +static void zynq_devcfg_isr( + void *args +) +{ + uint32_t intrs[] = { + ZYNQ_DEVCFG_INT_DMA_DONE_INT, + ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT, + ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT, + ZYNQ_DEVCFG_INT_PCFG_DONE_INT, + ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT + }; + volatile uint32_t *int_sts = &data.regs->int_sts; + volatile uint32_t *int_mask = &data.regs->int_mask; + + (void) args; + + for ( size_t i = 0; i < RTEMS_ARRAY_SIZE( intrs ); ++i ) + if ( check_and_set( int_sts, *int_mask, intrs[i] ) ) + { + *int_mask |= intrs[i]; + rtems_semaphore_release( data.sem_id_int_wait ); + return; + } +} + +static size_t get_bitstream_len( void ) +{ + switch ( ZYNQ_SLCR_PSS_IDCODE_DEVICE_GET( zynq_slcr_pss_idcode_get() ) ) + { + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z007s: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z007s; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z012s: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z012s; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z014s: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z014s; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z010: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z010; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z015: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z015; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z020: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z020; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z030: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z030; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z035: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z035; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z045: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z045; + case ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z100: + return ZYNQ_DEVCFG_BITSTREAM_LEN_7z100; + default: + return 0; + } +} + +/** + * @brief Create an aligned buffer for the bitstream. + * + * @param Desired length of the buffer in bytes. + * + * @retval NULL malloc failed. + */ +static uint8_t *dma_buf_get( + size_t len +) +{ + dma_buf = malloc( len + ZYNQ_DEVCFG_PCAP_DMA_ALIGN ); + if ( NULL == dma_buf ) + return NULL; + if ( (size_t)dma_buf % ZYNQ_DEVCFG_PCAP_DMA_ALIGN != 0 ) + { + return dma_buf + ZYNQ_DEVCFG_PCAP_DMA_ALIGN + - ( (size_t)dma_buf % ZYNQ_DEVCFG_PCAP_DMA_ALIGN ); + } + return dma_buf; +} + +static void dma_buf_release( void ) +{ + free( dma_buf ); +} + +/** + * @brief Initiates a PCAP DMA transfer. + * + * @param src[in] For programming the FPGA, this is the location of the + * bitstream data. For readback, it is the location of the PL readback command + * sequence. + * @param src_len Typically the length of bitstream in dwords, or the number of + * PL commands. The user must check this value for correctness. + * @param dst[in,out] For programming the FPGA use ZYNQ_DEVCFG_BITSTREAM_ADDR, + * for readback this is where the readback data is stored. + * @param dst_len Typically the Length of bitstream in dwords, or the number of + * readback words expected. The user must check this value for correctness. + * + * @retval 0 Transfer was started. + * @retval -1 src_len or dst_len invalid. + * @retval -2 The DMA queue was full. + */ +static int pcap_dma_xfer( + volatile zynq_devcfg_regs *regs, + uint32_t *src, + size_t src_len, + uint32_t *dst, + size_t dst_len +) +{ +#ifdef ZYNQ_DEVCFG_DEBUG + printf( "DMA TRANSFER REQUESTED:\n" ); + printf( "Source: %p\n", src ); + printf( "Source length: %zu\n", src_len ); + printf( "Destination: %p\n", dst ); + printf( "Destination length: %zu\n", dst_len ); +#endif /* ZYNQ_DEVCFG_DEBUG */ + + if ( ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( src_len ) != src_len ) + return -1; + if ( ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( dst_len ) != dst_len ) + return -1; + + /* Check if the command queue is full */ + if ( ZYNQ_DEVCFG_STATUS_DMA_CMD_Q_F( regs->status ) ) + { + WARN( "Zynq DMA queue full\n" ); + return -2; + } + + /* Order is important */ + regs->dma_src_addr = (uint32_t)src; + regs->dma_dst_addr = (uint32_t)dst; + regs->dma_src_len = ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( src_len ); + regs->dma_dest_len = ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( dst_len ); + + return 0; +} + +static int pcap_dma_xfer_wait_and_check( + volatile zynq_devcfg_regs *regs +) +{ + uint32_t int_sts; + rtems_status_code status; + + /* NOTE: The ISR will handle acknowledging the transfer. */ + regs->int_mask &= ~ZYNQ_DEVCFG_INT_DMA_DONE_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + regs->int_mask |= ZYNQ_DEVCFG_INT_DMA_DONE_INT; + WARN( "DMA timed out\n" ); + return -1; + } + + /* TODO: More descriptive error handling */ + int_sts = regs->int_sts; + if ( + ZYNQ_DEVCFG_INT_AXI_WERR_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_AXI_RTO_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_AXI_RERR_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_RX_FIFO_OV_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_DMA_CMD_ERR_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_DMA_Q_OV_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_P2D_LEN_ERR_INT_GET( int_sts ) + || ZYNQ_DEVCFG_INT_PCFG_HMAC_ERR_INT_GET( int_sts ) + ) + return -2; + + return 0; +} + +/** + * @brief Configure the PCAP controller. + */ +static void pl_init( + volatile zynq_devcfg_regs *regs +) +{ + regs->ctrl = ZYNQ_DEVCFG_CTRL_PCAP_MODE( 1 ) | + ZYNQ_DEVCFG_CTRL_PCAP_PR( ZYNQ_DEVCFG_CTRL_PCAP_PR_PCAP ) | + ZYNQ_DEVCFG_CTRL_RESERVED_BITS | regs->ctrl; + /* Disable loopback */ + regs->mctrl = ZYNQ_DEVCFG_MCTRL_SET( + regs->mctrl, + ~ZYNQ_DEVCFG_MCTRL_INT_PCAP_LPBK( 1 ) & regs->mctrl + ); + /* Clear all interrupts */ + regs->int_sts = ZYNQ_DEVCFG_INT_ALL; + + if ( !data.secure ) + { + if ( ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( regs->ctrl ) ) + regs->ctrl = ( ~ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) & regs->ctrl ) + | ZYNQ_DEVCFG_CTRL_RESERVED_BITS; + } + else + { + if ( !ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( regs->ctrl ) ) + regs->ctrl = ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) | regs->ctrl + | ZYNQ_DEVCFG_CTRL_RESERVED_BITS; + } +} + +/** + * @brief Clear the FPGA's configuration. + * + * @retval 0 Success + * @retval -1 PCAP intialization timeout. + * @retval -2 PCAP deinitialization timeout. + * @retval -3 PCAP reinitialization timeout. + * @retval -4 Device reset timeout. + */ +static int pl_clear( + volatile zynq_devcfg_regs *regs +) +{ + /* TODO: Check that controller is available */ + rtems_status_code status; + + regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 ) | + ZYNQ_DEVCFG_CTRL_RESERVED_BITS | regs->ctrl; + regs->int_mask &= ~ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + WARN( "PCAP init timed out\n" ); + regs->int_mask |= ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT; + return -1; + } + + regs->ctrl = ( ~ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 ) & regs->ctrl ) | + ZYNQ_DEVCFG_CTRL_RESERVED_BITS; + regs->int_mask &= ~ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + WARN( "PCAP deinit timed out\n" ); + regs->int_mask |= ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT; + return -2; + } + + regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 ) | + ZYNQ_DEVCFG_CTRL_RESERVED_BITS | regs->ctrl; + regs->int_mask &= ~ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + WARN( "PCAP reinit timed out\n" ); + regs->int_mask |= ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT; + return -3; + } + + regs->int_mask &= ~ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + WARN( "PSS_CFG_RESET_B_INT timed out\n" ); + regs->int_mask |= ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT; + return -4; + } + + return 0; +} + +/* TODO: Check that PL power is on. + * TODO: Check for configuration differences between silicon revisions. + */ +rtems_device_driver zynq_devcfg_init( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_status_code status; + + (void) args; + + status = rtems_io_register_name( ZYNQ_DEVCFG_NAME, major, minor ); + if ( RTEMS_SUCCESSFUL != status ) + { + status = RTEMS_INVALID_NAME; + goto err; + } + + data.regs = (zynq_devcfg_regs *)ZYNQ_DEVCFG_BASE_ADDR; + data.secure = false; + status = rtems_semaphore_create( + rtems_build_name( 'D', 'e', 'v', 'C' ), + 1, + RTEMS_LOCAL | RTEMS_SIMPLE_BINARY_SEMAPHORE, + RTEMS_NO_PRIORITY, + &data.sem_id_open + ); + if ( RTEMS_SUCCESSFUL != status ) + { + status = RTEMS_UNSATISFIED; + goto err; + } + status = rtems_semaphore_create( + rtems_build_name( 'D', 'v', 'C', 'i' ), + 1, + RTEMS_LOCAL | RTEMS_SIMPLE_BINARY_SEMAPHORE, + RTEMS_NO_PRIORITY, + &data.sem_id_internal + ); + if ( RTEMS_SUCCESSFUL != status ) + { + status = RTEMS_UNSATISFIED; + goto err_sem_internal; + } + status = rtems_semaphore_create( + rtems_build_name( 'D', 'v', 'C', 'w' ), + 0, + RTEMS_LOCAL | RTEMS_SIMPLE_BINARY_SEMAPHORE, + RTEMS_NO_PRIORITY, + &data.sem_id_int_wait + ); + if ( RTEMS_SUCCESSFUL != status ) + { + status = RTEMS_UNSATISFIED; + goto err_sem_wait; + } + + /* Mask and clear all interrupts and install handler */ + data.regs->int_mask |= ZYNQ_DEVCFG_INT_ALL; + data.regs->int_sts = ZYNQ_DEVCFG_INT_ALL; + status = rtems_interrupt_handler_install( + ZYNQ_DEVCFG_INTERRUPT_VECTOR, + "DevC ISR", + RTEMS_INTERRUPT_UNIQUE, + zynq_devcfg_isr, + NULL + ); + if ( RTEMS_SUCCESSFUL != status ) + { + WARN( "Failed to assign interrupt handler\n" ); + status = RTEMS_INTERNAL_ERROR; + goto err_intr; + } + + return RTEMS_SUCCESSFUL; +err_intr: + rtems_semaphore_delete( data.sem_id_int_wait ); +err_sem_wait: + rtems_semaphore_delete( data.sem_id_internal ); +err_sem_internal: + rtems_semaphore_delete( data.sem_id_open ); +err: + return status; +} + +rtems_device_driver zynq_devcfg_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_status_code rstatus; + + (void) major; + (void) minor; + (void) args; + + rstatus = rtems_semaphore_obtain( + data.sem_id_open, + RTEMS_NO_WAIT, + 0 + ); + if ( RTEMS_SUCCESSFUL == rstatus ) + return RTEMS_SUCCESSFUL; + else if ( RTEMS_UNSATISFIED == rstatus ) + return RTEMS_RESOURCE_IN_USE; + else + return RTEMS_INTERNAL_ERROR; +} + +rtems_device_driver zynq_devcfg_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_status_code rstatus; + + (void) major; + (void) minor; + (void) args; + + rstatus = rtems_semaphore_release( data.sem_id_open ); + if ( RTEMS_SUCCESSFUL != rstatus ) + { + WARN( rtems_status_text( rstatus ) ); + return RTEMS_INTERNAL_ERROR; + } + else + return RTEMS_SUCCESSFUL; +} + +rtems_device_driver zynq_devcfg_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_libio_rw_args_t *rw_args; + int status; + rtems_status_code rstatus; + rtems_status_code final_status; + uint8_t *data_buf; + + (void) major; + (void) minor; + rw_args = args; + rw_args->bytes_moved = 0; + + rstatus = rtems_semaphore_obtain( data.sem_id_internal, RTEMS_NO_WAIT, 0 ); + if ( RTEMS_SUCCESSFUL != rstatus ) + { + final_status = RTEMS_RESOURCE_IN_USE; + goto err_obtain; + } + + if ( rw_args->count < 4 ) + { + final_status = RTEMS_INVALID_SIZE; + goto err_insane; + } + /* TODO: It might be valid to read configuration registers while the PL is + * not programmed. + */ + /* PCFG_DONE must be asserted before readback */ + if ( !ZYNQ_DEVCFG_INT_PCFG_DONE_INT_GET( data.regs->int_sts ) ) + { + WARN( "read attempted when FPGA configuration not done\n" ); + final_status = RTEMS_IO_ERROR; + goto err_insane; + } + + if ( 0 != (size_t)rw_args->buffer % ZYNQ_DEVCFG_PCAP_DMA_ALIGN ) + data_buf = dma_buf_get( rw_args->count ); + else + data_buf = (uint8_t *)rw_args->buffer; + + status = pcap_dma_xfer( + data.regs, + (uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR, + rw_args->count / 4, + (uint32_t *)( (uint32_t)data_buf | 1 ), + rw_args->count / 4 + ); + if ( status ) + { + WARN( "DMA setup FAILED\n" ); + final_status = RTEMS_IO_ERROR; + goto err_dma; + } + else + { + status = pcap_dma_xfer_wait_and_check( data.regs ); + if ( status ) + { + WARN( "DMA FAILED\n" ); + final_status = RTEMS_IO_ERROR; + goto err_dma; + } + } + + /* Ensure stale data is not read */ + rtems_cache_invalidate_multiple_data_lines( data_buf, rw_args->count ); + + final_status = RTEMS_SUCCESSFUL; + rw_args->bytes_moved = rw_args->count; + if ( data_buf != (uint8_t *)rw_args->buffer ) + memcpy( rw_args->buffer, data_buf, rw_args->count ); +err_dma: + if ( data_buf != (uint8_t *)rw_args->buffer ) + dma_buf_release(); + rstatus = rtems_semaphore_release( data.sem_id_internal ); +err_insane: + if ( RTEMS_SUCCESSFUL != rstatus ) + final_status = RTEMS_INTERNAL_ERROR; +err_obtain: + return final_status; +} + +rtems_device_driver zynq_devcfg_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_libio_rw_args_t *rw_args; + int status; + rtems_status_code rstatus; + rtems_status_code final_status; + uint8_t *data_buf; + + (void) major; + (void) minor; + rw_args = args; + rw_args->bytes_moved = 0; + + rstatus = rtems_semaphore_obtain( data.sem_id_internal, RTEMS_NO_WAIT, 0 ); + if ( RTEMS_SUCCESSFUL != rstatus ) + { + final_status = RTEMS_RESOURCE_IN_USE; + goto err_obtain; + } + + if ( 0 != (size_t)rw_args->buffer % ZYNQ_DEVCFG_PCAP_DMA_ALIGN ) + { + data_buf = dma_buf_get( rw_args->count ); + memcpy( data_buf, rw_args->buffer, rw_args->count ); + } + else + data_buf = (uint8_t *)rw_args->buffer; + + /* Ensure data is available to the DMA engine */ + rtems_cache_flush_multiple_data_lines( data_buf, rw_args->count ); + + status = pcap_dma_xfer( + data.regs, + (uint32_t *)( (uint32_t)data_buf | 1 ), + rw_args->count / 4, + (uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR, + rw_args->count / 4 + ); + if ( status ) + { + final_status = RTEMS_IO_ERROR; + goto err_dma; + } + else + { + status = pcap_dma_xfer_wait_and_check( data.regs ); + if ( status ) + { + final_status = RTEMS_IO_ERROR; + goto err_dma; + } + } + + final_status = RTEMS_SUCCESSFUL; + rw_args->bytes_moved = rw_args->count; +err_dma: + if ( data_buf != (uint8_t *)rw_args->buffer ) + dma_buf_release(); + rstatus = rtems_semaphore_release( data.sem_id_internal ); + if ( RTEMS_SUCCESSFUL != rstatus ) + final_status = RTEMS_INTERNAL_ERROR; +err_obtain: + return final_status; +} + +rtems_device_driver zynq_devcfg_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +) +{ + rtems_libio_ioctl_args_t *ioctl_args; + char *str; + int status; + rtems_status_code rstatus; + rtems_status_code final_status; + + (void) major; + (void) minor; + ioctl_args = args; + + rstatus = rtems_semaphore_obtain( data.sem_id_internal, RTEMS_NO_WAIT, 0 ); + if ( RTEMS_UNSATISFIED == rstatus ) + { + ioctl_args->ioctl_return = -1; + return RTEMS_RESOURCE_IN_USE; + } + else if ( RTEMS_SUCCESSFUL != rstatus ) + { + ioctl_args->ioctl_return = -1; + return RTEMS_INTERNAL_ERROR; + } + + final_status = RTEMS_SUCCESSFUL; + ioctl_args->ioctl_return = 0; + switch ( ioctl_args->command ) { + case ZYNQ_DEVCFG_IOCTL_VERSION: + str = ioctl_args->buffer; + switch( ZYNQ_DEVCFG_MCTRL_PS_VERSION_GET( data.regs->mctrl ) ) { + case ZYNQ_DEVCFG_MCTRL_PS_VERSION_1_0: + strncpy( str, "1.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN ); + break; + case ZYNQ_DEVCFG_MCTRL_PS_VERSION_2_0: + strncpy( str, "2.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN ); + break; + case ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_0: + strncpy( str, "3.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN ); + break; + case ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_1: + strncpy( str, "3.1", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN ); + break; + default: + strncpy( str, "???", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN ); + break; + } + break; + case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_PRE: + pl_init( data.regs ); + /* Hold FPGA clocks in reset */ + zynq_slcr_fpga_clk_rst( 0xf ); + /* Enable PS to PL level shifters */ + zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_DISABLE ); + zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_PS_TO_PL ); + status = pl_clear( data.regs ); + if ( 0 != status ) + { + ioctl_args->ioctl_return = -1; + final_status = RTEMS_UNSATISFIED; + } + break; + case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_POST: + /* Enable all PS-PL level shifters */ + zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_ALL ); + /* Release FPGA clocks from reset */ + zynq_slcr_fpga_clk_rst( 0 ); + break; + case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_WAIT_DONE: + data.regs->int_mask &= ~ZYNQ_DEVCFG_INT_PCFG_DONE_INT; + status = rtems_semaphore_obtain( + data.sem_id_int_wait, + RTEMS_WAIT, + INT_TIMEOUT + ); + if ( RTEMS_SUCCESSFUL != status ) + { + ioctl_args->ioctl_return = -1; + data.regs->int_mask |= ZYNQ_DEVCFG_INT_PCFG_DONE_INT; + final_status = RTEMS_TIMEOUT; + } + break; + case ZYNQ_DEVCFG_IOCTL_SET_SECURE: + data.secure = *(bool *)ioctl_args->buffer; + break; + case ZYNQ_DEVCFG_IOCTL_BITSTREAM_LEN_GET: + *(size_t *)ioctl_args->buffer = get_bitstream_len(); + break; + default: + ioctl_args->ioctl_return = -1; + final_status = RTEMS_INVALID_NAME; /* Maps to EINVAL */ + break; + } + + rstatus = rtems_semaphore_release( data.sem_id_internal ); + if ( rstatus != RTEMS_SUCCESSFUL ) + WARN( "Failed to release internal semaphore\n" ); + return final_status; +} diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg-regs.h b/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg-regs.h new file mode 100644 index 0000000..d3601d6 --- /dev/null +++ b/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg-regs.h @@ -0,0 +1,194 @@ +/** + * @file + * @ingroup zynq_devcfg + * @brief Device configuration interface register definitions. + */ + +/* + * Copyright (c) 2016 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Florida. All rights reserved. + * Copyright (c) 2017 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Pittsburgh. All rights reserved. + * + * 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of CHREC. + * + * Author: Patrick Gauvin <gau...@hcs.ufl.edu> + */ + +/** + * @defgroup zynq_devcfg_regs Device Configuration Interface Register Definitions + * @ingroup zynq_devcfg + * @brief Device Configuration Interface Register Definitions + */ + +#ifndef LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_REGS_H +#define LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_REGS_H + +#include <bsp/utility.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Zynq-7000 series devcfg address */ +#define ZYNQ_DEVCFG_BASE_ADDR 0xF8007000UL +/* For use with the PCAP DMA */ +#define ZYNQ_DEVCFG_BITSTREAM_ADDR 0xFFFFFFFFUL +/* PCAP DMA transfers must be 64-byte aligned */ +#define ZYNQ_DEVCFG_PCAP_DMA_ALIGN 64 +#define ZYNQ_DEVCFG_INTERRUPT_VECTOR 40 + +typedef struct { + uint32_t ctrl; +#define ZYNQ_DEVCFG_CTRL_FORCE_RST( val ) BSP_FLD32( val, 31, 31 ) +#define ZYNQ_DEVCFG_CTRL_FORCE_RST_GET( reg ) BSP_FLD32GET( reg, 31, 31 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_PROG_B_GET( reg ) BSP_FLD32GET( reg, 30, 30 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( val ) BSP_FLD32( val, 30, 30 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_POR_CNT_4K_GET( reg ) BSP_FLD32GET( reg, 29, 29 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_POR_CNT_4K( val ) BSP_FLD32( val, 29, 29 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_PR( val ) BSP_FLD32( val, 27, 27 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_PR_GET( reg ) BSP_FLD32GET( reg, 27, 27 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_PR_ICAP ( 0 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_PR_PCAP ( 1 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_MODE( val ) BSP_FLD32( val, 26, 26 ) +#define ZYNQ_DEVCFG_CTRL_PCAP_MODE_GET( reg ) BSP_FLD32GET( reg, 26, 26 ) +#define ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( val ) BSP_FLD32( val, 25, 25 ) +#define ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN_GET( reg ) \ + BSP_FLD32GET( reg, 25, 25 ) +#define ZYNQ_DEVCFG_CTRL_MULTIBOOT_EN( val ) BSP_FLD32( val, 24, 24 ) +#define ZYNQ_DEVCFG_CTRL_MULTIBOOT_EN_GET( reg ) BSP_FLD32GET( reg, 24, 24 ) +#define ZYNQ_DEVCFG_CTRL_JTAG_CHAIN_DIS( val ) BSP_FLD32( val, 23, 23 ) +#define ZYNQ_DEVCFG_CTRL_JTAG_CHAIN_DIS_GET( reg ) BSP_FLD32GET( reg, 23, 23 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_FUSE( val ) BSP_FLD32( val, 12, 12 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_FUSE_GET( reg ) BSP_FLD32GET( reg, 12, 12 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_FUSE_BBRAM ( 0 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_FUSE_EFUSE ( 1 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_EN( val ) BSP_FLD32( val, 9, 11 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_EN_GET( reg ) BSP_FLD32GET( reg, 9, 11 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_EN_ENABLE ( 0x3 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_EN_DISABLE ( 0x0 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_AES_EN_LOCKDOWN ( 0x1 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SEU_EN( val ) BSP_FLD32( val, 8, 8 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SEU_EN_GET( reg ) BSP_FLD32GET( reg, 8, 8 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SEC_EN_GET( reg ) BSP_FLD32GET( reg, 7, 7 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SPNIDEN( val ) BSP_FLD32( val, 6, 6 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SPNIDEN_GET( reg ) BSP_FLD32GET( reg, 6, 6 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SPIDEN( val ) BSP_FLD32( val, 5, 5 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_SPIDEN_GET( reg ) BSP_FLD32GET( reg, 5, 5 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_NIDEN( val ) BSP_FLD32( val, 4, 4 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_NIDEN_GET( reg ) BSP_FLD32GET( reg, 4, 4 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DBGEN( val ) BSP_FLD32( val, 3, 3 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DBGEN_GET( reg ) BSP_FLD32GET( reg, 3, 3 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DAP_EN( val ) BSP_FLD32( val, 0, 2 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DAP_EN_GET( reg ) BSP_FLD32GET( reg, 0, 2 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DAP_EN_ENABLE ( 0x3 ) +#define ZYNQ_DEVCFG_CTRL_PCFG_DAP_EN_BYPASS ( 0x0 ) +#define ZYNQ_DEVCFG_CTRL_RESERVED_BITS ( 0x6000 ) + uint32_t lock; + uint32_t cfg; + /* int_sts and int_mask directly overlap, so they share the ZYNQ_DEVCFG_INT_* + * macros */ + uint32_t int_sts; + uint32_t int_mask; +#define ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT BSP_BIT32( 27 ) +#define ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT_GET( reg ) \ + BSP_FLD32GET( reg, 27, 27 ) +#define ZYNQ_DEVCFG_INT_AXI_WERR_INT_GET( reg ) BSP_FLD32GET( reg, 22, 22 ) +#define ZYNQ_DEVCFG_INT_AXI_RTO_INT_GET( reg ) BSP_FLD32GET( reg, 21, 21 ) +#define ZYNQ_DEVCFG_INT_AXI_RERR_INT_GET( reg ) BSP_FLD32GET( reg, 20, 20 ) +#define ZYNQ_DEVCFG_INT_RX_FIFO_OV_INT_GET( reg ) \ + BSP_FLD32GET( reg, 18, 18 ) +#define ZYNQ_DEVCFG_INT_DMA_CMD_ERR_INT_GET( reg ) \ + BSP_FLD32GET( reg, 15, 15 ) +#define ZYNQ_DEVCFG_INT_DMA_Q_OV_INT_GET( reg ) BSP_FLD32GET( reg, 14, 14 ) +#define ZYNQ_DEVCFG_INT_DMA_DONE_INT BSP_BIT32( 13 ) +#define ZYNQ_DEVCFG_INT_DMA_DONE_INT_GET( reg ) BSP_FLD32GET( reg, 13, 13 ) +#define ZYNQ_DEVCFG_INT_D_P_DONE_INT BSP_BIT32( 12 ) +#define ZYNQ_DEVCFG_INT_D_P_DONE_INT_GET( reg ) BSP_FLD32GET( reg, 12, 12 ) +#define ZYNQ_DEVCFG_INT_P2D_LEN_ERR_INT_GET( reg ) \ + BSP_FLD32GET( reg, 11, 11 ) +#define ZYNQ_DEVCFG_INT_PCFG_HMAC_ERR_INT_GET( reg ) \ + BSP_FLD32GET( reg, 6, 6 ) +#define ZYNQ_DEVCFG_INT_PCFG_SEU_ERR_INT_GET( reg ) \ + BSP_FLD32GET( reg, 5, 5 ) +#define ZYNQ_DEVCFG_INT_PCFG_POR_B_INT_GET( reg ) BSP_FLD32GET( reg, 4, 4 ) +#define ZYNQ_DEVCFG_INT_PCFG_CFG_RST_INT_GET( reg ) \ + BSP_FLD32GET( reg, 3, 3 ) +#define ZYNQ_DEVCFG_INT_PCFG_DONE_INT BSP_BIT32( 2 ) +#define ZYNQ_DEVCFG_INT_PCFG_DONE_INT_GET( reg ) BSP_FLD32GET( reg, 2, 2 ) +#define ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT BSP_BIT32( 1 ) +#define ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT_GET( reg ) \ + BSP_FLD32GET( reg, 1, 1 ) +#define ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT BSP_BIT32( 0 ) +#define ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT_GET( reg ) \ + BSP_FLD32GET( reg, 0, 0 ) +#define ZYNQ_DEVCFG_INT_ALL ( 0xf8f7f87f ) + uint32_t status; +#define ZYNQ_DEVCFG_STATUS_DMA_CMD_Q_F( val ) BSP_FLD32( val, 31, 31 ) +#define ZYNQ_DEVCFG_STATUS_DMA_CMD_Q_F_GET( reg ) BSP_FLD32GET( reg, 31, 31 ) +#define ZYNQ_DEVCFG_STATUS_PCFG_INIT_GET( reg ) BSP_FLD32GET( reg, 4, 4 ) + uint32_t dma_src_addr; + uint32_t dma_dst_addr; + uint32_t dma_src_len; +#define ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( val ) BSP_FLD32( val, 0, 26 ) + uint32_t dma_dest_len; /* (sic) */ +#define ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( val ) BSP_FLD32( val, 0, 26 ) + uint32_t reserved0; + uint32_t multiboot_addr; + uint32_t reserved1; + uint32_t unlock; + uint32_t reserved2[18]; + uint32_t mctrl; +#define ZYNQ_DEVCFG_MCTRL_PS_VERSION_GET( reg ) BSP_FLD32GET( reg, 28, 31 ) +#define ZYNQ_DEVCFG_MCTRL_PS_VERSION_1_0 0x0 +#define ZYNQ_DEVCFG_MCTRL_PS_VERSION_2_0 0x1 +#define ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_0 0x2 +#define ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_1 0x3 +#define ZYNQ_DEVCFG_MCTRL_PCFG_POR_B_GET( reg ) BSP_FLD32GET( reg, 8, 8 ) +#define ZYNQ_DEVCFG_MCTRL_INT_PCAP_LPBK_GET( reg ) BSP_FLD32GET( reg, 4, 4 ) +#define ZYNQ_DEVCFG_MCTRL_INT_PCAP_LPBK( val ) BSP_FLD32( val, 4, 4 ) +#define ZYNQ_DEVCFG_MCTRL_RESERVED_SET_BITS ( 0x800000 ) +#define ZYNQ_DEVCFG_MCTRL_RESERVED_UNSET_BITS ( 0x3 ) +#define ZYNQ_DEVCFG_MCTRL_SET( reg, val ) ( ( ( reg ) & \ + ~ZYNQ_DEVCFG_MCTRL_RESERVED_UNSET_BITS ) | \ + ZYNQ_DEVCFG_MCTRL_RESERVED_SET_BITS | ( val ) ) + uint32_t reserved3[32]; + uint32_t xadcif_cfg; + uint32_t xadcif_int_sts; + uint32_t xadcif_int_mask; + uint32_t xadcif_msts; + uint32_t xadcif_cmdfifo; + uint32_t xadcif_rdfifo; + uint32_t xadcif_mctrl; +} zynq_devcfg_regs; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_REGS_H */ diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg.h b/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg.h new file mode 100644 index 0000000..9da7e2b --- /dev/null +++ b/c/src/lib/libbsp/arm/xilinx-zynq/include/zynq-devcfg.h @@ -0,0 +1,160 @@ +/** + * @file + * @ingroup zynq_devcfg + * @brief Device configuration support. + * + * Provides support for the Zynq7000 series device configuration interface + * controller. PCAP command sequences are written using the write interface, + * and PCAP responses are retrieved with the read interface. The driver can be + * used for reconfiguration of the FPGA, and also reading FPGA configuration + * data for error checking. + */ + +/* + * Copyright (c) 2016 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Florida. All rights reserved. + * Copyright (c) 2017 + * NSF Center for High-Performance Reconfigurable Computing (CHREC), + * University of Pittsburgh. All rights reserved. + * + * 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. + * + * The views and conclusions contained in the software and documentation + * are those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of CHREC. + * + * Author: Patrick Gauvin <gau...@hcs.ufl.edu> + */ + +/** + * @defgroup zynq_devcfg Device Configuration Interface Support + * @ingroup arm_zynq + * @brief Device Configuration Interface Support + */ + +#ifndef LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_H +#define LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_H + +#include <rtems/libio.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define ZYNQ_DEVCFG_NAME "/dev/devcfg" +#define ZYNQ_DEVCFG_DRIVER_TABLE_ENTRY \ + { zynq_devcfg_init, zynq_devcfg_open, zynq_devcfg_close, zynq_devcfg_read, \ + zynq_devcfg_write, zynq_devcfg_control } + +/** @brief Zynq configuration frame length in bytes */ +#define ZYNQ_DEVCFG_CONFIG_FRAME_LEN ( 101 * 4 ) + +#define ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN 16 + +/** @brief Bitstream lengths in bytes */ +enum zynq_devcfg_bitstream_length { + ZYNQ_DEVCFG_BITSTREAM_LEN_7z007s = 16669920UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z012s = 28085344UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z014s = 32364512UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z010 = 16669920UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z015 = 28085344UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z020 = 32364512UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z030 = 47839328UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z035 = 106571232UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z045 = 106571232UL / 8, + ZYNQ_DEVCFG_BITSTREAM_LEN_7z100 = 139330784UL / 8 +}; + +enum zynq_devcfg_ioctl { + /** @brief Argument: Buffer for character string of at least + * ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN bytes. + */ + ZYNQ_DEVCFG_IOCTL_VERSION, + /** @brief Argument: size_t. */ + ZYNQ_DEVCFG_IOCTL_BITSTREAM_LEN_GET, + /** @brief Argument: None. */ + ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_PRE, + /** @brief Argument: None. */ + ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_POST, + /** @brief Agument: None. */ + ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_WAIT_DONE, + /** @brief Argument: bool. */ + ZYNQ_DEVCFG_IOCTL_SET_SECURE +}; + +rtems_device_driver zynq_devcfg_init( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +rtems_device_driver zynq_devcfg_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +rtems_device_driver zynq_devcfg_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +/** + * @brief Read from the PCAP controller. + * + * Readback reads cannot be split into multiple DMA reads, this may cause the + * PCAP DMA to exhibit unexpected behavior. Therefore, the read length must + * match the preceding command sequence's expected data output length. + */ +rtems_device_driver zynq_devcfg_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +/** + * @brief Write to the PCAP controller. + * + * Data format: dword aligned bistream data or PCAP commands. Bitstream data is + * expected to be formatted as Vivado 2016.4 outputs BIN-format bitstreams by + * default (not bit-swapped) BUT with the byte order within each dword changed + * to little endian. See UG470 for information on data ordering. + */ +rtems_device_driver zynq_devcfg_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +rtems_device_driver zynq_devcfg_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *args +); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_XILINX_ZYNQ_DEVCFG_H */ diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am b/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am index 814095f..4eaab68 100644 --- a/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am +++ b/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am @@ -150,6 +150,14 @@ $(PROJECT_INCLUDE)/bsp/zynq-uart-regs.h: include/zynq-uart-regs.h $(PROJECT_INCL $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/zynq-uart-regs.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/zynq-uart-regs.h +$(PROJECT_INCLUDE)/bsp/zynq-devcfg.h: include/zynq-devcfg.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/zynq-devcfg.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/zynq-devcfg.h + +$(PROJECT_INCLUDE)/bsp/zynq-devcfg-regs.h: include/zynq-devcfg-regs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/zynq-devcfg-regs.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/zynq-devcfg-regs.h + $(PROJECT_INCLUDE)/bsp/zynq-slcr.h: include/zynq-slcr.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/zynq-slcr.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/zynq-slcr.h -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel