Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:43

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSBSPsARMCycVContrib
0005  */
0006 
0007 /******************************************************************************
0008 *
0009 * alt_qspi.c - API for the Altera SoC FPGA QSPI device.
0010 *
0011 ******************************************************************************/
0012 
0013 /******************************************************************************
0014  *
0015  * Copyright 2013 Altera Corporation. All Rights Reserved.
0016  * 
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions are met:
0019  * 
0020  * 1. Redistributions of source code must retain the above copyright notice,
0021  * this list of conditions and the following disclaimer.
0022  * 
0023  * 2. Redistributions in binary form must reproduce the above copyright notice,
0024  * this list of conditions and the following disclaimer in the documentation
0025  * and/or other materials provided with the distribution.
0026  * 
0027  * 3. The name of the author may not be used to endorse or promote products
0028  * derived from this software without specific prior written permission.
0029  * 
0030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
0031  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0032  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO
0033  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0034  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
0035  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0036  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0037  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
0038  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
0039  * OF SUCH DAMAGE.
0040  * 
0041  ******************************************************************************/
0042 
0043 #include <string.h>
0044 #include <stdio.h>
0045 #include <inttypes.h>
0046 #include <bsp/hwlib.h>
0047 #include <bsp/alt_clock_manager.h>
0048 #include "alt_qspi.h"
0049 #include <bsp/alt_qspi_private.h>
0050 #include <bsp/socal/alt_qspi.h>
0051 #include <bsp/socal/alt_rstmgr.h>
0052 #include <bsp/socal/alt_sysmgr.h>
0053 #include <bsp/socal/hps.h>
0054 #include <bsp/socal/socal.h>
0055 
0056 /////
0057 
0058 // NOTE: To enable debugging output, delete the next line and uncomment the
0059 //   line after.
0060 #define dprintf(...)
0061 // #define dprintf printf
0062 
0063 /////
0064 
0065 #define MIN(a, b) ((a) > (b) ? (b) : (a))
0066 
0067 // qspi_clk operating frequency range.
0068 #define ALT_QSPI_CLK_FREQ_MIN ((alt_freq_t)0)
0069 #define ALT_QSPI_CLK_FREQ_MAX ((alt_freq_t)432000000)
0070 
0071 // The set of all valid QSPI controller interrupt status mask values.
0072 #define ALT_QSPI_INT_STATUS_ALL ( \
0073         ALT_QSPI_INT_STATUS_MODE_FAIL         | \
0074         ALT_QSPI_INT_STATUS_UFL               | \
0075         ALT_QSPI_INT_STATUS_IDAC_OP_COMPLETE  | \
0076         ALT_QSPI_INT_STATUS_IDAC_OP_REJECT    | \
0077         ALT_QSPI_INT_STATUS_WR_PROT_VIOL      | \
0078         ALT_QSPI_INT_STATUS_ILL_AHB_ACCESS    | \
0079         ALT_QSPI_INT_STATUS_IDAC_WTRMK_TRIG   | \
0080         ALT_QSPI_INT_STATUS_RX_OVF            | \
0081         ALT_QSPI_INT_STATUS_TX_FIFO_NOT_FULL  | \
0082         ALT_QSPI_INT_STATUS_TX_FIFO_FULL      | \
0083         ALT_QSPI_INT_STATUS_RX_FIFO_NOT_EMPTY | \
0084         ALT_QSPI_INT_STATUS_RX_FIFO_FULL      | \
0085         ALT_QSPI_INT_STATUS_IDAC_RD_FULL        \
0086         )
0087 
0088 static uint32_t qspi_device_size = 0;
0089 
0090 /////
0091 
0092 static ALT_STATUS_CODE alt_qspi_device_status(uint32_t * status)
0093 {
0094     // Read flag status register through STIG
0095     return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDSR, 0, 1, status, 10000);
0096 }
0097 
0098 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
0099 static ALT_STATUS_CODE alt_qspi_N25Q_device_flag(uint32_t * flagsr)
0100 {
0101     if (qspi_device_size < 0x4000000)
0102     {
0103         return ALT_E_SUCCESS;
0104     }
0105 
0106     // Read flag status register through STIG
0107     return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDFLGSR, 0, 1, flagsr, 10000);
0108 }
0109 
0110 // NOTE: This must be called after QSPI has been enabled. Communications with
0111 //   the device will not happen until QSPI is enabled.
0112 static inline ALT_STATUS_CODE alt_qspi_N25Q_enable(void)
0113 {
0114     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0115 
0116     // Reset the volatile memory on the N25Q
0117 
0118     if (status == ALT_E_SUCCESS)
0119     {
0120         status = alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_RESET_EN, 0, 10000);
0121     }
0122 
0123     if (status == ALT_E_SUCCESS)
0124     {
0125         status = alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_RESET_MEM, 0, 10000);
0126     }
0127 
0128     /////
0129 
0130     if (status == ALT_E_SUCCESS)
0131     {
0132         ALT_QSPI_DEV_INST_CONFIG_t cfg =
0133         {
0134             .op_code        = ALT_QSPI_STIG_OPCODE_FASTREAD_QUAD_IO,
0135             .inst_type      = ALT_QSPI_MODE_SINGLE, // RDID does not support QUAD.
0136             .addr_xfer_type = ALT_QSPI_MODE_QUAD,
0137             .data_xfer_type = ALT_QSPI_MODE_QUAD,
0138             .dummy_cycles   = 10
0139         };
0140 
0141         status = alt_qspi_device_read_config_set(&cfg);
0142     }
0143 
0144 /*
0145     // CASE 157096: Investigate using QUAD for writes.
0146     if (status == ALT_E_SUCCESS)
0147     {
0148         ALT_QSPI_DEV_INST_CONFIG_t cfg =
0149         {
0150             .op_code        = ALT_QSPI_STIG_OPCODE_PP,
0151             .inst_type      = ALT_QSPI_MODE_SINGLE,
0152             .addr_xfer_type = ALT_QSPI_MODE_QUAD,
0153             .data_xfer_type = ALT_QSPI_MODE_QUAD,
0154             .dummy_cycles   = 0
0155         };
0156 
0157         status = alt_qspi_device_write_config_set(&cfg);
0158     }
0159 */
0160 
0161     return status;
0162 }
0163 
0164 static ALT_STATUS_CODE alt_qspi_N25Q_flag_wait_for_program(uint32_t timeout)
0165 {
0166     // The flag status register is only available on the 512 Mib and 1 Gib
0167     // (64 MiB and 128 MiB) Micron parts.
0168     if (qspi_device_size < 0x4000000)
0169     {
0170         return ALT_E_SUCCESS;
0171     }
0172 
0173     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0174 
0175     uint32_t time_out = timeout;
0176     uint32_t stat = 0;
0177     bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
0178 
0179     do
0180     {
0181         status = alt_qspi_device_status(&stat);
0182         if (status != ALT_E_SUCCESS)
0183         {
0184             break;
0185         }
0186         if (!ALT_QSPI_STIG_SR_BUSY_GET(stat))
0187         {
0188             break;
0189         }
0190     }
0191     while (time_out-- || infinite);
0192 
0193     if (time_out == (uint32_t)-1 && !infinite)
0194     {
0195         status = ALT_E_TMO;
0196     }
0197 
0198     if (status == ALT_E_SUCCESS)
0199     {
0200         uint32_t flagsr = 0;
0201 
0202         do
0203         {
0204             status = alt_qspi_N25Q_device_flag(&flagsr);
0205             if (status != ALT_E_SUCCESS)
0206             {
0207                 break;
0208             }
0209             if (ALT_QSPI_STIG_FLAGSR_PROGRAMREADY_GET(flagsr))
0210             {
0211                 break;
0212             }
0213         }
0214         while (timeout-- || infinite);
0215 
0216         if (timeout == (uint32_t)-1 && !infinite)
0217         {
0218             status = ALT_E_TMO;
0219         }
0220 
0221         if (status == ALT_E_SUCCESS)
0222         {
0223             if (ALT_QSPI_STIG_FLAGSR_PROGRAMERROR_GET(flagsr))
0224             {
0225                 status = ALT_E_ERROR;
0226             }
0227         }
0228     }
0229     return status;
0230 }
0231 
0232 static ALT_STATUS_CODE alt_qspi_N25Q_flag_wait_for_erase(uint32_t timeout)
0233 {
0234     // The flag status register is only available on the 512 Mib and 1 Gib
0235     // (64 MiB and 128 MiB) Micron parts.
0236     if (qspi_device_size < 0x4000000)
0237     {
0238         return ALT_E_SUCCESS;
0239     }
0240 
0241     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0242 
0243     uint32_t time_out = timeout;
0244     uint32_t stat = 0;
0245     bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
0246 
0247     do
0248     {
0249         status = alt_qspi_device_status(&stat);
0250         if (status != ALT_E_SUCCESS)
0251         {
0252             break;
0253         }
0254         if (!ALT_QSPI_STIG_SR_BUSY_GET(stat))
0255         {
0256             break;
0257         }
0258     }
0259     while (time_out-- || infinite);
0260 
0261     if (time_out == (uint32_t)-1 && !infinite)
0262     {
0263         status = ALT_E_TMO;
0264     }
0265 
0266     if (status == ALT_E_SUCCESS)
0267     {
0268 
0269         uint32_t flagsr = 0;
0270 
0271         do
0272         {
0273             status = alt_qspi_N25Q_device_flag(&flagsr);
0274             if (status != ALT_E_SUCCESS)
0275             {
0276                 break;
0277             }
0278             if (ALT_QSPI_STIG_FLAGSR_ERASEREADY_GET(flagsr))
0279             {
0280                 break;
0281             }
0282         }
0283         while (timeout-- || infinite);
0284 
0285         if (timeout == (uint32_t)-1 && !infinite)
0286         {
0287             status = ALT_E_TMO;
0288         }
0289 
0290         if (status == ALT_E_SUCCESS)
0291         {
0292             if (ALT_QSPI_STIG_FLAGSR_ERASEERROR_GET(flagsr))
0293             {
0294                 status = ALT_E_ERROR;
0295             }
0296         }
0297     }
0298  
0299     return status;
0300 }
0301 #endif
0302 
0303 //
0304 // A helper function which converts a ns interval into a delay interval for a given MHz.
0305 // The +999 is there to round up the result.
0306 //
0307 static inline int alt_qspi_ns_to_multiplier(int ns, int mhz)
0308 {
0309     return ((ns * mhz) + 999) / 1000;
0310 }
0311 
0312 ALT_STATUS_CODE alt_qspi_init(void)
0313 {
0314     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0315     alt_freq_t qspi_clk_freq = 0;
0316 
0317     // Validate QSPI module input clocks.
0318     //  - pclk    - l4_mp_clk
0319     //  - hclk    - l4_mp_clk
0320     //  - ref_clk - qspi_clk
0321 
0322     // Check and validate the QSPI ref_clk which is connected to the HPS qspi_clk.
0323     if (status == ALT_E_SUCCESS)
0324     {
0325         if (alt_clk_is_enabled(ALT_CLK_QSPI) != ALT_E_TRUE)
0326         {
0327             status = ALT_E_BAD_CLK;
0328         }
0329     }
0330 
0331     if (status == ALT_E_SUCCESS)
0332     {
0333         status = alt_clk_freq_get(ALT_CLK_QSPI, &qspi_clk_freq);
0334         if (status == ALT_E_SUCCESS)
0335         {
0336             if (qspi_clk_freq > ALT_QSPI_CLK_FREQ_MAX)
0337             {
0338                 return ALT_E_BAD_CLK;
0339             }
0340         }
0341     }
0342 
0343     int qspi_clk_mhz = qspi_clk_freq / 1000000;
0344 
0345     /////
0346 
0347     // Take QSPI controller out of reset.
0348     alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_QSPI_SET_MSK);
0349 
0350     /////
0351 
0352     // Configure the device timing
0353 
0354     if (status == ALT_E_SUCCESS)
0355     {
0356         ALT_QSPI_TIMING_CONFIG_t timing_cfg =
0357         {
0358             .clk_phase  = (ALT_QSPI_CLK_PHASE_t)ALT_QSPI_CFG_SELCLKPHASE_RESET,
0359             .clk_pol    = (ALT_QSPI_CLK_POLARITY_t)ALT_QSPI_CFG_SELCLKPOL_RESET,
0360             .cs_da      = alt_qspi_ns_to_multiplier(ALT_QSPI_TSHSL_NS_DEF, qspi_clk_mhz),
0361             .cs_dads    = alt_qspi_ns_to_multiplier(ALT_QSPI_TSD2D_NS_DEF, qspi_clk_mhz),
0362             .cs_eot     = alt_qspi_ns_to_multiplier(ALT_QSPI_TCHSH_NS_DEF, qspi_clk_mhz),
0363             .cs_sot     = alt_qspi_ns_to_multiplier(ALT_QSPI_TSLCH_NS_DEF, qspi_clk_mhz),
0364             .rd_datacap = 1
0365         };
0366 
0367         dprintf("DEBUG[QSPI]: cs_da   = %" PRIu32 ".\n", timing_cfg.cs_da);
0368         dprintf("DEBUG[QSPI]: cs_dads = %" PRIu32 ".\n", timing_cfg.cs_dads);
0369         dprintf("DEBUG[QSPI]: cs_eot  = %" PRIu32 ".\n", timing_cfg.cs_eot);
0370         dprintf("DEBUG[QSPI]: cs_sot  = %" PRIu32 ".\n", timing_cfg.cs_sot);
0371 
0372         status = alt_qspi_timing_config_set(&timing_cfg);
0373     }
0374 
0375     /////
0376 
0377     // Configure the remap address register, no remap
0378 
0379     if (status == ALT_E_SUCCESS)
0380     {
0381         status = alt_qspi_ahb_remap_address_set(0);
0382     }
0383 
0384     // Configure the interrupt mask register, disabled all first
0385 
0386     if (status == ALT_E_SUCCESS)
0387     {
0388         status = alt_qspi_int_disable(ALT_QSPI_INT_STATUS_ALL);
0389     }
0390 
0391     // Configure the baud rate divisor
0392     // CASE 157095: Investigate using 108 MHz, and tweaking the rd_datacap param.
0393 
0394     if (status == ALT_E_SUCCESS)
0395     {
0396         uint32_t device_sclk_mhz = 54;
0397         uint32_t div_actual = (qspi_clk_mhz + (device_sclk_mhz - 1)) / device_sclk_mhz;
0398         dprintf("DEBUG[QSPI]: div_actual = %" PRIu32 ".\n", div_actual);
0399 
0400         ALT_QSPI_BAUD_DIV_t div_bits = (ALT_QSPI_BAUD_DIV_t)(((div_actual + 1) / 2) - 1);
0401         status = alt_qspi_baud_rate_div_set(div_bits);
0402     }
0403 
0404     return status;
0405 }
0406 
0407 ALT_STATUS_CODE alt_qspi_uninit(void)
0408 {
0409     // Put QSPI controller into reset.
0410     alt_setbits_word(ALT_RSTMGR_PERMODRST_ADDR, ALT_RSTMGR_PERMODRST_QSPI_SET_MSK);
0411 
0412     return ALT_E_SUCCESS;
0413 }
0414 
0415 ALT_STATUS_CODE alt_qspi_disable(void)
0416 {
0417     alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_EN_SET_MSK);
0418 
0419     return ALT_E_SUCCESS;
0420 }
0421 
0422 ALT_STATUS_CODE alt_qspi_enable(void)
0423 {
0424     alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_EN_SET_MSK);
0425 
0426     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0427 
0428     /////
0429 
0430     // Device specific configuration
0431 
0432 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
0433     if (status == ALT_E_SUCCESS)
0434     {
0435         status = alt_qspi_N25Q_enable();
0436     }
0437 #endif
0438 
0439     uint32_t rdid = 0;
0440 
0441     // Query device capabilities
0442     // This requires QSPI to be enabled.
0443 
0444     if (status == ALT_E_SUCCESS)
0445     {
0446         status = alt_qspi_device_rdid(&rdid);
0447     }
0448 
0449     if (status == ALT_E_SUCCESS)
0450     {
0451         // NOTE: The size code seems to be a form of BCD (binary coded decimal).
0452         //   The first nibble is the 10's digit and the second nibble is the 1's
0453         //   digit in the number of bytes.
0454 
0455         // Capacity ID samples:
0456         //  0x15 :   16 Mb =>   2 MiB => 1 << 21 ; BCD=15
0457         //  0x16 :   32 Mb =>   4 MiB => 1 << 22 ; BCD=16
0458         //  0x17 :   64 Mb =>   8 MiB => 1 << 23 ; BCD=17
0459         //  0x18 :  128 Mb =>  16 MiB => 1 << 24 ; BCD=18
0460         //  0x19 :  256 Mb =>  32 MiB => 1 << 25 ; BCD=19
0461         //  0x1a
0462         //  0x1b
0463         //  0x1c
0464         //  0x1d
0465         //  0x1e
0466         //  0x1f
0467         //  0x20 :  512 Mb =>  64 MiB => 1 << 26 ; BCD=20
0468         //  0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21
0469 
0470         int cap_code = ALT_QSPI_STIG_RDID_CAPACITYID_GET(rdid);
0471 
0472         if ( ((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))
0473         {
0474             // If a non-valid BCD value is detected at the top or bottom nibble, chances
0475             // are that the chip has a problem.
0476 
0477             dprintf("DEBUG[QSPI]: Invalid CapacityID encountered: 0x%02x.\n", cap_code);
0478             status = ALT_E_ERROR;
0479         }
0480         else
0481         {
0482             int cap_decoded = ((cap_code >> 4) * 10) + (cap_code & 0xf);
0483 
0484             qspi_device_size = 1 << (cap_decoded + 6);
0485 
0486             dprintf("DEBUG[QSPI]: Device size = 0x%" PRIx32 ".\n", qspi_device_size);
0487         }
0488     }
0489 
0490     // Configure the device size and address bytes
0491 
0492     if (status == ALT_E_SUCCESS)
0493     {
0494         ALT_QSPI_DEV_SIZE_CONFIG_t size_cfg =
0495         {
0496             .block_size         = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_RESET,  // 0x10  => 2^16 = 64 KiB
0497             .page_size          = ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_RESET, // 0x100 => 256 B
0498             .addr_size          = ALT_QSPI_DEVSZ_NUMADDRBYTES_RESET,       // 0x2   => 3 bytes or 0x00ffffff mask.
0499             .lower_wrprot_block = 0,
0500             .upper_wrprot_block = (qspi_device_size - 1) >> 16,
0501             .wrprot_enable      = ALT_QSPI_WRPROT_EN_RESET
0502         };
0503 
0504         status = alt_qspi_device_size_config_set(&size_cfg);
0505     }
0506 
0507     /////
0508 
0509     // Configure the DMA parameters
0510 
0511     // This will allow DMA to work well without much intervention by users.
0512 
0513     if (status == ALT_E_SUCCESS)
0514     {
0515         status = alt_qspi_dma_config_set(4, 32);
0516     }
0517 
0518     /////
0519 
0520     return status;
0521 }
0522 
0523 /////
0524 
0525 uint32_t alt_qspi_int_status_get(void)
0526 {
0527     // Read and return the value of the QSPI controller Interrupt Status
0528     // Register (irqstat).
0529     return alt_read_word(ALT_QSPI_IRQSTAT_ADDR);
0530 }
0531 
0532 ALT_STATUS_CODE alt_qspi_int_clear(const uint32_t mask)
0533 {
0534     // Check that the [mask] contains valid interrupt status conditions values.
0535     if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
0536     {
0537         return ALT_E_BAD_ARG;
0538     }
0539 
0540     // Write 1's to clear the desired interrupt status condition(s).
0541     alt_write_word(ALT_QSPI_IRQSTAT_ADDR, mask);
0542 
0543     return ALT_E_SUCCESS;
0544 }
0545 
0546 ALT_STATUS_CODE alt_qspi_int_disable(const uint32_t mask)
0547 {
0548     if (alt_qspi_is_idle() == false)
0549     {
0550         return ALT_E_ERROR;
0551     }
0552 
0553     // Check that the [mask] contains valid interrupt status conditions values.
0554     if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
0555     {
0556         return ALT_E_BAD_ARG;
0557     }
0558 
0559     // Write 0's to disable the desired interrupt status condition(s).
0560     alt_clrbits_word(ALT_QSPI_IRQMSK_ADDR, mask);
0561 
0562     return ALT_E_SUCCESS;
0563 }
0564 
0565 ALT_STATUS_CODE alt_qspi_int_enable(const uint32_t mask)
0566 {
0567     if (alt_qspi_is_idle() == false)
0568     {
0569         return ALT_E_ERROR;
0570     }
0571 
0572     // Check that the [mask] contains valid interrupt status conditions values.
0573     if ((ALT_QSPI_INT_STATUS_ALL & mask) == 0)
0574     {
0575         return ALT_E_BAD_ARG;
0576     }
0577 
0578     // Write 1's to enable the desired interrupt status condition(s).
0579     alt_setbits_word(ALT_QSPI_IRQMSK_ADDR, mask);
0580 
0581     return ALT_E_SUCCESS;
0582 }
0583 
0584 /////
0585 
0586 bool alt_qspi_is_idle(void)
0587 {
0588     // If the idle field of the QSPI configuration register is 1 then the serial
0589     // interface and QSPI pipeline is idle.
0590     return ALT_QSPI_CFG_IDLE_GET(alt_read_word(ALT_QSPI_CFG_ADDR)) == 1;
0591 }
0592 
0593 /////
0594 
0595 static ALT_STATUS_CODE alt_qspi_indirect_write_start_bank(uint32_t dst, size_t length);
0596 
0597 static ALT_STATUS_CODE alt_qspi_indirect_page_bound_write_helper(uint32_t dst, const char * src, size_t length)
0598 {
0599     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0600 
0601     if (status == ALT_E_SUCCESS)
0602     {
0603         status = alt_qspi_indirect_write_start_bank(dst, length);
0604     }
0605 
0606     if (status == ALT_E_SUCCESS)
0607     {
0608         uint32_t write_count = 0;
0609         uint32_t write_capacity = ALT_QSPI_SRAM_FIFO_ENTRY_COUNT - alt_qspi_sram_partition_get();
0610 
0611         while (write_count < length)
0612         {
0613             uint32_t space = write_capacity - alt_qspi_indirect_write_fill_level();
0614             space = MIN(space, (length - write_count)/ sizeof(uint32_t));
0615 
0616             const uint32_t * data = (const uint32_t *)(src + write_count);
0617             for (uint32_t i = 0; i < space; ++i)
0618             {
0619                 alt_write_word(ALT_QSPIDATA_ADDR, *data++);
0620             }
0621 
0622             write_count += space * sizeof(uint32_t);
0623         }
0624     }
0625 
0626     if (status == ALT_E_SUCCESS)
0627     {
0628         status = alt_qspi_indirect_write_finish();
0629     }
0630 
0631     return status;
0632 }
0633 
0634 static ALT_STATUS_CODE alt_qspi_indirect_subsector_aligned_write_helper(const char * data, uint32_t subsec_addr)
0635 {
0636     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0637 
0638     for (int i = 0; i < ALT_QSPI_SUBSECTOR_SIZE / ALT_QSPI_PAGE_SIZE; i++)
0639     {
0640         int offset = i * ALT_QSPI_PAGE_SIZE;
0641 
0642         status = alt_qspi_indirect_page_bound_write_helper(subsec_addr + offset, data + offset, ALT_QSPI_PAGE_SIZE);
0643         if (status != ALT_E_SUCCESS)
0644         {
0645             break;
0646         }
0647     }
0648 
0649     return status;
0650 }
0651 
0652 static ALT_STATUS_CODE alt_qspi_indirect_read_start_bank(uint32_t src, size_t size);
0653 
0654 //
0655 // This helper function reads a segment of data, which is limited to 1 bank
0656 // (24 bits of addressing).
0657 //
0658 static ALT_STATUS_CODE alt_qspi_read_bank(char * dst, uint32_t src, size_t size)
0659 {
0660     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0661 
0662     if (status == ALT_E_SUCCESS)
0663     {
0664         status = alt_qspi_indirect_read_start_bank(src, size);
0665     }
0666 
0667     if (status == ALT_E_SUCCESS)
0668     {
0669         uint32_t read_count = 0;
0670 
0671         while (!alt_qspi_indirect_read_is_complete())
0672         {
0673             uint32_t level = alt_qspi_indirect_read_fill_level();
0674 //            level = MIN(level, (size - read_count) / sizeof(uint32_t));
0675 
0676             uint32_t * data = (uint32_t *)(dst + read_count);
0677             for (uint32_t i = 0; i < level; ++i)
0678             {
0679                 *data++ = alt_read_word(ALT_QSPIDATA_ADDR);
0680             }
0681 
0682             read_count += level * sizeof(uint32_t);
0683         }
0684     }
0685 
0686     if (status == ALT_E_SUCCESS)
0687     {
0688         status = alt_qspi_indirect_read_finish();
0689     }
0690 
0691     return status;
0692 }
0693 
0694 ALT_STATUS_CODE alt_qspi_read(void * dst, uint32_t src, size_t size)
0695 {
0696     if (src >= qspi_device_size)
0697     {
0698         return ALT_E_ERROR;
0699     }
0700 
0701     if (src + size - 1 >= qspi_device_size)
0702     {
0703         return ALT_E_ERROR;
0704     }
0705 
0706     if (size == 0)
0707     {
0708         return ALT_E_SUCCESS;
0709     }
0710 
0711     if ((uintptr_t)dst & 0x3)
0712     {
0713         return ALT_E_ERROR;
0714     }
0715 
0716     if (src & 0x3)
0717     {
0718         return ALT_E_ERROR;
0719     }
0720 
0721     if (size & 0x3)
0722     {
0723         return ALT_E_ERROR;
0724     }
0725 
0726     /////
0727 
0728     // Verify that there is not already a read in progress.
0729     if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
0730     {
0731         return ALT_E_ERROR;
0732     }
0733 
0734     /////
0735 
0736     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0737 
0738     //
0739     // bank_count : The number of bank(s) affected, including partial banks.
0740     // bank_addr  : The aligned address of the first affected bank, including partial bank(s).
0741     // bank_ofst  : The offset of the bank to read. Only used when reading the first bank.
0742     //
0743     uint32_t bank_count = ((src + size - 1) >> 24) - (src >> 24) + 1;
0744     uint32_t bank_addr  = src & ALT_QSPI_BANK_ADDR_MSK;
0745     uint32_t bank_ofst  = src & (ALT_QSPI_BANK_SIZE - 1);
0746 
0747     char * data = (char *)dst;
0748 
0749     uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
0750 
0751     dprintf("DEBUG[QSPI]: read(): bulk: mem_addr = %p; flash_addr = 0x%" PRIx32 ".\n", data, src);
0752     dprintf("DEBUG[QSPI]: read(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
0753 
0754     for (uint32_t i = 0; i < bank_count; ++i)
0755     {
0756         dprintf("DEBUG[QSPI]: read(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
0757 
0758         status = alt_qspi_device_bank_select(bank_addr >> 24);
0759         if (status != ALT_E_SUCCESS)
0760         {
0761             break;
0762         }
0763 
0764         status = alt_qspi_read_bank(dst, bank_ofst, copy_length);
0765         if (status != ALT_E_SUCCESS)
0766         {
0767             break;
0768         }
0769 
0770         bank_addr += ALT_QSPI_BANK_SIZE;
0771         data += copy_length;
0772         size -= copy_length;
0773 
0774         copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
0775     }
0776 
0777     return status;
0778 }
0779 
0780 static ALT_STATUS_CODE alt_qspi_write_bank(uint32_t dst, const char * src, size_t size)
0781 {
0782     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0783 
0784     /////
0785 
0786     uint32_t page_ofst  = dst & (ALT_QSPI_PAGE_SIZE - 1);
0787     uint32_t write_size = MIN(size, ALT_QSPI_PAGE_SIZE - page_ofst);
0788 
0789     while (size)
0790     {
0791         dprintf("DEBUG[QSPI]: write(): flash dst = 0x%" PRIx32 ", mem src = %p, write size = 0x%" PRIx32 ", size left = 0x%x.\n", dst, src, write_size, size);
0792 
0793         status = alt_qspi_indirect_page_bound_write_helper(dst, src, write_size);
0794         if (status != ALT_E_SUCCESS)
0795         {
0796             break;
0797         }
0798 
0799         dst  += write_size;
0800         src  += write_size;
0801         size -= write_size;
0802 
0803         write_size = MIN(size, ALT_QSPI_PAGE_SIZE);
0804     }
0805 
0806     return status;
0807 }
0808 
0809 ALT_STATUS_CODE alt_qspi_write(uint32_t dst, const void * src, size_t size)
0810 {
0811     if (dst >= qspi_device_size)
0812     {
0813         return ALT_E_ERROR;
0814     }
0815 
0816     if (dst + size - 1 >= qspi_device_size)
0817     {
0818         return ALT_E_ERROR;
0819     }
0820 
0821     if (size == 0)
0822     {
0823         return ALT_E_SUCCESS;
0824     }
0825 
0826     if ((uintptr_t)src & 0x3)
0827     {
0828         return ALT_E_ERROR;
0829     }
0830 
0831     if (dst & 0x3)
0832     {
0833         return ALT_E_ERROR;
0834     }
0835 
0836     if (size & 0x3)
0837     {
0838         return ALT_E_ERROR;
0839     }
0840 
0841     /////
0842 
0843     // Verify that there is not already a write in progress.
0844     if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
0845     {
0846         return ALT_E_ERROR;
0847     }
0848 
0849     /////
0850 
0851     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0852 
0853     uint32_t bank_count = ((dst + size - 1) >> 24) - (dst >> 24) + 1;
0854     uint32_t bank_addr  = dst & ALT_QSPI_BANK_ADDR_MSK;
0855     uint32_t bank_ofst  = dst & (ALT_QSPI_BANK_SIZE - 1);
0856 
0857     const char * data  = src;
0858 
0859     uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
0860 
0861     dprintf("DEBUG[QSPI]: write(): bulk: flash_addr = 0x%" PRIx32 "; mem_addr = %p.\n", dst, data);
0862     dprintf("DEBUG[QSPI]: write(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
0863 
0864     for (uint32_t i = 0; i < bank_count; ++i)
0865     {
0866         dprintf("DEBUG[QSPI]: write(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
0867 
0868         status = alt_qspi_device_bank_select(bank_addr >> 24);
0869         if (status != ALT_E_SUCCESS)
0870         {
0871             break;
0872         }
0873 
0874         status = alt_qspi_write_bank(bank_ofst, data, copy_length);
0875         if (status != ALT_E_SUCCESS)
0876         {
0877             break;
0878         }
0879 
0880         bank_addr += ALT_QSPI_BANK_SIZE;
0881         data += copy_length;
0882         size -= copy_length;
0883 
0884         copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
0885     }
0886 
0887     return status;
0888 }
0889 
0890 static ALT_STATUS_CODE alt_qspi_erase_subsector_bank(uint32_t addr);
0891 
0892 static ALT_STATUS_CODE alt_qspi_replace_bank(uint32_t dst, const char * src, size_t size)
0893 {
0894     ALT_STATUS_CODE status = ALT_E_SUCCESS;
0895 
0896     //
0897     // subsec_count        : The total number of affected subsector(s),
0898     //                       including partial subsector(s).
0899     // subsec_addr         : The aligned address of the next affected subsector,
0900     //                       including partial subsector(s).
0901     // subsec_partial_head : The number of subsector unaligned data to be
0902     //                       written out at the start of the flash write
0903     //                       request. This data ends at the end of the subsector
0904     //                       or earlier depending on the number of data to be
0905     //                       written.
0906     // subsec_partial_tail : The number of subsector unaligned data to be
0907     //                       written out at the end of the flash write request.
0908     //                       This data starts at the start of the subsector. If
0909     //                       only a single subsector is written (partial or
0910     //                       full), this value will be zero.
0911     //
0912 
0913     uint32_t subsec_count = ((dst + size - 1) >> 12) - (dst >> 12) + 1;
0914     uint32_t subsec_addr  = dst & ALT_QSPI_SUBSECTOR_ADDR_MSK;
0915 
0916     uint32_t subsec_partial_head = MIN(ALT_QSPI_SUBSECTOR_SIZE - (dst & (ALT_QSPI_SUBSECTOR_SIZE - 1)), size) & (ALT_QSPI_SUBSECTOR_SIZE - 1);
0917     uint32_t subsec_partial_tail = (size - subsec_partial_head) & (ALT_QSPI_SUBSECTOR_SIZE - 1);
0918 
0919     dprintf("DEBUG[QSPI]: replace(): report: dst = 0x%" PRIx32 "; size = 0x%x.\n",
0920             dst, size);
0921     dprintf("DEBUG[QSPI]: replace(): report: subsec_count = 0x%" PRIx32 "; subsec_addr = 0x%" PRIx32 ".\n",
0922             subsec_count, subsec_addr);
0923     dprintf("DEBUG[QSPI]: replace(): report: partial_head = 0x%" PRIx32 "; partial_tail = 0x%" PRIx32 ".\n",
0924             subsec_partial_head, subsec_partial_tail);
0925 
0926     // Write the first subsector, partial case.
0927 
0928     if (subsec_partial_head)
0929     {
0930         // The write request is not aligned to a subsector so we must do the
0931         // Read-Modify-Write cycle to preserve the existing data at the head of
0932         // the subsector not affected by the write.
0933 
0934         char subsec_buf[ALT_QSPI_SUBSECTOR_SIZE];
0935 
0936         uint32_t subsec_ofst = dst & ~ALT_QSPI_SUBSECTOR_ADDR_MSK;
0937 
0938         // - Read the subsector into buffer
0939         // - Erase that subsector
0940         // - Copy in the user data into buffer
0941         // - Write out buffer to subsector
0942 
0943         if (status == ALT_E_SUCCESS)
0944         {
0945             status = alt_qspi_read_bank(subsec_buf, subsec_addr, subsec_ofst);
0946         }
0947         if (status == ALT_E_SUCCESS)
0948         {
0949             status = alt_qspi_erase_subsector_bank(subsec_addr);
0950         }
0951         if (status == ALT_E_SUCCESS)
0952         {
0953             memcpy(subsec_buf + subsec_ofst, src, subsec_partial_head);
0954             status = alt_qspi_indirect_subsector_aligned_write_helper(subsec_buf, subsec_addr);
0955         }
0956 
0957         // Do some bookkeeping on the user buffer information
0958         src  += subsec_partial_head;
0959         size -= subsec_partial_head;
0960 
0961         // Do some bookkeeping on the subsector tracking
0962         subsec_count--;
0963         subsec_addr += ALT_QSPI_SUBSECTOR_SIZE;
0964 
0965         dprintf("DEBUG[QSPI]: replace(): partial head: subsec_ofst = 0x%" PRIx32 "; size left = 0x%x; status = %" PRIi32 ".\n",
0966                 subsec_ofst, size, status);
0967     }
0968 
0969     // If there is a partial tail, then take 1 off the subsec_count. This way
0970     // the following loop will write out all the complete subsectors. The tail
0971     // will be written out afterwards.
0972     
0973     if (subsec_partial_tail)
0974     {
0975         subsec_count--;
0976     }
0977 
0978     // Write the aligned subsectors following any partial subsectors.
0979 
0980     for (uint32_t i = 0; i < subsec_count; ++i)
0981     {
0982         // - Erase subsector
0983         // - Write out buffer to subsector
0984 
0985         if (status == ALT_E_SUCCESS)
0986         {
0987             status = alt_qspi_erase_subsector_bank(subsec_addr);
0988         }
0989         if (status == ALT_E_SUCCESS)
0990         {
0991             status = alt_qspi_indirect_subsector_aligned_write_helper(src, subsec_addr);
0992         }
0993 
0994         src  += ALT_QSPI_SUBSECTOR_SIZE;
0995         size -= ALT_QSPI_SUBSECTOR_SIZE;
0996 
0997         // Don't modify subsec_count as it's being used by the loop.
0998         subsec_addr += ALT_QSPI_SUBSECTOR_SIZE;
0999 
1000         dprintf("DEBUG[QSPI]: replace(): subsec aligned: size left = 0x%x, status = %" PRIi32 ".\n",
1001                 size, status);
1002     }
1003 
1004     // Write the last subsector, partial case.
1005 
1006     if (subsec_partial_tail)
1007     {
1008         // The write request is not aligned to a subsector so we must do the
1009         // Read-Modify-Write cycle to preserve the existing data at the end of
1010         // the subsector not affected by the write.
1011 
1012         char subsec_buf[ALT_QSPI_SUBSECTOR_SIZE];
1013 
1014         // - Read the subsector into buffer
1015         // - Erase that subsector
1016         // - Copy in the user data into buffer
1017         // - Write out buffer to subsector
1018 
1019         if (status == ALT_E_SUCCESS)
1020         {
1021             status = alt_qspi_read_bank(subsec_buf  + subsec_partial_tail,
1022                                         subsec_addr + subsec_partial_tail,
1023                                         ALT_QSPI_SUBSECTOR_SIZE - subsec_partial_tail);
1024         }
1025         if (status == ALT_E_SUCCESS)
1026         {
1027             status = alt_qspi_erase_subsector_bank(subsec_addr);
1028         }
1029         if (status == ALT_E_SUCCESS)
1030         {
1031             memcpy(subsec_buf, src, subsec_partial_tail);
1032             status = alt_qspi_indirect_subsector_aligned_write_helper(subsec_buf, subsec_addr);
1033         }
1034 
1035         src  += subsec_partial_tail;
1036         size -= subsec_partial_tail;
1037 
1038         dprintf("DEBUG[QSPI]: replace(): partial tail: size left = 0x%x, status = %" PRIi32 ".\n",
1039                 size, status);
1040     }
1041 
1042     return status;
1043 }
1044 
1045 ALT_STATUS_CODE alt_qspi_replace(uint32_t dst, const void * src, size_t size)
1046 {
1047     if (dst >= qspi_device_size)
1048     {
1049         return ALT_E_ERROR;
1050     }
1051 
1052     if (dst + size - 1 >= qspi_device_size)
1053     {
1054         return ALT_E_ERROR;
1055     }
1056 
1057     if (size == 0)
1058     {
1059         return ALT_E_SUCCESS;
1060     }
1061 
1062     if ((uintptr_t)src & 0x3)
1063     {
1064         return ALT_E_ERROR;
1065     }
1066 
1067     if (dst & 0x3)
1068     {
1069         return ALT_E_ERROR;
1070     }
1071 
1072     if (size & 0x3)
1073     {
1074         return ALT_E_ERROR;
1075     }
1076 
1077     /////
1078 
1079     // Verify that there is not already a read in progress.
1080     if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1081     {
1082         return ALT_E_ERROR;
1083     }
1084 
1085     // Verify that there is not already a write in progress.
1086     if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1087     {
1088         return ALT_E_ERROR;
1089     }
1090 
1091     /////
1092 
1093     ALT_STATUS_CODE status = ALT_E_SUCCESS;
1094 
1095     uint32_t bank_count = ((dst + size - 1) >> 24) - (dst >> 24) + 1;
1096     uint32_t bank_addr  = dst & ALT_QSPI_BANK_ADDR_MSK;
1097     uint32_t bank_ofst  = dst & (ALT_QSPI_BANK_SIZE - 1);
1098 
1099     const char * data = (const char *)src;
1100 
1101     uint32_t copy_length = MIN(size, ALT_QSPI_BANK_SIZE - bank_ofst);
1102 
1103     dprintf("DEBUG[QSPI]: replace(): bulk: flash_addr = 0x%" PRIx32 "; mem_addr = %p.\n", dst, data);
1104     dprintf("DEBUG[QSPI]: replace(): bulk: bank_count = 0x%" PRIx32 ", bank_ofst = 0x%" PRIx32 ".\n", bank_count, bank_ofst);
1105 
1106     for (uint32_t i = 0; i < bank_count; ++i)
1107     {
1108         dprintf("DEBUG[QSPI]: replace(): bank 0x%" PRIx32 "; copy_length = 0x%" PRIx32 ".\n", bank_addr >> 24, copy_length);
1109 
1110         status = alt_qspi_device_bank_select(bank_addr >> 24);
1111         if (status != ALT_E_SUCCESS)
1112         {
1113             break;
1114         }
1115 
1116         status = alt_qspi_replace_bank(bank_ofst, data, copy_length);
1117         if (status != ALT_E_SUCCESS)
1118         {
1119             break;
1120         }
1121 
1122         bank_addr += ALT_QSPI_BANK_SIZE;
1123         data += copy_length;
1124         size -= copy_length;
1125 
1126         copy_length = MIN(size, ALT_QSPI_BANK_SIZE);
1127     }
1128 
1129     return status;
1130 }
1131 
1132 /////
1133 
1134 ALT_QSPI_BAUD_DIV_t alt_qspi_baud_rate_div_get(void)
1135 {
1136     uint32_t baud_rate_div = ALT_QSPI_CFG_BAUDDIV_GET(alt_read_word(ALT_QSPI_CFG_ADDR));
1137     return (ALT_QSPI_BAUD_DIV_t) baud_rate_div;
1138 }
1139 
1140 ALT_STATUS_CODE alt_qspi_baud_rate_div_set(const ALT_QSPI_BAUD_DIV_t baud_rate_div)
1141 {
1142     if (0xf < (uint32_t)baud_rate_div)
1143     {
1144         // Invalid baud rate divisor value.
1145         return ALT_E_BAD_ARG;
1146     }
1147 
1148     // Set the Master Mode Baud Rate Divisor Field of the QSPI Configuration Register.
1149     alt_replbits_word(ALT_QSPI_CFG_ADDR,
1150                       ALT_QSPI_CFG_BAUDDIV_SET_MSK,
1151                       ALT_QSPI_CFG_BAUDDIV_SET(baud_rate_div));
1152 
1153     return ALT_E_SUCCESS;
1154 }
1155 
1156 ALT_STATUS_CODE alt_qspi_chip_select_config_get(uint32_t* cs,
1157                                                 ALT_QSPI_CS_MODE_t* cs_mode)
1158 {
1159     uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
1160 
1161     *cs      = ALT_QSPI_CFG_PERCSLINES_GET(cfg);
1162     *cs_mode = (ALT_QSPI_CS_MODE_t) ALT_QSPI_CFG_PERSELDEC_GET(cfg);
1163 
1164     return ALT_E_SUCCESS;
1165 }
1166 
1167 ALT_STATUS_CODE alt_qspi_chip_select_config_set(const uint32_t cs,
1168                                                 const ALT_QSPI_CS_MODE_t cs_mode)
1169 {
1170     // chip select cs:
1171     // four bit value, bit 0 = cs0, bit 1 = cs1, bit 2 = cs2, bit 3 = cs3
1172     // since cs is low true, the value of each bit should be zero if enable the cs.
1173     // 
1174     // also allows multiple cs line enabled together.
1175  
1176     if (cs > ((1 << ALT_QSPI_CFG_PERCSLINES_WIDTH) - 1))
1177     {
1178         // [cs] not within possible 4 bit chip select line value range.
1179         return ALT_E_ARG_RANGE;
1180     }
1181 
1182     if ((cs_mode != ALT_QSPI_CS_MODE_SINGLE_SELECT) && (cs_mode != ALT_QSPI_CS_MODE_DECODE))
1183     {
1184         return ALT_E_INV_OPTION;
1185     }
1186 
1187     // Update the Peripheral Chip Select Lines and Peripheral Select Decode
1188     // Fields of the QSPI Configuration Register value with the chip select
1189     // options.
1190     uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
1191     cfg &= ALT_QSPI_CFG_PERCSLINES_CLR_MSK & ALT_QSPI_CFG_PERSELDEC_CLR_MSK;
1192     cfg |= ALT_QSPI_CFG_PERCSLINES_SET(cs) | ALT_QSPI_CFG_PERSELDEC_SET(cs_mode);
1193     alt_write_word(ALT_QSPI_CFG_ADDR, cfg);
1194 
1195     return ALT_E_SUCCESS;
1196 }
1197 
1198 ALT_STATUS_CODE alt_qspi_mode_bit_disable(void)
1199 {
1200     // Clear the Mode Bit Enable Field of the Device Read Instruction Register
1201     // to disable mode bits from being sent after the address bytes.
1202     alt_clrbits_word(ALT_QSPI_DEVRD_ADDR, ALT_QSPI_DEVRD_ENMODBITS_SET_MSK);
1203 
1204     return ALT_E_SUCCESS;
1205 }
1206 
1207 ALT_STATUS_CODE alt_qspi_mode_bit_enable(void)
1208 {
1209     // Set the Mode Bit Enable Field of the Device Read Instruction Register
1210     // to enable mode bits to be sent after the address bytes.
1211     alt_setbits_word(ALT_QSPI_DEVRD_ADDR, ALT_QSPI_DEVRD_ENMODBITS_SET_MSK);
1212 
1213     return ALT_E_SUCCESS;
1214 }
1215 
1216 uint32_t alt_qspi_mode_bit_config_get(void)
1217 {
1218     // Return the 8 bit value from the Mode Field of the Mode Bit Configuration
1219     // Register.
1220     return ALT_QSPI_MODBIT_MOD_GET(alt_read_word(ALT_QSPI_MODBIT_ADDR));
1221 }
1222 
1223 ALT_STATUS_CODE alt_qspi_mode_bit_config_set(const uint32_t mode_bits)
1224 {
1225     if (alt_qspi_is_idle() == false)
1226     {
1227         return ALT_E_ERROR;
1228     }
1229 
1230     if (mode_bits > ((1 << ALT_QSPI_MODBIT_MOD_WIDTH) - 1))
1231     {
1232         // 'mode_bits' not within possible 8 bit mode value range.
1233         return ALT_E_ARG_RANGE;
1234     }
1235 
1236     // Set the 8 bit value in the Mode Field of the Mode Bit Configuration
1237     // Register.
1238     alt_replbits_word(ALT_QSPI_MODBIT_ADDR,
1239                       ALT_QSPI_MODBIT_MOD_SET_MSK,
1240                       ALT_QSPI_MODBIT_MOD_SET(mode_bits));
1241 
1242     return ALT_E_SUCCESS;
1243 }
1244 
1245 ALT_STATUS_CODE alt_qspi_device_size_config_get(ALT_QSPI_DEV_SIZE_CONFIG_t * cfg)
1246 {
1247     // Although not required, it is recommended that the write protect feature
1248     // be enabled prior to enabling the QSPI controller. This will block any AHB
1249     // writes from taking effect. This also means the write protection registers
1250     // (Lower Write Protection, Upper Write Protection, and Write Protection)
1251     // should be setup and the number of bytes per device block in the device
1252     // size configuration register should be setup prior to enabling the QSPI
1253     // controller.
1254 
1255     // Read Device Size Register and get the Number of Bytes per Block, Number
1256     // of Bytes per Device, and Number of Address Bytes Fields.
1257 
1258     uint32_t devsz = alt_read_word(ALT_QSPI_DEVSZ_ADDR);
1259 
1260     cfg->block_size = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_GET(devsz);
1261     cfg->page_size  = ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_GET(devsz);
1262     cfg->addr_size  = ALT_QSPI_DEVSZ_NUMADDRBYTES_GET(devsz);
1263 
1264     // Read Lower Write Protection, Upper Write Protection, and Write Protection
1265     // Registers.
1266 
1267     cfg->lower_wrprot_block = ALT_QSPI_LOWWRPROT_SUBSECTOR_GET(alt_read_word(ALT_QSPI_LOWWRPROT_ADDR));
1268     cfg->upper_wrprot_block = ALT_QSPI_UPPWRPROT_SUBSECTOR_GET(alt_read_word(ALT_QSPI_UPPWRPROT_ADDR));
1269     cfg->wrprot_enable      = ALT_QSPI_WRPROT_EN_GET(alt_read_word(ALT_QSPI_WRPROT_ADDR));
1270 
1271     return ALT_E_SUCCESS;
1272 }
1273 
1274 ALT_STATUS_CODE alt_qspi_device_size_config_set(const ALT_QSPI_DEV_SIZE_CONFIG_t * cfg)
1275 {
1276     if (cfg->block_size > ((1 << ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_WIDTH) - 1))
1277     {
1278         return ALT_E_ARG_RANGE;
1279     }
1280 
1281     if (cfg->page_size > ((1 << ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_WIDTH) - 1))
1282     {
1283         return ALT_E_ARG_RANGE;
1284     }
1285 
1286     if (cfg->addr_size > ((1 << ALT_QSPI_DEVSZ_NUMADDRBYTES_WIDTH) - 1))
1287     {
1288         return ALT_E_ARG_RANGE;
1289     }
1290 
1291     if (cfg->lower_wrprot_block > cfg->upper_wrprot_block)
1292     {
1293         // Null write protection regions are not allowed.
1294         return ALT_E_ARG_RANGE;
1295     }
1296 
1297     /////
1298 
1299     uint32_t value = ALT_QSPI_DEVSZ_BYTESPERSUBSECTOR_SET(cfg->block_size) |
1300                      ALT_QSPI_DEVSZ_BYTESPERDEVICEPAGE_SET(cfg->page_size) |
1301                      ALT_QSPI_DEVSZ_NUMADDRBYTES_SET(cfg->addr_size);
1302 
1303     alt_write_word(ALT_QSPI_DEVSZ_ADDR, value);
1304 
1305     if (cfg->wrprot_enable)
1306     {
1307         alt_write_word(ALT_QSPI_LOWWRPROT_ADDR, cfg->lower_wrprot_block);
1308         alt_write_word(ALT_QSPI_UPPWRPROT_ADDR, cfg->upper_wrprot_block);
1309     }
1310 
1311     // Read Upper Write Protection Register - uppwrprot.
1312     // Set the Write Protection Enable Bit Field of the Write Protection
1313     // Register accordingly.
1314     if (cfg->wrprot_enable)
1315     {
1316         alt_setbits_word(ALT_QSPI_WRPROT_ADDR, ALT_QSPI_WRPROT_EN_SET(1));
1317     }
1318     else
1319     {
1320         alt_clrbits_word(ALT_QSPI_WRPROT_ADDR, ALT_QSPI_WRPROT_EN_SET(1));
1321     }
1322     return ALT_E_SUCCESS;
1323 }
1324 
1325 ALT_STATUS_CODE alt_qspi_device_read_config_get(ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1326 {
1327     // Read the Device Read Instruction Register - devrd.
1328     uint32_t devrd = alt_read_word(ALT_QSPI_DEVRD_ADDR);
1329 
1330     cfg->op_code        = ALT_QSPI_DEVRD_RDOPCODE_GET(devrd);
1331     cfg->inst_type      = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_INSTWIDTH_GET(devrd);
1332     cfg->addr_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_ADDRWIDTH_GET(devrd);
1333     cfg->data_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_DATAWIDTH_GET(devrd);
1334     cfg->dummy_cycles   = ALT_QSPI_DEVRD_DUMMYRDCLKS_GET(devrd);
1335 
1336     return ALT_E_SUCCESS;
1337 }
1338 
1339 ALT_STATUS_CODE alt_qspi_device_read_config_set(const ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1340 {
1341     if (alt_qspi_is_idle() == false)
1342     {
1343         return ALT_E_ERROR;
1344     }
1345 
1346     // Validate input
1347 
1348     if (cfg->op_code > ((1 << ALT_QSPI_DEVRD_RDOPCODE_WIDTH) - 1))
1349     {
1350         return ALT_E_BAD_ARG;
1351     }
1352 
1353     switch (cfg->inst_type)
1354     {
1355     case ALT_QSPI_MODE_SINGLE:
1356     case ALT_QSPI_MODE_DUAL:
1357     case ALT_QSPI_MODE_QUAD:
1358         break;
1359     default:
1360         return ALT_E_BAD_ARG;
1361     }
1362 
1363     switch (cfg->addr_xfer_type)
1364     {
1365     case ALT_QSPI_MODE_SINGLE:
1366     case ALT_QSPI_MODE_DUAL:
1367     case ALT_QSPI_MODE_QUAD:
1368         break;
1369     default:
1370         return ALT_E_BAD_ARG;
1371     }
1372 
1373     switch (cfg->data_xfer_type)
1374     {
1375     case ALT_QSPI_MODE_SINGLE:
1376     case ALT_QSPI_MODE_DUAL:
1377     case ALT_QSPI_MODE_QUAD:
1378         break;
1379     default:
1380         return ALT_E_BAD_ARG;
1381     }
1382 
1383     if (cfg->dummy_cycles > ((1 << ALT_QSPI_DEVRD_DUMMYRDCLKS_WIDTH) - 1))
1384     {
1385         return ALT_E_BAD_ARG;
1386     }
1387 
1388     /////
1389 
1390     // Read the Device Read Instruction Register - devrd.
1391     uint32_t devrd = alt_read_word(ALT_QSPI_DEVRD_ADDR);
1392 
1393     devrd &= ALT_QSPI_DEVRD_RDOPCODE_CLR_MSK &
1394              ALT_QSPI_DEVRD_INSTWIDTH_CLR_MSK &
1395              ALT_QSPI_DEVRD_ADDRWIDTH_CLR_MSK &
1396              ALT_QSPI_DEVRD_DATAWIDTH_CLR_MSK &
1397              ALT_QSPI_DEVRD_DUMMYRDCLKS_CLR_MSK;
1398 
1399     devrd |= ALT_QSPI_DEVRD_RDOPCODE_SET(cfg->op_code) |
1400              ALT_QSPI_DEVRD_INSTWIDTH_SET(cfg->inst_type) |
1401              ALT_QSPI_DEVRD_ADDRWIDTH_SET(cfg->addr_xfer_type) |
1402              ALT_QSPI_DEVRD_DATAWIDTH_SET(cfg->data_xfer_type) |
1403              ALT_QSPI_DEVRD_DUMMYRDCLKS_SET(cfg->dummy_cycles);
1404 
1405     alt_write_word(ALT_QSPI_DEVRD_ADDR, devrd);
1406 
1407     return ALT_E_SUCCESS;
1408 }
1409 
1410 ALT_STATUS_CODE alt_qspi_device_write_config_get(ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1411 {
1412     // Device Write Instruction Register - devwr.
1413     uint32_t devwr = alt_read_word(ALT_QSPI_DEVWR_ADDR);
1414 
1415     cfg->op_code        = ALT_QSPI_DEVWR_WROPCODE_GET(devwr);
1416     // The Instruction Type field in the Device READ Instruction Register only appears
1417     // once and applies to both READ and WRITE opertions. it is not included in the
1418     // Device WRITE Instruction Register.
1419     cfg->inst_type      = (ALT_QSPI_MODE_t) ALT_QSPI_DEVRD_INSTWIDTH_GET(alt_read_word(ALT_QSPI_DEVRD_ADDR));
1420     cfg->addr_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVWR_ADDRWIDTH_GET(devwr);
1421     cfg->data_xfer_type = (ALT_QSPI_MODE_t) ALT_QSPI_DEVWR_DATAWIDTH_GET(devwr);
1422     cfg->dummy_cycles   = ALT_QSPI_DEVWR_DUMMYWRCLKS_GET(devwr);
1423 
1424     return ALT_E_SUCCESS;
1425 }
1426 
1427 ALT_STATUS_CODE alt_qspi_device_write_config_set(const ALT_QSPI_DEV_INST_CONFIG_t * cfg)
1428 {
1429     if (alt_qspi_is_idle() == false)
1430     {
1431         return ALT_E_ERROR;
1432     }
1433 
1434     // Validate input
1435 
1436     if (cfg->op_code > ((1 << ALT_QSPI_DEVWR_WROPCODE_WIDTH) - 1))
1437     {
1438         return ALT_E_BAD_ARG;
1439     }
1440 
1441     switch (cfg->inst_type)
1442     {
1443     case ALT_QSPI_MODE_SINGLE:
1444     case ALT_QSPI_MODE_DUAL:
1445     case ALT_QSPI_MODE_QUAD:
1446         break;
1447     default:
1448         return ALT_E_BAD_ARG;
1449     }
1450 
1451     switch (cfg->addr_xfer_type)
1452     {
1453     case ALT_QSPI_MODE_SINGLE:
1454     case ALT_QSPI_MODE_DUAL:
1455     case ALT_QSPI_MODE_QUAD:
1456         break;
1457     default:
1458         return ALT_E_BAD_ARG;
1459     }
1460 
1461     switch (cfg->data_xfer_type)
1462     {
1463     case ALT_QSPI_MODE_SINGLE:
1464     case ALT_QSPI_MODE_DUAL:
1465     case ALT_QSPI_MODE_QUAD:
1466         break;
1467     default:
1468         return ALT_E_BAD_ARG;
1469     }
1470 
1471     if (cfg->dummy_cycles > ((1 << ALT_QSPI_DEVWR_DUMMYWRCLKS_WIDTH) - 1))
1472     {
1473         return ALT_E_BAD_ARG;
1474     }
1475 
1476     /////
1477 
1478     // Read the Device Write Instruction Register - devwr.
1479     uint32_t devwr = alt_read_word(ALT_QSPI_DEVWR_ADDR);
1480 
1481     devwr &= ALT_QSPI_DEVWR_WROPCODE_CLR_MSK &
1482              ALT_QSPI_DEVWR_ADDRWIDTH_CLR_MSK &
1483              ALT_QSPI_DEVWR_DATAWIDTH_CLR_MSK &
1484              ALT_QSPI_DEVWR_DUMMYWRCLKS_CLR_MSK;
1485 
1486     devwr |= ALT_QSPI_DEVWR_WROPCODE_SET(cfg->op_code) |
1487              ALT_QSPI_DEVWR_ADDRWIDTH_SET(cfg->addr_xfer_type) |
1488              ALT_QSPI_DEVWR_DATAWIDTH_SET(cfg->data_xfer_type) |
1489              ALT_QSPI_DEVWR_DUMMYWRCLKS_SET(cfg->dummy_cycles);
1490 
1491     alt_write_word(ALT_QSPI_DEVWR_ADDR, devwr);
1492 
1493     // The Instruction Type field in the Device READ Instruction Register only appears
1494     // once and applies to both READ and WRITE operations - it is not included in the
1495     // Device WRITE Instruction Register. Therefore, modify the Instruction Type
1496     // Field in the Device Read Register.
1497     alt_replbits_word(ALT_QSPI_DEVRD_ADDR,
1498                       ALT_QSPI_DEVRD_INSTWIDTH_SET_MSK,
1499                       ALT_QSPI_DEVRD_INSTWIDTH_SET((uint32_t) cfg->inst_type));
1500 
1501     return ALT_E_SUCCESS;
1502 }
1503 
1504 ALT_STATUS_CODE alt_qspi_timing_config_get(ALT_QSPI_TIMING_CONFIG_t * cfg)
1505 {
1506     // QSPI Configuration Register - cfg
1507     uint32_t cfgreg = alt_read_word(ALT_QSPI_CFG_ADDR);
1508     cfg->clk_phase  = (ALT_QSPI_CLK_PHASE_t) ALT_QSPI_CFG_SELCLKPHASE_GET(cfgreg);
1509     cfg->clk_pol    = (ALT_QSPI_CLK_POLARITY_t) ALT_QSPI_CFG_SELCLKPOL_GET(cfgreg);
1510 
1511     // QSPI Device Delay Register
1512     uint32_t delayreg = alt_read_word(ALT_QSPI_DELAY_ADDR);
1513     cfg->cs_sot  = ALT_QSPI_DELAY_INIT_GET(delayreg);
1514     cfg->cs_eot  = ALT_QSPI_DELAY_AFTER_GET(delayreg);
1515     cfg->cs_dads = ALT_QSPI_DELAY_BTWN_GET(delayreg);
1516     cfg->cs_da   = ALT_QSPI_DELAY_NSS_GET(delayreg);
1517 
1518     // Read Data Capture Register
1519     cfg->rd_datacap = ALT_QSPI_RDDATACAP_DELAY_GET(alt_read_word(ALT_QSPI_RDDATACAP_ADDR));
1520 
1521     return ALT_E_SUCCESS;
1522 }
1523 
1524 ALT_STATUS_CODE alt_qspi_timing_config_set(const ALT_QSPI_TIMING_CONFIG_t * cfg)
1525 {
1526     if (alt_qspi_is_idle() == false)
1527     {
1528         return ALT_E_ERROR;
1529     }
1530 
1531     // Validate parameter(s)
1532 
1533     switch (cfg->clk_phase)
1534     {
1535     case ALT_QSPI_CLK_PHASE_ACTIVE:
1536     case ALT_QSPI_CLK_PHASE_INACTIVE:
1537         break;
1538     default:
1539         return ALT_E_BAD_ARG;
1540     }
1541 
1542     switch (cfg->clk_pol)
1543     {
1544     case ALT_QSPI_CLK_POLARITY_LOW:
1545     case ALT_QSPI_CLK_POLARITY_HIGH:
1546         break;
1547     default:
1548         return ALT_E_BAD_ARG;
1549     }
1550 
1551     if (cfg->cs_da > ((1 << ALT_QSPI_DELAY_NSS_WIDTH) - 1))
1552     {
1553         return ALT_E_BAD_ARG;
1554     }
1555     if (cfg->cs_dads > ((1 << ALT_QSPI_DELAY_BTWN_WIDTH) - 1))
1556     {
1557         return ALT_E_BAD_ARG;
1558     }
1559     if (cfg->cs_eot > ((1 << ALT_QSPI_DELAY_AFTER_WIDTH) - 1))
1560     {
1561         return ALT_E_BAD_ARG;
1562     }
1563     if (cfg->cs_sot > ((1 << ALT_QSPI_DELAY_INIT_WIDTH) - 1))
1564     {
1565         return ALT_E_BAD_ARG;
1566     }
1567 
1568     if (cfg->rd_datacap > ((1 << ALT_QSPI_RDDATACAP_DELAY_WIDTH) - 1))
1569     {
1570         return ALT_E_BAD_ARG;
1571     }
1572 
1573     /////
1574 
1575     // QSPI Configuration Register - cfg
1576     uint32_t cfgreg = alt_read_word(ALT_QSPI_CFG_ADDR);
1577     cfgreg &= ALT_QSPI_CFG_SELCLKPHASE_CLR_MSK &
1578               ALT_QSPI_CFG_SELCLKPOL_CLR_MSK;
1579     cfgreg |= ALT_QSPI_CFG_SELCLKPHASE_SET(cfg->clk_phase) |
1580               ALT_QSPI_CFG_SELCLKPOL_SET(cfg->clk_pol);
1581     alt_write_word(ALT_QSPI_CFG_ADDR, cfgreg);
1582 
1583     // QSPI Device Delay Register
1584     uint32_t delayreg = ALT_QSPI_DELAY_INIT_SET(cfg->cs_sot)  |
1585                         ALT_QSPI_DELAY_AFTER_SET(cfg->cs_eot) |
1586                         ALT_QSPI_DELAY_BTWN_SET(cfg->cs_dads) |
1587                         ALT_QSPI_DELAY_NSS_SET(cfg->cs_da);
1588     alt_write_word(ALT_QSPI_DELAY_ADDR, delayreg);
1589 
1590     // Read Data Capture Register
1591 
1592     alt_write_word(ALT_QSPI_RDDATACAP_ADDR,
1593                    ALT_QSPI_RDDATACAP_BYP_SET(1) | 
1594                    ALT_QSPI_RDDATACAP_DELAY_SET(cfg->rd_datacap));
1595 
1596     return ALT_E_SUCCESS;
1597 }
1598 
1599 /////
1600 
1601 ALT_STATUS_CODE alt_qspi_direct_disable(void)
1602 {
1603     // Clear (set to 0) the Enable Direct Access Controller Field of the QSPI
1604     // Configuration Register to disable the Direct Access Controller.
1605     alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDIRACC_SET_MSK);
1606 
1607     return ALT_E_SUCCESS;
1608 }
1609 
1610 ALT_STATUS_CODE alt_qspi_direct_enable(void)
1611 {
1612     // Set (set to 1) the Enable Direct Access Controller Field of the QSPI
1613     // Configuration Register to enable the Direct Access Controller.
1614     alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDIRACC_SET_MSK);
1615 
1616     return ALT_E_SUCCESS;
1617 }
1618 
1619 uint32_t alt_qspi_ahb_remap_address_get(void)
1620 {
1621     // Read and return the value of the Remap Address Register.
1622     return ALT_QSPI_REMAPADDR_VALUE_GET(alt_read_word(ALT_QSPI_REMAPADDR_ADDR));
1623 }
1624 
1625 ALT_STATUS_CODE alt_qspi_ahb_remap_address_set(const uint32_t ahb_remap_addr)
1626 {
1627     if (alt_qspi_is_idle() == false)
1628     {
1629         return ALT_E_ERROR;
1630     }
1631 
1632     // Read and return the value of the Remap Address Register.
1633     alt_setbits_word(ALT_QSPI_REMAPADDR_ADDR, ALT_QSPI_REMAPADDR_VALUE_SET(ahb_remap_addr));
1634 
1635     return ALT_E_SUCCESS;
1636 }
1637 
1638 ALT_STATUS_CODE alt_qspi_ahb_address_remap_disable(void)
1639 {
1640     // Clear (set to 0) the Enable AHB Address Remapping Field of the QSPI
1641     // Configuration Register to disable AHB address remapping.
1642     alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENAHBREMAP_SET_MSK);
1643 
1644     return ALT_E_SUCCESS;
1645 }
1646 
1647 ALT_STATUS_CODE alt_qspi_ahb_address_remap_enable(void)
1648 {
1649     // Set (set to 1) the Enable AHB Address Remapping Field of the QSPI
1650     // Configuration Register to enable AHB address remapping.
1651     alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENAHBREMAP_SET_MSK);
1652 
1653     return ALT_E_SUCCESS;
1654 }
1655 
1656 /////
1657 
1658 static ALT_STATUS_CODE alt_qspi_indirect_read_start_bank(uint32_t flash_addr,
1659                                                          size_t num_bytes)
1660 {
1661     alt_write_word(ALT_QSPI_INDRDSTADDR_ADDR, flash_addr);
1662     alt_write_word(ALT_QSPI_INDRDCNT_ADDR, num_bytes);
1663     alt_write_word(ALT_QSPI_INDRD_ADDR, ALT_QSPI_INDRD_START_SET_MSK |
1664                                         ALT_QSPI_INDRD_IND_OPS_DONE_STAT_SET_MSK);
1665 
1666     return ALT_E_SUCCESS;
1667 }
1668 
1669 ALT_STATUS_CODE alt_qspi_indirect_read_start(const uint32_t flash_addr,
1670                                              const size_t num_bytes)
1671 {
1672     // flash_addr and num_bytes restriction is to prevent possible unaligned
1673     // exceptions.
1674 
1675     if (flash_addr & 0x3)
1676     {
1677         return ALT_E_ERROR;
1678     }
1679 
1680     if (num_bytes & 0x3)
1681     {
1682         return ALT_E_ERROR;
1683     }
1684 
1685     if (num_bytes == 0)
1686     {
1687         // Do not report this as a success. If a indirect read was not
1688         // previously completed, it may be cleared already, at which point
1689         // alt_qspi_indirect_read_is_complete() will never report true.
1690         return ALT_E_ERROR;
1691     }
1692 
1693     if (flash_addr > qspi_device_size)
1694     {
1695         return ALT_E_ERROR;
1696     }
1697 
1698     if (flash_addr + num_bytes > qspi_device_size)
1699     {
1700         return ALT_E_ERROR;
1701     }
1702 
1703     // Verify request does not cross bank boundary.
1704     // This limitation is due to the 3-byte addressing limitation.
1705     if ((flash_addr & ALT_QSPI_BANK_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_BANK_ADDR_MSK))
1706     {
1707         return ALT_E_ERROR;
1708     }
1709 
1710     // Verify that there is not already a read in progress.
1711     if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1712     {
1713         return ALT_E_ERROR;
1714     }
1715 
1716     /////
1717 
1718     ALT_STATUS_CODE status;
1719     status = alt_qspi_device_bank_select(flash_addr >> 24);
1720     if (status != ALT_E_SUCCESS)
1721     {
1722         return status;
1723     }
1724 
1725     /////
1726 
1727     return alt_qspi_indirect_read_start_bank(flash_addr,
1728                                              num_bytes);
1729 
1730 }
1731 
1732 ALT_STATUS_CODE alt_qspi_indirect_read_finish(void)
1733 {
1734     return ALT_E_SUCCESS;
1735 }
1736 
1737 ALT_STATUS_CODE alt_qspi_indirect_read_cancel(void)
1738 {
1739     // An indirect operation may be cancelled at any time by setting Indirect
1740     // Transfer Control Register bit [1].
1741     alt_write_word(ALT_QSPI_INDRD_ADDR, ALT_QSPI_INDRD_CANCEL_SET_MSK);
1742 
1743     return ALT_E_SUCCESS;
1744 }
1745 
1746 uint32_t alt_qspi_indirect_read_fill_level(void)
1747 {
1748     // Return the SRAM Fill Level (Indirect Read Partition) Field of the SRAM
1749     // Fill Register to get the SRAM Fill Level for the Indirect Read Partition
1750     // in units of SRAM Words (4 bytes).
1751     return ALT_QSPI_SRAMFILL_INDRDPART_GET(alt_read_word(ALT_QSPI_SRAMFILL_ADDR));
1752 }
1753 
1754 uint32_t alt_qspi_indirect_read_watermark_get(void)
1755 {
1756     // Return the Watermark value in the Indirect Read Transfer Watermark Register.
1757     return alt_read_word(ALT_QSPI_INDRDWATER_ADDR);
1758 }
1759 
1760 ALT_STATUS_CODE alt_qspi_indirect_read_watermark_set(const uint32_t watermark)
1761 {
1762     // Verify that there is not already a read in progress.
1763     if (ALT_QSPI_INDRD_RD_STAT_GET(alt_read_word(ALT_QSPI_INDRD_ADDR)))
1764     {
1765         return ALT_E_ERROR;
1766     }
1767 
1768     // Set the Watermark value in the Indirect Read Transfer Watermark Register.
1769     alt_write_word(ALT_QSPI_INDRDWATER_ADDR, watermark);
1770 
1771     return ALT_E_SUCCESS;
1772 }
1773 
1774 bool alt_qspi_indirect_read_is_complete(void)
1775 {
1776     // The value of the Indirect Completion Status Field of the Indirect Read
1777     // Transfer Control Register is set by hardware when an indirect read
1778     // operation has completed.
1779     return (alt_read_word(ALT_QSPI_INDRD_ADDR) & ALT_QSPI_INDRD_IND_OPS_DONE_STAT_SET_MSK) != 0;
1780 }
1781 
1782 static ALT_STATUS_CODE alt_qspi_indirect_write_start_bank(uint32_t flash_addr,
1783                                                           size_t num_bytes)
1784 {
1785     alt_write_word(ALT_QSPI_INDWRSTADDR_ADDR, flash_addr);
1786     alt_write_word(ALT_QSPI_INDWRCNT_ADDR, num_bytes);
1787     alt_write_word(ALT_QSPI_INDWR_ADDR, ALT_QSPI_INDWR_START_SET_MSK |
1788                                         ALT_QSPI_INDWR_INDDONE_SET_MSK);
1789 
1790     return ALT_E_SUCCESS;
1791 }
1792 
1793 ALT_STATUS_CODE alt_qspi_indirect_write_start(const uint32_t flash_addr,
1794                                               const size_t num_bytes)
1795 {
1796     // flash_addr and num_bytes restriction is to prevent possible unaligned
1797     // exceptions.
1798 
1799     if (flash_addr & 0x3)
1800     {
1801         return ALT_E_ERROR;
1802     }
1803 
1804     if (num_bytes & 0x3)
1805     {
1806         return ALT_E_ERROR;
1807     }
1808 
1809     if (num_bytes == 0)
1810     {
1811         // Do not report this as a success. If a indirect write was not
1812         // previously completed, it may be cleared already, at which point
1813         // alt_qspi_indirect_write_is_complete() will never report true.
1814         return ALT_E_ERROR;
1815     }
1816 
1817     if (num_bytes > 256)
1818     {
1819         // The Micron part can only write up to 256 bytes at a time.
1820         return ALT_E_ERROR;
1821     }
1822 
1823     if (flash_addr > qspi_device_size)
1824     {
1825         return ALT_E_ERROR;
1826     }
1827 
1828     if (flash_addr + num_bytes > qspi_device_size)
1829     {
1830         return ALT_E_ERROR;
1831     }
1832 
1833 /*
1834     // Verify request does not cross bank boundary.
1835     // This limitation is due to the 3-byte addressing limitation.
1836     if ((flash_addr & ALT_QSPI_BANK_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_BANK_ADDR_MSK))
1837     {
1838         return ALT_E_ERROR;
1839     }
1840 */
1841     // Verify request does not cross page boundary.
1842     // This limitation is in place for the Micron part used.
1843     if ((flash_addr & ALT_QSPI_PAGE_ADDR_MSK) != ((flash_addr + num_bytes - 1) & ALT_QSPI_PAGE_ADDR_MSK))
1844     {
1845         return ALT_E_ERROR;
1846     }
1847 
1848     // Verify that there is not already a write in progress.
1849     if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1850     {
1851         return ALT_E_ERROR;
1852     }
1853 
1854     /////
1855 
1856     ALT_STATUS_CODE status = ALT_E_SUCCESS;
1857     status = alt_qspi_device_bank_select(flash_addr >> 24);
1858     if (status != ALT_E_SUCCESS)
1859     {
1860         return status;
1861     }
1862 
1863     /////
1864 
1865     return alt_qspi_indirect_write_start_bank(flash_addr,
1866                                               num_bytes);
1867 }
1868 
1869 ALT_STATUS_CODE alt_qspi_indirect_write_finish(void)
1870 {
1871 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1872     return alt_qspi_N25Q_flag_wait_for_program(ALT_QSPI_TIMEOUT_INFINITE);
1873 #else
1874     return ALT_E_SUCCESS;
1875 #endif
1876 }
1877 
1878 ALT_STATUS_CODE alt_qspi_indirect_write_cancel(void)
1879 {
1880     ALT_STATUS_CODE status = ALT_E_SUCCESS;
1881 
1882 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1883     if (status == ALT_E_SUCCESS)
1884     {
1885         status = alt_qspi_N25Q_flag_wait_for_program(ALT_QSPI_TIMEOUT_INFINITE);
1886     }
1887 #endif
1888 
1889     if (status == ALT_E_SUCCESS)
1890     {
1891         // An indirect operation may be cancelled at any time by setting Indirect
1892         // Transfer Control Register bit [1].
1893         alt_write_word(ALT_QSPI_INDWR_ADDR, ALT_QSPI_INDWR_CANCEL_SET_MSK);
1894     }
1895 
1896     return status;
1897 }
1898 
1899 uint32_t alt_qspi_indirect_write_fill_level(void)
1900 {
1901     // Return the SRAM Fill Level (Indirect Write Partition) Field of the SRAM
1902     // Fill Register to get the SRAM Fill Level for the Indirect Write Partition
1903     // in units of SRAM Words (4 bytes).
1904     return ALT_QSPI_SRAMFILL_INDWRPART_GET(alt_read_word(ALT_QSPI_SRAMFILL_ADDR));
1905 }
1906 
1907 uint32_t alt_qspi_indirect_write_watermark_get(void)
1908 {
1909     // Return the Watermark value in the Indirect Write Transfer Watermark Register.
1910     return alt_read_word(ALT_QSPI_INDWRWATER_ADDR);
1911 }
1912 
1913 ALT_STATUS_CODE alt_qspi_indirect_write_watermark_set(const uint32_t watermark)
1914 {
1915     // Verify that there is not already a write in progress.
1916     if (ALT_QSPI_INDWR_RDSTAT_GET(alt_read_word(ALT_QSPI_INDWR_ADDR)))
1917     {
1918         return ALT_E_ERROR;
1919     }
1920 
1921     // Set the Watermark value in the Indirect Write Transfer Watermark Register.
1922     alt_write_word(ALT_QSPI_INDWRWATER_ADDR, watermark);
1923 
1924     return ALT_E_SUCCESS;
1925 }
1926 
1927 bool alt_qspi_indirect_write_is_complete(void)
1928 {
1929     // The value of the Indirect Completion Status Field of the Indirect Write
1930     // Transfer Control Register is set by hardware when an indirect write
1931     // operation has completed.
1932     return (alt_read_word(ALT_QSPI_INDWR_ADDR) & ALT_QSPI_INDWR_INDDONE_SET_MSK) != 0;
1933 }
1934 
1935 /////
1936 
1937 uint32_t alt_qspi_sram_partition_get(void)
1938 {
1939     // The number of locations allocated to indirect read is equal to the value
1940     // of the SRAM partition register. See the documentation for this function
1941     // regarding the + 1 in the IP documentation. This way the get() and set()
1942     // will be symmetrical.
1943 
1944     return ALT_QSPI_SRAMPART_ADDR_GET(alt_read_word(ALT_QSPI_SRAMPART_ADDR));
1945 }
1946 
1947 ALT_STATUS_CODE alt_qspi_sram_partition_set(const uint32_t read_part_size)
1948 {
1949     if (read_part_size > ((1 << ALT_QSPI_SRAMPART_ADDR_WIDTH) - 1))
1950     {
1951         return ALT_E_ARG_RANGE;
1952     }
1953 
1954     alt_replbits_word(ALT_QSPI_SRAMPART_ADDR,
1955                       ALT_QSPI_SRAMPART_ADDR_SET_MSK,
1956                       ALT_QSPI_SRAMPART_ADDR_SET(read_part_size));
1957 
1958     return ALT_E_SUCCESS;
1959 }
1960 
1961 /////
1962 
1963 
1964 static ALT_STATUS_CODE alt_qspi_erase_subsector_bank(uint32_t addr)
1965 {
1966     ALT_STATUS_CODE status = ALT_E_SUCCESS;
1967 
1968     if (status == ALT_E_SUCCESS)
1969     {
1970         status = alt_qspi_device_wren();
1971     }
1972     
1973     if (status == ALT_E_SUCCESS)
1974     {
1975         status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0, addr, 10000);
1976     }
1977 
1978 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
1979     if (status == ALT_E_SUCCESS)
1980     {
1981         status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
1982     }
1983 #endif
1984 
1985     return status;
1986 }
1987 
1988 ALT_STATUS_CODE alt_qspi_erase_subsector(const uint32_t addr)
1989 {
1990     ALT_STATUS_CODE status = ALT_E_SUCCESS;
1991 
1992     if (status == ALT_E_SUCCESS)
1993     {
1994         status = alt_qspi_device_bank_select(addr >> 24);
1995     }
1996 
1997     if (status == ALT_E_SUCCESS)
1998     {
1999         status = alt_qspi_erase_subsector_bank(addr);
2000     }
2001 
2002     return status;
2003 }
2004 
2005 ALT_STATUS_CODE alt_qspi_erase_sector(const uint32_t addr)
2006 {
2007     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2008 
2009     if (status == ALT_E_SUCCESS)
2010     {
2011         status = alt_qspi_device_bank_select(addr >> 24);
2012     }
2013 
2014     if (status == ALT_E_SUCCESS)
2015     {
2016         status = alt_qspi_device_wren();
2017     }
2018 
2019     if (status == ALT_E_SUCCESS)
2020     {
2021         status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_SEC_ERASE, 0, addr, ALT_QSPI_TIMEOUT_INFINITE);
2022     }
2023 
2024 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2025     if (status == ALT_E_SUCCESS)
2026     {
2027         status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2028     }
2029 #endif
2030 
2031     return status;
2032 }
2033 
2034 ALT_STATUS_CODE alt_qspi_erase_chip(void)
2035 {
2036     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2037 
2038     if (qspi_device_size >= (2 * ALT_QSPI_N25Q_DIE_SIZE))
2039     {
2040         // NOTE: This path is specifically for 512 Mib and 1 Gib Micron N25Q
2041         //   chips only.
2042 
2043         dprintf("DEBUG[QSPI]: erase[chip]: FYI, wait time is ~800s for 128 MiB.\n");
2044 
2045         uint32_t die_count = qspi_device_size / ALT_QSPI_N25Q_DIE_SIZE;
2046 
2047         for (int i = 0; i < die_count; ++i)
2048         {
2049             if (status != ALT_E_SUCCESS)
2050             {
2051                 break;
2052             }
2053 
2054             dprintf("DEBUG[QSPI]: Erase chip: die = %d, total = %" PRIu32 ".\n", i, die_count);
2055 
2056             if (status == ALT_E_SUCCESS)
2057             {
2058                 status = alt_qspi_device_bank_select(i * (ALT_QSPI_N25Q_DIE_SIZE / ALT_QSPI_BANK_SIZE));
2059             }
2060 
2061             if (status == ALT_E_SUCCESS)
2062             {
2063                 status = alt_qspi_device_wren(); 
2064             }
2065 
2066             if (status == ALT_E_SUCCESS)
2067             {
2068                 status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_DIE_ERASE, 0,
2069                                                 i * ALT_QSPI_N25Q_DIE_SIZE,
2070                                                 ALT_QSPI_TIMEOUT_INFINITE);
2071             }
2072 
2073 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2074             if (status == ALT_E_SUCCESS)
2075             {
2076                 status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2077             }
2078 #endif
2079         }
2080     }
2081     else
2082     {
2083         // NOTE: Untested path.
2084 
2085         dprintf("DEBUG[QSPI]: Bulk erase.\n");
2086 
2087         if (status == ALT_E_SUCCESS)
2088         {
2089             status = alt_qspi_device_bank_select(0);
2090         }
2091 
2092         if (status == ALT_E_SUCCESS)
2093         {
2094             status = alt_qspi_device_wren();
2095         }
2096 
2097         if (status == ALT_E_SUCCESS)
2098         {
2099             // If BULK_ERASE is like other ERASE, it needs the address command.
2100             status = alt_qspi_stig_addr_cmd(ALT_QSPI_STIG_OPCODE_BULK_ERASE, 0,
2101                                             0,
2102                                             ALT_QSPI_TIMEOUT_INFINITE);
2103         }
2104 
2105 #if ALT_QSPI_PROVISION_MICRON_N25Q_SUPPORT
2106         if (status == ALT_E_SUCCESS)
2107         {
2108             status = alt_qspi_N25Q_flag_wait_for_erase(ALT_QSPI_TIMEOUT_INFINITE);
2109         }
2110 #endif
2111     }
2112 
2113     return status;
2114 }
2115 
2116 /////
2117 
2118 ALT_STATUS_CODE alt_qspi_dma_disable(void)
2119 {
2120     // Clear (set to 0) the Enable DMA Peripheral Interface Field of the QSPI
2121     // Configuration Register to disable the DMA peripheral interface.
2122     alt_clrbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDMA_SET_MSK);
2123 
2124     return ALT_E_SUCCESS;
2125 }
2126 
2127 ALT_STATUS_CODE alt_qspi_dma_enable(void)
2128 {
2129     // Set (set to 1) the Enable DMA Peripheral Interface Field of the QSPI
2130     // Configuration Register to enable the DMA peripheral interface.
2131     alt_setbits_word(ALT_QSPI_CFG_ADDR, ALT_QSPI_CFG_ENDMA_SET_MSK);
2132 
2133     return ALT_E_SUCCESS;
2134 }
2135 
2136 ALT_STATUS_CODE alt_qspi_dma_config_get(uint32_t * single_type_sz,
2137                                         uint32_t * burst_type_sz)
2138 {
2139     // Get the current value of the DMA Peripheral Register - dmaper
2140     uint32_t dmaper = alt_read_word(ALT_QSPI_DMAPER_ADDR);
2141 
2142     // For both values, a programmed value of 0 represents a single byte. The
2143     // actual number of bytes used is 2 ** (value in this register field).
2144     *single_type_sz = 1 << ALT_QSPI_DMAPER_NUMSGLREQBYTES_GET(dmaper);
2145     *burst_type_sz  = 1 << ALT_QSPI_DMAPER_NUMBURSTREQBYTES_GET(dmaper);
2146 
2147     return ALT_E_SUCCESS;
2148 }
2149 
2150 //
2151 // Returns true if [n] is a power of 2 value otherwise returns false.
2152 //
2153 static bool is_pow_2(uint32_t n)
2154 {
2155     return ((n > 0) && ((n & (n - 1)) == 0));
2156 }
2157 
2158 //
2159 // Return the log base 2 value of a number that is known to be a power of 2.
2160 //
2161 static uint32_t log2u(uint32_t value)
2162 {
2163     uint32_t exp = 0;
2164     while ((exp < 32) && (value != (1 << exp)))
2165     {
2166         ++exp;
2167     }
2168     return exp;
2169 }
2170 
2171 ALT_STATUS_CODE alt_qspi_dma_config_set(const uint32_t single_type_sz,
2172                                         const uint32_t burst_type_sz)
2173 {
2174     if (alt_qspi_is_idle() == false)
2175     {
2176         return ALT_E_ERROR;
2177     }
2178 
2179     if (single_type_sz < 4)
2180     {
2181         return ALT_E_ERROR;
2182     }
2183 
2184     if (burst_type_sz < 4)
2185     {
2186         return ALT_E_ERROR;
2187     }
2188 
2189     if (burst_type_sz < single_type_sz)
2190     {
2191         return ALT_E_ERROR;
2192     }
2193 
2194     const uint32_t single_type_sz_max = 1 << ((1 << ALT_QSPI_DMAPER_NUMSGLREQBYTES_WIDTH) - 1);
2195     const uint32_t burst_type_sz_max  = 1 << ((1 << ALT_QSPI_DMAPER_NUMBURSTREQBYTES_WIDTH) - 1);
2196 
2197     // Both parameter values must be a power of 2 between 1 and 32728.
2198     if (  (single_type_sz > single_type_sz_max) || !is_pow_2(single_type_sz)
2199        || (burst_type_sz  > burst_type_sz_max)  || !is_pow_2(burst_type_sz)
2200        )
2201     {
2202         return ALT_E_ARG_RANGE;
2203     }
2204 
2205     // Get the current value of the DMA Peripheral Register - dmaper
2206     uint32_t dmaper = alt_read_word(ALT_QSPI_DMAPER_ADDR);
2207     dmaper &= ALT_QSPI_DMAPER_NUMBURSTREQBYTES_CLR_MSK &
2208               ALT_QSPI_DMAPER_NUMSGLREQBYTES_CLR_MSK;
2209     dmaper |= ALT_QSPI_DMAPER_NUMBURSTREQBYTES_SET(log2u(burst_type_sz)) |
2210               ALT_QSPI_DMAPER_NUMSGLREQBYTES_SET(log2u(single_type_sz));
2211     alt_write_word(ALT_QSPI_DMAPER_ADDR, dmaper);
2212 
2213     return ALT_E_SUCCESS;
2214 }
2215 
2216 /////
2217 
2218 //
2219 // Private STIG and device commands
2220 //
2221 
2222 static ALT_STATUS_CODE alt_qspi_stig_cmd_helper(uint32_t reg_value, uint32_t timeout)
2223 {
2224     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2225     bool infinite = (timeout == ALT_QSPI_TIMEOUT_INFINITE);
2226 
2227     alt_write_word(ALT_QSPI_FLSHCMD_ADDR, reg_value);
2228     alt_write_word(ALT_QSPI_FLSHCMD_ADDR, reg_value | ALT_QSPI_FLSHCMD_EXECCMD_E_EXECUTE);
2229 
2230     do
2231     {
2232         reg_value = alt_read_word(ALT_QSPI_FLSHCMD_ADDR);
2233         if (!(reg_value & ALT_QSPI_FLSHCMD_CMDEXECSTAT_SET_MSK))
2234         {
2235             break;
2236         }
2237 
2238     } while (timeout-- || infinite);
2239 
2240     if (timeout == (uint32_t)-1 && !infinite)
2241     {
2242         status = ALT_E_TMO;
2243     }
2244 
2245     return status;
2246 }
2247 
2248 ALT_STATUS_CODE alt_qspi_stig_cmd(uint32_t opcode, uint32_t dummy, uint32_t timeout)
2249 {
2250     if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2251     {
2252         return ALT_E_ERROR;
2253     }
2254 
2255     uint32_t reg = ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode) |
2256                    ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2257 
2258     return alt_qspi_stig_cmd_helper(reg, timeout);
2259 }
2260 
2261 ALT_STATUS_CODE alt_qspi_stig_rd_cmd(uint8_t opcode,
2262                                      uint32_t dummy,
2263                                      uint32_t num_bytes,
2264                                      uint32_t * output,
2265                                      uint32_t timeout)
2266 {
2267     if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2268     {
2269         return ALT_E_ERROR;
2270     }
2271 
2272     // STIG read can only return up to 8 bytes.
2273     if ((num_bytes > 8) || (num_bytes == 0))
2274     {
2275         return ALT_E_BAD_ARG;
2276     }
2277 
2278     uint32_t reg_value = 
2279         ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode)                              |
2280         ALT_QSPI_FLSHCMD_ENRDDATA_SET(ALT_QSPI_FLSHCMD_ENRDDATA_E_EN)       |
2281         ALT_QSPI_FLSHCMD_NUMRDDATABYTES_SET(num_bytes - 1)                  |
2282         ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_DISD)   |
2283         ALT_QSPI_FLSHCMD_ENMODBIT_SET(ALT_QSPI_FLSHCMD_ENMODBIT_E_DISD)     |
2284         ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(0)                                |
2285         ALT_QSPI_FLSHCMD_ENWRDATA_SET(ALT_QSPI_FLSHCMD_ENWRDATA_E_NOACTION) |
2286         ALT_QSPI_FLSHCMD_NUMWRDATABYTES_SET(0)                              |
2287         ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2288 
2289     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2290 
2291     status = alt_qspi_stig_cmd_helper(reg_value, timeout);
2292     if (status != ALT_E_SUCCESS)
2293     {
2294         return status;
2295     }
2296 
2297     output[0] = alt_read_word(ALT_QSPI_FLSHCMDRDDATALO_ADDR);
2298 
2299     if (num_bytes > 4)
2300     {
2301         output[1] = alt_read_word(ALT_QSPI_FLSHCMDRDDATAUP_ADDR);
2302     }
2303 
2304     return ALT_E_SUCCESS;
2305 }
2306 
2307 ALT_STATUS_CODE alt_qspi_stig_wr_cmd(uint8_t opcode,
2308                                      uint32_t dummy,
2309                                      uint32_t num_bytes, 
2310                                      const uint32_t * input,
2311                                      uint32_t timeout)
2312 {
2313     if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2314     {
2315         return ALT_E_ERROR;
2316     }
2317 
2318     // STIG can only write up to 8 bytes.
2319     if ((num_bytes > 8) || (num_bytes == 0))
2320     {
2321         return ALT_E_BAD_ARG;
2322     }
2323 
2324     uint32_t reg_value =
2325         ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode)                                 |
2326         ALT_QSPI_FLSHCMD_ENRDDATA_SET(ALT_QSPI_FLSHCMD_ENRDDATA_E_NOACTION)    |
2327         ALT_QSPI_FLSHCMD_NUMRDDATABYTES_SET(0)                                 |
2328         ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_DISD)      |
2329         ALT_QSPI_FLSHCMD_ENMODBIT_SET(ALT_QSPI_FLSHCMD_ENMODBIT_E_DISD)        |
2330         ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(0)                                   |
2331         ALT_QSPI_FLSHCMD_ENWRDATA_SET(ALT_QSPI_FLSHCMD_ENWRDATA_E_WRDATABYTES) |
2332         ALT_QSPI_FLSHCMD_NUMWRDATABYTES_SET(num_bytes - 1)                     |
2333         ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2334 
2335     alt_write_word(ALT_QSPI_FLSHCMDWRDATALO_ADDR, input[0]);
2336 
2337     if (num_bytes > 4)
2338     {
2339         alt_write_word(ALT_QSPI_FLSHCMDWRDATAUP_ADDR, input[1]);
2340     }
2341 
2342     return alt_qspi_stig_cmd_helper(reg_value, timeout);
2343 }
2344 
2345 ALT_STATUS_CODE alt_qspi_stig_addr_cmd(uint8_t opcode,
2346                                        uint32_t dummy,
2347                                        uint32_t address,
2348                                        uint32_t timeout)
2349 {
2350     if (dummy > ((1 << ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_WIDTH) - 1))
2351     {
2352         return ALT_E_ERROR;
2353     }
2354 
2355     uint32_t reg = ALT_QSPI_FLSHCMD_CMDOPCODE_SET(opcode) |
2356                    ALT_QSPI_FLSHCMD_NUMDUMMYBYTES_SET(dummy);
2357 
2358     reg |= ALT_QSPI_FLSHCMD_ENCMDADDR_SET(ALT_QSPI_FLSHCMD_ENCMDADDR_E_END);
2359     reg |= ALT_QSPI_FLSHCMD_NUMADDRBYTES_SET(ALT_QSPI_FLSHCMD_NUMADDRBYTES_E_ADDRBYTE3);
2360 
2361     alt_write_word(ALT_QSPI_FLSHCMDADDR_ADDR, address);
2362 
2363     return alt_qspi_stig_cmd_helper(reg, timeout);
2364 }
2365 
2366 /////
2367 
2368 ALT_STATUS_CODE alt_qspi_device_wren(void) 
2369 {
2370     // Write enable through STIG (not required, auto send by controller during write)
2371     return alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_WREN, 0, 10000);
2372 }
2373 
2374 ALT_STATUS_CODE alt_qspi_device_wrdis(void) 
2375 {
2376     // Write disable through STIG (not required, auto send by controller during write)
2377     return alt_qspi_stig_cmd(ALT_QSPI_STIG_OPCODE_WRDIS, 0, 10000);
2378 }
2379 
2380 ALT_STATUS_CODE alt_qspi_device_rdid(uint32_t * rdid)
2381 {
2382     // Read flash device ID through STIG
2383     return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_RDID, 0, 4, rdid, 10000);
2384 }
2385 
2386 ALT_STATUS_CODE alt_qspi_discovery_parameter(uint32_t * param)
2387 {
2388     // Read flash discovery parameters through STIG
2389 
2390     return alt_qspi_stig_rd_cmd(ALT_QSPI_STIG_OPCODE_DISCVR_PARAM, 8, 8, param, 10000);
2391 }
2392 
2393 ALT_STATUS_CODE alt_qspi_device_bank_select(uint32_t bank) 
2394 {
2395     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2396     dprintf("DEBUG[QSPI]: bank_select(): switching to bank 0x%" PRIu32 ".\n", bank);
2397 
2398     if (status == ALT_E_SUCCESS)
2399     {
2400         status = alt_qspi_device_wren();
2401     }
2402 
2403     if (status == ALT_E_SUCCESS)
2404     {
2405         status = alt_qspi_stig_wr_cmd(ALT_QSPI_STIG_OPCODE_WR_EXT_REG, 0, 1, &bank, 10000);
2406     }
2407 
2408     if (status == ALT_E_SUCCESS)
2409     {
2410         status = alt_qspi_device_wrdis();
2411     }
2412 
2413     return status;
2414 }
2415 
2416 /////
2417 
2418 static bool alt_qspi_is_enabled(void)
2419 {
2420     uint32_t cfg = alt_read_word(ALT_QSPI_CFG_ADDR);
2421 
2422     if (cfg & ALT_QSPI_CFG_EN_SET_MSK)
2423     {
2424         return true;
2425     }
2426     else
2427     {
2428         return false;
2429     }
2430 }
2431 
2432 ALT_STATUS_CODE alt_qspi_ecc_start(void * block, size_t size)
2433 {
2434     if (size < (ALT_QSPI_PAGE_SIZE * 8))
2435     {
2436         return ALT_E_ERROR;
2437     }
2438 
2439     if (alt_qspi_is_enabled() == false)
2440     {
2441         return ALT_E_ERROR;
2442     }
2443 
2444     if (alt_qspi_is_idle() == false)
2445     {
2446         return ALT_E_ERROR;
2447     }
2448 
2449     ALT_STATUS_CODE status = ALT_E_SUCCESS;
2450 
2451     // 1. Configure SRAM Partition Register to 126 words for read, 2 words for write.
2452     // 2. Enable ECC on QSPI RAM
2453     // 3. Trigger an indirect read transfer that will fill up 126 words in FIFO by
2454     //    monitoring read FIFO fill level; Do not read out data through AHB.
2455     // 4. Start AHB read and start indirect write operation to write back to the same
2456     //    device location, this will fill up and initilaize the write partition RAM.
2457     // 5. To clear spurious interrupts, reset the QSPI controller.
2458 
2459     // Save the previous partition size
2460 
2461     uint32_t sram_orig = alt_qspi_sram_partition_get();
2462     dprintf("DEBUG[QSPI][ECC]: Save original SRAM as %" PRIu32 ".\n", sram_orig);
2463 
2464     // Step 1
2465 
2466     uint32_t sram_fill = (1 << ALT_QSPI_SRAMPART_ADDR_WIDTH) - 2;
2467     alt_qspi_sram_partition_set(sram_fill);
2468     dprintf("DEBUG[QSPI][ECC]: Set new SRAM as %" PRIu32 ".\n", sram_fill);
2469 
2470     // Step 2
2471 
2472     dprintf("DEBUG[QSPI][ECC]: Enable ECC in SysMgr.\n");
2473     alt_write_word(ALT_SYSMGR_ECC_QSPI_ADDR, ALT_SYSMGR_ECC_QSPI_EN_SET_MSK);
2474 
2475     // Step 3
2476 
2477     // Issue a read ~ 2x larger than the read partition. We will read out 1 page,
2478     // which will be used as the buffer to write back to QSPI. This way no data
2479     // actually changes thus no erase will be needed.
2480 
2481     if (status == ALT_E_SUCCESS)
2482     {
2483         dprintf("DEBUG[QSPI][ECC]: Start indirect read PAGE * 8.\n");
2484         status = alt_qspi_indirect_read_start(0x0, ALT_QSPI_PAGE_SIZE * 8);
2485     }
2486 
2487     // Read out 1 page for the write data
2488 
2489     if (status == ALT_E_SUCCESS)
2490     {
2491         dprintf("DEBUG[QSPI][ECC]: Reading out 1 page ...\n");
2492 
2493         uint32_t read_size = 0;
2494         char *   buffer    = block;
2495         while (read_size < ALT_QSPI_PAGE_SIZE)
2496         {
2497             uint32_t level = alt_qspi_indirect_read_fill_level();
2498             level = MIN(level, (ALT_QSPI_PAGE_SIZE - read_size) / sizeof(uint32_t));
2499 
2500             uint32_t * data = (uint32_t *)(&buffer[read_size]);
2501             for (uint32_t i = 0; i < level; ++i)
2502             {
2503                 *data = alt_read_word(ALT_QSPIDATA_ADDR);
2504                 ++data;
2505             }
2506 
2507             read_size += level * sizeof(uint32_t);
2508         }
2509 
2510         if (read_size != ALT_QSPI_PAGE_SIZE)
2511         {
2512             status = ALT_E_ERROR;
2513         }
2514     }
2515 
2516     // Wait for read FIFO to report it is up to the specified fill level.
2517 
2518     if (status == ALT_E_SUCCESS)
2519     {
2520         dprintf("DEBUG[QSPI][ECC]: Waiting for read fill level ...\n");
2521 
2522         uint32_t timeout = 10000;
2523 
2524         while (alt_qspi_indirect_read_fill_level() < sram_fill)
2525         {
2526             if (--timeout == 0)
2527             {
2528                 dprintf("DEBUG[QSPI][ECC]: Waiting for read fill timeout !!!\n");
2529                 status = ALT_E_TMO;
2530                 break;
2531             }
2532         }
2533     }
2534 
2535     // Step 4
2536 
2537     // Issue a write of 1 page of the same data from 0x0.
2538 
2539     if (status == ALT_E_SUCCESS)
2540     {
2541         dprintf("DEBUG[QSPI][ECC]: Start indirect write PAGE.\n");
2542         status = alt_qspi_indirect_write_start(0x0, ALT_QSPI_PAGE_SIZE);
2543     }
2544 
2545     if (status == ALT_E_SUCCESS)
2546     {
2547         dprintf("DEBUG[QSPI][ECC]: Writing in 1 page ...\n");
2548 
2549         uint32_t write_size = 0;
2550         char *   buffer     = block;
2551 
2552         while (write_size < ALT_QSPI_PAGE_SIZE)
2553         {
2554             uint32_t space = 2 - alt_qspi_indirect_write_fill_level();
2555             if (space == 0)
2556             {
2557                 dprintf("DEBUG[QSPI][ECC]: Write FIFO filled at write_size = %" PRIu32 ".\n", write_size);
2558                 // Space = 0; which means all 2 positions in the write FIFO is filled,
2559                 // meaning it has been initialized with respect to ECC.
2560                 break;
2561             }
2562 
2563             space = MIN(space, (ALT_QSPI_PAGE_SIZE - write_size) / sizeof(uint32_t));
2564 
2565             uint32_t * data = (uint32_t *)(&buffer[write_size]);
2566             for (uint32_t i = 0; i < space; ++i)
2567             {
2568                 alt_write_word(ALT_QSPIDATA_ADDR, *data);
2569                 ++data;
2570             }
2571 
2572             write_size += space * sizeof(uint32_t);
2573         }
2574 
2575         if (write_size != ALT_QSPI_PAGE_SIZE)
2576         {
2577             dprintf("DEBUG[QSPI][ECC]: Cancel indirect write.\n");
2578             status = alt_qspi_indirect_write_cancel();
2579         }
2580     }
2581 
2582     if (status == ALT_E_SUCCESS)
2583     {
2584         dprintf("DEBUG[QSPI][ECC]: Finish indirect write.\n");
2585         status = alt_qspi_indirect_write_finish();
2586     }
2587 
2588     // Cancel the indirect read as it has initialized the read FIFO partition.
2589 
2590     if (status == ALT_E_SUCCESS)
2591     {
2592         dprintf("DEBUG[QSPI][ECC]: Cancel indirect read.\n");
2593         status = alt_qspi_indirect_read_cancel();
2594     }
2595 
2596     if (status == ALT_E_SUCCESS)
2597     {
2598         dprintf("DEBUG[QSPI][ECC]: Finish indirect read.\n");
2599         status = alt_qspi_indirect_read_finish();
2600     }
2601 
2602     // Step 5
2603 
2604     if (status == ALT_E_SUCCESS)
2605     {
2606         dprintf("DEBUG[QSPI][ECC]: Clear any pending spurious QSPI ECC interrupts.\n");
2607 
2608         alt_write_word(ALT_SYSMGR_ECC_QSPI_ADDR,
2609                          ALT_SYSMGR_ECC_QSPI_EN_SET_MSK
2610                        | ALT_SYSMGR_ECC_QSPI_SERR_SET_MSK
2611                        | ALT_SYSMGR_ECC_QSPI_DERR_SET_MSK);
2612     }
2613 
2614     /////
2615 
2616     // Restore original partition
2617 
2618     if (status == ALT_E_SUCCESS)
2619     {
2620         dprintf("DEBUG[QSPI][ECC]: Restore original SRAM as %" PRIu32 ".\n", sram_orig);
2621         status = alt_qspi_sram_partition_set(sram_orig);
2622     }
2623 
2624     return status;
2625 }