bsp/xilinx-zynq: Add devcfg and slcr drivers

The devfg driver loads the PL with a bitfile image. The driver can also
support scrubbing.

These drivers are from Patrick Gauvin <pggauvin at gmail.com> and a thread
on the devel list: https://lists.rtems.org/pipermail/devel/2017-May/017705.html
This commit is contained in:
Chris Johns
2024-10-30 17:08:28 +11:00
committed by Amar Takhar
parent a1c3d4ba8e
commit bc8ffae115
7 changed files with 1561 additions and 0 deletions

View File

@@ -0,0 +1,898 @@
/*
* 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.
* - Secure loading is not supported.
*
* 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 <gauvin@hcs.ufl.edu>
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/rtems/sem.h>
#include <rtems/irq-extension.h>
#include <dev/slcr/zynq-slcr.h>
#include <dev/slcr/zynq-slcr-regs.h>
#include <dev/devcfg/zynq-devcfg.h>
#include <dev/devcfg/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() )
#define ZYNQ_DEVCFG_EVENT_SET RTEMS_EVENT_0
typedef struct {
volatile zynq_devcfg_regs *regs;
/* Used to restrict the device to being opened once at a time. */
rtems_id sem_id_open;
/* Used for mutual exclusion between read/write/ioctl. */
rtems_id sem_id_internal;
/* Indicates if the PCAP will be used for a secure bitstream. Secure
* bitstreams are untested with this driver. Defaults to false.
*/
bool secure;
/* If true, write data is not assumed to be a complete bitstream and no
* checks are performed on it.
*/
bool write_mode_restricted;
rtems_id current_task;
} driver_data;
typedef struct {
uint8_t *buf;
uint8_t *buf_orig;
} dma_buf;
static driver_data data;
/**
* @brief Check if bit is set in reg (and also not masked by mask), and if it
* is, write that bit to reg.
*
* @retval true The bit was set and not masked, and was written to.
* @retval false The bit was not written to.
*/
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 event 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
)
{
const 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];
if ( RTEMS_INVALID_ID != data.current_task )
rtems_event_system_send( data.current_task, ZYNQ_DEVCFG_EVENT_SET );
return;
}
}
static inline bool ptr_is_pcap_dma_aligned(
void *ptr
)
{
return 0 == (uintptr_t)ptr % ZYNQ_DEVCFG_PCAP_DMA_ALIGN;
}
/**
* @brief Create an aligned buffer for the bitstream.
*
* @param len Desired length of the buffer in bytes.
*
* @return dma_buf members are NULL if malloc failed.
*/
static dma_buf dma_buf_get(
size_t len
)
{
dma_buf dbuf;
dbuf.buf_orig = malloc( len + ZYNQ_DEVCFG_PCAP_DMA_ALIGN );
if ( NULL == dbuf.buf_orig )
{
dbuf.buf = NULL;
return dbuf;
}
if ( !ptr_is_pcap_dma_aligned( dbuf.buf_orig ) )
{
dbuf.buf = dbuf.buf_orig + ZYNQ_DEVCFG_PCAP_DMA_ALIGN
- ( (size_t)dbuf.buf_orig % ZYNQ_DEVCFG_PCAP_DMA_ALIGN );
}
else
dbuf.buf = dbuf.buf_orig;
return dbuf;
}
/**
* @brief Frees the originally allocated area for dbuf.
*/
static void dma_buf_release(
dma_buf dbuf
)
{
free( dbuf.buf_orig );
}
/**
* @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.
* @param pcap_wait If true, interrupt assertion waits for both the AXI
* transfer and the PCAP to finish.
*
* @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(
uint32_t *src,
size_t src_len,
uint32_t *dst,
size_t dst_len,
bool pcap_wait
)
{
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;
if ( pcap_wait )
{
src = (uint32_t *)
( (uintptr_t)src | ZYNQ_DEVCFG_DMA_SRC_ADDR_DMA_DONE_INT_WAIT_PCAP );
dst = (uint32_t *)
( (uintptr_t)dst | ZYNQ_DEVCFG_DMA_DST_ADDR_DMA_DONE_INT_WAIT_PCAP );
}
#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 */
/* Check if the command queue is full */
if ( ZYNQ_DEVCFG_STATUS_DMA_CMD_Q_F( data.regs->status ) )
{
WARN( "Zynq DMA queue full\n" );
return -2;
}
/* Order is important */
data.regs->dma_src_addr = (uint32_t)src;
data.regs->dma_dst_addr = (uint32_t)dst;
data.regs->dma_src_len = ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( src_len );
data.regs->dma_dest_len = ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( dst_len );
return 0;
}
/**
* @brief Unmasks and waits for the interrupt in int_bit.
*
* @param int_bit The interrupt bit in int_sts (NOT a bit number).
* @return The result of rtems_event_system_receive.
*/
static rtems_status_code int_enable_and_wait(
uint32_t int_bit
)
{
rtems_event_set ev;
rtems_status_code status;
data.current_task = rtems_task_self();
/* data.current_task must be updated before an interrupt is handled. */
RTEMS_COMPILER_MEMORY_BARRIER();
data.regs->int_mask &= ~int_bit;
status = rtems_event_system_receive(
ZYNQ_DEVCFG_EVENT_SET,
RTEMS_WAIT,
INT_TIMEOUT,
&ev
);
/* Re-mask interrupt if not received. */
if ( RTEMS_SUCCESSFUL != status )
data.regs->int_mask |= int_bit;
return status;
}
/**
* @brief Wait for a DMA transfer to finish and check for failure.
*
* @retval 0 Success.
* @retval -1 DMA timeout.
* @retval -2 AXI transfer error.
* @retval -3 Receive FIFO overflow.
* @retval -4 DMA command error or command queue overflow.
* @retval -5 Mismatch between PCAP output length and DMA transfer length.
* @retval -6 HMAC error.
*/
static int pcap_dma_xfer_wait_and_check( void )
{
uint32_t int_sts;
rtems_status_code status;
/* NOTE: The ISR will handle acknowledging the transfer. */
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_DMA_DONE_INT );
if ( RTEMS_SUCCESSFUL != status )
{
WARN( "DMA timed out\n" );
return -1;
}
int_sts = data.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 )
)
return -2;
if ( ZYNQ_DEVCFG_INT_RX_FIFO_OV_INT_GET( int_sts ) )
return -3;
if (
ZYNQ_DEVCFG_INT_DMA_CMD_ERR_INT_GET( int_sts )
|| ZYNQ_DEVCFG_INT_DMA_Q_OV_INT_GET( int_sts )
)
return -4;
if ( ZYNQ_DEVCFG_INT_P2D_LEN_ERR_INT_GET( int_sts ) )
return -5;
if ( ZYNQ_DEVCFG_INT_PCFG_HMAC_ERR_INT_GET( int_sts ) )
return -6;
return 0;
}
/**
* @brief Configure the PCAP controller.
*/
static void pl_init( void )
{
data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCAP_MODE( 1 )
| ZYNQ_DEVCFG_CTRL_PCAP_PR( ZYNQ_DEVCFG_CTRL_PCAP_PR_PCAP )
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
/* Disable loopback */
data.regs->mctrl = ZYNQ_DEVCFG_MCTRL_SET(
data.regs->mctrl,
~ZYNQ_DEVCFG_MCTRL_INT_PCAP_LPBK( 1 ) & data.regs->mctrl
);
/* Clear all interrupts */
data.regs->int_sts = ZYNQ_DEVCFG_INT_ALL;
if ( !data.secure )
{
if ( ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( data.regs->ctrl ) )
data.regs->ctrl =
( ~ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) & data.regs->ctrl )
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
}
else
{
if ( !ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( data.regs->ctrl ) )
data.regs->ctrl =
ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) | data.regs->ctrl
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
}
}
/**
* @brief Initialize the PCAP and 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( void )
{
/* TODO: Check that controller is available */
rtems_status_code status;
if ( !ZYNQ_DEVCFG_CTRL_PCFG_PROG_B_GET( data.regs->ctrl ) )
data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 )
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
if ( !ZYNQ_DEVCFG_STATUS_PCFG_INIT_GET( data.regs->status ) )
{
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT );
if ( RTEMS_SUCCESSFUL != status )
{
WARN( "PCAP init timed out\n" );
return -1;
}
}
data.regs->ctrl = ( ~ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 ) & data.regs->ctrl )
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT );
if ( RTEMS_SUCCESSFUL != status )
{
WARN( "PCAP deinit timed out\n" );
return -2;
}
data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 )
| ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT );
if ( RTEMS_SUCCESSFUL != status )
{
WARN( "PCAP reinit timed out\n" );
return -3;
}
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT );
if ( RTEMS_SUCCESSFUL != status )
{
WARN( "PSS_CFG_RESET_B_INT timed out\n" );
return -4;
}
return 0;
}
static int pl_prog_pre( void )
{
int status;
pl_init();
/* 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();
return status;
}
static int pl_prog_post( void )
{
/* 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 );
return 0;
}
static int pl_prog_done_wait( void )
{
rtems_status_code status;
status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_DONE_INT );
if ( RTEMS_SUCCESSFUL != status )
return -1;
return 0;
}
static bool hdr_check_bin(
const uint32_t *bitstream,
size_t len
)
{
const uint32_t valid_header[] = {
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_BUS_WIDTH_SYNC,
ZYNQ_DEVCFG_CFG_BUS_WIDTH_DETECT,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_DUMMY,
ZYNQ_DEVCFG_CFG_SYNC
};
if ( len < RTEMS_ARRAY_SIZE( valid_header ) )
return false;
for ( size_t i = 0; i < RTEMS_ARRAY_SIZE( valid_header ); ++i )
if ( valid_header[i] != bitstream[i] ) {
return false;
}
return true;
}
/* 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;
data.regs = (zynq_devcfg_regs *)ZYNQ_DEVCFG_BASE_ADDR;
data.secure = false;
data.current_task = RTEMS_INVALID_ID;
data.write_mode_restricted = true;
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;
}
/* 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;
}
status = rtems_io_register_name( ZYNQ_DEVCFG_NAME, major, minor );
if ( RTEMS_SUCCESSFUL != status )
{
status = RTEMS_INVALID_NAME;
goto err_register;
}
return RTEMS_SUCCESSFUL;
err_register:
rtems_interrupt_handler_remove(
ZYNQ_DEVCFG_INTERRUPT_VECTOR,
zynq_devcfg_isr,
NULL
);
err_intr:
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;
dma_buf 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 ( !ptr_is_pcap_dma_aligned ( rw_args->buffer ) )
{
data_buf = dma_buf_get( rw_args->count );
if ( NULL == data_buf.buf )
{
final_status = RTEMS_NO_MEMORY;
goto err_insane;
}
}
else
data_buf.buf = (uint8_t *)rw_args->buffer;
status = pcap_dma_xfer(
(uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR,
rw_args->count / 4,
(uint32_t *)data_buf.buf,
rw_args->count / 4,
true
);
if ( status )
{
WARN( "DMA setup FAILED\n" );
final_status = RTEMS_IO_ERROR;
goto err_dma;
}
else
{
status = pcap_dma_xfer_wait_and_check();
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.buf, rw_args->count );
final_status = RTEMS_SUCCESSFUL;
rw_args->bytes_moved = rw_args->count;
if ( data_buf.buf != (uint8_t *)rw_args->buffer )
memcpy( rw_args->buffer, data_buf.buf, rw_args->count );
err_dma:
if ( data_buf.buf != (uint8_t *)rw_args->buffer )
dma_buf_release( data_buf );
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;
dma_buf 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;
}
/* TODO: Check byte order. */
if ( data.write_mode_restricted )
{
/* Only BIN files in restricted mode. */
if ( !hdr_check_bin ( (uint32_t *)rw_args->buffer, rw_args->count / 4 ) )
{
/* Closest status to invalid argument I could find. */
final_status = RTEMS_INVALID_NUMBER;
goto err_obtain;
}
status = pl_prog_pre();
if ( 0 != status )
{
final_status = RTEMS_IO_ERROR;
goto err_obtain;
}
}
if ( !ptr_is_pcap_dma_aligned( rw_args->buffer ) )
{
data_buf = dma_buf_get( rw_args->count );
if ( NULL == data_buf.buf )
{
final_status = RTEMS_NO_MEMORY;
goto err_obtain;
}
memcpy( data_buf.buf, rw_args->buffer, rw_args->count );
}
else
data_buf.buf = (uint8_t *)rw_args->buffer;
/* Ensure data is available to the DMA engine */
rtems_cache_flush_multiple_data_lines( data_buf.buf, rw_args->count );
status = pcap_dma_xfer(
(uint32_t *)data_buf.buf,
rw_args->count / 4,
(uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR,
rw_args->count / 4,
true
);
if ( status )
{
final_status = RTEMS_IO_ERROR;
goto err_dma;
}
else
{
status = pcap_dma_xfer_wait_and_check();
if ( status )
{
final_status = RTEMS_IO_ERROR;
goto err_dma;
}
}
if ( data.write_mode_restricted )
{
status = pl_prog_post();
if ( 0 != status )
{
final_status = RTEMS_IO_ERROR;
goto err_dma;
}
status = pl_prog_done_wait();
if ( 0 != status )
{
final_status = RTEMS_TIMEOUT;
goto err_dma;
}
}
final_status = RTEMS_SUCCESSFUL;
rw_args->bytes_moved = rw_args->count;
err_dma:
if ( data_buf.buf != (uint8_t *)rw_args->buffer )
dma_buf_release( data_buf );
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:
status = pl_prog_pre();
if ( 0 != status )
{
ioctl_args->ioctl_return = -1;
final_status = RTEMS_UNSATISFIED;
}
break;
case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_POST:
status = pl_prog_post();
if ( 0 != status )
{
ioctl_args->ioctl_return = -1;
final_status = RTEMS_UNSATISFIED;
}
break;
case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_WAIT_DONE:
status = pl_prog_done_wait();
if ( 0 != status )
{
ioctl_args->ioctl_return = -1;
final_status = RTEMS_TIMEOUT;
}
break;
case ZYNQ_DEVCFG_IOCTL_SET_SECURE:
data.secure = *(bool *)ioctl_args->buffer;
break;
case ZYNQ_DEVCFG_IOCTL_SET_WRITE_MODE_RESTRICTED:
data.write_mode_restricted = *(bool *)ioctl_args->buffer;
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;
}

View File

@@ -0,0 +1,101 @@
/*
* SLCR Support Implementation
*
* At this point, only a few operations related to programming the FPGA are
* supported.
*
* 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 <gauvin@hcs.ufl.edu>
*/
#include <stdint.h>
#include <rtems.h>
#include <dev/slcr/zynq-slcr.h>
#include <dev/slcr/zynq-slcr-regs.h>
static uint32_t rst_mask = 0xf;
static rtems_interrupt_lock zynq_slcr_lock =
RTEMS_INTERRUPT_LOCK_INITIALIZER( "zynq_slcr" );
static inline void slcr_unlock( void )
{
zynq_slcr_write32( ZYNQ_SLCR_UNLOCK_OFF, ZYNQ_SLCR_UNLOCK_KEY );
}
static inline void slcr_lock( void )
{
zynq_slcr_write32( ZYNQ_SLCR_LOCK_OFF, ZYNQ_SLCR_LOCK_KEY );
}
void zynq_slcr_fpga_clk_rst_mask_set(
uint32_t mask
)
{
rtems_interrupt_lock_context lcontext;
rtems_interrupt_lock_acquire( &zynq_slcr_lock, &lcontext );
rst_mask = 0xf & mask;
rtems_interrupt_lock_release( &zynq_slcr_lock, &lcontext );
}
void zynq_slcr_fpga_clk_rst(
uint32_t val
)
{
uint32_t rst_ctrl;
rtems_interrupt_lock_context lcontext;
rtems_interrupt_lock_acquire( &zynq_slcr_lock, &lcontext );
slcr_unlock();
rst_ctrl = ZYNQ_SLCR_FPGA_RST_CTRL_FPGA_OUT_RST_GET(
zynq_slcr_read32( ZYNQ_SLCR_FPGA_RST_CTRL_OFF )
);
/* Only modify resets that are set in the mask */
zynq_slcr_write32( ZYNQ_SLCR_FPGA_RST_CTRL_OFF,
ZYNQ_SLCR_FPGA_RST_CTRL_FPGA_OUT_RST(
( ~rst_mask & rst_ctrl ) | ( rst_mask & val )
)
);
slcr_lock();
rtems_interrupt_lock_release( &zynq_slcr_lock, &lcontext );
}
void zynq_slcr_level_shifter_enable(
uint32_t val
)
{
rtems_interrupt_lock_context lcontext;
rtems_interrupt_lock_acquire( &zynq_slcr_lock, &lcontext );
slcr_unlock();
zynq_slcr_write32( ZYNQ_SLCR_LVL_SHFTR_EN_OFF, val );
slcr_lock();
rtems_interrupt_lock_release( &zynq_slcr_lock, &lcontext );
}

View File

@@ -0,0 +1,197 @@
/**
* @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 <gauvin@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 <stdint.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;
#define ZYNQ_DEVCFG_DMA_SRC_ADDR_DMA_DONE_INT_WAIT_PCAP ( 0x1 )
uint32_t dma_dst_addr;
#define ZYNQ_DEVCFG_DMA_DST_ADDR_DMA_DONE_INT_WAIT_PCAP ( 0x1 )
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 */

View File

@@ -0,0 +1,155 @@
/**
* @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 <gauvin@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/fgpa"
/*
* Add to CONFIGURE_APPLICATION_PREREQUISITE_DRIVERS
*/
#define ZYNQ_DEVCFG_DRIVER_TABLE_ENTRY \
{ zynq_devcfg_init, zynq_devcfg_open, zynq_devcfg_close, zynq_devcfg_read, \
zynq_devcfg_write, zynq_devcfg_control }
/* Configuration command words. */
#define ZYNQ_DEVCFG_CFG_DUMMY ( 0xffffffff )
#define ZYNQ_DEVCFG_CFG_BUS_WIDTH_SYNC ( 0x000000bb )
#define ZYNQ_DEVCFG_CFG_BUS_WIDTH_DETECT ( 0x11220044 )
#define ZYNQ_DEVCFG_CFG_SYNC ( 0xaa995566 )
/** @brief Zynq configuration frame length in bytes */
#define ZYNQ_DEVCFG_CONFIG_FRAME_LEN ( 101 * 4 )
#define ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN 16
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: None. */
ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_PRE,
/** @brief Argument: None. */
ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_POST,
/** @brief Argument: None. */
ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_WAIT_DONE,
/** @brief Argument: bool. */
ZYNQ_DEVCFG_IOCTL_SET_SECURE,
/** @brief Argument: bool. */
ZYNQ_DEVCFG_IOCTL_SET_WRITE_MODE_RESTRICTED
};
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 */

View File

@@ -0,0 +1,111 @@
/**
* @file
* @ingroup zynq_slcr
* @brief SLCR register definitions.
*/
/*
* 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 <gauvin@hcs.ufl.edu>
*/
/**
* @defgroup zynq_slcr_regs SLCR Register Definitions
* @ingroup zynq_slcr
* @brief SLCR Register Definitions
*/
#ifndef LIBBSP_ARM_XILINX_ZYNQ_SLCR_REGS_H
#define LIBBSP_ARM_XILINX_ZYNQ_SLCR_REGS_H
#include <bsp/utility.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define ZYNQ_SLCR_BASE_ADDR ( 0xF8000000 )
#define ZYNQ_SLCR_LOCK_OFF ( 0x4 )
#define ZYNQ_SLCR_UNLOCK_OFF ( 0x8 )
#define ZYNQ_SLCR_FPGA_RST_CTRL_OFF ( 0x240 )
#define ZYNQ_SLCR_PSS_IDCODE_OFF ( 0x530 )
#define ZYNQ_SLCR_LVL_SHFTR_EN_OFF ( 0x900 )
#define ZYNQ_SLCR_LOCK_KEY ( 0x767b )
#define ZYNQ_SLCR_UNLOCK_KEY ( 0xdf0d )
/** \brief Get FPGA0_OUT_RST (bit 0) through FPGA3_OUT_RST fields (bit 3). */
#define ZYNQ_SLCR_FPGA_RST_CTRL_FPGA_OUT_RST_GET( reg ) \
BSP_FLD32GET( reg, 0, 3 )
#define ZYNQ_SLCR_FPGA_RST_CTRL_FPGA_OUT_RST( val ) BSP_FLD32( val, 0, 3 )
/* NOTE: QEMU gives a value of 0 for the pss_idcode. */
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_GET( reg ) BSP_FLD32GET( reg, 12, 16 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z007s ( 0x03 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z012s ( 0x1c )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z014s ( 0x08 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z010 ( 0x02 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z015 ( 0x1b )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z020 ( 0x07 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z030 ( 0x0c )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z035 ( 0x12 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z045 ( 0x11 )
#define ZYNQ_SLCR_PSS_IDCODE_DEVICE_7z100 ( 0x16 )
#define ZYNQ_SLCR_LVL_SHFTR_EN_DISABLE ( 0 )
#define ZYNQ_SLCR_LVL_SHFTR_EN_PS_TO_PL ( 0xA )
#define ZYNQ_SLCR_LVL_SHFTR_EN_ALL ( 0xF )
static inline void zynq_slcr_write32(
const uint32_t reg_off,
const uint32_t val
)
{
volatile uint32_t *slcr_reg;
slcr_reg = (volatile uint32_t *)( ZYNQ_SLCR_BASE_ADDR + reg_off );
*slcr_reg = val;
}
static inline uint32_t zynq_slcr_read32(
const uint32_t reg_off
)
{
volatile uint32_t *slcr_reg;
slcr_reg = (volatile uint32_t *)( ZYNQ_SLCR_BASE_ADDR + reg_off);
return *slcr_reg;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LIBBSP_ARM_XILINX_ZYNQ_SLCR_REGS_H */

View File

@@ -0,0 +1,91 @@
/**
* @file
* @ingroup zynq_slcr
* @brief SLCR support.
*/
/*
*
* 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 <gauvin@hcs.ufl.edu>
*/
/**
* @defgroup zynq_slcr SLCR Support
* @ingroup arm_zynq
* @brief SLCR Support
*/
#ifndef LIBBSP_ARM_XILINX_ZYNQ_SLCR_H
#define LIBBSP_ARM_XILINX_ZYNQ_SLCR_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @brief Set the mask that allows the FPGA resets to be modified.
*
* Bit 0 corresponds to FPGA0_OUT_RST, and bit 3 to FPGA3_OUT_RST. Setting a
* bit in the mask to 1 allows calls to zynq_slcr_fpga_clk_rst to modify that
* reset. The default mask is 0xf.
*/
void zynq_slcr_fpga_clk_rst_mask_set(
uint32_t mask
);
/**
* @brief Control the FPGA reset values.
*
* @param val Bits 0 through 3 correspond to FPGA RST 0 through 3. A bit value
* of 1 asserts the reset.
*/
void zynq_slcr_fpga_clk_rst(
uint32_t val
);
/**
* @brief Control the level shifters between the PS and PL.
*
* @param val Acceptable values are ZYNQ_SLCR_LVL_SHFTR_EN_DISABLE,
* ZYNQ_SLCR_LVL_SHFTR_EN_PS_TO_PL, and ZYNQ_SLCR_LVL_SHFTR_EN_ALL.
*/
void zynq_slcr_level_shifter_enable(
uint32_t val
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LIBBSP_ARM_XILINX_ZYNQ_SLCR_H */

View File

@@ -19,6 +19,12 @@ install:
source:
- bsps/include/dev/i2c/cadence-i2c-regs.h
- bsps/include/dev/i2c/cadence-i2c.h
- destination: ${BSP_INCLUDEDIR}/dev/devcfg
source:
- bsps/arm/xilinx-zynq/include/dev/devcfg/zynq-devcfg.h
- destination: ${BSP_INCLUDEDIR}/dev/slcr
source:
- bsps/arm/xilinx-zynq/include/dev/slcr/zynq-slcr.h
links: []
source:
- bsps/arm/shared/cache/cache-l2c-310.c
@@ -40,4 +46,6 @@ source:
- bsps/shared/start/gettargethash-default.c
- bsps/shared/start/sbrk.c
- bsps/shared/start/stackalloc.c
- bsps/arm/xilinx-zynq/dev/devcfg/zynq-devcfg.c
- bsps/arm/xilinx-zynq/dev/slcr/zynq-slcr.c
type: build