Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:39

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Xilinx Zynq7000 Device Configuration Driver Implementation
0005  *
0006  * Notes:
0007  * - There will only ever be 1 of these controllers in the Zynq, so this driver
0008  *   is designed to be run as a single instance.
0009  * - Even if an interrupt bit is already asserted, unmasking it will lead to
0010  *   triggering the interrupt. In several areas operations are started before
0011  *   unmasking an interrupt which could be triggered by those operations; this
0012  *   interrupt behavior allows for such code to not be racy.
0013  * - Secure loading is not supported.
0014  *
0015  * Copyright (c) 2016
0016  *  NSF Center for High-Performance Reconfigurable Computing (CHREC),
0017  *  University of Florida.  All rights reserved.
0018  * Copyright (c) 2017
0019  *  NSF Center for High-Performance Reconfigurable Computing (CHREC),
0020  *  University of Pittsburgh.  All rights reserved.
0021  *
0022  * Redistribution and use in source and binary forms, with or without
0023  * modification, are permitted provided that the following conditions are
0024  * met:
0025  * 1. Redistributions of source code must retain the above copyright
0026  *    notice, this list of conditions and the following disclaimer.
0027  * 2. Redistributions in binary form must reproduce the above copyright
0028  *    notice, this list of conditions and the following disclaimer in the
0029  *    documentation and/or other materials provided with the distribution.
0030  *
0031  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
0032  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
0033  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
0034  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
0035  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0036  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0037  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0038  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0039  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0040  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0041  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0042  *
0043  * The views and conclusions contained in the software and documentation
0044  * are those of the authors and should not be interpreted as representing
0045  * official policies, either expressed or implied, of CHREC.
0046  *
0047  * Author: Patrick Gauvin <gauvin@hcs.ufl.edu>
0048  */
0049 #include <stdlib.h>
0050 #include <stdint.h>
0051 #include <stdbool.h>
0052 #include <string.h>
0053 #include <rtems.h>
0054 #include <rtems/libio.h>
0055 #include <rtems/rtems/sem.h>
0056 #include <rtems/irq-extension.h>
0057 #include <dev/slcr/zynq-slcr.h>
0058 #include <dev/slcr/zynq-slcr-regs.h>
0059 #include <dev/devcfg/zynq-devcfg.h>
0060 #include <dev/devcfg/zynq-devcfg-regs.h>
0061 
0062 #include <rtems/bspIo.h>
0063 
0064 #define WARN( msg ) printk( "%s:%s: %s", __FILE__, __func__, msg )
0065 /* Timeout for interrupt waits, 2 seconds should be enough for any operation.
0066  */
0067 #define INT_TIMEOUT ( 2 * rtems_clock_get_ticks_per_second() )
0068 #define ZYNQ_DEVCFG_EVENT_SET RTEMS_EVENT_0
0069 
0070 typedef struct {
0071   volatile zynq_devcfg_regs *regs;
0072   /* Used to restrict the device to being opened once at a time. */
0073   rtems_mutex                open_lock;
0074   /* Used for mutual exclusion between read/write/ioctl. */
0075   rtems_mutex                internal_lock;
0076   /* Indicates if the PCAP will be used for a secure bitstream. Secure
0077    * bitstreams are untested with this driver. Defaults to false.
0078    */
0079   bool                       secure;
0080   /* If true, write data is not assumed to be a complete bitstream and no
0081    * checks are performed on it.
0082    */
0083   bool                       write_mode_restricted;
0084   rtems_id                   current_task;
0085 } driver_data;
0086 
0087 typedef struct {
0088   uint8_t *buf;
0089   uint8_t *buf_orig;
0090 } dma_buf;
0091 
0092 static driver_data data;
0093 
0094 /**
0095  * @brief Check if bit is set in reg (and also not masked by mask), and if it
0096  * is, write that bit to reg.
0097  *
0098  * @retval true The bit was set and not masked, and was written to.
0099  * @retval false The bit was not written to.
0100  */
0101 static inline bool check_and_set(
0102   volatile uint32_t *reg,
0103   uint32_t           mask,
0104   uint32_t           bit
0105 )
0106 {
0107   if ( *reg & bit & ~mask )
0108   {
0109     *reg = bit;
0110     return true;
0111   }
0112   return false;
0113 }
0114 
0115 /* Only one event is used since only one interrupt is unmasked at a time.  The
0116  * interrupt is cleared and masked after it is caught here.
0117  */
0118 static void zynq_devcfg_isr(
0119   void *args
0120 )
0121 {
0122   const uint32_t intrs[] = {
0123     ZYNQ_DEVCFG_INT_DMA_DONE_INT,
0124     ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT,
0125     ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT,
0126     ZYNQ_DEVCFG_INT_PCFG_DONE_INT,
0127     ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT
0128   };
0129   volatile uint32_t *int_sts = &data.regs->int_sts;
0130   volatile uint32_t *int_mask = &data.regs->int_mask;
0131 
0132   (void) args;
0133 
0134   for ( size_t i = 0; i < RTEMS_ARRAY_SIZE( intrs ); ++i )
0135     if ( check_and_set( int_sts, *int_mask, intrs[i] ) )
0136     {
0137       *int_mask |= intrs[i];
0138       if ( RTEMS_INVALID_ID != data.current_task )
0139         rtems_event_system_send( data.current_task, ZYNQ_DEVCFG_EVENT_SET );
0140       return;
0141     }
0142 }
0143 
0144 static inline bool ptr_is_pcap_dma_aligned(
0145   void *ptr
0146 )
0147 {
0148   return 0 == (uintptr_t)ptr % ZYNQ_DEVCFG_PCAP_DMA_ALIGN;
0149 }
0150 
0151 /**
0152  * @brief Create an aligned buffer for the bitstream.
0153  *
0154  * @param len Desired length of the buffer in bytes.
0155  *
0156  * @return dma_buf members are NULL if malloc failed.
0157  */
0158 static dma_buf dma_buf_get(
0159   size_t len
0160 )
0161 {
0162   dma_buf dbuf;
0163 
0164   dbuf.buf_orig = malloc( len + ZYNQ_DEVCFG_PCAP_DMA_ALIGN );
0165   if ( NULL == dbuf.buf_orig )
0166   {
0167     dbuf.buf = NULL;
0168     return dbuf;
0169   }
0170 
0171   if ( !ptr_is_pcap_dma_aligned( dbuf.buf_orig ) )
0172   {
0173     dbuf.buf = dbuf.buf_orig + ZYNQ_DEVCFG_PCAP_DMA_ALIGN
0174         - ( (size_t)dbuf.buf_orig % ZYNQ_DEVCFG_PCAP_DMA_ALIGN );
0175   }
0176   else
0177     dbuf.buf = dbuf.buf_orig;
0178   return dbuf;
0179 }
0180 
0181 /**
0182  * @brief Frees the originally allocated area for dbuf.
0183  */
0184 static void dma_buf_release(
0185   dma_buf dbuf
0186 )
0187 {
0188   free( dbuf.buf_orig );
0189 }
0190 
0191 /**
0192  * @brief Initiates a PCAP DMA transfer.
0193  *
0194  * @param src[in] For programming the FPGA, this is the location of the
0195  * bitstream data. For readback, it is the location of the PL readback command
0196  * sequence.
0197  * @param src_len Typically the length of bitstream in dwords, or the number of
0198  * PL commands. The user must check this value for correctness.
0199  * @param dst[in,out] For programming the FPGA use ZYNQ_DEVCFG_BITSTREAM_ADDR,
0200  * for readback this is where the readback data is stored.
0201  * @param dst_len Typically the Length of bitstream in dwords, or the number of
0202  * readback words expected. The user must check this value for correctness.
0203  * @param pcap_wait If true, interrupt assertion waits for both the AXI
0204  * transfer and the PCAP to finish.
0205  *
0206  * @retval 0 Transfer was started.
0207  * @retval -1 src_len or dst_len invalid.
0208  * @retval -2 The DMA queue was full.
0209  */
0210 static int pcap_dma_xfer(
0211   uint32_t                  *src,
0212   size_t                     src_len,
0213   uint32_t                  *dst,
0214   size_t                     dst_len,
0215   bool                       pcap_wait
0216 )
0217 {
0218   if ( ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( src_len ) != src_len )
0219     return -1;
0220   if ( ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( dst_len ) != dst_len )
0221     return -1;
0222 
0223   if ( pcap_wait )
0224   {
0225     src = (uint32_t *)
0226         ( (uintptr_t)src | ZYNQ_DEVCFG_DMA_SRC_ADDR_DMA_DONE_INT_WAIT_PCAP );
0227     dst = (uint32_t *)
0228         ( (uintptr_t)dst | ZYNQ_DEVCFG_DMA_DST_ADDR_DMA_DONE_INT_WAIT_PCAP );
0229   }
0230 
0231 #ifdef ZYNQ_DEVCFG_DEBUG
0232   printk( "DMA TRANSFER REQUESTED:\n" );
0233   printk( "Source: %p\n", src );
0234   printk( "Source length: %zu\n", src_len );
0235   printk( "Destination: %p\n", dst );
0236   printk( "Destination length: %zu\n", dst_len );
0237 #endif /* ZYNQ_DEVCFG_DEBUG */
0238 
0239   /* Check if the command queue is full */
0240   if ( ZYNQ_DEVCFG_STATUS_DMA_CMD_Q_F( data.regs->status ) )
0241   {
0242     WARN( "Zynq DMA queue full\n" );
0243     return -2;
0244   }
0245 
0246   /* Order is important */
0247   data.regs->dma_src_addr = (uint32_t)src;
0248   data.regs->dma_dst_addr = (uint32_t)dst;
0249   data.regs->dma_src_len = ZYNQ_DEVCFG_DMA_SRC_LEN_LEN( src_len );
0250   data.regs->dma_dest_len = ZYNQ_DEVCFG_DMA_DEST_LEN_LEN( dst_len );
0251 
0252   return 0;
0253 }
0254 
0255 /**
0256  * @brief Unmasks and waits for the interrupt in int_bit.
0257  *
0258  * @param int_bit The interrupt bit in int_sts (NOT a bit number).
0259  * @return The result of rtems_event_system_receive.
0260  */
0261 static rtems_status_code int_enable_and_wait(
0262   uint32_t int_bit
0263 )
0264 {
0265   rtems_event_set   ev;
0266   rtems_status_code status;
0267 
0268   data.current_task = rtems_task_self();
0269   /* data.current_task must be updated before an interrupt is handled. */
0270   RTEMS_COMPILER_MEMORY_BARRIER();
0271   data.regs->int_mask &= ~int_bit;
0272   status = rtems_event_system_receive(
0273     ZYNQ_DEVCFG_EVENT_SET,
0274     RTEMS_WAIT,
0275     INT_TIMEOUT,
0276     &ev
0277   );
0278   /* Re-mask interrupt if not received. */
0279   if ( RTEMS_SUCCESSFUL != status )
0280     data.regs->int_mask |= int_bit;
0281   return status;
0282 }
0283 
0284 /**
0285  * @brief Wait for a DMA transfer to finish and check for failure.
0286  *
0287  * @retval 0 Success.
0288  * @retval -1 DMA timeout.
0289  * @retval -2 AXI transfer error.
0290  * @retval -3 Receive FIFO overflow.
0291  * @retval -4 DMA command error or command queue overflow.
0292  * @retval -5 Mismatch between PCAP output length and DMA transfer length.
0293  * @retval -6 HMAC error.
0294  */
0295 static int pcap_dma_xfer_wait_and_check( void )
0296 {
0297   uint32_t          int_sts;
0298   rtems_status_code status;
0299 
0300   /* NOTE: The ISR will handle acknowledging the transfer. */
0301   status = int_enable_and_wait( ZYNQ_DEVCFG_INT_DMA_DONE_INT );
0302   if ( RTEMS_SUCCESSFUL != status )
0303   {
0304     WARN( "DMA timed out\n" );
0305     return -1;
0306   }
0307 
0308   int_sts = data.regs->int_sts;
0309   if (
0310     ZYNQ_DEVCFG_INT_AXI_WERR_INT_GET( int_sts )
0311     || ZYNQ_DEVCFG_INT_AXI_RTO_INT_GET( int_sts )
0312     || ZYNQ_DEVCFG_INT_AXI_RERR_INT_GET( int_sts )
0313   )
0314     return -2;
0315   if ( ZYNQ_DEVCFG_INT_RX_FIFO_OV_INT_GET( int_sts ) )
0316     return -3;
0317   if (
0318     ZYNQ_DEVCFG_INT_DMA_CMD_ERR_INT_GET( int_sts )
0319     || ZYNQ_DEVCFG_INT_DMA_Q_OV_INT_GET( int_sts )
0320   )
0321     return -4;
0322   if ( ZYNQ_DEVCFG_INT_P2D_LEN_ERR_INT_GET( int_sts ) )
0323     return -5;
0324   if ( ZYNQ_DEVCFG_INT_PCFG_HMAC_ERR_INT_GET( int_sts ) )
0325     return -6;
0326 
0327   return 0;
0328 }
0329 
0330 /**
0331  * @brief Configure the PCAP controller.
0332  */
0333 static void pl_init( void )
0334 {
0335   data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCAP_MODE( 1 )
0336       | ZYNQ_DEVCFG_CTRL_PCAP_PR( ZYNQ_DEVCFG_CTRL_PCAP_PR_PCAP )
0337       | ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
0338   /* Disable loopback */
0339   data.regs->mctrl = ZYNQ_DEVCFG_MCTRL_SET(
0340     data.regs->mctrl,
0341     ~ZYNQ_DEVCFG_MCTRL_INT_PCAP_LPBK( 1 ) & data.regs->mctrl
0342   );
0343   /* Clear all interrupts */
0344   data.regs->int_sts = ZYNQ_DEVCFG_INT_ALL;
0345 
0346   if ( !data.secure )
0347   {
0348     if ( ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( data.regs->ctrl ) )
0349       data.regs->ctrl =
0350           ( ~ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) & data.regs->ctrl )
0351           | ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
0352   }
0353   else
0354   {
0355     if ( !ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( data.regs->ctrl ) )
0356       data.regs->ctrl =
0357           ZYNQ_DEVCFG_CTRL_QUARTER_PCAP_RATE_EN( 1 ) | data.regs->ctrl
0358           | ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
0359   }
0360 }
0361 
0362 /**
0363  * @brief Initialize the PCAP and clear the FPGA's configuration.
0364  *
0365  * @retval 0 Success.
0366  * @retval -1 PCAP intialization timeout.
0367  * @retval -2 PCAP deinitialization timeout.
0368  * @retval -3 PCAP reinitialization timeout.
0369  * @retval -4 Device reset timeout.
0370  */
0371 static int pl_clear( void )
0372 {
0373   /* TODO: Check that controller is available */
0374   rtems_status_code status;
0375 
0376   if ( !ZYNQ_DEVCFG_CTRL_PCFG_PROG_B_GET( data.regs->ctrl ) )
0377     data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 )
0378         | ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
0379   if ( !ZYNQ_DEVCFG_STATUS_PCFG_INIT_GET( data.regs->status ) )
0380   {
0381     status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT );
0382     if ( RTEMS_SUCCESSFUL != status )
0383     {
0384       WARN( "PCAP init timed out\n" );
0385       return -1;
0386     }
0387   }
0388 
0389   data.regs->ctrl = ( ~ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 ) & data.regs->ctrl )
0390       | ZYNQ_DEVCFG_CTRL_RESERVED_BITS;
0391   status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_NE_INT );
0392   if ( RTEMS_SUCCESSFUL != status )
0393   {
0394     WARN( "PCAP deinit timed out\n" );
0395     return -2;
0396   }
0397 
0398   data.regs->ctrl = ZYNQ_DEVCFG_CTRL_PCFG_PROG_B( 1 )
0399       | ZYNQ_DEVCFG_CTRL_RESERVED_BITS | data.regs->ctrl;
0400   status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_INIT_PE_INT );
0401   if ( RTEMS_SUCCESSFUL != status )
0402   {
0403     WARN( "PCAP reinit timed out\n" );
0404     return -3;
0405   }
0406 
0407   status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PSS_CFG_RESET_B_INT );
0408   if ( RTEMS_SUCCESSFUL != status )
0409   {
0410     WARN( "PSS_CFG_RESET_B_INT timed out\n" );
0411     return -4;
0412   }
0413 
0414   return 0;
0415 }
0416 
0417 static int pl_prog_pre( void )
0418 {
0419   int status;
0420 
0421   pl_init();
0422   /* Hold FPGA clocks in reset */
0423   zynq_slcr_fpga_clk_rst( 0xf );
0424   /* Enable PS to PL level shifters */
0425   zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_DISABLE );
0426   zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_PS_TO_PL );
0427   status = pl_clear();
0428   return status;
0429 }
0430 
0431 static int pl_prog_post( void )
0432 {
0433   /* Enable all PS-PL level shifters */
0434   zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_ALL );
0435   /* Release FPGA clocks from reset */
0436   zynq_slcr_fpga_clk_rst( 0 );
0437   return 0;
0438 }
0439 
0440 static int pl_prog_done_wait( void )
0441 {
0442   rtems_status_code status;
0443 
0444   status = int_enable_and_wait( ZYNQ_DEVCFG_INT_PCFG_DONE_INT );
0445   if ( RTEMS_SUCCESSFUL != status )
0446     return -1;
0447   return 0;
0448 }
0449 
0450 static bool hdr_check_bin(
0451   const uint32_t *bitstream,
0452   size_t len
0453 )
0454 {
0455   const uint32_t valid_header[] = {
0456     ZYNQ_DEVCFG_CFG_DUMMY,
0457     ZYNQ_DEVCFG_CFG_DUMMY,
0458     ZYNQ_DEVCFG_CFG_DUMMY,
0459     ZYNQ_DEVCFG_CFG_DUMMY,
0460     ZYNQ_DEVCFG_CFG_DUMMY,
0461     ZYNQ_DEVCFG_CFG_DUMMY,
0462     ZYNQ_DEVCFG_CFG_DUMMY,
0463     ZYNQ_DEVCFG_CFG_DUMMY,
0464     ZYNQ_DEVCFG_CFG_BUS_WIDTH_SYNC,
0465     ZYNQ_DEVCFG_CFG_BUS_WIDTH_DETECT,
0466     ZYNQ_DEVCFG_CFG_DUMMY,
0467     ZYNQ_DEVCFG_CFG_DUMMY,
0468     ZYNQ_DEVCFG_CFG_SYNC
0469   };
0470 
0471   if ( len < RTEMS_ARRAY_SIZE( valid_header ) )
0472     return false;
0473   for ( size_t i = 0; i < RTEMS_ARRAY_SIZE( valid_header ); ++i )
0474     if ( valid_header[i] != bitstream[i] ) {
0475       return false;
0476     }
0477   return true;
0478 }
0479 
0480 /* TODO: Check that PL power is on.
0481  * TODO: Check for configuration differences between silicon revisions.
0482  */
0483 rtems_device_driver zynq_devcfg_init(
0484   rtems_device_major_number  major,
0485   rtems_device_minor_number  minor,
0486   void                      *args
0487 )
0488 {
0489   rtems_status_code status;
0490 
0491   (void) args;
0492 
0493   data.regs = (zynq_devcfg_regs *)ZYNQ_DEVCFG_BASE_ADDR;
0494   data.secure = false;
0495   data.current_task = RTEMS_INVALID_ID;
0496   data.write_mode_restricted = true;
0497 
0498   rtems_mutex_init( &data.open_lock, "DevC" );
0499   rtems_mutex_init( &data.internal_lock, "DvCi" );
0500 
0501   /* Mask and clear all interrupts and install handler */
0502   data.regs->int_mask |= ZYNQ_DEVCFG_INT_ALL;
0503   data.regs->int_sts = ZYNQ_DEVCFG_INT_ALL;
0504   status = rtems_interrupt_handler_install(
0505     ZYNQ_DEVCFG_INTERRUPT_VECTOR,
0506     "DevC ISR",
0507     RTEMS_INTERRUPT_UNIQUE,
0508     zynq_devcfg_isr,
0509     NULL
0510   );
0511   if ( RTEMS_SUCCESSFUL != status )
0512   {
0513     WARN( "Failed to assign interrupt handler\n" );
0514     status = RTEMS_INTERNAL_ERROR;
0515     goto err;
0516   }
0517 
0518   status = rtems_io_register_name( ZYNQ_DEVCFG_NAME, major, minor );
0519   if ( RTEMS_SUCCESSFUL != status )
0520   {
0521     status = RTEMS_INVALID_NAME;
0522     goto err_register;
0523   }
0524 
0525   return RTEMS_SUCCESSFUL;
0526 err_register:
0527   rtems_interrupt_handler_remove(
0528     ZYNQ_DEVCFG_INTERRUPT_VECTOR,
0529     zynq_devcfg_isr,
0530     NULL
0531   );
0532 err:
0533   return status;
0534 }
0535 
0536 rtems_device_driver zynq_devcfg_open(
0537   rtems_device_major_number  major,
0538   rtems_device_minor_number  minor,
0539   void                      *args
0540 )
0541 {
0542   int rstatus;
0543 
0544   (void) major;
0545   (void) minor;
0546   (void) args;
0547 
0548   rstatus = rtems_mutex_try_lock( &data.open_lock );
0549   if ( EBUSY == rstatus )
0550     return RTEMS_RESOURCE_IN_USE;
0551 
0552   return RTEMS_SUCCESSFUL;
0553 }
0554 
0555 rtems_device_driver zynq_devcfg_close(
0556   rtems_device_major_number  major,
0557   rtems_device_minor_number  minor,
0558   void                      *args
0559 )
0560 {
0561   (void) major;
0562   (void) minor;
0563   (void) args;
0564 
0565   rtems_mutex_unlock( &data.open_lock );
0566 
0567   return RTEMS_SUCCESSFUL;
0568 }
0569 
0570 rtems_device_driver zynq_devcfg_read(
0571   rtems_device_major_number  major,
0572   rtems_device_minor_number  minor,
0573   void                      *args
0574 )
0575 {
0576   rtems_libio_rw_args_t *rw_args;
0577   int                    status;
0578   rtems_status_code      final_status;
0579   dma_buf                data_buf;
0580 
0581   (void) major;
0582   (void) minor;
0583   rw_args = args;
0584   rw_args->bytes_moved = 0;
0585 
0586   status = rtems_mutex_try_lock( &data.internal_lock );
0587   if ( EBUSY == status )
0588   {
0589     final_status = RTEMS_RESOURCE_IN_USE;
0590     goto err_obtain;
0591   }
0592 
0593   if ( rw_args->count < 4 )
0594   {
0595     final_status = RTEMS_INVALID_SIZE;
0596     goto err_insane;
0597   }
0598   /* TODO: It might be valid to read configuration registers while the PL is
0599    * not programmed.
0600    */
0601   /* PCFG_DONE must be asserted before readback */
0602   if ( !ZYNQ_DEVCFG_INT_PCFG_DONE_INT_GET( data.regs->int_sts ) )
0603   {
0604     WARN( "read attempted when FPGA configuration not done\n" );
0605     final_status = RTEMS_IO_ERROR;
0606     goto err_insane;
0607   }
0608 
0609   if ( !ptr_is_pcap_dma_aligned ( rw_args->buffer ) )
0610   {
0611     data_buf = dma_buf_get( rw_args->count );
0612     if ( NULL == data_buf.buf )
0613     {
0614       final_status = RTEMS_NO_MEMORY;
0615       goto err_insane;
0616     }
0617   }
0618   else
0619     data_buf.buf = (uint8_t *)rw_args->buffer;
0620 
0621   status = pcap_dma_xfer(
0622     (uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR,
0623     rw_args->count / 4,
0624     (uint32_t *)data_buf.buf,
0625     rw_args->count / 4,
0626     true
0627   );
0628   if ( status )
0629   {
0630     WARN( "DMA setup FAILED\n" );
0631     final_status = RTEMS_IO_ERROR;
0632     goto err_dma;
0633   }
0634   else
0635   {
0636     status = pcap_dma_xfer_wait_and_check();
0637     if ( status )
0638     {
0639       WARN( "DMA FAILED\n" );
0640       final_status = RTEMS_IO_ERROR;
0641       goto err_dma;
0642     }
0643   }
0644 
0645   /* Ensure stale data is not read */
0646   rtems_cache_invalidate_multiple_data_lines( data_buf.buf, rw_args->count );
0647 
0648   final_status = RTEMS_SUCCESSFUL;
0649   rw_args->bytes_moved = rw_args->count;
0650   if ( data_buf.buf != (uint8_t *)rw_args->buffer )
0651     memcpy( rw_args->buffer, data_buf.buf, rw_args->count );
0652 err_dma:
0653   if ( data_buf.buf != (uint8_t *)rw_args->buffer )
0654     dma_buf_release( data_buf );
0655   rtems_mutex_unlock( &data.internal_lock );
0656 err_insane:
0657 err_obtain:
0658   return final_status;
0659 }
0660 
0661 rtems_device_driver zynq_devcfg_write(
0662   rtems_device_major_number  major,
0663   rtems_device_minor_number  minor,
0664   void                      *args
0665 )
0666 {
0667   rtems_libio_rw_args_t *rw_args;
0668   int                    status;
0669   rtems_status_code      final_status;
0670   dma_buf                data_buf;
0671 
0672   (void) major;
0673   (void) minor;
0674   rw_args = args;
0675   rw_args->bytes_moved = 0;
0676 
0677   status = rtems_mutex_try_lock( &data.internal_lock );
0678   if ( EBUSY == status )
0679   {
0680     final_status = RTEMS_RESOURCE_IN_USE;
0681     goto err_obtain;
0682   }
0683 
0684   /* TODO: Check byte order. */
0685   if ( data.write_mode_restricted )
0686   {
0687     /* Only BIN files in restricted mode. */
0688     if ( !hdr_check_bin ( (uint32_t *)rw_args->buffer, rw_args->count / 4 ) )
0689     {
0690       /* Closest status to invalid argument I could find. */
0691       final_status = RTEMS_INVALID_NUMBER;
0692       goto err_obtain;
0693     }
0694     status = pl_prog_pre();
0695     if ( 0 != status )
0696     {
0697       final_status = RTEMS_IO_ERROR;
0698       goto err_obtain;
0699     }
0700   }
0701 
0702   if ( !ptr_is_pcap_dma_aligned( rw_args->buffer ) )
0703   {
0704     data_buf = dma_buf_get( rw_args->count );
0705     if ( NULL == data_buf.buf )
0706     {
0707       final_status = RTEMS_NO_MEMORY;
0708       goto err_obtain;
0709     }
0710     memcpy( data_buf.buf, rw_args->buffer, rw_args->count );
0711   }
0712   else
0713     data_buf.buf = (uint8_t *)rw_args->buffer;
0714 
0715   /* Ensure data is available to the DMA engine */
0716   rtems_cache_flush_multiple_data_lines( data_buf.buf, rw_args->count );
0717 
0718   status = pcap_dma_xfer(
0719     (uint32_t *)data_buf.buf,
0720     rw_args->count / 4,
0721     (uint32_t *)ZYNQ_DEVCFG_BITSTREAM_ADDR,
0722     rw_args->count / 4,
0723     true
0724   );
0725   if ( status )
0726   {
0727     final_status = RTEMS_IO_ERROR;
0728     goto err_dma;
0729   }
0730   else
0731   {
0732     status = pcap_dma_xfer_wait_and_check();
0733     if ( status )
0734     {
0735       final_status = RTEMS_IO_ERROR;
0736       goto err_dma;
0737     }
0738   }
0739 
0740   if ( data.write_mode_restricted )
0741   {
0742     status = pl_prog_post();
0743     if ( 0 != status )
0744     {
0745       final_status = RTEMS_IO_ERROR;
0746       goto err_dma;
0747     }
0748     status = pl_prog_done_wait();
0749     if ( 0 != status )
0750     {
0751       final_status = RTEMS_TIMEOUT;
0752       goto err_dma;
0753     }
0754   }
0755 
0756   final_status = RTEMS_SUCCESSFUL;
0757   rw_args->bytes_moved = rw_args->count;
0758 err_dma:
0759   if ( data_buf.buf != (uint8_t *)rw_args->buffer )
0760     dma_buf_release( data_buf );
0761   rtems_mutex_unlock( &data.internal_lock );
0762 err_obtain:
0763   return final_status;
0764 }
0765 
0766 rtems_device_driver zynq_devcfg_control(
0767   rtems_device_major_number  major,
0768   rtems_device_minor_number  minor,
0769   void                      *args
0770 )
0771 {
0772   rtems_libio_ioctl_args_t *ioctl_args;
0773   char                     *str;
0774   int                       status;
0775   rtems_status_code         final_status;
0776 
0777   (void) major;
0778   (void) minor;
0779   ioctl_args = args;
0780 
0781   status = rtems_mutex_try_lock( &data.internal_lock );
0782   if ( EBUSY == status )
0783   {
0784     ioctl_args->ioctl_return = -1;
0785     return RTEMS_RESOURCE_IN_USE;
0786   }
0787 
0788   final_status = RTEMS_SUCCESSFUL;
0789   ioctl_args->ioctl_return = 0;
0790   switch ( ioctl_args->command ) {
0791   case ZYNQ_DEVCFG_IOCTL_VERSION:
0792     str = ioctl_args->buffer;
0793     switch( ZYNQ_DEVCFG_MCTRL_PS_VERSION_GET( data.regs->mctrl ) ) {
0794       case ZYNQ_DEVCFG_MCTRL_PS_VERSION_1_0:
0795         strncpy( str, "1.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN );
0796         break;
0797       case ZYNQ_DEVCFG_MCTRL_PS_VERSION_2_0:
0798         strncpy( str, "2.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN );
0799         break;
0800       case ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_0:
0801         strncpy( str, "3.0", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN );
0802         break;
0803       case ZYNQ_DEVCFG_MCTRL_PS_VERSION_3_1:
0804         strncpy( str, "3.1", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN );
0805         break;
0806       default:
0807         strncpy( str, "???", ZYNQ_DEVCFG_IOCTL_VERSION_MAX_LEN );
0808         break;
0809     }
0810     break;
0811   case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_PRE:
0812     status = pl_prog_pre();
0813     if ( 0 != status )
0814     {
0815       ioctl_args->ioctl_return = -1;
0816       final_status = RTEMS_UNSATISFIED;
0817     }
0818     break;
0819   case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_POST:
0820     status = pl_prog_post();
0821     if ( 0 != status )
0822     {
0823       ioctl_args->ioctl_return = -1;
0824       final_status = RTEMS_UNSATISFIED;
0825     }
0826     break;
0827   case ZYNQ_DEVCFG_IOCTL_FPGA_PROGRAM_WAIT_DONE:
0828     status = pl_prog_done_wait();
0829     if ( 0 != status )
0830     {
0831       ioctl_args->ioctl_return = -1;
0832       final_status = RTEMS_TIMEOUT;
0833     }
0834     break;
0835   case ZYNQ_DEVCFG_IOCTL_SET_SECURE:
0836     data.secure = *(bool *)ioctl_args->buffer;
0837     break;
0838   case ZYNQ_DEVCFG_IOCTL_SET_WRITE_MODE_RESTRICTED:
0839     data.write_mode_restricted = *(bool *)ioctl_args->buffer;
0840     break;
0841   default:
0842     ioctl_args->ioctl_return = -1;
0843     final_status = RTEMS_INVALID_NAME; /* Maps to EINVAL */
0844     break;
0845   }
0846 
0847   rtems_mutex_unlock( &data.internal_lock );
0848 
0849   return final_status;
0850 }