File indexing completed on 2025-05-11 08:23:39
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
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
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
0073 rtems_mutex open_lock;
0074
0075 rtems_mutex internal_lock;
0076
0077
0078
0079 bool secure;
0080
0081
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
0096
0097
0098
0099
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
0116
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
0153
0154
0155
0156
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
0183
0184 static void dma_buf_release(
0185 dma_buf dbuf
0186 )
0187 {
0188 free( dbuf.buf_orig );
0189 }
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
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
0238
0239
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
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
0257
0258
0259
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
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
0279 if ( RTEMS_SUCCESSFUL != status )
0280 data.regs->int_mask |= int_bit;
0281 return status;
0282 }
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295 static int pcap_dma_xfer_wait_and_check( void )
0296 {
0297 uint32_t int_sts;
0298 rtems_status_code status;
0299
0300
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
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
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
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
0364
0365
0366
0367
0368
0369
0370
0371 static int pl_clear( void )
0372 {
0373
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
0423 zynq_slcr_fpga_clk_rst( 0xf );
0424
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
0434 zynq_slcr_level_shifter_enable( ZYNQ_SLCR_LVL_SHFTR_EN_ALL );
0435
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
0481
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
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
0599
0600
0601
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
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
0685 if ( data.write_mode_restricted )
0686 {
0687
0688 if ( !hdr_check_bin ( (uint32_t *)rw_args->buffer, rw_args->count / 4 ) )
0689 {
0690
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
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;
0844 break;
0845 }
0846
0847 rtems_mutex_unlock( &data.internal_lock );
0848
0849 return final_status;
0850 }