Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:00

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *
0005  * Copyright (C) 2024 Kevin Kirspel
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  *
0016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0019  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0020  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0021  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0022  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0026  * SUCH DAMAGE.
0027  */
0028 
0029 /******************************************************************************
0030 *                                                                             *
0031 * License Agreement                                                           *
0032 *                                                                             *
0033 * Copyright (c) 2008 Altera Corporation, San Jose, California, USA.           *
0034 * All rights reserved.                                                        *
0035 *                                                                             *
0036 * Permission is hereby granted, free of charge, to any person obtaining a     *
0037 * copy of this software and associated documentation files (the "Software"),  *
0038 * to deal in the Software without restriction, including without limitation   *
0039 * the rights to use, copy, modify, merge, publish, distribute, sublicense,    *
0040 * and/or sell copies of the Software, and to permit persons to whom the       *
0041 * Software is furnished to do so, subject to the following conditions:        *
0042 *                                                                             *
0043 * The above copyright notice and this permission notice shall be included in  *
0044 * all copies or substantial portions of the Software.                         *
0045 *                                                                             *
0046 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  *
0047 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,    *
0048 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
0049 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      *
0050 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING     *
0051 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER         *
0052 * DEALINGS IN THE SOFTWARE.                                                   *
0053 *                                                                             *
0054 * This agreement shall be governed in all respects by the laws of the State   *
0055 * of California and by the laws of the United States of America.              *
0056 *                                                                             *
0057 ******************************************************************************/
0058 
0059 #include <stdint.h>
0060 #include <stddef.h>
0061 #include <string.h>
0062 #include <errno.h>
0063 #include <altera_avalon_epcq_regs.h>
0064 #include <altera_avalon_timer_regs.h>
0065 
0066 #include <rtems/counter.h>
0067 
0068 #ifndef ALT_MAX_NUMBER_OF_FLASH_REGIONS
0069 #define ALT_MAX_NUMBER_OF_FLASH_REGIONS 8
0070 #endif /* ALT_MAX_NUMBER_OF_FLASH_REGIONS */
0071 
0072 /* MACROS */
0073 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
0074 
0075 /*
0076  * Description of a single Erase region
0077  */
0078 typedef struct flash_region
0079 {
0080   int   offset;
0081   int   region_size;
0082   int   number_of_blocks;
0083   int   block_size;
0084 }flash_region;
0085 
0086 /**
0087  *  Description of the flash device
0088  */
0089 typedef struct alt_flash_dev alt_flash_dev;
0090 
0091 /**
0092  *  Description of the flash device api
0093  */
0094 typedef int (*alt_flash_read)(
0095   alt_flash_dev* flash,
0096   int offset,
0097   void* dest_addr,
0098   int length
0099 );
0100 
0101 /**
0102  *  Description of the flash device implementation
0103  */
0104 struct alt_flash_dev
0105 {
0106   const char*               name;
0107   alt_flash_read            read;
0108   void*                     base_addr;
0109   int                       length;
0110   int                       number_of_regions;
0111   flash_region              region_info[ALT_MAX_NUMBER_OF_FLASH_REGIONS];
0112 };
0113 
0114 
0115 /**
0116  *  Description of the EPCQ controller
0117  */
0118 typedef struct alt_epcq_controller2_dev
0119 {
0120   alt_flash_dev dev;
0121 
0122   uint32_t data_base;         /* base address of data slave */
0123   uint32_t data_end;          /* end address of data slave (not inclusive) */
0124   uint32_t csr_base;          /* base address of CSR slave */
0125   uint32_t size_in_bytes;     /* size of memory in bytes */
0126   uint32_t is_epcs;           /* 1 if device is an EPCS device */
0127   uint32_t number_of_sectors; /* number of flash sectors */
0128   uint32_t sector_size;       /* size of each flash sector */
0129   uint32_t page_size;         /* page size */
0130   uint32_t silicon_id;        /* ID of silicon used with EPCQ IP */
0131 } alt_epcq_controller2_dev;
0132 
0133 static int altera_epcq_controller2_init(alt_epcq_controller2_dev *dev);
0134 static int alt_epcq_controller2_erase_block(
0135   alt_flash_dev *flash_info,
0136   int block_offset
0137 );
0138 static int alt_epcq_controller2_write_block(
0139   alt_flash_dev *flash_info,
0140   int block_offset,
0141   int data_offset,
0142   const void *data, int length
0143 );
0144 static int alt_epcq_controller2_write(
0145   alt_flash_dev *flash_info,
0146   int offset,
0147   const void *src_addr,
0148   int length,
0149   bool erase
0150 );
0151 static int alt_epcq_controller2_read(
0152   alt_flash_dev *flash_info,
0153   int offset,
0154   void *dest_addr,
0155   int length
0156 );
0157 static inline int alt_epcq_validate_read_write_arguments(
0158   alt_epcq_controller2_dev *flash_info,
0159   uint32_t offset,
0160   uint32_t length
0161 );
0162 static int alt_epcq_poll_for_write_in_progress(
0163   alt_epcq_controller2_dev* flash_info
0164 );
0165 
0166 /**
0167 *   Macros used by alt_sys_init.c to create data storage for driver instance
0168 */
0169 #define ALTERA_EPCQ_CSR_INSTANCE(epcq_name, avl_mem, avl_csr, epcq_dev)        \
0170 static alt_epcq_controller2_dev epcq_dev = {                                   \
0171   .dev = {                                                                     \
0172     .read = alt_epcq_controller2_read,                                         \
0173     .base_addr = ((void*)(avl_mem##_BASE)),                                    \
0174     .length = ((int)(avl_mem##_SPAN)),                                         \
0175   },                                                                           \
0176   .data_base = ((uint32_t)(avl_mem##_BASE)),                                   \
0177   .data_end = ((uint32_t)(avl_mem##_BASE) + (uint32_t)(avl_mem##_SPAN)),       \
0178   .csr_base = ((uint32_t)(avl_csr##_BASE)),                                    \
0179   .size_in_bytes = ((uint32_t)(avl_mem##_SPAN)),                               \
0180   .is_epcs = ((uint32_t)(avl_mem##_IS_EPCS)),                                  \
0181   .number_of_sectors = ((uint32_t)(avl_mem##_NUMBER_OF_SECTORS)),              \
0182   .sector_size = ((uint32_t)(avl_mem##_SECTOR_SIZE)),                          \
0183   .page_size = ((uint32_t)(avl_mem##_PAGE_SIZE))  ,                            \
0184 }
0185 
0186 #define ALTERA_EPCQ_CONTROLLER2_INIT(name, dev)   \
0187   altera_epcq_controller2_init(&dev);
0188 
0189 /**
0190 *   The EPCQ device instance
0191 */
0192 ALTERA_EPCQ_CSR_INSTANCE(
0193   EPCQ_CONTROLLER,
0194   EPCQ_CONTROLLER_AVL_MEM,
0195   EPCQ_CONTROLLER_AVL_CSR,
0196   epcq_controller
0197 );
0198 
0199 /**
0200  * epcq_initialize
0201  *
0202  * Initializes the epcq device interface.
0203  *
0204 **/
0205 void epcq_initialize( void )
0206 {
0207   ALTERA_EPCQ_CONTROLLER2_INIT( EPCQ_CONTROLLER, epcq_controller);
0208 }
0209 
0210 /**
0211  * epcq_read_buffer
0212  *
0213  * Reads data from the epcq device.
0214  *
0215  * Arguments:
0216  * - offset: offset within the memory area to read.
0217  * - dest_addr: the location to store the returned data.
0218  * - length: The number of bytes to read.
0219  *
0220  * Returns:
0221  * 0 -> The number of bytes actually read
0222  * -EINVAL -> Invalid arguments.
0223 **/
0224 int epcq_read_buffer( int offset, uint8_t *dest_addr, int length )
0225 {
0226   return alt_epcq_controller2_read(
0227     &epcq_controller.dev,
0228     offset,
0229     dest_addr,
0230     length
0231   );
0232 }
0233 
0234 /**
0235  * epcs_write_buffer
0236  *
0237  * Writes data to the epcq device.
0238  *
0239  * Arguments:
0240  * - offset: offset within the memory area to read.
0241  * - src_addr: the data top store.
0242  * - length: The number of bytes to write.
0243  *
0244  * Returns:
0245  * 0 -> The number of bytes actually read
0246  * -EINVAL -> Invalid arguments.
0247 **/
0248 int epcq_write_buffer (
0249   int offset,
0250   const uint8_t* src_addr,
0251   int length,
0252   bool erase
0253 )
0254 {
0255   return alt_epcq_controller2_write (
0256     &epcq_controller.dev,
0257     offset,
0258     src_addr,
0259     length,
0260     erase
0261   );
0262 }
0263 
0264 /**
0265  * altera_epcq_controller2_init
0266  *
0267  * Information in system.h is checked against expected values that are
0268  * determined by the silicon_id. If the information doesn't match then this
0269  * system is configured incorrectly. Most likely the wrong type of EPCS or EPCQ
0270  * device was selected when instantiating the soft IP.
0271  *
0272  * Arguments:
0273  * - *flash: Pointer to EPCQ flash device structure.
0274  *
0275  * Returns:
0276  * 0 -> success
0277  * -EINVAL -> Invalid arguments.
0278  * -ENODEV -> System is configured incorrectly.
0279 **/
0280 static int altera_epcq_controller2_init(alt_epcq_controller2_dev *flash)
0281 {
0282   uint32_t silicon_id = 0;
0283   uint32_t size_in_bytes = 0;
0284   uint32_t number_of_sectors = 0;
0285 
0286   /* return -EINVAL if flash is NULL */
0287   if ( NULL == flash ) {
0288     return -EINVAL;
0289   }
0290 
0291   /* return -ENODEV if CSR slave is not attached */
0292   if ( NULL == ( void * )flash->csr_base ) {
0293     return -ENODEV;
0294   }
0295 
0296   /*
0297    * If flash is an EPCQ device, we read the EPCQ_RD_RDID register for the ID
0298    * If flash is an EPCS device, we read the EPCQ_RD_SID register for the ID
0299    *
0300    * Whether or not the flash is a EPCQ or EPCS is indicated in the system.h.
0301    * The system.h gets this value from the hw.tcl of the IP. If this value is
0302    * set incorrectly, then things will go badly.
0303    *
0304    * In both cases, we can determine the number of sectors, which we can use
0305    * to calculate a size. We compare that size to the system.h value to make
0306    * sure the EPCQ soft IP was configured correctly.
0307    */
0308   if ( 0 == flash->is_epcs ) {
0309     /* If we're an EPCQ, we read EPCQ_RD_RDID for the silicon ID */
0310     silicon_id = EPCQ_REGS->rd_rdid;
0311     silicon_id &= ALTERA_EPCQ_CONTROLLER2_RDID_MASK;
0312 
0313     /* Determine which EPCQ device so we can figure out the number of sectors */
0314     /* EPCQ share the same ID for the same capacity*/
0315     switch( silicon_id ) {
0316       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ16:
0317         number_of_sectors = 32;
0318         break;
0319       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ32:
0320         number_of_sectors = 64;
0321         break;
0322       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ64:
0323         number_of_sectors = 128;
0324         break;
0325       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ128:
0326         number_of_sectors = 256;
0327         break;
0328       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ256:
0329         number_of_sectors = 512;
0330         break;
0331       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ512:
0332         number_of_sectors = 1024;
0333         break;
0334       case ALTERA_EPCQ_CONTROLLER2_RDID_EPCQ1024:
0335         number_of_sectors = 2048;
0336         break;
0337       default:
0338         return -ENODEV;
0339     }
0340   } else {
0341     /* If we're an EPCS, we read EPCQ_RD_SID for the silicon ID */
0342     silicon_id = EPCQ_REGS->rd_sid;
0343     silicon_id &= ALTERA_EPCQ_CONTROLLER2_SID_MASK;
0344 
0345     /* Determine which EPCS device so we can figure out various properties */
0346     switch(silicon_id) {
0347       case ALTERA_EPCQ_CONTROLLER2_SID_EPCS16:
0348         number_of_sectors = 32;
0349         break;
0350       case ALTERA_EPCQ_CONTROLLER2_SID_EPCS64:
0351         number_of_sectors = 128;
0352         break;
0353       case ALTERA_EPCQ_CONTROLLER2_SID_EPCS128:
0354         number_of_sectors = 256;
0355         break;
0356       default:
0357         return -ENODEV;
0358     }
0359   }
0360 
0361   /* Calculate size of flash based on number of sectors */
0362   size_in_bytes = number_of_sectors * flash->sector_size;
0363 
0364   /*
0365    * Make sure calculated size is the same size given in system.h
0366    * Also check number of sectors is the same number given in system.h
0367    * Otherwise the EPCQ IP was not configured correctly
0368    */
0369   if (
0370     size_in_bytes != flash->size_in_bytes ||
0371     number_of_sectors != flash->number_of_sectors
0372   ) {
0373     flash->dev.number_of_regions = 0;
0374     return -ENODEV;
0375   } else {
0376     flash->silicon_id = silicon_id;
0377     flash->number_of_sectors = number_of_sectors;
0378 
0379     /*
0380      * populate fields of region_info required to conform to HAL API
0381      * create 1 region that composed of "number_of_sectors" blocks
0382      */
0383     flash->dev.number_of_regions = 1;
0384     flash->dev.region_info[0].offset = 0;
0385     flash->dev.region_info[0].region_size = size_in_bytes;
0386     flash->dev.region_info[0].number_of_blocks = number_of_sectors;
0387     flash->dev.region_info[0].block_size = flash->sector_size;
0388   }
0389 
0390   return 0;
0391 }
0392 
0393 /**
0394   * alt_epcq_controller2_erase_block
0395   *
0396   * This function erases a single flash sector.
0397   *
0398   * Arguments:
0399   * - *flash_info: Pointer to QSPI flash device structure.
0400   * - block_offset: byte-addressed offset, from start of flash, of the sector to
0401   *   be erased
0402   *
0403   * Returns:
0404   * 0 -> success
0405   * -EINVAL -> Invalid arguments
0406   * -EIO -> write failed, sector might be protected
0407 **/
0408 static int alt_epcq_controller2_erase_block(
0409   alt_flash_dev *flash_info,
0410   int block_offset
0411 )
0412 {
0413   int32_t ret_code = 0;
0414   uint32_t mem_op_value = 0; /* value to write to EPCQ_MEM_OP register */
0415   alt_epcq_controller2_dev* epcq_flash_info = NULL;
0416   uint32_t sector_number = 0;
0417 
0418   /* return -EINVAL if flash_info is NULL */
0419   if ( NULL == flash_info ) {
0420     return -EINVAL;
0421   }
0422 
0423   epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
0424 
0425   /*
0426    * Sanity checks that block_offset is within the flash memory span and that
0427    * the block offset is sector aligned.
0428    *
0429    */
0430   if (
0431     ( block_offset < 0 ) ||
0432     ( block_offset >= epcq_flash_info->size_in_bytes ) ||
0433     ( block_offset & ( epcq_flash_info->sector_size - 1 )) != 0
0434   ) {
0435     return -EINVAL;
0436   }
0437 
0438   alt_epcq_poll_for_write_in_progress(epcq_flash_info);
0439 
0440   /* calculate current sector/block number */
0441   sector_number = (block_offset/(epcq_flash_info->sector_size));
0442 
0443   /* sector value should occupy bits 23:8 */
0444   mem_op_value = (sector_number << 8) &
0445     ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_VALUE_MASK;
0446 
0447    /* write enable command */
0448   mem_op_value |= ALTERA_EPCQ_CONTROLLER2_MEM_OP_WRITE_ENABLE_CMD;
0449 
0450   /*
0451    * write sector erase command to EPCQ_MEM_OP register to erase sector
0452    * "sector_number"
0453    */
0454   EPCQ_REGS->mem_op = mem_op_value;
0455 
0456   /* sector value should occupy bits 23:8 */
0457   mem_op_value = (sector_number << 8) &
0458     ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_VALUE_MASK;
0459 
0460   /* sector erase commands 0b10 occupies lower 2 bits */
0461   mem_op_value |= ALTERA_EPCQ_CONTROLLER2_MEM_OP_SECTOR_ERASE_CMD;
0462 
0463   /*
0464    * write sector erase command to QSPI_MEM_OP register to erase sector
0465    * "sector_number"
0466    */
0467   EPCQ_REGS->mem_op = mem_op_value;
0468 
0469   alt_epcq_poll_for_write_in_progress(epcq_flash_info);
0470 
0471   /* check whether erase triggered a illegal erase interrupt  */
0472   if (
0473     ( EPCQ_REGS->isr & ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_MASK ) ==
0474     ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_ACTIVE
0475   ) {
0476     /* clear register */
0477     /* QSPI_ISR access is write one to clear (W1C) */
0478     EPCQ_REGS->isr = ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_ERASE_MASK;
0479     return -EIO; /* erase failed, sector might be protected */
0480   }
0481 
0482   return ret_code;
0483 }
0484 
0485 /**
0486  * alt_epcq_controller2_write_block
0487  *
0488  * This function writes one block/sector of data to flash. The length of the
0489  * write can NOT spill into the adjacent sector.
0490  *
0491  * It assumes that someone has already erased the appropriate sector(s).
0492  *
0493  * Arguments:
0494  * - *flash_info: Pointer to QSPI flash device structure.
0495  * - block_offset: byte-addressed offset, from the start of flash, of the sector
0496  *   to written to
0497  * - data-offset: Byte offset (unaligned access) of write into flash memory.
0498  *   For best performance, word(32 bits - aligned access) offset of write is
0499  *   recommended.
0500  * - *src_addr: source buffer
0501  * - length: size of writing
0502  *
0503  * Returns:
0504  * 0 -> success
0505  * -EINVAL -> Invalid arguments
0506  * -EIO -> write failed, sector might be protected
0507 **/
0508 static int alt_epcq_controller2_write_block (
0509   alt_flash_dev *flash_info, /** flash device info */
0510   int block_offset, /** sector/block offset in byte addressing */
0511   int data_offset, /** offset of write from base address */
0512   const void *data, /** data to be written */
0513   int length /** bytes of data to be written, >0 */
0514 )
0515 {
0516   uint32_t buffer_offset = 0; /** offset into data buffer to get write data */
0517   uint32_t remaining_length = length; /** length left to write */
0518   uint32_t write_offset = data_offset; /** offset into flash to write too */
0519   uint32_t write_offset_32;
0520 
0521   alt_epcq_controller2_dev *epcq_flash_info =
0522     (alt_epcq_controller2_dev*)flash_info;
0523 
0524   /*
0525    * Sanity checks that data offset is not larger then a sector, that block
0526    * offset is sector aligned and within the valid flash memory range and a
0527    * write doesn't spill into the adjacent flash sector.
0528    */
0529   if (
0530     block_offset < 0 ||
0531     data_offset < 0 ||
0532     NULL == flash_info ||
0533     NULL == data ||
0534     data_offset >= epcq_flash_info->size_in_bytes ||
0535     block_offset >= epcq_flash_info->size_in_bytes ||
0536     length > (epcq_flash_info->sector_size - (data_offset - block_offset)) ||
0537     length < 0 ||
0538     (block_offset & (epcq_flash_info->sector_size - 1)) != 0
0539   ) {
0540     return -EINVAL;
0541   }
0542 
0543   /*
0544    * Do writes one 32-bit word at a time.
0545    * We need to make sure that we pad the first few bytes so they're word
0546    * aligned if they are not already.
0547    */
0548   while ( remaining_length > 0 ) {
0549     volatile uint32_t dummy_read;
0550     /** initialize word to write to blank word */
0551     uint32_t word_to_write = 0xFFFFFFFF;
0552     /** bytes to pad the next word that is written */
0553     uint32_t padding = 0;
0554     /** number of bytes from source to copy */
0555     uint32_t bytes_to_copy = sizeof(uint32_t);
0556 
0557     /*
0558      * we need to make sure the write is word aligned
0559      * this should only be true at most 1 time
0560      */
0561     if ( 0 != ( write_offset & ( sizeof( uint32_t ) - 1 ))) {
0562       /*
0563        * data is not word aligned
0564        * calculate padding bytes need to add before start of a data offset
0565        */
0566       padding = write_offset & (sizeof(uint32_t) - 1);
0567 
0568       /* update variables to account for padding being added */
0569       bytes_to_copy -= padding;
0570 
0571       if(bytes_to_copy > remaining_length) {
0572         bytes_to_copy = remaining_length;
0573       }
0574 
0575       write_offset = write_offset - padding;
0576       if ( 0 != ( write_offset & ( sizeof( uint32_t ) - 1 ))) {
0577         return -EINVAL;
0578       }
0579     } else {
0580       if ( bytes_to_copy > remaining_length ) {
0581         bytes_to_copy = remaining_length;
0582       }
0583     }
0584 
0585     /* prepare the word to be written */
0586     memcpy (
0587       ((( void * )&word_to_write)) + padding,
0588       (( void * )data) + buffer_offset,
0589       bytes_to_copy
0590     );
0591 
0592     /* update offset and length variables */
0593     buffer_offset += bytes_to_copy;
0594     remaining_length -= bytes_to_copy;
0595 
0596     /* write to flash 32 bits at a time */
0597     write_offset_32 = write_offset >> 2;
0598     EPCQ_MEM_32[write_offset_32] = word_to_write;
0599     alt_epcq_poll_for_write_in_progress(epcq_flash_info);
0600     if ( EPCQ_MEM_32[write_offset_32] != word_to_write ) {
0601       EPCQ_MEM_32[write_offset_32] = word_to_write;
0602       alt_epcq_poll_for_write_in_progress(epcq_flash_info);
0603       dummy_read = EPCQ_MEM_32[write_offset_32];
0604     }
0605 
0606     /* check whether write triggered a illegal write interrupt */
0607     if (
0608       ( EPCQ_REGS->isr & ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_MASK ) ==
0609         ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_ACTIVE
0610     ) {
0611       /* clear register */
0612       EPCQ_REGS->isr = ALTERA_EPCQ_CONTROLLER2_ISR_ILLEGAL_WRITE_MASK;
0613       return -EIO; /** write failed, sector might be protected */
0614     }
0615 
0616     /* update current offset */
0617     write_offset = write_offset + sizeof(uint32_t);
0618   }
0619 
0620   return 0;
0621 }
0622 
0623 /**
0624  * alt_epcq_controller2_write
0625  *
0626  * Program the data into the flash at the selected address.
0627  *
0628  * The different between this function and alt_epcq_controller2_write_block
0629  * function is that this function (alt_epcq_controller2_write) will
0630  * automatically erase a block as needed
0631  *
0632  * Arguments:
0633  * - *flash_info: Pointer to QSPI flash device structure.
0634  * - offset: Byte offset (unaligned access) of write to flash memory. For best
0635  *   performance, word(32 bits - aligned access) offset of write is recommended.
0636  * - *src_addr: source buffer
0637  * - length: size of writing
0638  *
0639  * Returns:
0640  * 0 -> success
0641  * -EINVAL -> Invalid arguments
0642  * -EIO -> write failed, sector might be protected
0643  *
0644 **/
0645 static int alt_epcq_controller2_write (
0646   alt_flash_dev *flash_info, /** device info */
0647   int offset, /** offset of write from base address */
0648   const void *src_addr, /** source buffer */
0649   int length, /** size of writing */
0650   bool erase /** whether or not to erase before writing */
0651 )
0652 {
0653   int32_t ret_code = 0;
0654 
0655   alt_epcq_controller2_dev *epcq_flash_info = NULL;
0656 
0657 /** address of next byte to write */
0658   uint32_t write_offset = offset;
0659   /** length of write data left to be written */
0660   uint32_t remaining_length = length;
0661   /** offset into source buffer to get write data */
0662   uint32_t buffer_offset = 0;
0663   uint32_t i = 0;
0664 
0665   /* return -EINVAL if flash_info and src_addr are NULL */
0666   if( NULL == flash_info || NULL == src_addr ) {
0667     return -EINVAL;
0668   }
0669 
0670   epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
0671 
0672   /* make sure the write parameters are within the bounds of the flash */
0673   ret_code = alt_epcq_validate_read_write_arguments (
0674     epcq_flash_info,
0675     offset,
0676     length
0677   );
0678 
0679   if ( 0 != ret_code ) {
0680     return ret_code;
0681   }
0682 
0683   /*
0684    * This loop erases and writes data one sector at a time. We check for write
0685    * completion before starting the next sector.
0686    */
0687   for (
0688     i = offset / epcq_flash_info->sector_size;
0689     i < epcq_flash_info->number_of_sectors;
0690     i++
0691   ) {
0692     /** block offset in byte addressing */
0693     uint32_t block_offset = 0;
0694     /** offset into current sector to write */
0695     uint32_t offset_within_current_sector = 0;
0696     /** length to write to current sector */
0697     uint32_t length_to_write = 0;
0698 
0699     if( 0 >= remaining_length ) {
0700       break; /* out of data to write */
0701     }
0702 
0703     /* calculate current sector/block offset in byte addressing */
0704     block_offset = write_offset & ~(epcq_flash_info->sector_size - 1);
0705 
0706     /* calculate offset into sector/block if there is one */
0707     if ( block_offset != write_offset ) {
0708       offset_within_current_sector = write_offset - block_offset;
0709     }
0710 
0711     /* erase sector */
0712     if( erase ) {
0713       ret_code = alt_epcq_controller2_erase_block(flash_info, block_offset);
0714 
0715       if( 0 != ret_code ) {
0716         return ret_code;
0717       }
0718     }
0719 
0720     /* calculate the byte size of data to be written in a sector */
0721     length_to_write = MIN (
0722       epcq_flash_info->sector_size - offset_within_current_sector,
0723       remaining_length
0724     );
0725 
0726     /* write data to erased block */
0727     ret_code = alt_epcq_controller2_write_block (
0728       flash_info,
0729       block_offset,
0730       write_offset,
0731       src_addr + buffer_offset,
0732       length_to_write
0733     );
0734 
0735     if( 0 != ret_code ) {
0736       return ret_code;
0737     }
0738 
0739     /* update remaining length and buffer_offset pointer */
0740     remaining_length -= length_to_write;
0741     buffer_offset += length_to_write;
0742     write_offset += length_to_write;
0743   }
0744 
0745   return ret_code;
0746 }
0747 
0748 /**
0749  * alt_epcq_controller2_read
0750  *
0751  * There's no real need to use this function as opposed to using memcpy
0752  * directly. It does do some sanity checks on the bounds of the read.
0753  *
0754  * Arguments:
0755  * - *flash_info: Pointer to general flash device structure.
0756  * - offset: offset read from flash memory.
0757  * - *dest_addr: destination buffer
0758  * - length: size of reading
0759  *
0760  * Returns:
0761  * 0 -> success
0762  * -EINVAL -> Invalid arguments
0763 **/
0764 static int alt_epcq_controller2_read (
0765   alt_flash_dev *flash_info, /** device info */
0766   int offset, /** offset of read from base address */
0767   void *dest_addr, /** destination buffer */
0768   int length /** size of read */
0769 )
0770 {
0771   int32_t ret_code = 0;
0772   alt_epcq_controller2_dev *epcq_flash_info = NULL;
0773 
0774   /* return -EINVAL if flash_info and dest_addr are NULL */
0775   if ( NULL == flash_info || NULL == dest_addr ) {
0776     return -EINVAL;
0777   }
0778 
0779   epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
0780 
0781   /* validate arguments */
0782   ret_code = alt_epcq_validate_read_write_arguments (
0783     epcq_flash_info,
0784     offset,
0785     length
0786   );
0787 
0788   /* copy data from flash to destination address */
0789   if( 0 == ret_code ) {
0790     memcpy(dest_addr, (uint8_t*)epcq_flash_info->data_base + offset, length);
0791   }
0792 
0793   return ret_code;
0794 }
0795 
0796 /*
0797  *    Helper functions used by Public API functions.
0798  *
0799  * Arguments:
0800  * - *flash_info: Pointer to EPCQ flash device structure.
0801  * - offset: Offset of read/write from base address.
0802  * - length: Length of read/write in bytes.
0803  *
0804  * Returns:
0805  * 0 -> success
0806  * -EINVAL -> Invalid arguments
0807  */
0808 /**
0809  * Used to check that arguments to a read or write are valid
0810  */
0811 static inline int alt_epcq_validate_read_write_arguments (
0812   alt_epcq_controller2_dev *flash_info,
0813   uint32_t offset,
0814   uint32_t length
0815 )
0816 {
0817   alt_epcq_controller2_dev *epcq_flash_info = NULL;
0818   uint32_t start_address = 0;
0819   int32_t end_address = 0;
0820 
0821   /* return -EINVAL if flash_info is NULL */
0822   if( NULL == flash_info ) {
0823     return -EINVAL;
0824   }
0825 
0826   epcq_flash_info = (alt_epcq_controller2_dev*)flash_info;
0827 
0828   /* first address of read or write */
0829   start_address = epcq_flash_info->data_base + offset;
0830   /* last address of read or write (not inclusive) */
0831   end_address = start_address + length;
0832 
0833   /* make sure start and end address is less then the end address of the flash */
0834   if (
0835     start_address >= epcq_flash_info->data_end ||
0836     end_address > epcq_flash_info->data_end ||
0837     offset < 0 ||
0838     length < 0
0839   ) {
0840     return -EINVAL;
0841   }
0842 
0843   return 0;
0844 }
0845 
0846 /*
0847  * Private function that polls write in progress bit QSPI_RD_STATUS.
0848  *
0849  * Write in progress will be set if any of the following operations are in
0850  * progress:
0851  *     -WRITE STATUS REGISTER
0852  *     -WRITE NONVOLATILE CONFIGURATION REGISTER
0853  *     -PROGRAM
0854  *     -ERASE
0855  *
0856  * Assumes QSPI was configured correctly.
0857  *
0858  * If ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE is set, the function will time
0859  * out after a period of time determined by that value.
0860  *
0861  * Arguments:
0862  * - *epcq_flash_info: Pointer to QSPI flash device structure.
0863  *
0864  * Returns:
0865  * 0 -> success
0866  * -EINVAL -> Invalid arguments
0867  * -ETIME  -> Time out and skipping the looping after 0.7 sec.
0868  */
0869 int static alt_epcq_poll_for_write_in_progress (
0870  alt_epcq_controller2_dev* epcq_flash_info
0871 )
0872 {
0873   /* we'll want to implement timeout if a timeout value is specified */
0874 #if ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE > 0
0875   uint32_t timeout = ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE;
0876   uint16_t counter = 0;
0877 #endif
0878 
0879   /* return -EINVAL if epcq_flash_info is NULL */
0880   if ( NULL == epcq_flash_info ) {
0881     return -EINVAL;
0882   }
0883 
0884   /* while Write in Progress bit is set, we wait */
0885   while (
0886     (EPCQ_REGS->rd_status & ALTERA_EPCQ_CONTROLLER2_STATUS_WIP_MASK) ==
0887     ALTERA_EPCQ_CONTROLLER2_STATUS_WIP_BUSY
0888   ) {
0889     if ( counter > (ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE >> 1 )) {
0890       rtems_counter_delay_ticks(2); /* delay 2us */
0891     }
0892 #if ALTERA_EPCQ_CONTROLLER2_1US_TIMEOUT_VALUE > 0
0893     if ( timeout <= counter ) {
0894       return -ETIME;
0895     }
0896 
0897     counter++;
0898 #endif
0899   }
0900 
0901   return 0;
0902 }